diff options
415 files changed, 7475 insertions, 3633 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0934e42b277..de144ee6104 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,6 +70,7 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }} SCCACHE_BUCKET: rust-lang-ci-sccache2 + SCCACHE_REGION: us-west-1 CACHE_DOMAIN: ci-caches.rust-lang.org continue-on-error: ${{ matrix.continue_on_error || false }} strategy: @@ -173,6 +174,11 @@ jobs: - name: ensure the stable version number is correct run: src/ci/scripts/verify-stable-version-number.sh + # Show the environment just before we run the build + # This makes it easier to diagnose problems with the above install scripts. + - name: show the current environment + run: src/ci/scripts/dump-environment.sh + - name: run the build # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. run: src/ci/scripts/run-build-from-ci.sh 2>&1 diff --git a/Cargo.lock b/Cargo.lock index e9ee3c6b36e..c31fed86bc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,19 +62,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] -name = "ammonia" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" -dependencies = [ - "html5ever", - "maplit", - "once_cell", - "tendril", - "url", -] - -[[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -513,16 +500,6 @@ dependencies = [ "anstyle", "clap_lex", "strsim", - "terminal_size", -] - -[[package]] -name = "clap_complete" -version = "4.5.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" -dependencies = [ - "clap", ] [[package]] @@ -1085,18 +1062,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] -name = "elasticlunr-rs" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e83863a500656dfa214fee6682de9c5b9f03de6860fec531235ed2ae9f6571" -dependencies = [ - "regex", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] name = "elsa" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1160,13 +1125,6 @@ dependencies = [ ] [[package]] -name = "error_index_generator" -version = "0.0.0" -dependencies = [ - "mdbook", -] - -[[package]] name = "expect-test" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1518,22 +1476,6 @@ dependencies = [ ] [[package]] -name = "handlebars" -version = "6.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6b224b95c1e668ac0270325ad563b2eef1469fbbb8959bc7c692c844b813d9" -dependencies = [ - "derive_builder", - "log", - "num-order", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror 2.0.11", -] - -[[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2190,12 +2132,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] name = "markup5ever" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2229,34 +2165,6 @@ dependencies = [ ] [[package]] -name = "mdbook" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" -dependencies = [ - "ammonia", - "anyhow", - "chrono", - "clap", - "clap_complete", - "elasticlunr-rs", - "env_logger", - "handlebars", - "log", - "memchr", - "once_cell", - "opener", - "pulldown-cmark 0.10.3", - "regex", - "serde", - "serde_json", - "shlex", - "tempfile", - "toml 0.5.11", - "topological-sort", -] - -[[package]] name = "measureme" version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2303,9 +2211,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf47565b1430f5fe6c81d3afcb4b835271348d7eb35294a4d592e38dd09ea22" +checksum = "9bfdc64e2f805f3d12965f10522000bae36e88d2cfea44112331f467d4f4bf68" [[package]] name = "minimal-lexical" @@ -2484,21 +2392,6 @@ dependencies = [ ] [[package]] -name = "num-modular" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" - -[[package]] -name = "num-order" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" -dependencies = [ - "num-modular", -] - -[[package]] name = "num-rational" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2719,51 +2612,6 @@ dependencies = [ ] [[package]] -name = "pest" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" -dependencies = [ - "memchr", - "thiserror 2.0.11", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.96", -] - -[[package]] -name = "pest_meta" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] name = "phf" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2923,36 +2771,18 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" -dependencies = [ - "bitflags", - "memchr", - "pulldown-cmark-escape 0.10.1", - "unicase", -] - -[[package]] -name = "pulldown-cmark" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ "bitflags", "memchr", - "pulldown-cmark-escape 0.11.0", + "pulldown-cmark-escape", "unicase", ] [[package]] name = "pulldown-cmark-escape" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" - -[[package]] -name = "pulldown-cmark-escape" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" @@ -3918,7 +3748,6 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_ast_ir", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -3983,7 +3812,6 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "rustc_ast_ir", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4174,7 +4002,6 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", - "rustc_ast_ir", "rustc_attr_parsing", "rustc_data_structures", "rustc_error_messages", @@ -4304,7 +4131,6 @@ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ "derive-where", - "rustc_ast_ir", "rustc_data_structures", "rustc_index", "rustc_macros", @@ -4624,7 +4450,6 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_ast_ir", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -4663,7 +4488,6 @@ version = "0.0.0" dependencies = [ "itertools", "rustc_abi", - "rustc_ast_ir", "rustc_data_structures", "rustc_hir", "rustc_infer", @@ -4679,7 +4503,6 @@ version = "0.0.0" dependencies = [ "itertools", "rustc_abi", - "rustc_ast_ir", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -5311,16 +5134,6 @@ dependencies = [ ] [[package]] -name = "terminal_size" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" -dependencies = [ - "rustix", - "windows-sys 0.59.0", -] - -[[package]] name = "termize" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5561,12 +5374,6 @@ dependencies = [ ] [[package]] -name = "topological-sort" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" - -[[package]] name = "tracing" version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5687,12 +5494,6 @@ dependencies = [ ] [[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - -[[package]] name = "ui_test" version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 97e782d0df0..20a43aaaeeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "src/tools/clippy/clippy_dev", "src/tools/compiletest", "src/tools/run-make-support", - "src/tools/error_index_generator", "src/tools/linkchecker", "src/tools/lint-docs", "src/tools/miropt-test-tools", diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 9fb70b80c9e..4529ab8058e 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -65,8 +65,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty: TyAbiInterface<'a, C> + Copy, { match self.backend_repr { - BackendRepr::Uninhabited => Err(Heterogeneous), - // The primitive for this algorithm. BackendRepr::Scalar(scalar) => { let kind = match scalar.primitive() { diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 45cd0b517f6..53243266f99 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -130,6 +130,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { }, backend_repr: BackendRepr::ScalarPair(a, b), largest_niche, + uninhabited: false, align, size, max_repr_align: None, @@ -221,8 +222,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { LayoutData { variants: Variants::Empty, fields: FieldsShape::Primitive, - backend_repr: BackendRepr::Uninhabited, + backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, + uninhabited: true, align: dl.i8_align, size: Size::ZERO, max_repr_align: None, @@ -400,6 +402,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { fields: FieldsShape::Union(union_field_count), backend_repr: abi, largest_niche: None, + uninhabited: false, align, size: size.align_to(align.abi), max_repr_align, @@ -447,7 +450,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Scalar::Union { .. } => {} }; match &mut st.backend_repr { - BackendRepr::Uninhabited => {} BackendRepr::Scalar(scalar) => hide_niches(scalar), BackendRepr::ScalarPair(a, b) => { hide_niches(a); @@ -639,9 +641,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let same_size = size == variant_layouts[largest_variant_index].size; let same_align = align == variant_layouts[largest_variant_index].align; - let abi = if variant_layouts.iter().all(|v| v.is_uninhabited()) { - BackendRepr::Uninhabited - } else if same_size && same_align && others_zst { + let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited()); + let abi = if same_size && same_align && others_zst { match variant_layouts[largest_variant_index].backend_repr { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. @@ -683,6 +684,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { }, backend_repr: abi, largest_niche, + uninhabited, size, align, max_repr_align, @@ -853,9 +855,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { }; let mut abi = BackendRepr::Memory { sized: true }; - if layout_variants.iter().all(|v| v.is_uninhabited()) { - abi = BackendRepr::Uninhabited; - } else if tag.size(dl) == size { + let uninhabited = layout_variants.iter().all(|v| v.is_uninhabited()); + if tag.size(dl) == size { // Make sure we only use scalar layout when the enum is entirely its // own tag (i.e. it has no padding nor any non-ZST variant fields). abi = BackendRepr::Scalar(tag); @@ -995,6 +996,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { memory_index: [0].into(), }, largest_niche, + uninhabited, backend_repr: abi, align, size, @@ -1355,9 +1357,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { _ => {} } } - if fields.iter().any(|f| f.is_uninhabited()) { - abi = BackendRepr::Uninhabited; - } + let uninhabited = fields.iter().any(|f| f.is_uninhabited()); let unadjusted_abi_align = if repr.transparent() { match layout_of_single_non_zst_field { @@ -1378,6 +1378,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { fields: FieldsShape::Arbitrary { offsets, memory_index }, backend_repr: abi, largest_niche, + uninhabited, align, size, max_repr_align, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index dbb4bed5cdd..098638b6bcf 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1404,7 +1404,6 @@ impl AddressSpace { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] pub enum BackendRepr { - Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), Vector { @@ -1423,10 +1422,9 @@ impl BackendRepr { #[inline] pub fn is_unsized(&self) -> bool { match *self { - BackendRepr::Uninhabited - | BackendRepr::Scalar(_) - | BackendRepr::ScalarPair(..) - | BackendRepr::Vector { .. } => false, + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { + false + } BackendRepr::Memory { sized } => !sized, } } @@ -1445,12 +1443,6 @@ impl BackendRepr { } } - /// Returns `true` if this is an uninhabited type - #[inline] - pub fn is_uninhabited(&self) -> bool { - matches!(*self, BackendRepr::Uninhabited) - } - /// Returns `true` if this is a scalar type #[inline] pub fn is_scalar(&self) -> bool { @@ -1471,7 +1463,7 @@ impl BackendRepr { BackendRepr::Vector { element, count } => { cx.data_layout().vector_align(element.size(cx) * count) } - BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, + BackendRepr::Memory { .. } => return None, }) } @@ -1492,7 +1484,7 @@ impl BackendRepr { // to make the size a multiple of align (e.g. for vectors of size 3). (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) } - BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, + BackendRepr::Memory { .. } => return None, }) } @@ -1506,9 +1498,7 @@ impl BackendRepr { BackendRepr::Vector { element, count } => { BackendRepr::Vector { element: element.to_union(), count } } - BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { - BackendRepr::Memory { sized: true } - } + BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, } } @@ -1704,6 +1694,11 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> { /// The leaf scalar with the largest number of invalid values /// (i.e. outside of its `valid_range`), if it exists. pub largest_niche: Option<Niche>, + /// Is this type known to be uninhabted? + /// + /// This is separate from BackendRepr because uninhabited return types can affect ABI, + /// especially in the case of by-pointer struct returns, which allocate stack even when unused. + pub uninhabited: bool, pub align: AbiAndPrefAlign, pub size: Size, @@ -1735,14 +1730,14 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.backend_repr { - BackendRepr::Uninhabited | BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => false, + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => false, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } /// Returns `true` if this is an uninhabited type pub fn is_uninhabited(&self) -> bool { - self.backend_repr.is_uninhabited() + self.uninhabited } pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { @@ -1778,6 +1773,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { fields: FieldsShape::Primitive, backend_repr: BackendRepr::Scalar(scalar), largest_niche, + uninhabited: false, size, align, max_repr_align: None, @@ -1802,6 +1798,7 @@ where backend_repr, fields, largest_niche, + uninhabited, variants, max_repr_align, unadjusted_abi_align, @@ -1813,6 +1810,7 @@ where .field("abi", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) + .field("uninhabited", uninhabited) .field("variants", variants) .field("max_repr_align", max_repr_align) .field("unadjusted_abi_align", unadjusted_abi_align) @@ -1877,7 +1875,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { false } - BackendRepr::Uninhabited => self.size.bytes() == 0, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } } diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index ff9d940ce9f..9884e191ea7 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -1,3 +1,10 @@ +//! Common utilities shared by both `rustc_ast` and `rustc_type_ir`. +//! +//! Don't depend on this crate directly; both of those crates should re-export +//! the functionality. Additionally, if you're in scope of `rustc_middle`, then +//! prefer imports via that too, to avoid needing to directly depend on (e.g.) +//! `rustc_type_ir` for a single import. + // tidy-alphabetical-start #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(never_type))] diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e778340cb65..b2cc58fbe11 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -18,12 +18,11 @@ use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, - Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, VarBindingForm, VarDebugInfoContents, + Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, StatementKind, + Terminator, TerminatorKind, VarBindingForm, VarDebugInfoContents, }; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index 26a090f5579..96f48840468 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use rustc_data_structures::fx::FxIndexSet; -use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; @@ -45,7 +45,22 @@ impl<'a, 'tcx> UseFinder<'a, 'tcx> { let block_data = &self.body[p.block]; - match self.def_use(p, block_data.visitable(p.statement_index)) { + let mut visitor = DefUseVisitor { + body: self.body, + tcx: self.tcx, + region_vid: self.region_vid, + def_use_result: None, + }; + + let is_statement = p.statement_index < block_data.statements.len(); + + if is_statement { + visitor.visit_statement(&block_data.statements[p.statement_index], p); + } else { + visitor.visit_terminator(block_data.terminator.as_ref().unwrap(), p); + } + + match visitor.def_use_result { Some(DefUseResult::Def) => {} Some(DefUseResult::UseLive { local }) => { @@ -57,7 +72,7 @@ impl<'a, 'tcx> UseFinder<'a, 'tcx> { } None => { - if p.statement_index < block_data.statements.len() { + if is_statement { queue.push_back(p.successor_within_block()); } else { queue.extend( @@ -77,19 +92,6 @@ impl<'a, 'tcx> UseFinder<'a, 'tcx> { None } - - fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> { - let mut visitor = DefUseVisitor { - body: self.body, - tcx: self.tcx, - region_vid: self.region_vid, - def_use_result: None, - }; - - thing.apply(location, &mut visitor); - - visitor.def_use_result - } } struct DefUseVisitor<'a, 'tcx> { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 07ea369c5c7..7da089c5e8c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,10 +13,9 @@ use rustc_infer::infer::{ }; use rustc_infer::traits::SelectionError; use rustc_middle::bug; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo, - LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, + LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, find_self_call, }; use rustc_middle::ty::print::Print; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 22ce0fd1ea7..a98984a4b4c 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -33,7 +33,6 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::fold::fold_regions; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index d2268c4779d..e0e3e028c61 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1267,6 +1267,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { let sub_region_scc = self.constraint_sccs.scc(sub_region); let sup_region_scc = self.constraint_sccs.scc(sup_region); + if sub_region_scc == sup_region_scc { + debug!("{sup_region:?}: {sub_region:?} holds trivially; they are in the same SCC"); + return true; + } + // If we are checking that `'sup: 'sub`, and `'sub` contains // some placeholder that `'sup` cannot name, then this is only // true if `'sup` outlives static. diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 62d49a62744..148e75aa84c 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -3,7 +3,8 @@ use rustc_index::bit_set::DenseBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::for_liveness; -use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; +use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location}; +use rustc_middle::span_bug; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; @@ -11,7 +12,10 @@ use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; -use rustc_span::DUMMY_SP; +use rustc_span::{DUMMY_SP, Span}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_trait_selection::traits::query::dropck_outlives; use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput}; use tracing::debug; @@ -162,9 +166,10 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) { for local in boring_locals { let local_ty = self.cx.body.local_decls[local].ty; + let local_span = self.cx.body.local_decls[local].source_info.span; let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({ let typeck = &self.cx.typeck; - move || LivenessContext::compute_drop_data(typeck, local_ty) + move || LivenessContext::compute_drop_data(typeck, local_ty, local_span) }); drop_data.dropck_result.report_overflows( @@ -522,9 +527,10 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { values::pretty_print_points(self.location_map, live_at.iter()), ); + let local_span = self.body.local_decls()[dropped_local].source_info.span; let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ let typeck = &self.typeck; - move || Self::compute_drop_data(typeck, dropped_ty) + move || Self::compute_drop_data(typeck, dropped_ty, local_span) }); if let Some(data) = &drop_data.region_constraint_data { @@ -589,19 +595,44 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { } } - fn compute_drop_data(typeck: &TypeChecker<'_, 'tcx>, dropped_ty: Ty<'tcx>) -> DropData<'tcx> { - debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); + fn compute_drop_data( + typeck: &TypeChecker<'_, 'tcx>, + dropped_ty: Ty<'tcx>, + span: Span, + ) -> DropData<'tcx> { + debug!("compute_drop_data(dropped_ty={:?})", dropped_ty); + + let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty }); - match typeck - .infcx - .param_env - .and(DropckOutlives { dropped_ty }) - .fully_perform(typeck.infcx, DUMMY_SP) - { + match op.fully_perform(typeck.infcx, DUMMY_SP) { Ok(TypeOpOutput { output, constraints, .. }) => { DropData { dropck_result: output, region_constraint_data: constraints } } - Err(_) => DropData { dropck_result: Default::default(), region_constraint_data: None }, + Err(_) => { + // We don't run dropck on HIR, and dropck looks inside fields of + // types, so there's no guarantee that it succeeds. We also + // can't rely on the the `ErrorGuaranteed` from `fully_perform` here + // because it comes from delay_span_bug. + let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx); + let errors = + match dropck_outlives::compute_dropck_outlives_with_errors(&ocx, op, span) { + Ok(_) => ocx.select_all_or_error(), + Err(e) => { + if e.is_empty() { + ocx.select_all_or_error() + } else { + e + } + } + }; + + if !errors.is_empty() { + typeck.infcx.err_ctxt().report_fulfillment_errors(errors); + } else { + span_bug!(span, "Rerunning drop data query produced no error."); + } + DropData { dropck_result: Default::default(), region_constraint_data: None } + } } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 93081919ec7..bd0d98028ae 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -19,7 +19,6 @@ use rustc_infer::infer::{ BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, }; use rustc_infer::traits::PredicateObligations; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; @@ -457,38 +456,38 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { self.super_local_decl(local, local_decl); - if let Some(user_ty) = &local_decl.user_ty { - for (user_ty, span) in user_ty.projections_and_spans() { - let ty = if !local_decl.is_nonref_binding() { - // If we have a binding of the form `let ref x: T = ..` - // then remove the outermost reference so we can check the - // type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.kind() { - *rty - } else { - bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); - } - } else { - local_decl.ty - }; + for user_ty in + local_decl.user_ty.as_deref().into_iter().flat_map(UserTypeProjections::projections) + { + let span = self.typeck.user_type_annotations[user_ty.base].span; + + let ty = if local_decl.is_nonref_binding() { + local_decl.ty + } else if let &ty::Ref(_, rty, _) = local_decl.ty.kind() { + // If we have a binding of the form `let ref x: T = ..` + // then remove the outermost reference so we can check the + // type annotation for the remaining type. + rty + } else { + bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); + }; - if let Err(terr) = self.typeck.relate_type_and_user_type( - ty, - ty::Invariant, - user_ty, - Locations::All(*span), - ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), - ) { - span_mirbug!( - self, - local, - "bad user type on variable {:?}: {:?} != {:?} ({:?})", - local, - local_decl.ty, - local_decl.user_ty, - terr, - ); - } + if let Err(terr) = self.typeck.relate_type_and_user_type( + ty, + ty::Invariant, + user_ty, + Locations::All(span), + ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), + ) { + span_mirbug!( + self, + local, + "bad user type on variable {:?}: {:?} != {:?} ({:?})", + local, + local_decl.ty, + local_decl.user_ty, + terr, + ); } } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 4e6f82ac849..9a68eeb3326 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -21,6 +21,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Diag; use rustc_hir::BodyOwnerKind; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_index::IndexVec; @@ -603,7 +604,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - if self.mir_def.to_def_id() == typeck_root_def_id { + if self.mir_def.to_def_id() == typeck_root_def_id + // Do not ICE when checking default_field_values consts with lifetimes (#135649) + && DefKind::Field != tcx.def_kind(tcx.parent(typeck_root_def_id)) + { let args = self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_args); DefiningTy::Const(self.mir_def.to_def_id(), args) diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 521a250ab82..c74efeb59f3 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -65,7 +65,7 @@ pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { if fx.clif_comments.enabled() { fx.add_global_comment(String::new()); fx.add_global_comment( - "kind local ty size align (abi,pref)".to_string(), + "kind local ty size align (abi)".to_string(), ); } } @@ -84,14 +84,13 @@ pub(super) fn add_local_place_comments<'tcx>( let (kind, extra) = place.debug_comment(); fx.add_global_comment(format!( - "{:<5} {:5} {:30} {:4}b {}, {}{}{}", + "{:<5} {:5} {:30} {:4}b {}{}{}", kind, format!("{:?}", local), format!("{:?}", ty), size.bytes(), align.abi.bytes(), - align.pref.bytes(), - if extra.is_empty() { "" } else { " " }, + if extra.is_empty() { "" } else { " " }, extra, )); } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 425b2adf32a..bcc70f4567f 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -272,7 +272,7 @@ fn data_id_for_static( .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .unwrap() .align - .pref + .abi .bytes(); let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index a9b8e1bd393..1b3f86c8405 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -638,9 +638,7 @@ impl<'tcx> CPlace<'tcx> { } CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self), CPlaceInner::Addr(to_ptr, None) => { - if dst_layout.size == Size::ZERO - || dst_layout.backend_repr == BackendRepr::Uninhabited - { + if dst_layout.size == Size::ZERO { return; } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index b8e37b60480..c8b7616e645 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -989,10 +989,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { OperandValue::Ref(place.val) } else if place.layout.is_gcc_immediate() { let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align); - if let abi::BackendRepr::Scalar(ref scalar) = place.layout.backend_repr { - scalar_load_metadata(self, load, scalar); - } - OperandValue::Immediate(self.to_immediate(load, place.layout)) + OperandValue::Immediate( + if let abi::BackendRepr::Scalar(ref scalar) = place.layout.backend_repr { + scalar_load_metadata(self, load, scalar); + self.to_immediate_scalar(load, *scalar) + } else { + load + }, + ) } else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr { let b_offset = a.size(self).align_to(b.align(self).abi); @@ -1694,7 +1698,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value { if scalar.is_bool() { - return self.trunc(val, self.cx().type_i1()); + return self.unchecked_utrunc(val, self.cx().type_i1()); } val } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index a1123fafe2f..433868e238a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -9,7 +9,7 @@ use gccjit::FunctionType; use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; #[cfg(feature = "master")] use rustc_abi::ExternAbi; -use rustc_abi::HasDataLayout; +use rustc_abi::{BackendRepr, HasDataLayout}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::common::IntPredicate; @@ -181,14 +181,19 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = fn_args.type_at(0); let ptr = args[0].immediate(); + let layout = self.layout_of(tp_ty); let load = if let PassMode::Cast { cast: ref ty, pad_i32: _ } = fn_abi.ret.mode { let gcc_ty = ty.gcc_type(self); self.volatile_load(gcc_ty, ptr) } else { - self.volatile_load(self.layout_of(tp_ty).gcc_type(self), ptr) + self.volatile_load(layout.gcc_type(self), ptr) }; // TODO(antoyo): set alignment. - self.to_immediate(load, self.layout_of(tp_ty)) + if let BackendRepr::Scalar(scalar) = layout.backend_repr { + self.to_immediate_scalar(load, scalar) + } else { + load + } } sym::volatile_store => { let dst = args[0].deref(self.cx()); @@ -310,7 +315,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, + Vector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 8b8b54753e7..bac4fc51300 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -84,7 +84,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( false, ); } - BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} + BackendRepr::Memory { .. } => {} } let name = match *layout.ty.kind() { @@ -179,19 +179,16 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, - BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { - false - } + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } fn is_gcc_scalar_pair(&self) -> bool { match self.backend_repr { BackendRepr::ScalarPair(..) => true, - BackendRepr::Uninhabited - | BackendRepr::Scalar(_) - | BackendRepr::Vector { .. } - | BackendRepr::Memory { .. } => false, + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => { + false + } } } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 28f423efc21..8c75125e009 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -2,19 +2,18 @@ use std::borrow::Borrow; use std::cmp; use libc::c_uint; -use rustc_abi as abi; -pub(crate) use rustc_abi::ExternAbi; -use rustc_abi::{HasDataLayout, Primitive, Reg, RegKind, Size}; +use rustc_abi::{BackendRepr, HasDataLayout, Primitive, Reg, RegKind, 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::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA}; use rustc_middle::{bug, ty}; use rustc_session::config; -pub(crate) use rustc_target::callconv::*; +use rustc_target::callconv::{ + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, Conv, FnAbi, PassMode, +}; use rustc_target::spec::SanitizerSet; use smallvec::SmallVec; @@ -458,7 +457,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { match &self.ret.mode { PassMode::Direct(attrs) => { attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); - if let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr { + if let BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr { apply_range_attr(llvm::AttributePlace::ReturnValue, scalar); } } @@ -499,7 +498,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } PassMode::Direct(attrs) => { let i = apply(attrs); - if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { + if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr { apply_range_attr(llvm::AttributePlace::Argument(i), scalar); } } @@ -514,9 +513,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Pair(a, b) => { let i = apply(a); let ii = apply(b); - if let abi::BackendRepr::ScalarPair(scalar_a, scalar_b) = - arg.layout.backend_repr - { + if let BackendRepr::ScalarPair(scalar_a, scalar_b) = arg.layout.backend_repr { apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a); apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b); } @@ -576,7 +573,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } if bx.cx.sess().opts.optimize != config::OptLevel::No && llvm_util::get_version() < (19, 0, 0) - && let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr + && let BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr && matches!(scalar.primitive(), Primitive::Int(..)) // If the value is a boolean, the range is 0..2 and that ultimately // become 0..0 when the type becomes i1, which would be rejected diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index e10a4d63407..e1609e31c07 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -29,13 +29,13 @@ use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::abi::FnAbiLlvmExt; -use crate::attributes; use crate::common::Funclet; use crate::context::{CodegenCx, SimpleCx}; use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, Metadata, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; +use crate::{attributes, llvm_util}; #[must_use] pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> { @@ -606,7 +606,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value { if scalar.is_bool() { - return self.trunc(val, self.cx().type_i1()); + return self.unchecked_utrunc(val, self.cx().type_i1()); } val } @@ -746,10 +746,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let load = self.load(llty, place.val.llval, place.val.align); if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO); + self.to_immediate_scalar(load, scalar) + } else { + load } - load }); - OperandValue::Immediate(self.to_immediate(llval, place.layout)) + OperandValue::Immediate(llval) } else if let abi::BackendRepr::ScalarPair(a, b) = place.layout.backend_repr { let b_offset = a.size(self).align_to(b.align(self).abi); @@ -942,6 +944,34 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, UNNAMED) } } + fn unchecked_utrunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { + debug_assert_ne!(self.val_ty(val), dest_ty); + + let trunc = self.trunc(val, dest_ty); + if llvm_util::get_version() >= (19, 0, 0) { + unsafe { + if llvm::LLVMIsAInstruction(trunc).is_some() { + llvm::LLVMSetNUW(trunc, True); + } + } + } + trunc + } + + fn unchecked_strunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { + debug_assert_ne!(self.val_ty(val), dest_ty); + + let trunc = self.trunc(val, dest_ty); + if llvm_util::get_version() >= (19, 0, 0) { + unsafe { + if llvm::LLVMIsAInstruction(trunc).is_some() { + llvm::LLVMSetNSW(trunc, True); + } + } + } + trunc + } + fn sext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 59c3fe635d0..98d59f5a8ae 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -11,7 +11,9 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; -use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{ + HasTypingEnv, LayoutOf, TyAndLayout, WIDE_PTR_ADDR, WIDE_PTR_EXTRA, +}; use rustc_middle::ty::{ self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility, }; @@ -34,12 +36,12 @@ use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::dwarf_const; use crate::debuginfo::metadata::type_map::build_type_with_children; use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; +use crate::llvm; use crate::llvm::debuginfo::{ DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind, DebugNameTableKind, }; use crate::value::Value; -use crate::{abi, llvm}; impl PartialEq for llvm::Metadata { fn eq(&self, other: &Self) -> bool { @@ -211,16 +213,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( }; let layout = cx.layout_of(layout_type); - let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR); - let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA); + let addr_field = layout.field(cx, WIDE_PTR_ADDR); + let extra_field = layout.field(cx, WIDE_PTR_EXTRA); let (addr_field_name, extra_field_name) = match wide_pointer_kind { WidePtrKind::Dyn => ("pointer", "vtable"), WidePtrKind::Slice => ("data_ptr", "length"), }; - assert_eq!(abi::WIDE_PTR_ADDR, 0); - assert_eq!(abi::WIDE_PTR_EXTRA, 1); + assert_eq!(WIDE_PTR_ADDR, 0); + assert_eq!(WIDE_PTR_EXTRA, 1); // The data pointer type is a regular, thin pointer, regardless of whether this // is a slice or a trait object. @@ -242,7 +244,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::WIDE_PTR_ADDR), + layout.fields.offset(WIDE_PTR_ADDR), DIFlags::FlagZero, data_ptr_type_di_node, None, @@ -252,7 +254,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::WIDE_PTR_EXTRA), + layout.fields.offset(WIDE_PTR_EXTRA), DIFlags::FlagZero, type_di_node(cx, extra_field.ty), None, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 17f2d5f4e73..10819a53b1d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -22,6 +22,7 @@ use rustc_session::config::{self, DebugInfo}; use rustc_span::{ BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol, }; +use rustc_target::callconv::FnAbi; use rustc_target::spec::DebuginfoKind; use smallvec::SmallVec; use tracing::debug; @@ -29,7 +30,6 @@ use tracing::debug; use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node}; use self::namespace::mangled_name_of_instance; use self::utils::{DIB, create_DIArray, is_node_local_to_unit}; -use crate::abi::FnAbi; use crate::builder::Builder; use crate::common::{AsCCharPtr, CodegenCx}; use crate::llvm; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index cebceef1b93..e79662ebc64 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -16,10 +16,11 @@ use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{Instance, Ty}; use rustc_sanitizers::{cfi, kcfi}; +use rustc_target::callconv::FnAbi; use smallvec::SmallVec; use tracing::debug; -use crate::abi::{FnAbi, FnAbiLlvmExt}; +use crate::abi::FnAbiLlvmExt; use crate::common::AsCCharPtr; use crate::context::{CodegenCx, SimpleCx}; use crate::llvm::AttributePlace::Function; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 8b976885904..f68365f6c69 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; use std::cmp::Ordering; -use rustc_abi::{self as abi, Align, Float, HasDataLayout, Primitive, Size}; +use rustc_abi::{Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization}; @@ -14,10 +14,11 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; +use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use tracing::debug; -use crate::abi::{ExternAbi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode}; +use crate::abi::{FnAbiLlvmExt, LlvmType}; use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Metadata}; @@ -257,7 +258,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::va_arg => { match fn_abi.ret.layout.backend_repr { - abi::BackendRepr::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { match scalar.primitive() { Primitive::Int(..) => { if self.cx().size_of(ret_ty).bytes() < 4 { @@ -470,12 +471,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::raw_eq => { - use abi::BackendRepr::*; + use BackendRepr::*; let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, + Vector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -582,8 +583,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } let llret_ty = if ret_ty.is_simd() - && let abi::BackendRepr::Memory { .. } = - self.layout_of(ret_ty).layout.backend_repr + && let BackendRepr::Memory { .. } = self.layout_of(ret_ty).layout.backend_repr { let (size, elem_ty) = ret_ty.simd_size_and_type(self.tcx()); let elem_ll_ty = match elem_ty.kind() { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index b0b6da869da..ba01fbff385 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -23,7 +23,7 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } - BackendRepr::Uninhabited | BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} + BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} } let name = match layout.ty.kind() { @@ -172,19 +172,16 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, - BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { - false - } + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } fn is_llvm_scalar_pair(&self) -> bool { match self.backend_repr { BackendRepr::ScalarPair(..) => true, - BackendRepr::Uninhabited - | BackendRepr::Scalar(_) - | BackendRepr::Vector { .. } - | BackendRepr::Memory { .. } => false, + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => { + false + } } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 105a4cb81f0..a8d917f0fdb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1990,6 +1990,7 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) if let Some(args) = sess.target.pre_link_args.get(&flavor) { cmd.verbatim_args(args.iter().map(Deref::deref)); } + cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args); } @@ -2518,6 +2519,12 @@ fn add_order_independent_options( "--target-cpu", &codegen_results.crate_info.target_cpu, ]); + if codegen_results.crate_info.target_features.len() > 0 { + cmd.link_arg(&format!( + "--target-feature={}", + &codegen_results.crate_info.target_features.join(",") + )); + } } else if flavor == LinkerFlavor::Ptx { cmd.link_args(&["--fallback-arch", &codegen_results.crate_info.target_cpu]); } else if flavor == LinkerFlavor::Bpf { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e3ace01c1eb..8900405c1b8 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -153,6 +153,7 @@ pub(crate) fn get_linker<'a>( hinted_static: None, is_ld: cc == Cc::No, is_gnu: flavor.is_gnu(), + uses_lld: flavor.uses_lld(), }) as Box<dyn Linker>, LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>, LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>, @@ -361,6 +362,7 @@ struct GccLinker<'a> { // Link as ld is_ld: bool, is_gnu: bool, + uses_lld: bool, } impl<'a> GccLinker<'a> { @@ -552,6 +554,7 @@ impl<'a> Linker for GccLinker<'a> { self.link_args(&["--entry", "_initialize"]); } } + // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, // it switches linking for libc and similar system libraries to static without using // any `#[link]` attributes in the `libc` crate, see #72782 for details. @@ -567,6 +570,15 @@ impl<'a> Linker for GccLinker<'a> { { self.cc_arg("--static-crt"); } + + // avr-none doesn't have default ISA, users must specify which specific + // CPU (well, microcontroller) they are targetting using `-Ctarget-cpu`. + // + // Currently this makes sense only when using avr-gcc as a linker, since + // it brings a couple of hand-written important intrinsics from libgcc. + if self.sess.target.arch == "avr" && !self.uses_lld { + self.verbatim_arg(format!("-mmcu={}", self.target_cpu)); + } } fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index e800492dad0..40238f4b491 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -24,7 +24,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::Session; -use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; +use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_span::{DUMMY_SP, Symbol, sym}; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; @@ -364,13 +364,7 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let rhs_sz = bx.cx().int_width(rhs_llty); let lhs_sz = bx.cx().int_width(lhs_llty); if lhs_sz < rhs_sz { - if is_unchecked && bx.sess().opts.optimize != OptLevel::No { - // FIXME: Use `trunc nuw` once that's available - let inrange = bx.icmp(IntPredicate::IntULE, rhs, mask); - bx.assume(inrange); - } - - bx.trunc(rhs, lhs_llty) + if is_unchecked { bx.unchecked_utrunc(rhs, lhs_llty) } else { bx.trunc(rhs, lhs_llty) } } else if lhs_sz > rhs_sz { // We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the // RHS to `255i32`. But then we mask the shift amount to be within the size of the LHS @@ -921,6 +915,7 @@ impl CrateInfo { let n_crates = crates.len(); let mut info = CrateInfo { target_cpu, + target_features: tcx.global_backend_features(()).clone(), crate_types, exported_symbols, linked_symbols, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 428a45975f1..9d2ac219d59 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -190,6 +190,7 @@ impl From<&cstore::NativeLib> for NativeLib { #[derive(Debug, Encodable, Decodable)] pub struct CrateInfo { pub target_cpu: String, + pub target_features: Vec<String>, pub crate_types: Vec<CrateType>, pub exported_symbols: UnordMap<CrateType, Vec<String>>, pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>, @@ -230,6 +231,7 @@ pub fn provide(providers: &mut Providers) { crate::base::provide(providers); crate::target_features::provide(providers); crate::codegen_attrs::provide(providers); + providers.queries.global_backend_features = |_tcx: TyCtxt<'_>, ()| vec![]; } /// Checks if the given filename ends with the `.rcgu.o` extension that `rustc` diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 616d748a299..49074996174 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -4,9 +4,7 @@ use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange}; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::{ - self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason, -}; +use rustc_middle::mir::{self, AssertKind, 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}; @@ -942,7 +940,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &fn_abi.ret, &mut llargs, Some(intrinsic), - target, ); let dest = match ret_dest { _ if fn_abi.ret.is_indirect() => llargs[0], @@ -998,19 +995,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let mut llargs = Vec::with_capacity(arg_count); - let destination = target.as_ref().map(|&target| { - ( - self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - None, - Some(target), - ), - target, - ) - }); + + // We still need to call `make_return_dest` even if there's no `target`, since + // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, + // and `make_return_dest` adds the return-place indirect pointer to `llargs`. + let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, None); + let destination = target.map(|target| (return_dest, target)); // Split the rust-call tupled arguments off. let (first_args, untuple) = if abi == ExternAbi::RustCall && !args.is_empty() { @@ -1040,7 +1030,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); - op = op.extract_field(bx, idx); + op = op.extract_field(self, bx, idx); } // Now that we have `*dyn Trait` or `&dyn Trait`, split it up into its @@ -1072,7 +1062,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); - op = op.extract_field(bx, idx); + op = op.extract_field(self, bx, idx); } // Make sure that we've actually unwrapped the rcvr down @@ -1572,9 +1562,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if scalar.is_bool() { bx.range_metadata(llval, WrappingRange { start: 0, end: 1 }); } + // We store bools as `i8` so we need to truncate to `i1`. + llval = bx.to_immediate_scalar(llval, scalar); } - // We store bools as `i8` so we need to truncate to `i1`. - llval = bx.to_immediate(llval, arg.layout); } } @@ -1604,7 +1594,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { // If the tuple is immediate, the elements are as well. for i in 0..tuple.layout.fields.count() { - let op = tuple.extract_field(bx, i); + let op = tuple.extract_field(self, bx, i); self.codegen_argument(bx, op, llargs, &args[i]); } } @@ -1813,11 +1803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, llargs: &mut Vec<Bx::Value>, intrinsic: Option<ty::IntrinsicDef>, - target: Option<BasicBlock>, ) -> ReturnDest<'tcx, Bx::Value> { - if target.is_none() { - return ReturnDest::Nothing; - } // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { return ReturnDest::Nothing; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 9ca7d4f8f00..faf1300e473 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -1,15 +1,14 @@ -use std::assert_matches::assert_matches; use std::fmt; use arrayvec::ArrayVec; use either::Either; use rustc_abi as abi; use rustc_abi::{Align, BackendRepr, 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_middle::{bug, span_bug}; use tracing::debug; use super::place::{PlaceRef, PlaceValue}; @@ -352,79 +351,81 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { pub(crate) fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>( &self, + fx: &mut FunctionCx<'a, 'tcx, Bx>, bx: &mut Bx, i: usize, ) -> Self { let field = self.layout.field(bx.cx(), i); let offset = self.layout.fields.offset(i); - let mut val = match (self.val, self.layout.backend_repr) { - // If the field is ZST, it has no data. - _ if field.is_zst() => OperandValue::ZeroSized, - - // Newtype of a scalar, scalar pair or vector. - (OperandValue::Immediate(_) | OperandValue::Pair(..), _) - if field.size == self.layout.size => - { - assert_eq!(offset.bytes(), 0); - self.val + let val = if field.is_zst() { + OperandValue::ZeroSized + } else if field.size == self.layout.size { + assert_eq!(offset.bytes(), 0); + if let Some(field_val) = fx.codegen_transmute_operand(bx, *self, field) { + field_val + } else { + // we have to go through memory for things like + // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); + let place = PlaceRef::alloca(bx, field); + self.val.store(bx, place.val.with_type(self.layout)); + bx.load_operand(place).val } - - // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => { - if offset.bytes() == 0 { - assert_eq!(field.size, a.size(bx.cx())); - OperandValue::Immediate(a_llval) - } else { - assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi)); - assert_eq!(field.size, b.size(bx.cx())); - OperandValue::Immediate(b_llval) + } else { + let (in_scalar, imm) = match (self.val, self.layout.backend_repr) { + // Extract a scalar component from a pair. + (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => { + if offset.bytes() == 0 { + assert_eq!(field.size, a.size(bx.cx())); + (Some(a), a_llval) + } else { + assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi)); + assert_eq!(field.size, b.size(bx.cx())); + (Some(b), b_llval) + } } - } - // `#[repr(simd)]` types are also immediate. - (OperandValue::Immediate(llval), BackendRepr::Vector { .. }) => { - OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64))) - } + // `#[repr(simd)]` types are also immediate. + (OperandValue::Immediate(llval), BackendRepr::Vector { .. }) => { + (None, bx.extract_element(llval, bx.cx().const_usize(i as u64))) + } - _ => bug!("OperandRef::extract_field({:?}): not applicable", self), + _ => { + span_bug!(fx.mir.span, "OperandRef::extract_field({:?}): not applicable", self) + } + }; + OperandValue::Immediate(match field.backend_repr { + BackendRepr::Vector { .. } => imm, + BackendRepr::Scalar(out_scalar) => { + let Some(in_scalar) = in_scalar else { + span_bug!( + fx.mir.span, + "OperandRef::extract_field({:?}): missing input scalar for output scalar", + self + ) + }; + if in_scalar != out_scalar { + // If the backend and backend_immediate types might differ, + // flip back to the backend type then to the new immediate. + // This avoids nop truncations, but still handles things like + // Bools in union fields needs to be truncated. + let backend = bx.from_immediate(imm); + bx.to_immediate_scalar(backend, out_scalar) + } else { + imm + } + } + BackendRepr::Memory { sized: true } => { + span_bug!( + fx.mir.span, + "Projecting into a simd type with padding doesn't work; \ + See <https://github.com/rust-lang/rust/issues/137108>", + ); + } + BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { sized: false } => bug!(), + }) }; - match (&mut val, field.backend_repr) { - (OperandValue::ZeroSized, _) => {} - ( - OperandValue::Immediate(llval), - BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. }, - ) => { - // Bools in union fields needs to be truncated. - *llval = bx.to_immediate(*llval, field); - } - (OperandValue::Pair(a, b), BackendRepr::ScalarPair(a_abi, b_abi)) => { - // Bools in union fields needs to be truncated. - *a = bx.to_immediate_scalar(*a, a_abi); - *b = bx.to_immediate_scalar(*b, b_abi); - } - // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); - (OperandValue::Immediate(llval), BackendRepr::Memory { sized: true }) => { - assert_matches!(self.layout.backend_repr, BackendRepr::Vector { .. }); - - let llfield_ty = bx.cx().backend_type(field); - - // Can't bitcast an aggregate, so round trip through memory. - let llptr = bx.alloca(field.size, field.align.abi); - bx.store(*llval, llptr, field.align.abi); - *llval = bx.load(llfield_ty, llptr, field.align.abi); - } - ( - OperandValue::Immediate(_), - BackendRepr::Uninhabited | BackendRepr::Memory { sized: false }, - ) => { - bug!() - } - (OperandValue::Pair(..), _) => bug!(), - (OperandValue::Ref(..), _) => bug!(), - } - OperandRef { val, layout: field } } } @@ -587,7 +588,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \ but tried to access field {f:?} of pointer {o:?}", ); - o = o.extract_field(bx, f.index()); + o = o.extract_field(self, bx, f.index()); } mir::ProjectionElem::Index(_) | mir::ProjectionElem::ConstantIndex { .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index eb4270ffe80..e32d298869b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -1,7 +1,7 @@ use rustc_abi::Primitive::{Int, Pointer}; use rustc_abi::{Align, BackendRepr, FieldsShape, Size, TagEncoding, VariantIdx, Variants}; +use rustc_middle::mir::PlaceTy; use rustc_middle::mir::interpret::Scalar; -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}; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4c5b183cfe9..daa4fa90ed7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// /// Returns `None` for cases that can't work in that framework, such as for /// `Immediate`->`Ref` that needs an `alloc` to get the location. - fn codegen_transmute_operand( + pub(crate) fn codegen_transmute_operand( &mut self, bx: &mut Bx, operand: OperandRef<'tcx, Bx::Value>, @@ -260,6 +260,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Ref(source_place_val) => { assert_eq!(source_place_val.llextra, None); assert_matches!(operand_kind, OperandValueKind::Ref); + // The existing alignment is part of `source_place_val`, + // so that alignment will be used, not `cast`'s. Some(bx.load_operand(source_place_val.with_type(cast)).val) } OperandValue::ZeroSized => { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 48ae000f2c6..2b00ba01946 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; use std::ops::Deref; -use rustc_abi::{Align, BackendRepr, Scalar, Size, WrappingRange}; +use rustc_abi::{Align, Scalar, Size, WrappingRange}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; @@ -223,13 +223,6 @@ pub trait BuilderMethods<'a, 'tcx>: ) -> (Self::Value, Self::Value); fn from_immediate(&mut self, val: Self::Value) -> Self::Value; - fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value { - if let BackendRepr::Scalar(scalar) = layout.backend_repr { - self.to_immediate_scalar(val, scalar) - } else { - val - } - } fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, size: Size, align: Align) -> Self::Value; @@ -340,6 +333,17 @@ pub trait BuilderMethods<'a, 'tcx>: } fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; + /// Produces the same value as [`Self::trunc`] (and defaults to that), + /// but is UB unless the *zero*-extending the result can reproduce `val`. + fn unchecked_utrunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + self.trunc(val, dest_ty) + } + /// Produces the same value as [`Self::trunc`] (and defaults to that), + /// but is UB unless the *sign*-extending the result can reproduce `val`. + fn unchecked_strunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + self.trunc(val, dest_ty) + } + fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index b53c1505f6b..7b706334ed8 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -430,10 +430,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; let erased_trait_ref = ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref); - assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env( - erased_trait_ref, - self.tcx.instantiate_bound_regions_with_erased(b) - ))); + assert_eq!( + data_b.principal().map(|b| { + self.tcx.normalize_erasing_late_bound_regions(self.typing_env, b) + }), + Some(erased_trait_ref), + ); } else { // In this case codegen would keep using the old vtable. We don't want to do // that as it has the wrong trait. The reason codegen can do this is that diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 66a75113652..c1948e9f31f 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,9 +4,6 @@ use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::infer::at::ToTrace; -use rustc_infer::traits::ObligationCause; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ @@ -17,8 +14,7 @@ use rustc_middle::{mir, span_bug}; use rustc_session::Limit; use rustc_span::Span; use rustc_target::callconv::FnAbi; -use rustc_trait_selection::traits::ObligationCtxt; -use tracing::{debug, instrument, trace}; +use tracing::{debug, trace}; use super::{ Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpErrorKind, InterpResult, MPlaceTy, Machine, @@ -320,40 +316,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - /// Check if the two things are equal in the current param_env, using an infcx to get proper - /// equality checks. - #[instrument(level = "trace", skip(self), ret)] - pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool - where - T: PartialEq + TypeFoldable<TyCtxt<'tcx>> + ToTrace<'tcx>, - { - // Fast path: compare directly. - if a == b { - return true; - } - // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); - let ocx = ObligationCtxt::new(&infcx); - let cause = ObligationCause::dummy_with_span(self.cur_span()); - // equate the two trait refs after normalization - let a = ocx.normalize(&cause, param_env, a); - let b = ocx.normalize(&cause, param_env, b); - - if let Err(terr) = ocx.eq(&cause, param_env, a, b) { - trace!(?terr); - return false; - } - - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - trace!(?errors); - return false; - } - - // All good. - true - } - /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a /// frame which is not `#[track_caller]`. This matches the `caller_location` intrinsic, /// and is primarily intended for the panic machinery. diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 5d905cff1f2..36da9037e43 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -385,7 +385,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { (Immediate::Uninit, _) => Immediate::Uninit, // If the field is uninhabited, we can forget the data (can happen in ConstProp). // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that - // has an `Uninhabited` variant, which means this case is possible. + // has an uninhabited variant, which means this case is possible. _ if layout.is_uninhabited() => Immediate::Uninit, // the field contains no information, can be left uninit // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST) diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 4cfaacebfcd..a5029eea5a7 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -86,21 +86,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }); } + // This checks whether there is a subtyping relation between the predicates in either direction. + // For example: + // - casting between `dyn for<'a> Trait<fn(&'a u8)>` and `dyn Trait<fn(&'static u8)>` is OK + // - casting between `dyn Trait<for<'a> fn(&'a u8)>` and either of the above is UB for (a_pred, b_pred) in std::iter::zip(sorted_vtable, sorted_expected) { - let is_eq = match (a_pred.skip_binder(), b_pred.skip_binder()) { - ( - ty::ExistentialPredicate::Trait(a_data), - ty::ExistentialPredicate::Trait(b_data), - ) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)), + let a_pred = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, a_pred); + let b_pred = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, b_pred); - ( - ty::ExistentialPredicate::Projection(a_data), - ty::ExistentialPredicate::Projection(b_data), - ) => self.eq_in_param_env(a_pred.rebind(a_data), b_pred.rebind(b_data)), - - _ => false, - }; - if !is_eq { + if a_pred != b_pred { throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }); } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 0ac34f4633b..40dec0cb39e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1264,21 +1264,20 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } } - // *After* all of this, check the ABI. We need to check the ABI to handle - // types like `NonNull` where the `Scalar` info is more restrictive than what - // the fields say (`rustc_layout_scalar_valid_range_start`). - // But in most cases, this will just propagate what the fields say, - // and then we want the error to point at the field -- so, first recurse, - // then check ABI. + // *After* all of this, check further information stored in the layout. We need to check + // this to handle types like `NonNull` where the `Scalar` info is more restrictive than what + // the fields say (`rustc_layout_scalar_valid_range_start`). But in most cases, this will + // just propagate what the fields say, and then we want the error to point at the field -- + // so, we first recurse, then we do this check. // // FIXME: We could avoid some redundant checks here. For newtypes wrapping // scalars, we do the same check on every "level" (e.g., first we check // MyNewtype and then the scalar in there). + if val.layout.is_uninhabited() { + let ty = val.layout.ty; + throw_validation_failure!(self.path, UninhabitedVal { ty }); + } match val.layout.backend_repr { - BackendRepr::Uninhabited => { - let ty = val.layout.ty; - throw_validation_failure!(self.path, UninhabitedVal { ty }); - } BackendRepr::Scalar(scalar_layout) => { if !scalar_layout.is_uninit_valid() { // There is something to check here. diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 79baf91c3ce..6426bca2332 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -111,13 +111,15 @@ fn check_validity_requirement_lax<'tcx>( }; // Check the ABI. - let valid = match this.backend_repr { - BackendRepr::Uninhabited => false, // definitely UB - BackendRepr::Scalar(s) => scalar_allows_raw_init(s), - BackendRepr::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), - BackendRepr::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), - BackendRepr::Memory { .. } => true, // Fields are checked below. - }; + let valid = !this.is_uninhabited() // definitely UB if uninhabited + && match this.backend_repr { + BackendRepr::Scalar(s) => scalar_allows_raw_init(s), + BackendRepr::ScalarPair(s1, s2) => { + scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2) + } + BackendRepr::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), + BackendRepr::Memory { .. } => true, // Fields are checked below. + }; if !valid { // This is definitely not okay. return Ok(false); diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index 850b052f564..8079212fac5 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -92,7 +92,10 @@ impl<'a, T: Ord> Ord for Interned<'a, T> { } } -impl<'a, T> Hash for Interned<'a, T> { +impl<'a, T> Hash for Interned<'a, T> +where + T: Hash, +{ #[inline] fn hash<H: Hasher>(&self, s: &mut H) { // Pointer hashing is sufficient, due to the uniqueness constraint. diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs index 08b7d937661..e7bc57c9749 100644 --- a/compiler/rustc_driver_impl/src/signal_handler.rs +++ b/compiler/rustc_driver_impl/src/signal_handler.rs @@ -6,6 +6,15 @@ use std::{fmt, mem, ptr, slice}; use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE}; +/// Signals that represent that we have a bug, and our prompt termination has +/// been ordered. +#[rustfmt::skip] +const KILL_SIGNALS: [(libc::c_int, &str); 3] = [ + (libc::SIGILL, "SIGILL"), + (libc::SIGBUS, "SIGBUS"), + (libc::SIGSEGV, "SIGSEGV") +]; + unsafe extern "C" { fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int); } @@ -39,8 +48,19 @@ macro raw_errln($tokens:tt) { /// # Safety /// /// Caller must ensure that this function is not re-entered. -unsafe extern "C" fn print_stack_trace(_: libc::c_int) { +unsafe extern "C" fn print_stack_trace(signum: libc::c_int) { const MAX_FRAMES: usize = 256; + + let signame = { + let mut signame = "<unknown>"; + for sig in KILL_SIGNALS { + if sig.0 == signum { + signame = sig.1; + } + } + signame + }; + let stack = unsafe { // Reserve data segment so we don't have to malloc in a signal handler, which might fail // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking @@ -54,7 +74,8 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) { }; // Just a stack trace is cryptic. Explain what we're doing. - raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n"); + raw_errln!("error: rustc interrupted by {signame}, printing backtrace\n"); + let mut written = 1; let mut consumed = 0; // Begin elaborating return addrs into symbols and writing them directly to stderr @@ -94,7 +115,7 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) { written += rem.len() + 1; let random_depth = || 8 * 16; // chosen by random diceroll (2d20) - if cyclic || stack.len() > random_depth() { + if (cyclic || stack.len() > random_depth()) && signum == libc::SIGSEGV { // technically speculation, but assert it with confidence anyway. // rustc only arrived in this signal handler because bad things happened // and this message is for explaining it's not the programmer's fault @@ -106,17 +127,22 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) { written += 1; } raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust"); - // get the current stack size WITHOUT blocking and double it - let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2; - raw_errln!("help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}"); - written += 2; + written += 1; + if signum == libc::SIGSEGV { + // get the current stack size WITHOUT blocking and double it + let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2; + raw_errln!( + "help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}" + ); + written += 1; + } if written > 24 { - // We probably just scrolled the earlier "we got SIGSEGV" message off the terminal - raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal"); + // We probably just scrolled the earlier "interrupted by {signame}" message off the terminal + raw_errln!("note: backtrace dumped due to {signame}! resuming signal"); }; } -/// When SIGSEGV is delivered to the process, print a stack trace and then exit. +/// When one of the KILL signals is delivered to the process, print a stack trace and then exit. pub(super) fn install() { unsafe { let alt_stack_size: usize = min_sigstack_size() + 64 * 1024; @@ -129,7 +155,9 @@ pub(super) fn install() { sa.sa_sigaction = print_stack_trace as libc::sighandler_t; sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK; libc::sigemptyset(&mut sa.sa_mask); - libc::sigaction(libc::SIGSEGV, &sa, ptr::null_mut()); + for (signum, _signame) in KILL_SIGNALS { + libc::sigaction(signum, &sa, ptr::null_mut()); + } } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0803.md b/compiler/rustc_error_codes/src/error_codes/E0803.md new file mode 100644 index 00000000000..4c022688a2d --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0803.md @@ -0,0 +1,46 @@ +A trait implementation returns a reference without an +explicit lifetime linking it to `self`. +It commonly arises in generic trait implementations +requiring explicit lifetime bounds. + +Erroneous code example: + +```compile_fail,E0803 +trait DataAccess<T> { + fn get_ref(&self) -> T; +} + +struct Container<'a> { + value: &'a f64, +} + +// Attempting to implement reference return +impl<'a> DataAccess<&f64> for Container<'a> { + fn get_ref(&self) -> &f64 { // Error: Lifetime mismatch + self.value + } +} +``` + +The trait method returns &f64 requiring an independent lifetime +The struct Container<'a> carries lifetime parameter 'a +The compiler cannot verify if the returned reference satisfies 'a constraints +Solution +Explicitly bind lifetimes to clarify constraints: +``` +// Modified trait with explicit lifetime binding +trait DataAccess<'a, T> { + fn get_ref(&'a self) -> T; +} + +struct Container<'a> { + value: &'a f64, +} + +// Correct implementation (bound lifetimes) +impl<'a> DataAccess<'a, &'a f64> for Container<'a> { + fn get_ref(&'a self) -> &'a f64 { + self.value + } +} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index e970b16f610..098ca42be2b 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -546,6 +546,7 @@ E0799: 0799, E0800: 0800, E0801: 0801, E0802: 0802, +E0803: 0803, ); ) } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 5560d087e96..47d5976be09 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -387,6 +387,8 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args +hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}` + hir_analysis_not_supported_delegation = {$descr} .label = callee defined here diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 0dd8296e66c..c193aad2afd 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2104,18 +2104,21 @@ pub(super) fn check_type_bounds<'tcx>( ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; - let mut obligations: Vec<_> = tcx - .explicit_item_bounds(trait_ty.def_id) - .iter_instantiated_copied(tcx, rebased_args) - .map(|(concrete_ty_bound, span)| { - debug!(?concrete_ty_bound); - traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) - }) - .collect(); + let mut obligations: Vec<_> = util::elaborate( + tcx, + tcx.explicit_item_bounds(trait_ty.def_id).iter_instantiated_copied(tcx, rebased_args).map( + |(concrete_ty_bound, span)| { + debug!(?concrete_ty_bound); + traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) + }, + ), + ) + .collect(); // Only in a const implementation do we need to check that the `~const` item bounds hold. if tcx.is_conditionally_const(impl_ty_def_id) { - obligations.extend( + obligations.extend(util::elaborate( + tcx, tcx.explicit_implied_const_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) .map(|(c, span)| { @@ -2126,7 +2129,7 @@ pub(super) fn check_type_bounds<'tcx>( c.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), ) }), - ); + )); } debug!(item_bounds=?obligations); @@ -2134,26 +2137,19 @@ pub(super) fn check_type_bounds<'tcx>( // to its definition type. This should be the param-env we use to *prove* the // predicate too, but we don't do that because of performance issues. // See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>. - let trait_projection_ty = Ty::new_projection_from_args(tcx, trait_ty.def_id, rebased_args); - let impl_identity_ty = tcx.type_of(impl_ty.def_id).instantiate_identity(); let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref); - for mut obligation in util::elaborate(tcx, obligations) { - let normalized_predicate = if infcx.next_trait_solver() { - obligation.predicate.fold_with(&mut ReplaceTy { - tcx, - from: trait_projection_ty, - to: impl_identity_ty, - }) - } else { - ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate) - }; - debug!(?normalized_predicate); - obligation.predicate = normalized_predicate; - - ocx.register_obligation(obligation); + for obligation in &mut obligations { + match ocx.deeply_normalize(&normalize_cause, normalize_param_env, obligation.predicate) { + Ok(pred) => obligation.predicate = pred, + Err(e) => { + return Err(infcx.err_ctxt().report_fulfillment_errors(e)); + } + } } + // Check that all obligations are satisfied by the implementation's // version. + ocx.register_obligations(obligations); let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); @@ -2165,22 +2161,6 @@ pub(super) fn check_type_bounds<'tcx>( ocx.resolve_regions_and_report_errors(impl_ty_def_id, param_env, assumed_wf_types) } -struct ReplaceTy<'tcx> { - tcx: TyCtxt<'tcx>, - from: Ty<'tcx>, - to: Ty<'tcx>, -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceTy<'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if self.from == ty { self.to } else { ty.super_fold_with(self) } - } -} - /// Install projection predicates that allow GATs to project to their own /// definition types. This is not allowed in general in cases of default /// associated types in trait definitions, or when specialization is involved, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index edfa897860b..f98504e19de 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -16,7 +16,6 @@ use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION; use rustc_macros::LintDiagnostic; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::query::Providers; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, @@ -143,33 +142,7 @@ where return Ok(()); } - let is_bevy = 'is_bevy: { - // We don't want to emit this for dependents of Bevy, for now. - // See #119956 - let is_bevy_paramset = |def: ty::AdtDef<'_>| { - let adt_did = with_no_trimmed_paths!(infcx.tcx.def_path_str(def.0.did)); - adt_did.contains("ParamSet") - }; - for ty in assumed_wf_types.iter() { - match ty.kind() { - ty::Adt(def, _) => { - if is_bevy_paramset(*def) { - break 'is_bevy true; - } - } - ty::Ref(_, ty, _) => match ty.kind() { - ty::Adt(def, _) => { - if is_bevy_paramset(*def) { - break 'is_bevy true; - } - } - _ => {} - }, - _ => {} - } - } - false - }; + let is_bevy = assumed_wf_types.visit_with(&mut ContainsBevyParamSet { tcx }).is_break(); // If we have set `no_implied_bounds_compat`, then do not attempt compatibility. // We could also just always enter if `is_bevy`, and call `implied_bounds_tys`, @@ -194,6 +167,31 @@ where } } +struct ContainsBevyParamSet<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsBevyParamSet<'tcx> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + // We only care to match `ParamSet<T>` or `&ParamSet<T>`. + match t.kind() { + ty::Adt(def, _) => { + if self.tcx.item_name(def.did()) == sym::ParamSet + && self.tcx.crate_name(def.did().krate) == sym::bevy_ecs + { + return ControlFlow::Break(()); + } + } + ty::Ref(_, ty, _) => ty.visit_with(self)?, + _ => {} + } + + ControlFlow::Continue(()) + } +} + 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 { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 14ea10461cb..1a0b0edb257 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1417,6 +1417,15 @@ pub(crate) struct CrossCrateTraitsDefined { pub traits: String, } +#[derive(Diagnostic)] +#[diag(hir_analysis_no_variant_named, code = E0599)] +pub struct NoVariantNamed<'tcx> { + #[primary_span] + pub span: Span, + pub ident: Ident, + pub ty: Ty<'tcx>, +} + // FIXME(fmease): Deduplicate: #[derive(Diagnostic)] 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 ec8343bb2bf..e9b99caf737 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -53,7 +53,9 @@ use rustc_type_ir::Upcast; use tracing::{debug, instrument}; use crate::check::check_abi_fn_ptr; -use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType}; +use crate::errors::{ + AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, NoVariantNamed, +}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -1205,14 +1207,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let msg = format!("expected type, found variant `{assoc_ident}`"); self.dcx().span_err(span, msg) } else if qself_ty.is_enum() { - let mut err = struct_span_code_err!( - self.dcx(), - assoc_ident.span, - E0599, - "no variant named `{}` found for enum `{}`", - assoc_ident, - qself_ty, - ); + let mut err = self.dcx().create_err(NoVariantNamed { + span: assoc_ident.span, + ident: assoc_ident, + ty: qself_ty, + }); let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(variant_name) = find_best_match_for_name( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 66d7c9377ed..0859a39b155 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -92,6 +92,7 @@ mod impl_wf_check; mod outlives; mod variance; +pub use errors::NoVariantNamed; use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 1f5acaa58a9..0331a20f95b 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b46d7c49063..1c63b8b3655 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -19,6 +19,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; +use rustc_hir_analysis::NoVariantNamed; use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; use rustc_infer::infer; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; @@ -3837,15 +3838,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else { - type_error_struct!( - self.dcx(), - ident.span, - container, - E0599, - "no variant named `{ident}` found for enum `{container}`", - ) - .with_span_label(field.span, "variant not found") - .emit(); + self.dcx() + .create_err(NoVariantNamed { span: ident.span, ident, ty: container }) + .with_span_label(field.span, "variant not found") + .emit_unless(container.references_error()); break; }; let Some(&subfield) = fields.next() else { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index cd07666ca6c..e63cc090993 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -230,10 +230,19 @@ enum InheritedRefMatchRule { /// underlying type is not a reference type, the inherited reference will be consumed. EatInner, /// When the underlying type is a reference type, reference patterns consume both layers of - /// reference, i.e. they both reset the binding mode and consume the reference type. Reference - /// patterns are not permitted when there is no underlying reference type, i.e. they can't eat - /// only an inherited reference. This is the current stable Rust behavior. - EatBoth, + /// reference, i.e. they both reset the binding mode and consume the reference type. + EatBoth { + /// If `true`, an inherited reference will be considered when determining whether a reference + /// pattern matches a given type: + /// - If the underlying type is not a reference, a reference pattern may eat the inherited reference; + /// - If the underlying type is a reference, a reference pattern matches if it can eat either one + /// of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the + /// underlying type is `&mut` or the inherited reference is `&mut`. + /// If `false`, a reference pattern is only matched against the underlying type. + /// This is `false` for stable Rust and `true` for both the `ref_pat_eat_one_layer_2024` and + /// `ref_pat_eat_one_layer_2024_structural` feature gates. + consider_inherited_ref: bool, + }, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -259,10 +268,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Currently, matching against an inherited ref on edition 2024 is an error. // Use `EatBoth` as a fallback to be similar to stable Rust. - InheritedRefMatchRule::EatBoth + InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } } } else { - InheritedRefMatchRule::EatBoth + InheritedRefMatchRule::EatBoth { + consider_inherited_ref: self.tcx.features().ref_pat_eat_one_layer_2024() + || self.tcx.features().ref_pat_eat_one_layer_2024_structural(), + } } } @@ -835,20 +847,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, pat, - ident.span, + 't', // last char of `mut` def_br_mutbl, ); BindingMode(ByRef::No, Mutability::Mut) } } BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), - BindingMode(ByRef::Yes(_), _) => { + BindingMode(ByRef::Yes(user_br_mutbl), _) => { if let ByRef::Yes(def_br_mutbl) = def_br { // `ref`/`ref mut` overrides the binding mode on edition <= 2021 self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, pat, - ident.span, + match user_br_mutbl { + Mutability::Not => 'f', // last char of `ref` + Mutability::Mut => 't', // last char of `ref mut` + }, def_br_mutbl, ); } @@ -2371,6 +2386,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // NB: This assumes that `&` patterns can match against mutable // references (RFC 3627, Rule 5). If we implement a pattern typing // ruleset with Rule 4 but not Rule 5, we'll need to check that here. + // FIXME(ref_pat_eat_one_layer_2024_structural): If we already tried + // matching the real reference, the error message should explain that + // falling back to the inherited reference didn't work. This should be + // the same error as the old-Edition version below. debug_assert!(ref_pat_matches_mut_ref); self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span); } @@ -2381,13 +2400,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return expected; } } - InheritedRefMatchRule::EatBoth => { + InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => { // Reset binding mode on old editions pat_info.binding_mode = ByRef::No; + + if let ty::Ref(_, inner_ty, _) = *expected.kind() { + // Consume both the inherited and inner references. + if pat_mutbl.is_mut() && inh_mut.is_mut() { + // As a special case, a `&mut` reference pattern will be able to match + // against a reference type of any mutability if the inherited ref is + // mutable. Since this allows us to match against a shared reference + // type, we refer to this as "falling back" to matching the inherited + // reference, though we consume the real reference as well. We handle + // this here to avoid adding this case to the common logic below. + self.check_pat(inner, inner_ty, pat_info); + return expected; + } else { + // Otherwise, use the common logic below for matching the inner + // reference type. + // FIXME(ref_pat_eat_one_layer_2024_structural): If this results in a + // mutability mismatch, the error message should explain that falling + // back to the inherited reference didn't work. This should be the same + // error as the Edition 2024 version above. + } + } else { + // The expected type isn't a reference type, so only match against the + // inherited reference. + if pat_mutbl > inh_mut { + // We can't match a lone inherited shared reference with `&mut`. + self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span); + } + + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } + } + InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => { + // Reset binding mode on stable Rust. This will be a type error below if + // `expected` is not a reference type. + pat_info.binding_mode = ByRef::No; self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, pat, - inner.span, + match pat_mutbl { + Mutability::Not => '&', // last char of `&` + Mutability::Mut => 't', // last char of `&mut` + }, inh_mut, ) } @@ -2779,18 +2838,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat_id: HirId, subpat: &'tcx Pat<'tcx>, - cutoff_span: Span, + final_char: char, def_br_mutbl: Mutability, ) { // Try to trim the span we're labeling to just the `&` or binding mode that's an issue. - // If the subpattern's span is is from an expansion, the emitted label will not be trimmed. - let source_map = self.tcx.sess.source_map(); - let cutoff_span = source_map - .span_extend_prev_while(cutoff_span, |c| c.is_whitespace() || c == '(') - .unwrap_or(cutoff_span); - // Ensure we use the syntax context and thus edition of `subpat.span`; this will be a hard - // error if the subpattern is of edition >= 2024. - let trimmed_span = subpat.span.until(cutoff_span).with_ctxt(subpat.span.ctxt()); + let from_expansion = subpat.span.from_expansion(); + let trimmed_span = if from_expansion { + // If the subpattern is from an expansion, highlight the whole macro call instead. + subpat.span + } else { + let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char); + // The edition of the trimmed span should be the same as `subpat.span`; this will be a + // a hard error if the subpattern is of edition >= 2024. We set it manually to be sure: + trimmed.with_ctxt(subpat.span.ctxt()) + }; let mut typeck_results = self.typeck_results.borrow_mut(); let mut table = typeck_results.rust_2024_migration_desugared_pats_mut(); @@ -2806,31 +2867,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(), }); + let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind { + info.bad_modifiers = true; + // If the user-provided binding modifier doesn't match the default binding mode, we'll + // need to suggest reference patterns, which can affect other bindings. + // For simplicity, we opt to suggest making the pattern fully explicit. + info.suggest_eliding_modes &= + user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); + "binding modifier" + } else { + info.bad_ref_pats = true; + // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll + // suggest adding them instead, which can affect the types assigned to bindings. + // As such, we opt to suggest making the pattern fully explicit. + info.suggest_eliding_modes = false; + "reference pattern" + }; // Only provide a detailed label if the problematic subpattern isn't from an expansion. // In the case that it's from a macro, we'll add a more detailed note in the emitter. - let from_expansion = subpat.span.from_expansion(); let primary_label = if from_expansion { + // We can't suggest eliding modifiers within expansions. + info.suggest_eliding_modes = false; // NB: This wording assumes the only expansions that can produce problematic reference // patterns and bindings are macros. If a desugaring or AST pass is added that can do // so, we may want to inspect the span's source callee or macro backtrace. "occurs within macro expansion".to_owned() } else { - let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind { - info.bad_modifiers |= true; - // If the user-provided binding modifier doesn't match the default binding mode, we'll - // need to suggest reference patterns, which can affect other bindings. - // For simplicity, we opt to suggest making the pattern fully explicit. - info.suggest_eliding_modes &= - user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); - "binding modifier" - } else { - info.bad_ref_pats |= true; - // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll - // suggest adding them instead, which can affect the types assigned to bindings. - // As such, we opt to suggest making the pattern fully explicit. - info.suggest_eliding_modes = false; - "reference pattern" - }; let dbm_str = match def_br_mutbl { Mutability::Not => "ref", Mutability::Mut => "ref mut", diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 6d1a2d3de9e..baf5dbbfd42 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -8,7 +8,6 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 31f585c0c9e..b346e193d0b 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -1,8 +1,7 @@ use std::fmt; -use rustc_ast_ir::try_visit; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor}; +use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor, try_visit}; use rustc_middle::ty::{self, TyCtxt}; use crate::traits; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c8de5e87753..044a613dad6 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -641,6 +641,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), + LintId::of(USAGE_OF_TYPE_IR_INHERENT), LintId::of(BAD_OPT_ACCESS), LintId::of(SPAN_USE_EQ_CTXT), ], diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index 527ca26c0eb..a7906d50d0f 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -36,12 +36,12 @@ pub(super) fn type_visitable_derive( s.add_bounds(synstructure::AddBounds::Generics); let body_visit = s.each(|bind| { quote! { - match ::rustc_ast_ir::visit::VisitorResult::branch( + match ::rustc_middle::ty::visit::VisitorResult::branch( ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor) ) { ::core::ops::ControlFlow::Continue(()) => {}, ::core::ops::ControlFlow::Break(r) => { - return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); + return ::rustc_middle::ty::visit::VisitorResult::from_residual(r); }, } } @@ -56,7 +56,7 @@ pub(super) fn type_visitable_derive( __visitor: &mut __V ) -> __V::Result { match *self { #body_visit } - <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + <__V::Result as ::rustc_middle::ty::visit::VisitorResult>::output() } }, ) diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 1b6a174c093..389c861c3b5 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -14,7 +14,6 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index dcfa81dab25..0b3c0be1a4e 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -37,9 +37,6 @@ middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty} middle_bounds_check = index out of bounds: the length is {$len} but the index is {$index} -middle_cannot_be_normalized = - unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized - middle_conflict_types = this expression supplies two conflicting concrete types for the same opaque type @@ -52,9 +49,6 @@ middle_const_eval_non_int = middle_const_not_used_in_type_alias = const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias -middle_cycle = - a cycle occurred during layout computation - middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note -> [true] : {$note} *[other] {""} @@ -78,9 +72,23 @@ middle_erroneous_constant = erroneous constant encountered middle_failed_writing_file = failed to write file {$path}: {$error}" +middle_layout_cycle = + a cycle occurred during layout computation + +middle_layout_normalization_failure = + unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized + middle_layout_references_error = the type has an unknown layout +middle_layout_size_overflow = + values of the type `{$ty}` are too big for the target architecture + +middle_layout_too_generic = the type `{$ty}` does not have a fixed layout + +middle_layout_unknown = + the type `{$ty}` has an unknown layout + middle_opaque_hidden_type_mismatch = concrete type differs from previous defining opaque type use .label = expected `{$self_ty}`, got `{$other_ty}` @@ -98,16 +106,8 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute -middle_too_generic = `{$ty}` does not have a fixed size - middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` -middle_unknown_layout = - the type `{$ty}` has an unknown layout - middle_unsupported_union = we don't support unions yet: '{$ty_name}' -middle_values_too_big = - values of the type `{$ty}` are too big for the target architecture - middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index c53e3d54cc4..be8a3403ba9 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -132,19 +132,19 @@ impl fmt::Debug for CustomSubdiagnostic<'_> { #[derive(Diagnostic)] pub enum LayoutError<'tcx> { - #[diag(middle_unknown_layout)] + #[diag(middle_layout_unknown)] Unknown { ty: Ty<'tcx> }, - #[diag(middle_too_generic)] + #[diag(middle_layout_too_generic)] TooGeneric { ty: Ty<'tcx> }, - #[diag(middle_values_too_big)] + #[diag(middle_layout_size_overflow)] Overflow { ty: Ty<'tcx> }, - #[diag(middle_cannot_be_normalized)] + #[diag(middle_layout_normalization_failure)] NormalizationFailure { ty: Ty<'tcx>, failure_ty: String }, - #[diag(middle_cycle)] + #[diag(middle_layout_cycle)] Cycle, #[diag(middle_layout_references_error)] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index b3064d8fe25..b5f3a0e1482 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -83,7 +83,7 @@ macro_rules! TrivialTypeTraversalImpls { _: &mut F) -> F::Result { - <F::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + <F::Result as ::rustc_middle::ty::visit::VisitorResult>::output() } } )+ diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 8861e31b099..743812e3a20 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -5,7 +5,6 @@ use std::{convert, fmt, mem, ops}; use either::Either; use rustc_abi::{Align, Size, VariantIdx, WrappingRange}; -use rustc_ast_ir::Mutability; use rustc_data_structures::sync::Lock; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; @@ -16,7 +15,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol}; use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; -use crate::ty::{self, Ty, TyCtxt, ValTree, layout, tls}; +use crate::ty::{self, Mutability, Ty, TyCtxt, ValTree, layout, tls}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum ErrorHandled { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cc22cabcb3e..71fed4b3e1e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use std::fmt::{self, Debug, Formatter}; +use std::iter; use std::ops::{Index, IndexMut}; -use std::{iter, mem}; pub use basic_blocks::{BasicBlocks, SwitchTargetValue}; use either::Either; @@ -32,7 +32,6 @@ use tracing::{debug, trace}; pub use self::query::*; use self::visit::TyContext; use crate::mir::interpret::{AllocRange, Scalar}; -use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::visit::TypeVisitableExt; @@ -53,7 +52,6 @@ pub mod pretty; mod query; mod statement; mod syntax; -pub mod tcx; mod terminator; pub mod traversal; @@ -1365,70 +1363,6 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator.as_mut().expect("invalid terminator state") } - pub fn retain_statements<F>(&mut self, mut f: F) - where - F: FnMut(&mut Statement<'_>) -> bool, - { - for s in &mut self.statements { - if !f(s) { - s.make_nop(); - } - } - } - - pub fn expand_statements<F, I>(&mut self, mut f: F) - where - F: FnMut(&mut Statement<'tcx>) -> Option<I>, - I: iter::TrustedLen<Item = Statement<'tcx>>, - { - // Gather all the iterators we'll need to splice in, and their positions. - let mut splices: Vec<(usize, I)> = vec![]; - let mut extra_stmts = 0; - for (i, s) in self.statements.iter_mut().enumerate() { - if let Some(mut new_stmts) = f(s) { - if let Some(first) = new_stmts.next() { - // We can already store the first new statement. - *s = first; - - // Save the other statements for optimized splicing. - let remaining = new_stmts.size_hint().0; - if remaining > 0 { - splices.push((i + 1 + extra_stmts, new_stmts)); - extra_stmts += remaining; - } - } else { - s.make_nop(); - } - } - } - - // Splice in the new statements, from the end of the block. - // FIXME(eddyb) This could be more efficient with a "gap buffer" - // where a range of elements ("gap") is left uninitialized, with - // splicing adding new elements to the end of that gap and moving - // existing elements from before the gap to the end of the gap. - // For now, this is safe code, emulating a gap but initializing it. - let mut gap = self.statements.len()..self.statements.len() + extra_stmts; - self.statements.resize( - gap.end, - Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop }, - ); - for (splice_start, new_stmts) in splices.into_iter().rev() { - let splice_end = splice_start + new_stmts.size_hint().0; - while gap.end > splice_end { - gap.start -= 1; - gap.end -= 1; - self.statements.swap(gap.start, gap.end); - } - self.statements.splice(splice_start..splice_end, new_stmts); - gap.end = splice_start; - } - } - - pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { - if index < self.statements.len() { &self.statements[index] } else { &self.terminator } - } - /// Does the block have no statements and an unreachable terminator? #[inline] pub fn is_empty_unreachable(&self) -> bool { @@ -1560,7 +1494,7 @@ pub struct SourceScopeLocalData { /// &'static str`. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct UserTypeProjections { - pub contents: Vec<(UserTypeProjection, Span)>, + pub contents: Vec<UserTypeProjection>, } impl<'tcx> UserTypeProjections { @@ -1572,26 +1506,17 @@ impl<'tcx> UserTypeProjections { self.contents.is_empty() } - pub fn projections_and_spans( - &self, - ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { - self.contents.iter() - } - pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator { - self.contents.iter().map(|&(ref user_type, _span)| user_type) + self.contents.iter() } - pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { - self.contents.push((user_ty.clone(), span)); + pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self { + self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] }); self } - fn map_projections( - mut self, - mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, - ) -> Self { - self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect(); + fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self { + self.contents = self.contents.into_iter().map(f).collect(); self } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d345c99f902..595a5e548b0 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1,7 +1,10 @@ //! Functionality for statements, operands, places, and things that appear in them. +use tracing::{debug, instrument}; + use super::interpret::GlobalAlloc; use super::*; +use crate::ty::CoroutineArgsExt; /////////////////////////////////////////////////////////////////////////// // Statements @@ -19,15 +22,6 @@ impl Statement<'_> { pub fn make_nop(&mut self) { self.kind = StatementKind::Nop } - - /// Changes a statement to a nop and returns the original statement. - #[must_use = "If you don't need the statement, use `make_nop` instead"] - pub fn replace_nop(&mut self) -> Self { - Statement { - source_info: self.source_info, - kind: mem::replace(&mut self.kind, StatementKind::Nop), - } - } } impl<'tcx> StatementKind<'tcx> { @@ -49,6 +43,162 @@ impl<'tcx> StatementKind<'tcx> { /////////////////////////////////////////////////////////////////////////// // Places +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +pub struct PlaceTy<'tcx> { + pub ty: Ty<'tcx>, + /// Downcast to a particular variant of an enum or a coroutine, if included. + pub variant_index: Option<VariantIdx>, +} + +// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. +#[cfg(target_pointer_width = "64")] +rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16); + +impl<'tcx> PlaceTy<'tcx> { + #[inline] + pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { + PlaceTy { ty, variant_index: None } + } + + /// `place_ty.field_ty(tcx, f)` computes the type of a given field. + /// + /// Most clients of `PlaceTy` can instead just extract the relevant type + /// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>` + /// do not carry a `Ty` for `T`. + /// + /// Note that the resulting type has not been normalized. + #[instrument(level = "debug", skip(tcx), ret)] + pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> { + if let Some(variant_index) = self.variant_index { + match *self.ty.kind() { + ty::Adt(adt_def, args) if adt_def.is_enum() => { + adt_def.variant(variant_index).fields[f].ty(tcx, args) + } + ty::Coroutine(def_id, args) => { + let mut variants = args.as_coroutine().state_tys(def_id, tcx); + let Some(mut variant) = variants.nth(variant_index.into()) else { + bug!("variant {variant_index:?} of coroutine out of range: {self:?}"); + }; + + variant + .nth(f.index()) + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")) + } + _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"), + } + } else { + match self.ty.kind() { + ty::Adt(adt_def, args) if !adt_def.is_enum() => { + adt_def.non_enum_variant().fields[f].ty(tcx, args) + } + ty::Closure(_, args) => args + .as_closure() + .upvar_tys() + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + ty::CoroutineClosure(_, args) => args + .as_coroutine_closure() + .upvar_tys() + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + // Only prefix fields (upvars and current state) are + // accessible without a variant index. + ty::Coroutine(_, args) => args + .as_coroutine() + .prefix_tys() + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + ty::Tuple(tys) => tys + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + _ => bug!("can't project out of {self:?}"), + } + } + } + + pub fn multi_projection_ty( + self, + tcx: TyCtxt<'tcx>, + elems: &[PlaceElem<'tcx>], + ) -> PlaceTy<'tcx> { + elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem)) + } + + /// Convenience wrapper around `projection_ty_core` for + /// `PlaceElem`, where we can just use the `Ty` that is already + /// stored inline on field projection elems. + pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { + self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty) + } + + /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` + /// projects `place_ty` onto `elem`, returning the appropriate + /// `Ty` or downcast variant corresponding to that projection. + /// The `handle_field` callback must map a `FieldIdx` to its `Ty`, + /// (which should be trivial when `T` = `Ty`). + pub fn projection_ty_core<V, T>( + self, + tcx: TyCtxt<'tcx>, + elem: &ProjectionElem<V, T>, + mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, + mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, + ) -> PlaceTy<'tcx> + where + V: ::std::fmt::Debug, + T: ::std::fmt::Debug + Copy, + { + if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) { + bug!("cannot use non field projection on downcasted place") + } + let answer = match *elem { + ProjectionElem::Deref => { + let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + bug!("deref projection of non-dereferenceable ty {:?}", self) + }); + PlaceTy::from_ty(ty) + } + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { + PlaceTy::from_ty(self.ty.builtin_index().unwrap()) + } + ProjectionElem::Subslice { from, to, from_end } => { + PlaceTy::from_ty(match self.ty.kind() { + ty::Slice(..) => self.ty, + ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), + ty::Array(inner, size) if from_end => { + let size = size + .try_to_target_usize(tcx) + .expect("expected subslice projection on fixed-size array"); + let len = size - from - to; + Ty::new_array(tcx, *inner, len) + } + _ => bug!("cannot subslice non-array type: `{:?}`", self), + }) + } + ProjectionElem::Downcast(_name, index) => { + PlaceTy { ty: self.ty, variant_index: Some(index) } + } + ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), + ProjectionElem::OpaqueCast(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + ProjectionElem::Subtype(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + + // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. + ProjectionElem::UnwrapUnsafeBinder(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + }; + debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); + answer + } +} + impl<V, T> ProjectionElem<V, T> { /// Returns `true` if the target of this projection may refer to a different region of memory /// than the base. @@ -192,6 +342,25 @@ impl<'tcx> Place<'tcx> { self.as_ref().project_deeper(more_projections, tcx) } + + pub fn ty_from<D: ?Sized>( + local: Local, + projection: &[PlaceElem<'tcx>], + local_decls: &D, + tcx: TyCtxt<'tcx>, + ) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection) + } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(self.local, self.projection, local_decls, tcx) + } } impl From<Local> for Place<'_> { @@ -294,6 +463,13 @@ impl<'tcx> PlaceRef<'tcx> { Place { local: self.local, projection: tcx.mk_place_elems(new_projections) } } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(self.local, self.projection, local_decls, tcx) + } } impl From<Local> for PlaceRef<'_> { @@ -388,6 +564,28 @@ impl<'tcx> Operand<'tcx> { let const_ty = self.constant()?.const_.ty(); if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None } } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> + where + D: HasLocalDecls<'tcx>, + { + match self { + &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, + Operand::Constant(c) => c.const_.ty(), + } + } + + pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span + where + D: HasLocalDecls<'tcx>, + { + match self { + &Operand::Copy(ref l) | &Operand::Move(ref l) => { + local_decls.local_decls()[l.local].source_info.span + } + Operand::Constant(c) => c.span, + } + } } impl<'tcx> ConstOperand<'tcx> { @@ -413,6 +611,11 @@ impl<'tcx> ConstOperand<'tcx> { /////////////////////////////////////////////////////////////////////////// /// Rvalues +pub enum RvalueInitializationState { + Shallow, + Deep, +} + impl<'tcx> Rvalue<'tcx> { /// Returns true if rvalue can be safely removed when the result is unused. #[inline] @@ -452,6 +655,70 @@ impl<'tcx> Rvalue<'tcx> { | Rvalue::WrapUnsafeBinder(_, _) => true, } } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> + where + D: HasLocalDecls<'tcx>, + { + match *self { + Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), + Rvalue::Repeat(ref operand, count) => { + Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count) + } + Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), + Rvalue::Ref(reg, bk, ref place) => { + let place_ty = place.ty(local_decls, tcx).ty; + Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy()) + } + Rvalue::RawPtr(kind, ref place) => { + let place_ty = place.ty(local_decls, tcx).ty; + Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy()) + } + Rvalue::Len(..) => tcx.types.usize, + Rvalue::Cast(.., ty) => ty, + Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { + let lhs_ty = lhs.ty(local_decls, tcx); + let rhs_ty = rhs.ty(local_decls, tcx); + op.ty(tcx, lhs_ty, rhs_ty) + } + Rvalue::UnaryOp(op, ref operand) => { + let arg_ty = operand.ty(local_decls, tcx); + op.ty(tcx, arg_ty) + } + Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { + tcx.types.usize + } + Rvalue::NullaryOp(NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, + Rvalue::Aggregate(ref ak, ref ops) => match **ak { + AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), + AggregateKind::Tuple => { + Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx))) + } + AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args), + AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args), + AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args), + AggregateKind::CoroutineClosure(did, args) => { + Ty::new_coroutine_closure(tcx, did, args) + } + AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability), + }, + Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), + Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, + Rvalue::WrapUnsafeBinder(_, ty) => ty, + } + } + + #[inline] + /// Returns `true` if this rvalue is deeply initialized (most rvalues) or + /// whether its only shallowly initialized (`Rvalue::Box`). + pub fn initialization_state(&self) -> RvalueInitializationState { + match *self { + Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, + _ => RvalueInitializationState::Deep, + } + } } impl BorrowKind { @@ -474,4 +741,124 @@ impl BorrowKind { BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } + + pub fn to_mutbl_lossy(self) -> hir::Mutability { + match self { + BorrowKind::Mut { .. } => hir::Mutability::Mut, + BorrowKind::Shared => hir::Mutability::Not, + + // We have no type corresponding to a shallow borrow, so use + // `&` as an approximation. + BorrowKind::Fake(_) => hir::Mutability::Not, + } + } +} + +impl<'tcx> UnOp { + pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { + match self { + UnOp::Not | UnOp::Neg => arg_ty, + UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx), + } + } +} + +impl<'tcx> BinOp { + pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> { + // FIXME: handle SIMD correctly + match self { + &BinOp::Add + | &BinOp::AddUnchecked + | &BinOp::Sub + | &BinOp::SubUnchecked + | &BinOp::Mul + | &BinOp::MulUnchecked + | &BinOp::Div + | &BinOp::Rem + | &BinOp::BitXor + | &BinOp::BitAnd + | &BinOp::BitOr => { + // these should be integers or floats of the same size. + assert_eq!(lhs_ty, rhs_ty); + lhs_ty + } + &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => { + // these should be integers of the same size. + assert_eq!(lhs_ty, rhs_ty); + Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool]) + } + &BinOp::Shl + | &BinOp::ShlUnchecked + | &BinOp::Shr + | &BinOp::ShrUnchecked + | &BinOp::Offset => { + lhs_ty // lhs_ty can be != rhs_ty + } + &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { + tcx.types.bool + } + &BinOp::Cmp => { + // these should be integer-like types of the same size. + assert_eq!(lhs_ty, rhs_ty); + tcx.ty_ordering_enum(None) + } + } + } + pub(crate) fn to_hir_binop(self) -> hir::BinOpKind { + match self { + // HIR `+`/`-`/`*` can map to either of these MIR BinOp, depending + // on whether overflow checks are enabled or not. + BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add, + BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub, + BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul, + BinOp::Div => hir::BinOpKind::Div, + BinOp::Rem => hir::BinOpKind::Rem, + BinOp::BitXor => hir::BinOpKind::BitXor, + BinOp::BitAnd => hir::BinOpKind::BitAnd, + BinOp::BitOr => hir::BinOpKind::BitOr, + BinOp::Shl => hir::BinOpKind::Shl, + BinOp::Shr => hir::BinOpKind::Shr, + BinOp::Eq => hir::BinOpKind::Eq, + BinOp::Ne => hir::BinOpKind::Ne, + BinOp::Lt => hir::BinOpKind::Lt, + BinOp::Gt => hir::BinOpKind::Gt, + BinOp::Le => hir::BinOpKind::Le, + BinOp::Ge => hir::BinOpKind::Ge, + // We don't have HIR syntax for these. + BinOp::Cmp + | BinOp::AddUnchecked + | BinOp::SubUnchecked + | BinOp::MulUnchecked + | BinOp::ShlUnchecked + | BinOp::ShrUnchecked + | BinOp::Offset => { + unreachable!() + } + } + } + + /// If this is a `FooWithOverflow`, return `Some(Foo)`. + pub fn overflowing_to_wrapping(self) -> Option<BinOp> { + Some(match self { + BinOp::AddWithOverflow => BinOp::Add, + BinOp::SubWithOverflow => BinOp::Sub, + BinOp::MulWithOverflow => BinOp::Mul, + _ => return None, + }) + } + + /// Returns whether this is a `FooWithOverflow` + pub fn is_overflowing(self) -> bool { + self.overflowing_to_wrapping().is_some() + } + + /// If this is a `Foo`, return `Some(FooWithOverflow)`. + pub fn wrapping_to_overflowing(self) -> Option<BinOp> { + Some(match self { + BinOp::Add => BinOp::AddWithOverflow, + BinOp::Sub => BinOp::SubWithOverflow, + BinOp::Mul => BinOp::MulWithOverflow, + _ => return None, + }) + } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index dfd40a9535b..389792a04f8 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1133,7 +1133,7 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; /// /// 1. The address in memory that the place refers to. /// 2. The provenance with which the place is being accessed. -/// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy]. +/// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::PlaceTy]. /// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. /// /// We'll give a description below of how all pieces of the place except for the provenance are diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs deleted file mode 100644 index 862f78d7259..00000000000 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ /dev/null @@ -1,416 +0,0 @@ -/*! - * Methods for the various MIR types. These are intended for use after - * building is complete. - */ - -use rustc_hir as hir; -use tracing::{debug, instrument}; -use ty::CoroutineArgsExt; - -use crate::mir::*; - -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] -pub struct PlaceTy<'tcx> { - pub ty: Ty<'tcx>, - /// Downcast to a particular variant of an enum or a coroutine, if included. - pub variant_index: Option<VariantIdx>, -} - -// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. -#[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16); - -impl<'tcx> PlaceTy<'tcx> { - #[inline] - pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { - PlaceTy { ty, variant_index: None } - } - - /// `place_ty.field_ty(tcx, f)` computes the type of a given field. - /// - /// Most clients of `PlaceTy` can instead just extract the relevant type - /// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>` - /// do not carry a `Ty` for `T`. - /// - /// Note that the resulting type has not been normalized. - #[instrument(level = "debug", skip(tcx), ret)] - pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> { - if let Some(variant_index) = self.variant_index { - match *self.ty.kind() { - ty::Adt(adt_def, args) if adt_def.is_enum() => { - adt_def.variant(variant_index).fields[f].ty(tcx, args) - } - ty::Coroutine(def_id, args) => { - let mut variants = args.as_coroutine().state_tys(def_id, tcx); - let Some(mut variant) = variants.nth(variant_index.into()) else { - bug!("variant {variant_index:?} of coroutine out of range: {self:?}"); - }; - - variant - .nth(f.index()) - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")) - } - _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"), - } - } else { - match self.ty.kind() { - ty::Adt(adt_def, args) if !adt_def.is_enum() => { - adt_def.non_enum_variant().fields[f].ty(tcx, args) - } - ty::Closure(_, args) => args - .as_closure() - .upvar_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - ty::CoroutineClosure(_, args) => args - .as_coroutine_closure() - .upvar_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - // Only prefix fields (upvars and current state) are - // accessible without a variant index. - ty::Coroutine(_, args) => args - .as_coroutine() - .prefix_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - ty::Tuple(tys) => tys - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - _ => bug!("can't project out of {self:?}"), - } - } - } - - pub fn multi_projection_ty( - self, - tcx: TyCtxt<'tcx>, - elems: &[PlaceElem<'tcx>], - ) -> PlaceTy<'tcx> { - elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem)) - } - - /// Convenience wrapper around `projection_ty_core` for - /// `PlaceElem`, where we can just use the `Ty` that is already - /// stored inline on field projection elems. - pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty) - } - - /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` - /// projects `place_ty` onto `elem`, returning the appropriate - /// `Ty` or downcast variant corresponding to that projection. - /// The `handle_field` callback must map a `FieldIdx` to its `Ty`, - /// (which should be trivial when `T` = `Ty`). - pub fn projection_ty_core<V, T>( - self, - tcx: TyCtxt<'tcx>, - elem: &ProjectionElem<V, T>, - mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, - mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, - ) -> PlaceTy<'tcx> - where - V: ::std::fmt::Debug, - T: ::std::fmt::Debug + Copy, - { - if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) { - bug!("cannot use non field projection on downcasted place") - } - let answer = match *elem { - ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", self) - }); - PlaceTy::from_ty(ty) - } - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { - PlaceTy::from_ty(self.ty.builtin_index().unwrap()) - } - ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match self.ty.kind() { - ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), - ty::Array(inner, size) if from_end => { - let size = size - .try_to_target_usize(tcx) - .expect("expected subslice projection on fixed-size array"); - let len = size - from - to; - Ty::new_array(tcx, *inner, len) - } - _ => bug!("cannot subslice non-array type: `{:?}`", self), - }) - } - ProjectionElem::Downcast(_name, index) => { - PlaceTy { ty: self.ty, variant_index: Some(index) } - } - ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), - ProjectionElem::OpaqueCast(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - ProjectionElem::Subtype(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - - // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. - ProjectionElem::UnwrapUnsafeBinder(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - }; - debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); - answer - } -} - -impl<'tcx> Place<'tcx> { - pub fn ty_from<D: ?Sized>( - local: Local, - projection: &[PlaceElem<'tcx>], - local_decls: &D, - tcx: TyCtxt<'tcx>, - ) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection) - } - - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - Place::ty_from(self.local, self.projection, local_decls, tcx) - } -} - -impl<'tcx> PlaceRef<'tcx> { - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - Place::ty_from(self.local, self.projection, local_decls, tcx) - } -} - -pub enum RvalueInitializationState { - Shallow, - Deep, -} - -impl<'tcx> Rvalue<'tcx> { - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match *self { - Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), - Rvalue::Repeat(ref operand, count) => { - Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count) - } - Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), - Rvalue::Ref(reg, bk, ref place) => { - let place_ty = place.ty(local_decls, tcx).ty; - Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy()) - } - Rvalue::RawPtr(kind, ref place) => { - let place_ty = place.ty(local_decls, tcx).ty; - Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy()) - } - Rvalue::Len(..) => tcx.types.usize, - Rvalue::Cast(.., ty) => ty, - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { - let lhs_ty = lhs.ty(local_decls, tcx); - let rhs_ty = rhs.ty(local_decls, tcx); - op.ty(tcx, lhs_ty, rhs_ty) - } - Rvalue::UnaryOp(op, ref operand) => { - let arg_ty = operand.ty(local_decls, tcx); - op.ty(tcx, arg_ty) - } - Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { - tcx.types.usize - } - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, - Rvalue::Aggregate(ref ak, ref ops) => match **ak { - AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), - AggregateKind::Tuple => { - Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx))) - } - AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args), - AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args), - AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args), - AggregateKind::CoroutineClosure(did, args) => { - Ty::new_coroutine_closure(tcx, did, args) - } - AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability), - }, - Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), - Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, - Rvalue::WrapUnsafeBinder(_, ty) => ty, - } - } - - #[inline] - /// Returns `true` if this rvalue is deeply initialized (most rvalues) or - /// whether its only shallowly initialized (`Rvalue::Box`). - pub fn initialization_state(&self) -> RvalueInitializationState { - match *self { - Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, - _ => RvalueInitializationState::Deep, - } - } -} - -impl<'tcx> Operand<'tcx> { - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match self { - &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - Operand::Constant(c) => c.const_.ty(), - } - } - - pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span - where - D: HasLocalDecls<'tcx>, - { - match self { - &Operand::Copy(ref l) | &Operand::Move(ref l) => { - local_decls.local_decls()[l.local].source_info.span - } - Operand::Constant(c) => c.span, - } - } -} - -impl<'tcx> BinOp { - pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> { - // FIXME: handle SIMD correctly - match self { - &BinOp::Add - | &BinOp::AddUnchecked - | &BinOp::Sub - | &BinOp::SubUnchecked - | &BinOp::Mul - | &BinOp::MulUnchecked - | &BinOp::Div - | &BinOp::Rem - | &BinOp::BitXor - | &BinOp::BitAnd - | &BinOp::BitOr => { - // these should be integers or floats of the same size. - assert_eq!(lhs_ty, rhs_ty); - lhs_ty - } - &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => { - // these should be integers of the same size. - assert_eq!(lhs_ty, rhs_ty); - Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool]) - } - &BinOp::Shl - | &BinOp::ShlUnchecked - | &BinOp::Shr - | &BinOp::ShrUnchecked - | &BinOp::Offset => { - lhs_ty // lhs_ty can be != rhs_ty - } - &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { - tcx.types.bool - } - &BinOp::Cmp => { - // these should be integer-like types of the same size. - assert_eq!(lhs_ty, rhs_ty); - tcx.ty_ordering_enum(None) - } - } - } -} - -impl<'tcx> UnOp { - pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { - match self { - UnOp::Not | UnOp::Neg => arg_ty, - UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx), - } - } -} - -impl BorrowKind { - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - BorrowKind::Mut { .. } => hir::Mutability::Mut, - BorrowKind::Shared => hir::Mutability::Not, - - // We have no type corresponding to a shallow borrow, so use - // `&` as an approximation. - BorrowKind::Fake(_) => hir::Mutability::Not, - } - } -} - -impl BinOp { - pub(crate) fn to_hir_binop(self) -> hir::BinOpKind { - match self { - // HIR `+`/`-`/`*` can map to either of these MIR BinOp, depending - // on whether overflow checks are enabled or not. - BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add, - BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub, - BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul, - BinOp::Div => hir::BinOpKind::Div, - BinOp::Rem => hir::BinOpKind::Rem, - BinOp::BitXor => hir::BinOpKind::BitXor, - BinOp::BitAnd => hir::BinOpKind::BitAnd, - BinOp::BitOr => hir::BinOpKind::BitOr, - BinOp::Shl => hir::BinOpKind::Shl, - BinOp::Shr => hir::BinOpKind::Shr, - BinOp::Eq => hir::BinOpKind::Eq, - BinOp::Ne => hir::BinOpKind::Ne, - BinOp::Lt => hir::BinOpKind::Lt, - BinOp::Gt => hir::BinOpKind::Gt, - BinOp::Le => hir::BinOpKind::Le, - BinOp::Ge => hir::BinOpKind::Ge, - // We don't have HIR syntax for these. - BinOp::Cmp - | BinOp::AddUnchecked - | BinOp::SubUnchecked - | BinOp::MulUnchecked - | BinOp::ShlUnchecked - | BinOp::ShrUnchecked - | BinOp::Offset => { - unreachable!() - } - } - } - - /// If this is a `FooWithOverflow`, return `Some(Foo)`. - pub fn overflowing_to_wrapping(self) -> Option<BinOp> { - Some(match self { - BinOp::AddWithOverflow => BinOp::Add, - BinOp::SubWithOverflow => BinOp::Sub, - BinOp::MulWithOverflow => BinOp::Mul, - _ => return None, - }) - } - - /// Returns whether this is a `FooWithOverflow` - pub fn is_overflowing(self) -> bool { - self.overflowing_to_wrapping().is_some() - } - - /// If this is a `Foo`, return `Some(FooWithOverflow)`. - pub fn wrapping_to_overflowing(self) -> Option<BinOp> { - Some(match self { - BinOp::Add => BinOp::AddWithOverflow, - BinOp::Sub => BinOp::SubWithOverflow, - BinOp::Mul => BinOp::MulWithOverflow, - _ => return None, - }) - } -} diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8ad88fbda7c..98e8f269c57 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -270,10 +270,12 @@ macro_rules! make_mir_visitor { fn visit_local( &mut self, - _local: $(& $mutability)? Local, - _context: PlaceContext, - _location: Location, - ) {} + local: $(& $mutability)? Local, + context: PlaceContext, + location: Location, + ) { + self.super_local(local, context, location) + } fn visit_source_scope( &mut self, @@ -292,9 +294,11 @@ macro_rules! make_mir_visitor { super_body!(self, body, $($mutability, true)?); } - fn super_basic_block_data(&mut self, - block: BasicBlock, - data: & $($mutability)? BasicBlockData<'tcx>) { + fn super_basic_block_data( + &mut self, + block: BasicBlock, + data: & $($mutability)? BasicBlockData<'tcx>) + { let BasicBlockData { statements, terminator, @@ -339,24 +343,24 @@ macro_rules! make_mir_visitor { match callee_def { ty::InstanceKind::Item(_def_id) => {} - ty::InstanceKind::Intrinsic(_def_id) | - ty::InstanceKind::VTableShim(_def_id) | - ty::InstanceKind::ReifyShim(_def_id, _) | - ty::InstanceKind::Virtual(_def_id, _) | - ty::InstanceKind::ThreadLocalShim(_def_id) | - ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceKind::ConstructCoroutineInClosureShim { + ty::InstanceKind::Intrinsic(_def_id) + | ty::InstanceKind::VTableShim(_def_id) + | ty::InstanceKind::ReifyShim(_def_id, _) + | ty::InstanceKind::Virtual(_def_id, _) + | ty::InstanceKind::ThreadLocalShim(_def_id) + | ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ } + | ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, receiver_by_ref: _, - } | - ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None) | - ty::InstanceKind::DropGlue(_def_id, None) => {} - - ty::InstanceKind::FnPtrShim(_def_id, ty) | - ty::InstanceKind::DropGlue(_def_id, Some(ty)) | - ty::InstanceKind::CloneShim(_def_id, ty) | - ty::InstanceKind::FnPtrAddrShim(_def_id, ty) | - ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { + } + | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None) + | ty::InstanceKind::DropGlue(_def_id, None) => {} + + ty::InstanceKind::FnPtrShim(_def_id, ty) + | ty::InstanceKind::DropGlue(_def_id, Some(ty)) + | ty::InstanceKind::CloneShim(_def_id, ty) + | ty::InstanceKind::FnPtrAddrShim(_def_id, ty) + | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } @@ -368,19 +372,16 @@ macro_rules! make_mir_visitor { } } - fn super_statement(&mut self, - statement: & $($mutability)? Statement<'tcx>, - location: Location) { - let Statement { - source_info, - kind, - } = statement; + fn super_statement( + &mut self, + statement: & $($mutability)? Statement<'tcx>, + location: Location + ) { + let Statement { source_info, kind } = statement; self.visit_source_info(source_info); match kind { - StatementKind::Assign( - box (place, rvalue) - ) => { + StatementKind::Assign(box (place, rvalue)) => { self.visit_assign(place, rvalue, location); } StatementKind::FakeRead(box (_, place)) => { @@ -428,11 +429,13 @@ macro_rules! make_mir_visitor { location ); } - StatementKind::AscribeUserType( - box (place, user_ty), - variance - ) => { - self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location); + StatementKind::AscribeUserType(box (place, user_ty), variance) => { + self.visit_ascribe_user_ty( + place, + $(& $mutability)? *variance, + user_ty, + location + ); } StatementKind::Coverage(coverage) => { self.visit_coverage( @@ -443,7 +446,11 @@ macro_rules! make_mir_visitor { StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => { match intrinsic { NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location), - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src, + dst, + count + }) => { self.visit_operand(src, location); self.visit_operand(dst, location); self.visit_operand(count, location); @@ -456,10 +463,12 @@ macro_rules! make_mir_visitor { } } - fn super_assign(&mut self, - place: &$($mutability)? Place<'tcx>, - rvalue: &$($mutability)? Rvalue<'tcx>, - location: Location) { + fn super_assign( + &mut self, + place: &$($mutability)? Place<'tcx>, + rvalue: &$($mutability)? Rvalue<'tcx>, + location: Location + ) { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Store), @@ -468,20 +477,22 @@ macro_rules! make_mir_visitor { self.visit_rvalue(rvalue, location); } - fn super_terminator(&mut self, - terminator: &$($mutability)? Terminator<'tcx>, - location: Location) { + fn super_terminator( + &mut self, + terminator: &$($mutability)? Terminator<'tcx>, + location: Location + ) { let Terminator { source_info, kind } = terminator; self.visit_source_info(source_info); match kind { - TerminatorKind::Goto { .. } | - TerminatorKind::UnwindResume | - TerminatorKind::UnwindTerminate(_) | - TerminatorKind::CoroutineDrop | - TerminatorKind::Unreachable | - TerminatorKind::FalseEdge { .. } | - TerminatorKind::FalseUnwind { .. } => {} + TerminatorKind::Goto { .. } + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::CoroutineDrop + | TerminatorKind::Unreachable + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => {} TerminatorKind::Return => { // `return` logically moves from the return place `_0`. Note that the place @@ -500,19 +511,11 @@ macro_rules! make_mir_visitor { ); } - TerminatorKind::SwitchInt { - discr, - targets: _ - } => { + TerminatorKind::SwitchInt { discr, targets: _ } => { self.visit_operand(discr, location); } - TerminatorKind::Drop { - place, - target: _, - unwind: _, - replace: _, - } => { + TerminatorKind::Drop { place, target: _, unwind: _, replace: _ } => { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Drop), @@ -541,11 +544,7 @@ macro_rules! make_mir_visitor { ); } - TerminatorKind::TailCall { - func, - args, - fn_span, - } => { + TerminatorKind::TailCall { func, args, fn_span } => { self.visit_span($(& $mutability)? *fn_span); self.visit_operand(func, location); for arg in args { @@ -553,23 +552,12 @@ macro_rules! make_mir_visitor { } }, - TerminatorKind::Assert { - cond, - expected: _, - msg, - target: _, - unwind: _, - } => { + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { self.visit_operand(cond, location); self.visit_assert_message(msg, location); } - TerminatorKind::Yield { - value, - resume: _, - resume_arg, - drop: _, - } => { + TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { self.visit_operand(value, location); self.visit_place( resume_arg, @@ -622,9 +610,11 @@ macro_rules! make_mir_visitor { } } - fn super_assert_message(&mut self, - msg: & $($mutability)? AssertMessage<'tcx>, - location: Location) { + fn super_assert_message( + &mut self, + msg: & $($mutability)? AssertMessage<'tcx>, + location: Location + ) { use crate::mir::AssertKind::*; match msg { BoundsCheck { len, index } => { @@ -648,9 +638,11 @@ macro_rules! make_mir_visitor { } } - fn super_rvalue(&mut self, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { + fn super_rvalue( + &mut self, + rvalue: & $($mutability)? Rvalue<'tcx>, + location: Location + ) { match rvalue { Rvalue::Use(operand) => { self.visit_operand(operand, location); @@ -677,6 +669,7 @@ macro_rules! make_mir_visitor { }; self.visit_place(path, ctx, location); } + Rvalue::CopyForDeref(place) => { self.visit_place( place, @@ -740,8 +733,7 @@ macro_rules! make_mir_visitor { AggregateKind::Array(ty) => { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } - AggregateKind::Tuple => { - } + AggregateKind::Tuple => {} AggregateKind::Adt( _adt_def, _variant_index, @@ -751,22 +743,13 @@ macro_rules! make_mir_visitor { ) => { self.visit_args(args, location); } - AggregateKind::Closure( - _, - closure_args - ) => { + AggregateKind::Closure(_, closure_args) => { self.visit_args(closure_args, location); } - AggregateKind::Coroutine( - _, - coroutine_args, - ) => { + AggregateKind::Coroutine(_, coroutine_args) => { self.visit_args(coroutine_args, location); } - AggregateKind::CoroutineClosure( - _, - coroutine_closure_args, - ) => { + AggregateKind::CoroutineClosure(_, coroutine_closure_args) => { self.visit_args(coroutine_closure_args, location); } AggregateKind::RawPtr(ty, _) => { @@ -791,9 +774,11 @@ macro_rules! make_mir_visitor { } } - fn super_operand(&mut self, - operand: & $($mutability)? Operand<'tcx>, - location: Location) { + fn super_operand( + &mut self, + operand: & $($mutability)? Operand<'tcx>, + location: Location + ) { match operand { Operand::Copy(place) => { self.visit_place( @@ -815,28 +800,36 @@ macro_rules! make_mir_visitor { } } - fn super_ascribe_user_ty(&mut self, - place: & $($mutability)? Place<'tcx>, - variance: $(& $mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection, - location: Location) { + fn super_ascribe_user_ty( + &mut self, + place: & $($mutability)? Place<'tcx>, + variance: $(& $mutability)? ty::Variance, + user_ty: & $($mutability)? UserTypeProjection, + location: Location) + { self.visit_place( place, - PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)), + PlaceContext::NonUse( + NonUseContext::AscribeUserTy($(* &$mutability *)? variance) + ), location ); self.visit_user_type_projection(user_ty); } - fn super_coverage(&mut self, - _kind: & $($mutability)? coverage::CoverageKind, - _location: Location) { + fn super_coverage( + &mut self, + _kind: & $($mutability)? coverage::CoverageKind, + _location: Location + ) { } - fn super_retag(&mut self, - _kind: $(& $mutability)? RetagKind, - place: & $($mutability)? Place<'tcx>, - location: Location) { + fn super_retag( + &mut self, + _kind: $(& $mutability)? RetagKind, + place: & $($mutability)? Place<'tcx>, + location: Location + ) { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Retag), @@ -844,9 +837,11 @@ macro_rules! make_mir_visitor { ); } - fn super_local_decl(&mut self, - local: Local, - local_decl: & $($mutability)? LocalDecl<'tcx>) { + fn super_local_decl( + &mut self, + local: Local, + local_decl: & $($mutability)? LocalDecl<'tcx> + ) { let LocalDecl { mutability: _, ty, @@ -862,12 +857,20 @@ macro_rules! make_mir_visitor { source_info: *source_info, }); if let Some(user_ty) = user_ty { - for (user_ty, _) in & $($mutability)? user_ty.contents { + for user_ty in & $($mutability)? user_ty.contents { self.visit_user_type_projection(user_ty); } } } + fn super_local( + &mut self, + _local: $(& $mutability)? Local, + _context: PlaceContext, + _location: Location, + ) { + } + fn super_var_debug_info( &mut self, var_debug_info: & $($mutability)? VarDebugInfo<'tcx> @@ -882,7 +885,10 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); let location = Location::START; - if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite { + if let Some(box VarDebugInfoFragment { + ref $($mutability)? ty, + ref $($mutability)? projection + }) = composite { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); for elem in projection { let ProjectionElem::Field(_, ty) = elem else { bug!() }; @@ -900,10 +906,7 @@ macro_rules! make_mir_visitor { } } - fn super_source_scope( - &mut self, - _scope: $(& $mutability)? SourceScope - ) {} + fn super_source_scope(&mut self, _scope: $(& $mutability)? SourceScope) {} fn super_const_operand( &mut self, @@ -919,8 +922,12 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); match const_ { Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location), - Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), - Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + Const::Val(_, ty) => { + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } + Const::Unevaluated(_, ty) => { + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } } } @@ -929,27 +936,18 @@ macro_rules! make_mir_visitor { _ct: $(& $mutability)? ty::Const<'tcx>, _location: Location, ) { - } - fn super_span(&mut self, _span: $(& $mutability)? Span) { - } + fn super_span(&mut self, _span: $(& $mutability)? Span) {} fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) { - let SourceInfo { - span, - scope, - } = source_info; + let SourceInfo { span, scope } = source_info; self.visit_span($(& $mutability)? *span); self.visit_source_scope($(& $mutability)? *scope); } - fn super_user_type_projection( - &mut self, - _ty: & $($mutability)? UserTypeProjection, - ) { - } + fn super_user_type_projection(&mut self, _ty: & $($mutability)? UserTypeProjection) {} fn super_user_type_annotation( &mut self, @@ -960,14 +958,11 @@ macro_rules! make_mir_visitor { self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); } - fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) { - } + fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {} - fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) { - } + fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {} - fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) { - } + fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) {} // Convenience methods @@ -976,7 +971,8 @@ macro_rules! make_mir_visitor { body: &$($mutability)? Body<'tcx>, location: Location ) { - let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; + let basic_block = + & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; if basic_block.statements.len() == location.statement_index { if let Some(ref $($mutability)? terminator) = basic_block.terminator { self.visit_terminator(terminator, location) @@ -1255,28 +1251,6 @@ macro_rules! visit_place_fns { make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor, mut); -pub trait MirVisitable<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>); -} - -impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_statement(self, location) - } -} - -impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_terminator(self, location) - } -} - -impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_terminator(self.as_ref().unwrap(), location) - } -} - /// Extra information passed to `visit_ty` and friends to give context /// about where the type etc appears. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 693823b4af4..7c4ea06a746 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -802,7 +802,7 @@ rustc_queries! { query adt_dtorck_constraint( key: DefId - ) -> Result<&'tcx DropckConstraint<'tcx>, NoSolution> { + ) -> &'tcx DropckConstraint<'tcx> { desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 2ab8750f727..98cc00c367c 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -376,7 +376,6 @@ pub enum ExprKind<'tcx> { /// A `match` expression. Match { scrutinee: ExprId, - scrutinee_hir_id: HirId, arms: Box<[ArmId]>, match_source: MatchSource, }, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index f659bf8125a..9c74f6263b3 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,9 +1,9 @@ -use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::HashStable; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; +use crate::ty::visit::try_visit; use crate::ty::{ self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 56a38a84c9f..b74ddb81710 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -6,8 +6,6 @@ use std::mem; use std::num::NonZero; use std::ptr::NonNull; -use rustc_ast_ir::visit::VisitorResult; -use rustc_ast_ir::walk_visitable_list; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; @@ -18,7 +16,7 @@ use smallvec::SmallVec; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::visit::{TypeVisitable, TypeVisitor}; +use crate::ty::visit::{TypeVisitable, TypeVisitor, VisitorResult, walk_visitable_list}; use crate::ty::{ self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt, }; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index bbb8a9fa671..eb14ed20fba 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -229,11 +229,32 @@ impl fmt::Display for ValidityRequirement { #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub enum LayoutError<'tcx> { + /// A type doesn't have a sensible layout. + /// + /// This variant is used for layout errors that don't necessarily cause + /// compile errors. + /// + /// For example, this can happen if a struct contains an unsized type in a + /// non-tail field, but has an unsatisfiable bound like `str: Sized`. Unknown(Ty<'tcx>), + /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`]. SizeOverflow(Ty<'tcx>), + /// The layout can vary due to a generic parameter. + /// + /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout + /// may become computable after further instantiating the generic parameter(s). TooGeneric(Ty<'tcx>), + /// An alias failed to normalize. + /// + /// This variant is necessary, because, due to trait solver incompleteness, it is + /// possible than an alias that was rigid during analysis fails to normalize after + /// revealing opaque types. + /// + /// See `tests/ui/layout/normalization-failure.rs` for an example. NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), + /// A non-layout error is reported elsewhere. ReferencesError(ErrorGuaranteed), + /// A type has cyclic layout, i.e. the type contains itself without indirection. Cycle(ErrorGuaranteed), } @@ -243,11 +264,11 @@ impl<'tcx> LayoutError<'tcx> { use crate::fluent_generated::*; match self { - Unknown(_) => middle_unknown_layout, - SizeOverflow(_) => middle_values_too_big, - TooGeneric(_) => middle_too_generic, - NormalizationFailure(_, _) => middle_cannot_be_normalized, - Cycle(_) => middle_cycle, + Unknown(_) => middle_layout_unknown, + SizeOverflow(_) => middle_layout_size_overflow, + TooGeneric(_) => middle_layout_too_generic, + NormalizationFailure(_, _) => middle_layout_normalization_failure, + Cycle(_) => middle_layout_cycle, ReferencesError(_) => middle_layout_references_error, } } @@ -276,7 +297,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { match *self { LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"), LayoutError::TooGeneric(ty) => { - write!(f, "`{ty}` does not have a fixed size") + write!(f, "the type `{ty}` does not have a fixed layout") } LayoutError::SizeOverflow(ty) => { write!(f, "values of the type `{ty}` are too big for the target architecture") @@ -773,8 +794,9 @@ where Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, - backend_repr: BackendRepr::Uninhabited, + backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, + uninhabited: true, align: tcx.data_layout.i8_align, size: Size::ZERO, max_repr_align: None, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c52e774c8b7..a1d44882e63 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,6 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -48,7 +47,7 @@ pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::relate::VarianceDiagInfo; -pub use rustc_type_ir::*; +pub use rustc_type_ir::{Movability, Mutability, *}; use tracing::{debug, instrument}; pub use vtable::*; use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6c15e033bb0..b2286c74402 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,13 +7,12 @@ use std::fmt::{self, Debug}; use rustc_abi::TyAndLayout; use rustc_ast::InlineAsmTemplatePiece; -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_type_ir::ConstKind; +use rustc_type_ir::visit::{VisitorResult, try_visit}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 4efaccefcf7..95256b55bb4 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxIndexSet; use rustc_type_ir::fold::TypeFoldable; -pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +pub use rustc_type_ir::visit::*; use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index eab414e150f..19669021eef 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -1,6 +1,5 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index ed577f7adeb..6334612eced 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -926,12 +926,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Note that the variance doesn't apply here, as we are tracking the effect // of `user_ty` on any bindings contained with subpattern. - let projection = UserTypeProjection { - base: self.canonical_user_type_annotations.push(annotation.clone()), - projs: Vec::new(), - }; - let subpattern_user_ty = - pattern_user_ty.push_projection(&projection, annotation.span); + let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); + let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty); self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 54da6924db4..d0fca76fcf0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -828,7 +828,6 @@ impl<'tcx> ThirBuildCx<'tcx> { }, hir::ExprKind::Match(discr, arms, match_source) => ExprKind::Match { scrutinee: self.mirror_expr(discr), - scrutinee_hir_id: discr.hir_id, arms: arms.iter().map(|a| self.convert_arm(a)).collect(), match_source, }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 1e738801011..6dbb460d8b1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -151,7 +151,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { } return; } - ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => { + ExprKind::Match { scrutinee, box ref arms, match_source } => { self.check_match(scrutinee, arms, match_source, ex.span); } ExprKind::Let { box ref pat, expr } => { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index b6c259aa4e0..8bbc89fdcec 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -1,7 +1,6 @@ use std::mem; use rustc_index::IndexVec; -use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index a51af8c40fd..104a2e8c091 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index afc49c5cc54..f3f3a65cd80 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -393,12 +393,13 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { // Remove StorageLive and StorageDead statements for remapped locals - data.retain_statements(|s| match s.kind { - StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - !self.remap.contains(l) + for s in &mut data.statements { + if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind + && self.remap.contains(l) + { + s.make_nop(); } - _ => true, - }); + } let ret_val = match data.terminator().kind { TerminatorKind::Return => { diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 264995efe8f..1ccae0fd7fe 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -346,35 +346,37 @@ fn extract_hole_spans_from_hir<'tcx>( body_span: Span, // Usually `hir_body.value.span`, but not always hir_body: &hir::Body<'tcx>, ) -> Vec<Span> { - struct HolesVisitor<'hir, F> { - tcx: TyCtxt<'hir>, - visit_hole_span: F, + struct HolesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + body_span: Span, + hole_spans: Vec<Span>, } - impl<'hir, F: FnMut(Span)> Visitor<'hir> for HolesVisitor<'hir, F> { - /// - We need `NestedFilter::INTRA = true` so that `visit_item` will be called. - /// - Bodies of nested items don't actually get visited, because of the - /// `visit_item` override. - /// - For nested bodies that are not part of an item, we do want to visit any - /// items contained within them. - type NestedFilter = nested_filter::All; + impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> { + /// We have special handling for nested items, but we still want to + /// traverse into nested bodies of things that are not considered items, + /// such as "anon consts" (e.g. array lengths). + type NestedFilter = nested_filter::OnlyBodies; - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { self.tcx } - fn visit_item(&mut self, item: &'hir hir::Item<'hir>) { - (self.visit_hole_span)(item.span); + /// We override `visit_nested_item` instead of `visit_item` because we + /// only need the item's span, not the item itself. + fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result { + let span = self.tcx.def_span(id.owner_id.def_id); + self.visit_hole_span(span); // Having visited this item, we don't care about its children, // so don't call `walk_item`. } // We override `visit_expr` instead of the more specific expression // visitors, so that we have direct access to the expression span. - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { match expr.kind { hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => { - (self.visit_hole_span)(expr.span); + self.visit_hole_span(expr.span); // Having visited this expression, we don't care about its // children, so don't call `walk_expr`. } @@ -384,18 +386,17 @@ fn extract_hole_spans_from_hir<'tcx>( } } } - - let mut hole_spans = vec![]; - let mut visitor = HolesVisitor { - tcx, - visit_hole_span: |hole_span| { + impl HolesVisitor<'_> { + fn visit_hole_span(&mut self, hole_span: Span) { // Discard any holes that aren't directly visible within the body span. - if body_span.contains(hole_span) && body_span.eq_ctxt(hole_span) { - hole_spans.push(hole_span); + if self.body_span.contains(hole_span) && self.body_span.eq_ctxt(hole_span) { + self.hole_spans.push(hole_span); } - }, - }; + } + } + + let mut visitor = HolesVisitor { tcx, body_span, hole_spans: vec![] }; visitor.visit_body(hir_body); - hole_spans + visitor.hole_spans } diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 2de55e38052..0d8cf524661 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -185,7 +185,7 @@ where place.ty(self.elaborator.body(), self.tcx()).ty } else { // We don't have a slice with all the locals, since some are in the patch. - tcx::PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local)) + PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local)) .multi_projection_ty(self.elaborator.tcx(), place.projection) .ty } @@ -266,8 +266,21 @@ where let tcx = self.tcx(); assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis); - let field_ty = - tcx.normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args)); + // The type error for normalization may have been in dropck: see + // `compute_drop_data` in rustc_borrowck, in which case we wouldn't have + // deleted the MIR body and could have an error here as well. + let field_ty = match tcx + .try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args)) + { + Ok(t) => t, + Err(_) => Ty::new_error( + self.tcx(), + self.elaborator + .body() + .tainted_by_errors + .expect("Error in drop elaboration not found by dropck."), + ), + }; (tcx.mk_place_field(base_place, field, field_ty), subpath) }) diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index ab6aafab446..530c72ca549 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -417,7 +417,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { .. } = data.terminator().kind { - assert!(!self.patch.is_patched(bb)); + assert!(!self.patch.is_term_patched(bb)); let loc = Location { block: tgt, statement_index: 0 }; let path = self.move_data().rev_lookup.find(destination.as_ref()); @@ -462,7 +462,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { // a Goto; see `MirPatch::new`). } _ => { - assert!(!self.patch.is_patched(bb)); + assert!(!self.patch.is_term_patched(bb)); } } } @@ -486,7 +486,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { .. } = data.terminator().kind { - assert!(!self.patch.is_patched(bb)); + assert!(!self.patch.is_term_patched(bb)); let loc = Location { block: bb, statement_index: data.statements.len() }; let path = self.move_data().rev_lookup.find(destination.as_ref()); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 77a3854ebde..2f8a3050199 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1558,8 +1558,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return true; }; + if layout.uninhabited { + return true; + } + match layout.backend_repr { - BackendRepr::Uninhabited => true, BackendRepr::Scalar(a) => !a.is_always_valid(&self.ecx), BackendRepr::ScalarPair(a, b) => { !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 1e546bfbeb3..47cb478fe33 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -6,6 +6,8 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::Session; +use crate::patch::MirPatch; + /// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large /// enough discrepancy between them. /// @@ -41,31 +43,34 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { let mut alloc_cache = FxHashMap::default(); let typing_env = body.typing_env(tcx); - let blocks = body.basic_blocks.as_mut(); - let local_decls = &mut body.local_decls; + let mut patch = MirPatch::new(body); - for bb in blocks { - bb.expand_statements(|st| { + for (block, data) in body.basic_blocks.as_mut().iter_enumerated_mut() { + for (statement_index, st) in data.statements.iter_mut().enumerate() { let StatementKind::Assign(box ( lhs, Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), )) = &st.kind else { - return None; + continue; }; - let ty = lhs.ty(local_decls, tcx).ty; + let location = Location { block, statement_index }; - let (adt_def, num_variants, alloc_id) = - self.candidate(tcx, typing_env, ty, &mut alloc_cache)?; + let ty = lhs.ty(&body.local_decls, tcx).ty; - let source_info = st.source_info; - let span = source_info.span; + let Some((adt_def, num_variants, alloc_id)) = + self.candidate(tcx, typing_env, ty, &mut alloc_cache) + else { + continue; + }; + + let span = st.source_info.span; let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64); - let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span)); - let store_live = - Statement { source_info, kind: StatementKind::StorageLive(size_array_local) }; + let size_array_local = patch.new_temp(tmp_ty, span); + + let store_live = StatementKind::StorageLive(size_array_local); let place = Place::from(size_array_local); let constant_vals = ConstOperand { @@ -77,108 +82,63 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { ), }; let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals))); - let const_assign = - Statement { source_info, kind: StatementKind::Assign(Box::new((place, rval))) }; - - let discr_place = Place::from( - local_decls.push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)), - ); - let store_discr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - discr_place, - Rvalue::Discriminant(*rhs), - ))), - }; - - let discr_cast_place = - Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span))); - let cast_discr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - discr_cast_place, - Rvalue::Cast( - CastKind::IntToInt, - Operand::Copy(discr_place), - tcx.types.usize, - ), - ))), - }; - - let size_place = - Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span))); - let store_size = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - size_place, - Rvalue::Use(Operand::Copy(Place { - local: size_array_local, - projection: tcx - .mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]), - })), - ))), - }; - - let dst = - Place::from(local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span))); - let dst_ptr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - dst, - Rvalue::RawPtr(RawPtrKind::Mut, *lhs), - ))), - }; + let const_assign = StatementKind::Assign(Box::new((place, rval))); + + let discr_place = + Place::from(patch.new_temp(adt_def.repr().discr_type().to_ty(tcx), span)); + let store_discr = + StatementKind::Assign(Box::new((discr_place, Rvalue::Discriminant(*rhs)))); + + let discr_cast_place = Place::from(patch.new_temp(tcx.types.usize, span)); + let cast_discr = StatementKind::Assign(Box::new(( + discr_cast_place, + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_place), tcx.types.usize), + ))); + + let size_place = Place::from(patch.new_temp(tcx.types.usize, span)); + let store_size = StatementKind::Assign(Box::new(( + size_place, + Rvalue::Use(Operand::Copy(Place { + local: size_array_local, + projection: tcx.mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]), + })), + ))); + + let dst = Place::from(patch.new_temp(Ty::new_mut_ptr(tcx, ty), span)); + let dst_ptr = + StatementKind::Assign(Box::new((dst, Rvalue::RawPtr(RawPtrKind::Mut, *lhs)))); let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8); - let dst_cast_place = - Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span))); - let dst_cast = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - dst_cast_place, - Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty), - ))), - }; + let dst_cast_place = Place::from(patch.new_temp(dst_cast_ty, span)); + let dst_cast = StatementKind::Assign(Box::new(( + dst_cast_place, + Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty), + ))); - let src = - Place::from(local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span))); - let src_ptr = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - src, - Rvalue::RawPtr(RawPtrKind::Const, *rhs), - ))), - }; + let src = Place::from(patch.new_temp(Ty::new_imm_ptr(tcx, ty), span)); + let src_ptr = + StatementKind::Assign(Box::new((src, Rvalue::RawPtr(RawPtrKind::Const, *rhs)))); let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8); - let src_cast_place = - Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span))); - let src_cast = Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - src_cast_place, - Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty), - ))), - }; + let src_cast_place = Place::from(patch.new_temp(src_cast_ty, span)); + let src_cast = StatementKind::Assign(Box::new(( + src_cast_place, + Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty), + ))); - let deinit_old = - Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) }; - - let copy_bytes = Statement { - source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src: Operand::Copy(src_cast_place), - dst: Operand::Copy(dst_cast_place), - count: Operand::Copy(size_place), - }), - )), - }; + let deinit_old = StatementKind::Deinit(Box::new(dst)); + + let copy_bytes = StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src: Operand::Copy(src_cast_place), + dst: Operand::Copy(dst_cast_place), + count: Operand::Copy(size_place), + }), + )); - let store_dead = - Statement { source_info, kind: StatementKind::StorageDead(size_array_local) }; + let store_dead = StatementKind::StorageDead(size_array_local); - let iter = [ + let stmts = [ store_live, const_assign, store_discr, @@ -191,14 +151,16 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { deinit_old, copy_bytes, store_dead, - ] - .into_iter(); + ]; + for stmt in stmts { + patch.add_statement(location, stmt); + } st.make_nop(); - - Some(iter) - }); + } } + + patch.apply(body); } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index b4f6fa514a4..d3d181f6cb2 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -4,11 +4,12 @@ use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; -/// This struct represents a patch to MIR, which can add -/// new statements and basic blocks and patch over block -/// terminators. +/// This struct lets you "patch" a MIR body, i.e. modify it. You can queue up +/// various changes, such as the addition of new statements and basic blocks +/// and replacement of terminators, and then apply the queued changes all at +/// once with `apply`. This is useful for MIR transformation passes. pub(crate) struct MirPatch<'tcx> { - patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>, + term_patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>, new_blocks: Vec<BasicBlockData<'tcx>>, new_statements: Vec<(Location, StatementKind<'tcx>)>, new_locals: Vec<LocalDecl<'tcx>>, @@ -24,9 +25,10 @@ pub(crate) struct MirPatch<'tcx> { } impl<'tcx> MirPatch<'tcx> { + /// Creates a new, empty patch. pub(crate) fn new(body: &Body<'tcx>) -> Self { let mut result = MirPatch { - patch_map: IndexVec::from_elem(None, &body.basic_blocks), + term_patch_map: IndexVec::from_elem(None, &body.basic_blocks), new_blocks: vec![], new_statements: vec![], new_locals: vec![], @@ -141,10 +143,12 @@ impl<'tcx> MirPatch<'tcx> { bb } - pub(crate) fn is_patched(&self, bb: BasicBlock) -> bool { - self.patch_map[bb].is_some() + /// Has a replacement of this block's terminator been queued in this patch? + pub(crate) fn is_term_patched(&self, bb: BasicBlock) -> bool { + self.term_patch_map[bb].is_some() } + /// Queues the addition of a new temporary with additional local info. pub(crate) fn new_local_with_info( &mut self, ty: Ty<'tcx>, @@ -159,6 +163,7 @@ impl<'tcx> MirPatch<'tcx> { Local::new(index) } + /// Queues the addition of a new temporary. pub(crate) fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; @@ -174,29 +179,46 @@ impl<'tcx> MirPatch<'tcx> { self.new_locals[new_local_idx].ty } + /// Queues the addition of a new basic block. pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { - let block = BasicBlock::new(self.patch_map.len()); + let block = BasicBlock::new(self.term_patch_map.len()); debug!("MirPatch: new_block: {:?}: {:?}", block, data); self.new_blocks.push(data); - self.patch_map.push(None); + self.term_patch_map.push(None); block } + /// Queues the replacement of a block's terminator. pub(crate) fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) { - assert!(self.patch_map[block].is_none()); + assert!(self.term_patch_map[block].is_none()); debug!("MirPatch: patch_terminator({:?}, {:?})", block, new); - self.patch_map[block] = Some(new); + self.term_patch_map[block] = Some(new); } + /// Queues the insertion of a statement at a given location. The statement + /// currently at that location, and all statements that follow, are shifted + /// down. If multiple statements are queued for addition at the same + /// location, the final statement order after calling `apply` will match + /// the queue insertion order. + /// + /// E.g. if we have `s0` at location `loc` and do these calls: + /// + /// p.add_statement(loc, s1); + /// p.add_statement(loc, s2); + /// p.apply(body); + /// + /// then the final order will be `s1, s2, s0`, with `s1` at `loc`. pub(crate) fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) { debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt); self.new_statements.push((loc, stmt)); } + /// Like `add_statement`, but specialized for assignments. pub(crate) fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { self.add_statement(loc, StatementKind::Assign(Box::new((place, rv)))); } + /// Applies the queued changes. pub(crate) fn apply(self, body: &mut Body<'tcx>) { debug!( "MirPatch: {:?} new temps, starting from index {}: {:?}", @@ -209,14 +231,14 @@ impl<'tcx> MirPatch<'tcx> { self.new_blocks.len(), body.basic_blocks.len() ); - let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() { + let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() { body.basic_blocks.as_mut_preserves_cfg() } else { body.basic_blocks.as_mut() }; bbs.extend(self.new_blocks); body.local_decls.extend(self.new_locals); - for (src, patch) in self.patch_map.into_iter_enumerated() { + for (src, patch) in self.term_patch_map.into_iter_enumerated() { if let Some(patch) = patch { debug!("MirPatch: patching block {:?}", src); bbs[src].terminator_mut().kind = patch; @@ -224,6 +246,9 @@ impl<'tcx> MirPatch<'tcx> { } let mut new_statements = self.new_statements; + + // This must be a stable sort to provide the ordering described in the + // comment for `add_statement`. new_statements.sort_by_key(|s| s.0); let mut delta = 0; diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs index c5e951eb8b2..02caa92ad3f 100644 --- a/compiler/rustc_mir_transform/src/single_use_consts.rs +++ b/compiler/rustc_mir_transform/src/single_use_consts.rs @@ -48,9 +48,11 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts { // We're only changing an operand, not the terminator kinds or successors let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); - let init_statement = - basic_blocks[init_loc.block].statements[init_loc.statement_index].replace_nop(); - let StatementKind::Assign(place_and_rvalue) = init_statement.kind else { + let init_statement_kind = std::mem::replace( + &mut basic_blocks[init_loc.block].statements[init_loc.statement_index].kind, + StatementKind::Nop, + ); + let StatementKind::Assign(place_and_rvalue) = init_statement_kind else { bug!("No longer an assign?"); }; let (place, rvalue) = *place_and_rvalue; diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 36cd3e00b76..8e93bdc61d0 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -1,9 +1,8 @@ //! This module ensures that if a function's ABI requires a particular target feature, //! that target feature is enabled both on the callee and all callers. -use rustc_abi::{BackendRepr, RegKind}; +use rustc_abi::{BackendRepr, ExternAbi, RegKind}; use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::{self, traversal}; -use rustc_middle::ty::inherent::*; use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt}; use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; use rustc_span::def_id::DefId; @@ -97,7 +96,7 @@ fn check_call_site_abi<'tcx>( span: Span, caller: InstanceKind<'tcx>, ) { - if callee.fn_sig(tcx).abi().is_rust() { + if callee.fn_sig(tcx).abi() == ExternAbi::Rust { // "Rust" ABI never passes arguments in vector registers. return; } diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 451c215566b..eacb6002f5a 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start derive-where = "1.2.7" -rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } @@ -22,7 +21,6 @@ nightly = [ "dep:rustc_data_structures", "dep:rustc_macros", "dep:rustc_serialize", - "rustc_ast_ir/nightly", "rustc_index/nightly", "rustc_type_ir/nightly", ] diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index d8c1dc8b4e9..0fc313e33b3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -34,7 +34,17 @@ where ) -> QueryResult<I> { let cx = self.cx(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; - debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); + + // Check that the alias-relate goal is reasonable. Writeback for + // `coroutine_stalled_predicates` can replace alias terms with + // `{type error}` if the alias still contains infer vars, so we also + // accept alias-relate goals where one of the terms is an error. + debug_assert!( + lhs.to_alias_term().is_some() + || rhs.to_alias_term().is_some() + || lhs.is_error() + || rhs.is_error() + ); // Structurally normalize the lhs. let lhs = if let Some(alias) = lhs.to_alias_term() { diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index b0f59ed1474..bfb590e8767 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -791,7 +791,7 @@ where return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity)); }; - let responses: Vec<_> = match proven_via { + match proven_via { // Even when a trait bound has been proven using a where-bound, we // still need to consider alias-bounds for normalization, see // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. @@ -800,7 +800,7 @@ where // constness checking. Doing so is *at least theoretically* breaking, // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => { - let mut candidates_from_env: Vec<_> = candidates + let mut candidates_from_env_and_bounds: Vec<_> = candidates .iter() .filter(|c| { matches!( @@ -813,16 +813,37 @@ where // If the trait goal has been proven by using the environment, we want to treat // aliases as rigid if there are no applicable projection bounds in the environment. - if candidates_from_env.is_empty() { + if candidates_from_env_and_bounds.is_empty() { if let Ok(response) = inject_normalize_to_rigid_candidate(self) { - candidates_from_env.push(response); + candidates_from_env_and_bounds.push(response); } } - candidates_from_env + + if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) { + Ok(response) + } else { + self.flounder(&candidates_from_env_and_bounds) + } } - TraitGoalProvenVia::Misc => candidates.iter().map(|c| c.result).collect(), - }; + TraitGoalProvenVia::Misc => { + // Prefer "orphaned" param-env normalization predicates, which are used + // (for example, and ideally only) when proving item bounds for an impl. + let candidates_from_env: Vec<_> = candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result) + .collect(); + if let Some(response) = self.try_merge_responses(&candidates_from_env) { + return Ok(response); + } - self.try_merge_responses(&responses).map_or_else(|| self.flounder(&responses), Ok) + let responses: Vec<_> = candidates.iter().map(|c| c.result).collect(); + if let Some(response) = self.try_merge_responses(&responses) { + Ok(response) + } else { + self.flounder(&responses) + } + } + } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 082c356cc5f..dc0f4c4483e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -2,12 +2,11 @@ //! traits, `Copy`/`Clone`. use derive_where::derive_where; -use rustc_ast_ir::{Movability, Mutability}; use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, Movability, Mutability, Upcast as _, elaborate}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; 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 dabfa5cc04c..1665dbb3018 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1,13 +1,14 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. -use rustc_ast_ir::Movability; use rustc_type_ir::data_structures::IndexSet; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::CanonicalResponse; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; +use rustc_type_ir::{ + self as ty, Interner, Movability, TraitPredicate, TypingMode, Upcast as _, elaborate, +}; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 72aebb5d121..67abc2d5394 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -301,13 +301,6 @@ impl<'a> Parser<'a> { &mut self, recover: bool, ) -> PResult<'a, (Ident, IdentIsRaw)> { - if let TokenKind::DocComment(..) = self.prev_token.kind { - return Err(self.dcx().create_err(DocCommentDoesNotDocumentAnything { - span: self.prev_token.span, - missing_comma: None, - })); - } - let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -319,6 +312,15 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Brace), TokenKind::CloseDelim(Delimiter::Parenthesis), ]; + if let TokenKind::DocComment(..) = self.prev_token.kind + && valid_follow.contains(&self.token.kind) + { + let err = self.dcx().create_err(DocCommentDoesNotDocumentAnything { + span: self.prev_token.span, + missing_comma: None, + }); + return Err(err); + } let mut recovered_ident = None; // we take this here so that the correct original token is retained in diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5111a025f94..74c48a45f18 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1431,37 +1431,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Warns against some misuses of `#[must_use]` fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { - if !matches!( + if matches!( target, Target::Fn | Target::Enum | Target::Struct | Target::Union - | Target::Method(_) + | Target::Method(MethodKind::Trait { body: false } | MethodKind::Inherent) | Target::ForeignFn // `impl Trait` in return position can trip // `unused_must_use` if `Trait` is marked as // `#[must_use]` | Target::Trait ) { - let article = match target { - Target::ExternCrate - | Target::Enum - | Target::Impl - | Target::Expression - | Target::Arm - | Target::AssocConst - | Target::AssocTy => "an", - _ => "a", - }; + return; + } - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::MustUseNoEffect { article, target }, - ); + // `#[must_use]` can be applied to a trait method definition with a default body + if let Target::Method(MethodKind::Trait { body: true }) = target + && let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id + && let containing_item = self.tcx.hir().expect_item(parent_def_id) + && let hir::ItemKind::Trait(..) = containing_item.kind + { + return; } + + let article = match target { + Target::ExternCrate + | Target::Enum + | Target::Impl + | Target::Expression + | Target::Arm + | Target::AssocConst + | Target::AssocTy => "an", + _ => "a", + }; + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MustUseNoEffect { article, target }, + ); } /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait. diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b1b234eb757..46e52e1f131 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -182,6 +182,19 @@ pub(crate) struct ImportData<'ra> { /// so we can use referential equality to compare them. pub(crate) type Import<'ra> = Interned<'ra, ImportData<'ra>>; +// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the +// contained data. +// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees +// are upheld. +impl std::hash::Hash for ImportData<'_> { + fn hash<H>(&self, _: &mut H) + where + H: std::hash::Hasher, + { + unreachable!() + } +} + impl<'ra> ImportData<'ra> { pub(crate) fn is_glob(&self) -> bool { matches!(self.kind, ImportKind::Glob { .. }) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0962865e7f1..b37c684a055 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty}; use rustc_ast::{ self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind, - Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind, + Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind, }; use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; @@ -1529,7 +1529,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { Applicability::MaybeIncorrect, ); true - } else if kind == DefKind::Struct + } else if matches!(kind, DefKind::Struct | DefKind::TyAlias) && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) && let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span) { @@ -1566,7 +1566,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let mut bad_struct_syntax_suggestion = |this: &mut Self, def_id: DefId| { + let bad_struct_syntax_suggestion = |this: &mut Self, err: &mut Diag<'_>, def_id: DefId| { let (followed_by_brace, closing_brace) = this.followed_by_brace(span); match source { @@ -1740,12 +1740,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } ( - Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _), + Res::Def(kind @ (DefKind::Mod | DefKind::Trait | DefKind::TyAlias), _), PathSource::Expr(Some(parent)), - ) => { - if !path_sep(self, err, parent, kind) { - return false; - } + ) if path_sep(self, err, parent, kind) => { + return true; } ( Res::Def(DefKind::Enum, def_id), @@ -1777,13 +1775,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor { if let PathSource::Expr(Some(parent)) = source { if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { - bad_struct_syntax_suggestion(self, def_id); + bad_struct_syntax_suggestion(self, err, def_id); return true; } } struct_ctor } else { - bad_struct_syntax_suggestion(self, def_id); + bad_struct_syntax_suggestion(self, err, def_id); return true; }; @@ -1861,7 +1859,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_label(span, "constructor is not visible here due to private fields"); } (Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => { - bad_struct_syntax_suggestion(self, def_id); + bad_struct_syntax_suggestion(self, err, def_id); } (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => { match source { @@ -2471,31 +2469,73 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { def_id: DefId, span: Span, ) { - let Some(variants) = self.collect_enum_ctors(def_id) else { + let Some(variant_ctors) = self.collect_enum_ctors(def_id) else { err.note("you might have meant to use one of the enum's variants"); return; }; - let suggest_only_tuple_variants = - matches!(source, PathSource::TupleStruct(..)) || source.is_call(); - if suggest_only_tuple_variants { + // If the expression is a field-access or method-call, try to find a variant with the field/method name + // that could have been intended, and suggest replacing the `.` with `::`. + // Otherwise, suggest adding `::VariantName` after the enum; + // and if the expression is call-like, only suggest tuple variants. + let (suggest_path_sep_dot_span, suggest_only_tuple_variants) = match source { + // `Type(a, b)` in a pattern, only suggest adding a tuple variant after `Type`. + PathSource::TupleStruct(..) => (None, true), + PathSource::Expr(Some(expr)) => match &expr.kind { + // `Type(a, b)`, only suggest adding a tuple variant after `Type`. + ExprKind::Call(..) => (None, true), + // `Type.Foo(a, b)`, suggest replacing `.` -> `::` if variant `Foo` exists and is a tuple variant, + // otherwise suggest adding a variant after `Type`. + ExprKind::MethodCall(box MethodCall { + receiver, + span, + seg: PathSegment { ident, .. }, + .. + }) => { + let dot_span = receiver.span.between(*span); + let found_tuple_variant = variant_ctors.iter().any(|(path, _, ctor_kind)| { + *ctor_kind == CtorKind::Fn + && path.segments.last().is_some_and(|seg| seg.ident == *ident) + }); + (found_tuple_variant.then_some(dot_span), false) + } + // `Type.Foo`, suggest replacing `.` -> `::` if variant `Foo` exists and is a unit or tuple variant, + // otherwise suggest adding a variant after `Type`. + ExprKind::Field(base, ident) => { + let dot_span = base.span.between(ident.span); + let found_tuple_or_unit_variant = variant_ctors.iter().any(|(path, ..)| { + path.segments.last().is_some_and(|seg| seg.ident == *ident) + }); + (found_tuple_or_unit_variant.then_some(dot_span), false) + } + _ => (None, false), + }, + _ => (None, false), + }; + + if let Some(dot_span) = suggest_path_sep_dot_span { + err.span_suggestion_verbose( + dot_span, + "use the path separator to refer to a variant", + "::", + Applicability::MaybeIncorrect, + ); + } else if suggest_only_tuple_variants { // Suggest only tuple variants regardless of whether they have fields and do not // suggest path with added parentheses. - let mut suggestable_variants = variants + let mut suggestable_variants = variant_ctors .iter() .filter(|(.., kind)| *kind == CtorKind::Fn) .map(|(variant, ..)| path_names_to_string(variant)) .collect::<Vec<_>>(); suggestable_variants.sort(); - let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); + let non_suggestable_variant_count = variant_ctors.len() - suggestable_variants.len(); - let source_msg = if source.is_call() { - "to construct" - } else if matches!(source, PathSource::TupleStruct(..)) { + let source_msg = if matches!(source, PathSource::TupleStruct(..)) { "to match against" } else { - unreachable!() + "to construct" }; if !suggestable_variants.is_empty() { @@ -2514,7 +2554,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } // If the enum has no tuple variants.. - if non_suggestable_variant_count == variants.len() { + if non_suggestable_variant_count == variant_ctors.len() { err.help(format!("the enum has no tuple variants {source_msg}")); } @@ -2537,7 +2577,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let mut suggestable_variants = variants + let mut suggestable_variants = variant_ctors .iter() .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) @@ -2564,7 +2604,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ); } - let mut suggestable_variants_with_placeholders = variants + let mut suggestable_variants_with_placeholders = variant_ctors .iter() .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 90191b7776f..5bc37e09f08 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -589,6 +589,19 @@ struct ModuleData<'ra> { #[rustc_pass_by_value] struct Module<'ra>(Interned<'ra, ModuleData<'ra>>); +// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the +// contained data. +// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees +// are upheld. +impl std::hash::Hash for ModuleData<'_> { + fn hash<H>(&self, _: &mut H) + where + H: std::hash::Hasher, + { + unreachable!() + } +} + impl<'ra> ModuleData<'ra> { fn new( parent: Option<Module<'ra>>, @@ -739,6 +752,19 @@ struct NameBindingData<'ra> { /// so we can use referential equality to compare them. type NameBinding<'ra> = Interned<'ra, NameBindingData<'ra>>; +// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the +// contained data. +// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees +// are upheld. +impl std::hash::Hash for NameBindingData<'_> { + fn hash<H>(&self, _: &mut H) + where + H: std::hash::Hasher, + { + unreachable!() + } +} + trait ToNameBinding<'ra> { fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>; } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index fb2e838cdc9..a627e0e69b6 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -202,7 +202,6 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match *self { - rustc_abi::BackendRepr::Uninhabited => ValueAbi::Uninhabited, rustc_abi::BackendRepr::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), rustc_abi::BackendRepr::ScalarPair(first, second) => { ValueAbi::ScalarPair(first.stable(tables), second.stable(tables)) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 94039089480..d4d435d9b74 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -192,6 +192,7 @@ symbols! { Capture, Cell, Center, + Child, Cleanup, Clone, CoercePointee, @@ -288,6 +289,7 @@ symbols! { OsString, Output, Param, + ParamSet, PartialEq, PartialOrd, Path, @@ -336,6 +338,7 @@ symbols! { SliceIter, Some, SpanCtxt, + Stdin, String, StructuralPartialEq, SubdiagMessage, @@ -518,6 +521,7 @@ symbols! { bang, begin_panic, bench, + bevy_ecs, bikeshed_guaranteed_no_drop, bin, binaryheap_iter, @@ -599,6 +603,9 @@ symbols! { cfi, cfi_encoding, char, + char_is_ascii, + child_id, + child_kill, client, clippy, clobber_abi, @@ -1468,6 +1475,7 @@ symbols! { panic_2015, panic_2021, panic_abort, + panic_any, panic_bounds_check, panic_cannot_unwind, panic_const_add_overflow, @@ -1573,6 +1581,7 @@ symbols! { proc_macro_mod, proc_macro_non_items, proc_macro_path_invoc, + process_abort, process_exit, profiler_builtins, profiler_runtime, diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 47566bde6b4..3fa67c624a7 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -80,7 +80,7 @@ where } } }, - BackendRepr::Vector { .. } | BackendRepr::Uninhabited => return Err(CannotUseFpConv), + BackendRepr::Vector { .. } => return Err(CannotUseFpConv), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 2bde1055622..1c044fe98b3 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -7,7 +7,7 @@ use rustc_abi::{ }; use rustc_macros::HashStable_Generic; -use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; +use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi}; mod aarch64; mod amdgpu; @@ -38,7 +38,7 @@ mod xtensa; pub enum PassMode { /// Ignore the argument. /// - /// The argument is either uninhabited or a ZST. + /// The argument is a ZST. Ignore, /// Pass the argument directly. /// @@ -350,7 +350,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> { scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, Scalar, Size) -> ArgAttributes, ) -> Self { let mode = match layout.backend_repr { - BackendRepr::Uninhabited => PassMode::Ignore, BackendRepr::Scalar(scalar) => { PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)) } @@ -386,6 +385,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { /// Pass this argument directly instead. Should NOT be used! /// Only exists because of past ABI mistakes that will take time to fix /// (see <https://github.com/rust-lang/rust/issues/115666>). + #[track_caller] pub fn make_direct_deprecated(&mut self) { match self.mode { PassMode::Indirect { .. } => { @@ -398,6 +398,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead. /// This is valid for both sized and unsized arguments. + #[track_caller] pub fn make_indirect(&mut self) { match self.mode { PassMode::Direct(_) | PassMode::Pair(_, _) => { @@ -412,6 +413,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { /// Same as `make_indirect`, but for arguments that are ignored. Only needed for ABIs that pass /// ZSTs indirectly. + #[track_caller] pub fn make_indirect_from_ignore(&mut self) { match self.mode { PassMode::Ignore => { @@ -716,7 +718,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { C: HasDataLayout + HasTargetSpec, { let spec = cx.target_spec(); - match &spec.arch[..] { + match &*spec.arch { "x86" => x86::compute_rust_abi_info(cx, self, abi), "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi), "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi), @@ -724,6 +726,24 @@ impl<'a, Ty> FnAbi<'a, Ty> { _ => {} }; + // Decides whether we can pass the given SIMD argument via `PassMode::Direct`. + // May only return `true` if the target will always pass those arguments the same way, + // no matter what the user does with `-Ctarget-feature`! In other words, whatever + // target features are required to pass a SIMD value in registers must be listed in + // the `abi_required_features` for the current target and ABI. + let can_pass_simd_directly = |arg: &ArgAbi<'_, Ty>| match &*spec.arch { + // On x86, if we have SSE2 (which we have by default for x86_64), we can always pass up + // to 128-bit-sized vectors. + "x86" if spec.rustc_abi == Some(RustcAbi::X86Sse2) => arg.layout.size.bits() <= 128, + "x86_64" if spec.rustc_abi != Some(RustcAbi::X86Softfloat) => { + // FIXME once https://github.com/bytecodealliance/wasmtime/issues/10254 is fixed + // accept vectors up to 128bit rather than vectors of exactly 128bit. + arg.layout.size.bits() == 128 + } + // So far, we haven't implemented this logic for any other target. + _ => false, + }; + for (arg_idx, arg) in self .args .iter_mut() @@ -731,12 +751,15 @@ impl<'a, Ty> FnAbi<'a, Ty> { .map(|(idx, arg)| (Some(idx), arg)) .chain(iter::once((None, &mut self.ret))) { - if arg.is_ignore() { + // If the logic above already picked a specific type to cast the argument to, leave that + // in place. + if matches!(arg.mode, PassMode::Ignore | PassMode::Cast { .. }) { continue; } if arg_idx.is_none() && arg.layout.size > Primitive::Pointer(AddressSpace::DATA).size(cx) * 2 + && !matches!(arg.layout.backend_repr, BackendRepr::Vector { .. }) { // Return values larger than 2 registers using a return area // pointer. LLVM and Cranelift disagree about how to return @@ -746,7 +769,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { // return value independently and decide to pass it in a // register or not, which would result in the return value // being passed partially in registers and partially through a - // return area pointer. + // return area pointer. For large IR-level values such as `i128`, + // cranelift will even split up the value into smaller chunks. // // While Cranelift may need to be fixed as the LLVM behavior is // generally more correct with respect to the surface language, @@ -776,53 +800,60 @@ impl<'a, Ty> FnAbi<'a, Ty> { // rustc_target already ensure any return value which doesn't // fit in the available amount of return registers is passed in // the right way for the current target. + // + // The adjustment is not necessary nor desired for types with a vector + // representation; those are handled below. arg.make_indirect(); continue; } match arg.layout.backend_repr { - BackendRepr::Memory { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - BackendRepr::Vector { .. } - if abi != ExternAbi::RustIntrinsic && spec.simd_types_indirect => - { - arg.make_indirect(); - continue; + BackendRepr::Memory { .. } => { + // Compute `Aggregate` ABI. + + let is_indirect_not_on_stack = + matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); + assert!(is_indirect_not_on_stack); + + let size = arg.layout.size; + if arg.layout.is_sized() + && size <= Primitive::Pointer(AddressSpace::DATA).size(cx) + { + // We want to pass small aggregates as immediates, but using + // an LLVM aggregate type for this leads to bad optimizations, + // so we pick an appropriately sized integer type instead. + arg.cast_to(Reg { kind: RegKind::Integer, size }); + } } - _ => continue, - } - // Compute `Aggregate` ABI. - - let is_indirect_not_on_stack = - matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); - assert!(is_indirect_not_on_stack); - - let size = arg.layout.size; - if !arg.layout.is_unsized() && size <= Primitive::Pointer(AddressSpace::DATA).size(cx) { - // We want to pass small aggregates as immediates, but using - // an LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { kind: RegKind::Integer, size }); + BackendRepr::Vector { .. } => { + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the intrinsic ABI is exempt here as those are not + // real functions anyway, and the backend expects very specific types. + if abi != ExternAbi::RustIntrinsic + && spec.simd_types_indirect + && !can_pass_simd_directly(arg) + { + arg.make_indirect(); + } + } + + _ => {} } } } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 265ae20f991..785175229b0 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -86,7 +86,7 @@ where } } }, - BackendRepr::Vector { .. } | BackendRepr::Uninhabited => return Err(CannotUseFpConv), + BackendRepr::Vector { .. } => return Err(CannotUseFpConv), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 5b9414536d8..7e5aab0201b 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -4,7 +4,7 @@ use rustc_abi::{ }; use crate::callconv::{ArgAttribute, FnAbi, PassMode}; -use crate::spec::HasTargetSpec; +use crate::spec::{HasTargetSpec, RustcAbi}; #[derive(PartialEq)] pub(crate) enum Flavor { @@ -108,9 +108,7 @@ where Ty: TyAbiInterface<'a, C> + Copy, { match layout.backend_repr { - BackendRepr::Uninhabited - | BackendRepr::Scalar(_) - | BackendRepr::ScalarPair(..) => false, + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) => false, BackendRepr::Vector { .. } => true, BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { @@ -236,8 +234,16 @@ where _ => false, // anyway not passed via registers on x86 }; if has_float { - if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::DATA).size(cx) { - // Same size or smaller than pointer, return in a register. + if cx.target_spec().rustc_abi == Some(RustcAbi::X86Sse2) + && fn_abi.ret.layout.backend_repr.is_scalar() + && fn_abi.ret.layout.size.bits() <= 128 + { + // This is a single scalar that fits into an SSE register, and the target uses the + // SSE ABI. We prefer this over integer registers as float scalars need to be in SSE + // registers for float operations, so that's the best place to pass them around. + fn_abi.ret.cast_to(Reg { kind: RegKind::Vector, size: fn_abi.ret.layout.size }); + } else if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::DATA).size(cx) { + // Same size or smaller than pointer, return in an integer register. fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size }); } else { // Larger than a pointer, return indirectly. diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index b15d82c26da..ab306e20239 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -51,8 +51,6 @@ where } let mut c = match layout.backend_repr { - BackendRepr::Uninhabited => return Ok(()), - BackendRepr::Scalar(scalar) => match scalar.primitive() { Primitive::Int(..) | Primitive::Pointer(_) => Class::Int, Primitive::Float(_) => Class::Sse, diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 23ef2cf8284..4d99a9f9ba0 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -1,14 +1,14 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size}; use crate::callconv::{ArgAbi, FnAbi, Reg}; -use crate::spec::HasTargetSpec; +use crate::spec::{HasTargetSpec, RustcAbi}; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing -pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| { match a.layout.backend_repr { - BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {} + BackendRepr::Memory { sized: false } => {} BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { match a.layout.size.bits() { 8 => a.cast_to(Reg::i8()), @@ -24,10 +24,14 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi< } BackendRepr::Scalar(scalar) => { if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) { - // `i128` is returned in xmm0 by Clang and GCC - // FIXME(#134288): This may change for the `-msvc` targets in the future. - let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) }; - a.cast_to(reg); + if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) { + // Use the native `i128` LLVM type for the softfloat ABI -- in other words, adjust nothing. + } else { + // `i128` is returned in xmm0 by Clang and GCC + // FIXME(#134288): This may change for the `-msvc` targets in the future. + let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) }; + a.cast_to(reg); + } } else if a.layout.size.bytes() > 8 && !matches!(scalar.primitive(), Primitive::Float(Float::F128)) { diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr.rs index 3554dcfcb4a..85b73e61e52 100644 --- a/compiler/rustc_target/src/spec/base/avr_gnu.rs +++ b/compiler/rustc_target/src/spec/base/avr.rs @@ -1,45 +1,5 @@ use object::elf; -use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions}; - -/// A base target for AVR devices using the GNU toolchain. -/// -/// Requires GNU avr-gcc and avr-binutils on the host system. -/// FIXME: Remove the second parameter when const string concatenation is possible. -pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { - Target { - arch: "avr".into(), - metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, - }, - data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), - 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(), - - linker: Some("avr-gcc".into()), - eh_frame_header: false, - pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]), - late_link_args: TargetOptions::link_args( - LinkerFlavor::Gnu(Cc::Yes, Lld::No), - &["-lgcc"], - ), - max_atomic_width: Some(16), - atomic_cas: false, - relocation_model: RelocModel::Static, - ..TargetOptions::default() - }, - } -} - /// Resolve the value of the EF_AVR_ARCH field for AVR ELF files, given the /// name of the target CPU / MCU. /// diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index b9139c8452c..6f88be5d37f 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -1,7 +1,7 @@ pub(crate) mod aix; pub(crate) mod android; pub(crate) mod apple; -pub(crate) mod avr_gnu; +pub(crate) mod avr; pub(crate) mod bpf; pub(crate) mod cygwin; pub(crate) mod dragonfly; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f7e467b0c11..65736770efb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -60,7 +60,7 @@ pub mod crt_objects; mod base; mod json; -pub use base::avr_gnu::ef_avr_arch; +pub use base::avr::ef_avr_arch; /// Linker is called through a C/C++ compiler. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -303,15 +303,16 @@ impl LinkerFlavor { } } - fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) { + fn infer_linker_hints(linker_stem: &str) -> Result<Self, (Option<Cc>, Option<Lld>)> { // Remove any version postfix. let stem = linker_stem .rsplit_once('-') .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) .unwrap_or(linker_stem); - // GCC/Clang can have an optional target prefix. - if stem == "emcc" + if stem == "llvm-bitcode-linker" { + Ok(Self::Llbc) + } else if stem == "emcc" // GCC/Clang can have an optional target prefix. || stem == "gcc" || stem.ends_with("-gcc") || stem == "g++" @@ -321,7 +322,7 @@ impl LinkerFlavor { || stem == "clang++" || stem.ends_with("-clang++") { - (Some(Cc::Yes), Some(Lld::No)) + Err((Some(Cc::Yes), Some(Lld::No))) } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") || stem == "ld.lld" @@ -329,11 +330,11 @@ impl LinkerFlavor { || stem == "rust-lld" || stem == "lld-link" { - (Some(Cc::No), Some(Lld::Yes)) + Err((Some(Cc::No), Some(Lld::Yes))) } else if stem == "ld" || stem.ends_with("-ld") || stem == "link" { - (Some(Cc::No), Some(Lld::No)) + Err((Some(Cc::No), Some(Lld::No))) } else { - (None, None) + Err((None, None)) } } @@ -357,7 +358,10 @@ impl LinkerFlavor { } pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor { - self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem)) + match LinkerFlavor::infer_linker_hints(linker_stem) { + Ok(linker_flavor) => linker_flavor, + Err(hints) => self.with_hints(hints), + } } pub fn check_compatibility(self, cli: LinkerFlavorCli) -> Option<String> { @@ -1797,7 +1801,7 @@ supported_targets! { ("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia), ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), - ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), + ("avr-none", avr_none), ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), @@ -2001,7 +2005,7 @@ supported_targets! { ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), ("x86_64-pc-nto-qnx710_iosock", x86_64_pc_nto_qnx710_iosock), ("x86_64-pc-nto-qnx800", x86_64_pc_nto_qnx800), - ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), + ("i686-pc-nto-qnx700", i686_pc_nto_qnx700), ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos), ("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos), @@ -3062,7 +3066,10 @@ impl Target { &self.post_link_args, ] { for (&flavor, flavor_args) in args { - check!(!flavor_args.is_empty(), "linker flavor args must not be empty"); + check!( + !flavor_args.is_empty() || self.arch == "avr", + "linker flavor args must not be empty" + ); // Check that flavors mentioned in link args are compatible with the default flavor. match self.linker_flavor { LinkerFlavor::Gnu(..) => { diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs new file mode 100644 index 00000000000..91d3197d099 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -0,0 +1,32 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + arch: "avr".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), + llvm_target: "avr-unknown-unknown".into(), + pointer_width: 16, + options: TargetOptions { + c_int_width: "16".into(), + exe_suffix: ".elf".into(), + linker: Some("avr-gcc".into()), + eh_frame_header: false, + pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[]), + late_link_args: TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::Yes, Lld::No), + &["-lgcc"], + ), + max_atomic_width: Some(16), + atomic_cas: false, + relocation_model: RelocModel::Static, + need_explicit_cpu: true, + ..TargetOptions::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs deleted file mode 100644 index c3d6fb72273..00000000000 --- a/compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::spec::{Target, base}; - -pub(crate) fn target() -> Target { - base::avr_gnu::target("atmega328", "-mmcu=atmega328") -} diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i686_pc_nto_qnx700.rs index 6a98a763b36..6a98a763b36 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_nto_qnx700.rs diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index b13a753c4ed..2f2361609a2 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 2bb38f3ed14..42b8199cb26 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::{ TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; -use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; use tracing::{debug, instrument, warn}; @@ -217,7 +216,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> { // `_` because then we'd end up with `Vec<_, _>`, instead of // `Vec<_>`. arg - } else if let GenericArgKind::Type(_) = arg.kind() { + } else if let GenericArgKind::Type(_) = arg.unpack() { // We don't replace lifetime or const params, only type params. self.new_infer().into() } else { 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 d009687ef14..fecb38ab597 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -2,7 +2,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - Applicability, Diag, E0309, E0310, E0311, E0495, Subdiagnostic, struct_span_code_err, + Applicability, Diag, E0309, E0310, E0311, E0803, Subdiagnostic, struct_span_code_err, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -1032,7 +1032,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct_span_code_err!( self.dcx(), var_origin.span(), - E0495, + E0803, "cannot infer an appropriate lifetime{} due to conflicting requirements", var_description ) 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 3d89b6ed2f0..ee0ab0dfbb8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3289,6 +3289,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); + if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id) + && !tcx.features().enabled(sym::try_trait_v2) + { + // If `#![feature(try_trait_v2)]` is not enabled, then there's no point on + // talking about `FromResidual<Result<A, B>>`, as the end user has nothing they + // can do about it. As far as they are concerned, `?` is compiler magic. + return; + } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 9fbc1d64d74..4b1bc316d5f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -11,12 +11,11 @@ use std::assert_matches::assert_matches; -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; +use rustc_middle::ty::visit::{VisitorResult, try_visit}; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::EagerResolver; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 92098e20448..f04a5feba30 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -2,12 +2,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_infer::traits::query::type_op::DropckOutlives; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; use tracing::{debug, instrument}; +use crate::solve::NextSolverError; use crate::traits::query::NoSolution; use crate::traits::query::normalize::QueryNormalizeExt; -use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; +use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -93,6 +94,20 @@ pub fn compute_dropck_outlives_inner<'tcx>( goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, span: Span, ) -> Result<DropckOutlivesResult<'tcx>, NoSolution> { + match compute_dropck_outlives_with_errors(ocx, goal, span) { + Ok(r) => Ok(r), + Err(_) => Err(NoSolution), + } +} + +pub fn compute_dropck_outlives_with_errors<'tcx, E>( + ocx: &ObligationCtxt<'_, 'tcx, E>, + goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, + span: Span, +) -> Result<DropckOutlivesResult<'tcx>, Vec<E>> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ let tcx = ocx.infcx.tcx; let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal; @@ -149,11 +164,11 @@ pub fn compute_dropck_outlives_inner<'tcx>( dtorck_constraint_for_ty_inner( tcx, ocx.infcx.typing_env(param_env), - DUMMY_SP, + span, depth, ty, &mut constraints, - )?; + ); // "outlives" represent types/regions that may be touched // by a destructor. @@ -173,11 +188,20 @@ pub fn compute_dropck_outlives_inner<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); + let ty = if let Ok(Normalized { value: ty, obligations }) = + ocx.infcx.at(&cause, param_env).query_normalize(ty) + { + ocx.register_obligations(obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + ty + } else { + ocx.deeply_normalize(&cause, param_env, ty)?; - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + let errors = ocx.select_where_possible(); + debug!("normalize errors: {ty} ~> {errors:#?}"); + return Err(errors); + }; match ty.kind() { // All parameters live for the duration of the @@ -213,14 +237,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( depth: usize, ty: Ty<'tcx>, constraints: &mut DropckConstraint<'tcx>, -) -> Result<(), NoSolution> { +) { if !tcx.recursion_limit().value_within_limit(depth) { constraints.overflows.push(ty); - return Ok(()); + return; } if trivial_dropck_outlives(tcx, ty) { - return Ok(()); + return; } match ty.kind() { @@ -244,22 +268,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints) - })?; + }); } ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in tys.iter() { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - Ok::<_, NoSolution>(()) - })?, + }), ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in args.as_closure().upvar_tys() { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - Ok::<_, NoSolution>(()) - })?, + }), ty::CoroutineClosure(_, args) => { rustc_data_structures::stack::ensure_sufficient_stack(|| { @@ -271,10 +293,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( depth + 1, ty, constraints, - )?; + ); } - Ok::<_, NoSolution>(()) - })? + }) } ty::Coroutine(_, args) => { @@ -313,7 +334,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Adt(def, args) => { let DropckConstraint { dtorck_types, outlives, overflows } = - tcx.at(span).adt_dtorck_constraint(def.did())?; + tcx.at(span).adt_dtorck_constraint(def.did()); // FIXME: we can try to recursively `dtorck_constraint_on_ty` // there, but that needs some way to handle cycles. constraints @@ -346,9 +367,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { // By the time this code runs, all type variables ought to // be fully resolved. - return Err(NoSolution); + tcx.dcx().span_delayed_bug(span, format!("Unresolved type in dropck: {:?}.", ty)); } } - - Ok(()) } diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index b3377e15aa7..5eddad39e2b 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -30,10 +30,7 @@ fn dropck_outlives<'tcx>( } /// Calculates the dtorck constraint for a type. -pub(crate) fn adt_dtorck_constraint( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Result<&DropckConstraint<'_>, NoSolution> { +pub(crate) fn adt_dtorck_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &DropckConstraint<'_> { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); @@ -52,20 +49,20 @@ pub(crate) fn adt_dtorck_constraint( overflows: vec![], }; debug!("dtorck_constraint: {:?} => {:?}", def, result); - return Ok(tcx.arena.alloc(result)); + return tcx.arena.alloc(result); } let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).instantiate_identity(); - dtorck_constraint_for_ty_inner(tcx, typing_env, span, 0, fty, &mut result)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, 0, fty, &mut result); } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); debug!("dtorck_constraint: {:?} => {:?}", def, result); - Ok(tcx.arena.alloc(result)) + tcx.arena.alloc(result) } fn dedup_dtorck_constraint(c: &mut DropckConstraint<'_>) { diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 6a98be18503..94c7695117c 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi", optional = true } -rustc_ast_ir = { path = "../rustc_ast_ir", optional = true } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir", optional = true } rustc_infer = { path = "../rustc_infer", optional = true } @@ -19,7 +18,6 @@ tracing = "0.1" [features] rustc = [ "dep:rustc_abi", - "dep:rustc_ast_ir", "dep:rustc_hir", "dep:rustc_infer", "dep:rustc_macros", diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index f88f8c38d50..ab903c6ed73 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" # 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" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index c5d2d0afbfa..0ff82f0c256 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -464,7 +464,7 @@ fn fn_abi_sanity_check<'tcx>( match &arg.mode { PassMode::Ignore => { - assert!(arg.layout.is_zst() || arg.layout.is_uninhabited()); + assert!(arg.layout.is_zst()); } PassMode::Direct(_) => { // Here the Rust type is used to determine the actual ABI, so we have to be very @@ -472,9 +472,7 @@ fn fn_abi_sanity_check<'tcx>( // `layout.backend_repr` and ignore everything else. We should just reject //`Aggregate` entirely here, but some targets need to be fixed first. match arg.layout.backend_repr { - BackendRepr::Uninhabited - | BackendRepr::Scalar(_) - | BackendRepr::Vector { .. } => {} + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => {} BackendRepr::ScalarPair(..) => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 8429e68b600..b6a14d147ca 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -134,42 +134,32 @@ fn univariant_uninterned<'tcx>( cx: &LayoutCx<'tcx>, ty: Ty<'tcx>, fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, - repr: &ReprOptions, kind: StructKind, ) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> { - let pack = repr.pack; - if pack.is_some() && repr.align.is_some() { - cx.tcx().dcx().bug("struct cannot be packed and aligned"); - } - - cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err)) + let repr = ReprOptions::default(); + cx.calc.univariant(fields, &repr, kind).map_err(|err| map_error(cx, ty, err)) } fn extract_const_value<'tcx>( - const_: ty::Const<'tcx>, - ty: Ty<'tcx>, cx: &LayoutCx<'tcx>, + ty: Ty<'tcx>, + ct: ty::Const<'tcx>, ) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> { - match const_.kind() { + match ct.kind() { ty::ConstKind::Value(cv) => Ok(cv), - ty::ConstKind::Error(guar) => { - return Err(error(cx, LayoutError::ReferencesError(guar))); - } - ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => { - if !const_.has_param() { - bug!("no generic type found in the type: {ty:?}"); - } - return Err(error(cx, LayoutError::TooGeneric(ty))); - } - ty::ConstKind::Unevaluated(_) => { - if !const_.has_param() { - return Err(error(cx, LayoutError::Unknown(ty))); - } else { - return Err(error(cx, LayoutError::TooGeneric(ty))); + ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => { + if !ct.has_param() { + bug!("failed to normalize const, but it is not generic: {ct:?}"); } + Err(error(cx, LayoutError::TooGeneric(ty))) } - ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - bug!("unexpected type: {ty:?}"); + ty::ConstKind::Infer(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Error(_) => { + // `ty::ConstKind::Error` is handled at the top of `layout_of_uncached` + // (via `ty.error_reported()`). + bug!("layout_of: unexpected const: {ct:?}"); } } } @@ -194,10 +184,9 @@ fn layout_of_uncached<'tcx>( }; let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value))); - let univariant = - |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| { - Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?)) - }; + let univariant = |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, kind| { + Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, kind)?)) + }; debug_assert!(!ty.has_non_region_infer()); Ok(match *ty.kind() { @@ -210,12 +199,12 @@ fn layout_of_uncached<'tcx>( &mut layout.backend_repr { if let Some(start) = start { - scalar.valid_range_mut().start = extract_const_value(start, ty, cx)? + scalar.valid_range_mut().start = extract_const_value(cx, ty, start)? .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; } if let Some(end) = end { - let mut end = extract_const_value(end, ty, cx)? + let mut end = extract_const_value(cx, ty, end)? .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; if !include_end { @@ -274,16 +263,11 @@ fn layout_of_uncached<'tcx>( data_ptr.valid_range_mut().start = 1; } - let pointee = tcx.normalize_erasing_regions(cx.typing_env, pointee); if pointee.is_sized(tcx, cx.typing_env) { return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } - let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() - // Projection eagerly bails out when the pointee references errors, - // fall back to structurally deducing metadata. - && !pointee.references_error() - { + let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() { let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]); let metadata_ty = match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) { @@ -354,7 +338,7 @@ fn layout_of_uncached<'tcx>( // Arrays and slices. ty::Array(element, count) => { - let count = extract_const_value(count, ty, cx)? + let count = extract_const_value(cx, ty, count)? .try_to_target_usize(tcx) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; @@ -364,19 +348,17 @@ fn layout_of_uncached<'tcx>( .checked_mul(count, dl) .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - let abi = if count != 0 && ty.is_privately_uninhabited(tcx, cx.typing_env) { - BackendRepr::Uninhabited - } else { - BackendRepr::Memory { sized: true } - }; + let abi = BackendRepr::Memory { sized: true }; let largest_niche = if count != 0 { element.largest_niche } else { None }; + let uninhabited = if count != 0 { element.uninhabited } else { false }; tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, backend_repr: abi, largest_niche, + uninhabited, align: element.align, size, max_repr_align: None, @@ -391,6 +373,7 @@ fn layout_of_uncached<'tcx>( fields: FieldsShape::Array { stride: element.size, count: 0 }, backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, + uninhabited: false, align: element.align, size: Size::ZERO, max_repr_align: None, @@ -406,6 +389,7 @@ fn layout_of_uncached<'tcx>( fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, + uninhabited: false, align: dl.i8_align, size: Size::ZERO, max_repr_align: None, @@ -415,17 +399,10 @@ fn layout_of_uncached<'tcx>( }), // Odd unit types. - ty::FnDef(..) => { - univariant(IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized)? - } + ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?, ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { - let mut unit = univariant_uninterned( - cx, - ty, - IndexSlice::empty(), - &ReprOptions::default(), - StructKind::AlwaysSized, - )?; + let mut unit = + univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?; match unit.backend_repr { BackendRepr::Memory { ref mut sized } => *sized = false, _ => bug!(), @@ -439,7 +416,6 @@ fn layout_of_uncached<'tcx>( let tys = args.as_closure().upvar_tys(); univariant( &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?, - &ReprOptions::default(), StructKind::AlwaysSized, )? } @@ -448,7 +424,6 @@ fn layout_of_uncached<'tcx>( let tys = args.as_coroutine_closure().upvar_tys(); univariant( &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?, - &ReprOptions::default(), StructKind::AlwaysSized, )? } @@ -457,11 +432,7 @@ fn layout_of_uncached<'tcx>( let kind = if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - univariant( - &tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?, - &ReprOptions::default(), - kind, - )? + univariant(&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?, kind)? } // SIMD vector types. @@ -584,6 +555,7 @@ fn layout_of_uncached<'tcx>( fields, backend_repr: abi, largest_niche: e_ly.largest_niche, + uninhabited: false, size, align, max_repr_align: None, @@ -719,25 +691,30 @@ fn layout_of_uncached<'tcx>( } // Types with no meaningful known layout. + ty::Param(_) => { + return Err(error(cx, LayoutError::TooGeneric(ty))); + } + ty::Alias(..) => { - if ty.has_param() { - return Err(error(cx, LayoutError::TooGeneric(ty))); - } // NOTE(eddyb) `layout_of` query should've normalized these away, // if that was possible, so there's no reason to try again here. - return Err(error(cx, LayoutError::Unknown(ty))); - } - - ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => { - bug!("Layout::compute: unexpected type `{}`", ty) - } - - ty::Param(_) => { - return Err(error(cx, LayoutError::TooGeneric(ty))); + let err = if ty.has_param() { + LayoutError::TooGeneric(ty) + } else { + // This is only reachable with unsatisfiable predicates. For example, if we have + // `u8: Iterator`, then we can't compute the layout of `<u8 as Iterator>::Item`. + LayoutError::Unknown(ty) + }; + return Err(error(cx, err)); } - ty::Placeholder(..) => { - return Err(error(cx, LayoutError::Unknown(ty))); + ty::Placeholder(..) + | ty::Bound(..) + | ty::CoroutineWitness(..) + | ty::Infer(_) + | ty::Error(_) => { + // `ty::Error` is handled at the top of this function. + bug!("layout_of: unexpected type `{ty}`") } }) } @@ -911,13 +888,7 @@ fn coroutine_layout<'tcx>( .chain(iter::once(Ok(tag_layout))) .chain(promoted_layouts) .try_collect::<IndexVec<_, _>>()?; - let prefix = univariant_uninterned( - cx, - ty, - &prefix_layouts, - &ReprOptions::default(), - StructKind::AlwaysSized, - )?; + let prefix = univariant_uninterned(cx, ty, &prefix_layouts, StructKind::AlwaysSized)?; let (prefix_size, prefix_align) = (prefix.size, prefix.align); @@ -982,7 +953,6 @@ fn coroutine_layout<'tcx>( cx, ty, &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?, - &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), )?; variant.variants = Variants::Single { index }; @@ -1045,13 +1015,8 @@ fn coroutine_layout<'tcx>( size = size.align_to(align.abi); - let abi = if prefix.backend_repr.is_uninhabited() - || variants.iter().all(|v| v.backend_repr.is_uninhabited()) - { - BackendRepr::Uninhabited - } else { - BackendRepr::Memory { sized: true } - }; + let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited()); + let abi = BackendRepr::Memory { sized: true }; // this is similar to how ReprOptions populates its field_shuffle_seed let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash(); @@ -1072,6 +1037,7 @@ fn coroutine_layout<'tcx>( // See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>. // FIXME: Remove when <https://github.com/rust-lang/rust/issues/125735> is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. largest_niche: None, + uninhabited, size, align, max_repr_align: None, diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 8d5403ed324..5ea6716c5ca 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -10,7 +10,11 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou // Type-level uninhabitedness should always imply ABI uninhabitedness. if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) { - assert!(layout.is_uninhabited()); + assert!( + layout.is_uninhabited(), + "{:?} is type-level uninhabited but not ABI-uninhabited?", + layout.ty + ); } if layout.size.bytes() % layout.align.abi.bytes() != 0 { @@ -71,7 +75,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou let Some((align, size)) = align.zip(size) else { assert_matches!( layout.layout.backend_repr(), - BackendRepr::Uninhabited | BackendRepr::Memory { .. }, + BackendRepr::Memory { .. }, "ABI unexpectedly missing alignment and/or size in {layout:#?}" ); return; @@ -235,7 +239,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } - BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} // Nothing to check. + BackendRepr::Memory { .. } => {} // Nothing to check. } } @@ -291,8 +295,8 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou || variant.is_uninhabited() { // These are never actually accessed anyway, so we can skip the coherence check - // for them. They also fail that check, since they have - // `Aggregate`/`Uninhabited` ABI even when the main type is + // for them. They also fail that check, since they may have + // a different ABI even when the main type is // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size // 0, and sometimes, variants without fields have non-0 size.) continue; @@ -306,7 +310,6 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { scalar_coherent(a1, a2) && scalar_coherent(b1, b2) } - (BackendRepr::Uninhabited, _) => true, (BackendRepr::Memory { .. }, _) => true, _ => false, }; diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 64e5a609b2f..d6f9277813d 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -1,11 +1,10 @@ //! This module contains helpers for walking all types of //! a signature, while preserving spans as much as possible -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; +use rustc_middle::ty::visit::{VisitorResult, try_visit}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; use rustc_type_ir::visit::TypeVisitable; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 6924216bd26..9277226b718 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -126,6 +126,10 @@ pub trait Ty<I: Interner<Ty = Self>>: matches!(self.kind(), ty::Infer(ty::TyVar(_))) } + fn is_ty_error(self) -> bool { + matches!(self.kind(), ty::Error(_)) + } + fn is_floating_point(self) -> bool { matches!(self.kind(), ty::Float(_) | ty::Infer(ty::FloatVar(_))) } @@ -284,6 +288,10 @@ pub trait Const<I: Interner<Const = Self>>: fn is_ct_var(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) } + + fn is_ct_error(self) -> bool { + matches!(self.kind(), ty::ConstKind::Error(_)) + } } pub trait ValueConst<I: Interner<ValueConst = Self>>: Copy + Debug + Hash + Eq { @@ -370,6 +378,13 @@ pub trait Term<I: Interner<Term = Self>>: } } + fn is_error(self) -> bool { + match self.kind() { + ty::TermKind::Ty(ty) => ty.is_ty_error(), + ty::TermKind::Const(ct) => ct.is_ct_error(), + } + } + fn to_alias_term(self) -> Option<ty::AliasTerm<I>> { match self.kind() { ty::TermKind::Ty(ty) => match ty.kind() { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e7ca24178cb..15ef4e7d6c1 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -74,6 +74,7 @@ pub use opaque_ty::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; +pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; pub use ty_info::*; pub use ty_kind::*; pub use upcast::*; diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index a12e9856304..119b658a2bf 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -45,8 +45,8 @@ use std::fmt; use std::ops::ControlFlow; use std::sync::Arc; -use rustc_ast_ir::visit::VisitorResult; -use rustc_ast_ir::{try_visit, walk_visitable_list}; +pub use rustc_ast_ir::visit::VisitorResult; +pub use rustc_ast_ir::{try_visit, walk_visitable_list}; use rustc_index::{Idx, IndexVec}; use smallvec::SmallVec; use thin_vec::ThinVec; @@ -224,6 +224,13 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix } } +impl<I: Interner, T: TypeVisitable<I>, S> TypeVisitable<I> for indexmap::IndexSet<T, S> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { + walk_visitable_list!(visitor, self.iter()); + V::Result::output() + } +} + pub trait Flags { fn flags(&self) -> TypeFlags; fn outer_exclusive_binder(&self) -> ty::DebruijnIndex; diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index ede6dcd469c..640299c2167 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -45,12 +45,12 @@ fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Tok s.add_bounds(synstructure::AddBounds::Fields); let body_visit = s.each(|bind| { quote! { - match ::rustc_ast_ir::visit::VisitorResult::branch( + match ::rustc_type_ir::visit::VisitorResult::branch( ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) ) { ::core::ops::ControlFlow::Continue(()) => {}, ::core::ops::ControlFlow::Break(r) => { - return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); + return ::rustc_type_ir::visit::VisitorResult::from_residual(r); }, } } @@ -65,7 +65,7 @@ fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Tok __visitor: &mut __V ) -> __V::Result { match *self { #body_visit } - <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + <__V::Result as ::rustc_type_ir::visit::VisitorResult>::output() } }, ) diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 861b6692b53..091f3e1a95e 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -227,7 +227,6 @@ pub enum TagEncoding { /// in terms of categories of C types there are ABI rules for. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum ValueAbi { - Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), Vector { @@ -244,10 +243,7 @@ impl ValueAbi { /// Returns `true` if the layout corresponds to an unsized type. pub fn is_unsized(&self) -> bool { match *self { - ValueAbi::Uninhabited - | ValueAbi::Scalar(_) - | ValueAbi::ScalarPair(..) - | ValueAbi::Vector { .. } => false, + ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false, ValueAbi::Aggregate { sized } => !sized, } } diff --git a/config.example.toml b/config.example.toml index fd27b24e461..a17d3ec9f88 100644 --- a/config.example.toml +++ b/config.example.toml @@ -793,12 +793,12 @@ # C compiler to be used to compile C code. Note that the # default value is platform specific, and if not specified it may also depend on # what platform is crossing to what platform. -# See `src/bootstrap/cc_detect.rs` for details. +# See `src/bootstrap/src/utils/cc_detect.rs` for details. #cc = "cc" (path) # C++ compiler to be used to compile C++ code (e.g. LLVM and our LLVM shims). # This is only used for host targets. -# See `src/bootstrap/cc_detect.rs` for details. +# See `src/bootstrap/src/utils/cc_detect.rs` for details. #cxx = "c++" (path) # Archiver to be used to assemble static libraries compiled from C/C++ code. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 1bb0f761064..b16d40e988e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -105,6 +105,7 @@ #![feature(box_uninit_write)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_eval_select)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 154da691078..9446afd4b24 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1419,7 +1419,9 @@ impl String { pub fn push(&mut self, ch: char) { match ch.len_utf8() { 1 => self.vec.push(ch as u8), - _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()), + _ => { + self.vec.extend_from_slice(ch.encode_utf8(&mut [0; char::MAX_LEN_UTF8]).as_bytes()) + } } } @@ -1716,7 +1718,7 @@ impl String { #[rustc_confusables("set")] pub fn insert(&mut self, idx: usize, ch: char) { assert!(self.is_char_boundary(idx)); - let mut bits = [0; 4]; + let mut bits = [0; char::MAX_LEN_UTF8]; let bits = ch.encode_utf8(&mut bits).as_bytes(); unsafe { @@ -2797,7 +2799,7 @@ impl SpecToString for core::ascii::Char { impl SpecToString for char { #[inline] fn spec_to_string(&self) -> String { - String::from(self.encode_utf8(&mut [0; 4])) + String::from(self.encode_utf8(&mut [0; char::MAX_LEN_UTF8])) } } @@ -3155,6 +3157,24 @@ impl From<String> for Vec<u8> { } } +#[stable(feature = "try_from_vec_u8_for_string", since = "CURRENT_RUSTC_VERSION")] +impl TryFrom<Vec<u8>> for String { + type Error = FromUtf8Error; + /// Converts the given [`Vec<u8>`] into a [`String`] if it contains valid UTF-8 data. + /// + /// # Examples + /// + /// ``` + /// let s1 = b"hello world".to_vec(); + /// let v1 = String::try_from(s1).unwrap(); + /// assert_eq!(v1, "hello world"); + /// + /// ``` + fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> { + Self::from_utf8(bytes) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Write for String { diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 1bcec4037cd..f95be6a6df0 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(iter_array_chunks)] #![feature(assert_matches)] #![feature(btree_extract_if)] +#![feature(char_max_len)] #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] #![feature(downcast_unchecked)] diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 23a0e5e5256..906fa2d425e 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -2,6 +2,7 @@ use std::assert_matches::assert_matches; use std::borrow::Cow; +use std::char::MAX_LEN_UTF8; use std::cmp::Ordering::{Equal, Greater, Less}; use std::str::{from_utf8, from_utf8_unchecked}; @@ -1231,7 +1232,7 @@ fn test_to_uppercase_rev_iterator() { #[test] #[cfg_attr(miri, ignore)] // Miri is too slow fn test_chars_decoding() { - let mut bytes = [0; 4]; + let mut bytes = [0; MAX_LEN_UTF8]; for c in (0..0x110000).filter_map(std::char::from_u32) { let s = c.encode_utf8(&mut bytes); if Some(c) != s.chars().next() { @@ -1243,7 +1244,7 @@ fn test_chars_decoding() { #[test] #[cfg_attr(miri, ignore)] // Miri is too slow fn test_chars_rev_decoding() { - let mut bytes = [0; 4]; + let mut bytes = [0; MAX_LEN_UTF8]; for c in (0..0x110000).filter_map(std::char::from_u32) { let s = c.encode_utf8(&mut bytes); if Some(c) != s.chars().rev().next() { diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index ccfdbf0eb70..85cc315626d 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -71,6 +71,16 @@ impl char { #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const MAX: char = '\u{10FFFF}'; + /// The maximum number of bytes required to [encode](char::encode_utf8) a `char` to + /// UTF-8 encoding. + #[unstable(feature = "char_max_len", issue = "121714")] + pub const MAX_LEN_UTF8: usize = 4; + + /// The maximum number of two-byte units required to [encode](char::encode_utf16) a `char` + /// to UTF-16 encoding. + #[unstable(feature = "char_max_len", issue = "121714")] + pub const MAX_LEN_UTF16: usize = 2; + /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a /// decoding error. /// @@ -1168,6 +1178,7 @@ impl char { #[must_use] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_char_is_ascii", since = "1.32.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "char_is_ascii")] #[inline] pub const fn is_ascii(&self) -> bool { *self as u32 <= 0x7F diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 59fd7250e8f..088c709f1a2 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -95,6 +95,16 @@ const MAX_THREE_B: u32 = 0x10000; #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: char = char::MAX; +/// The maximum number of bytes required to [encode](char::encode_utf8) a `char` to +/// UTF-8 encoding. +#[unstable(feature = "char_max_len", issue = "121714")] +pub const MAX_LEN_UTF8: usize = char::MAX_LEN_UTF8; + +/// The maximum number of two-byte units required to [encode](char::encode_utf16) a `char` +/// to UTF-16 encoding. +#[unstable(feature = "char_max_len", issue = "121714")] +pub const MAX_LEN_UTF16: usize = char::MAX_LEN_UTF16; + /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a /// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead. #[stable(feature = "decode_utf16", since = "1.9.0")] diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a1bf3a4d7a7..764e7fff33e 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -3,7 +3,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell}; -use crate::char::EscapeDebugExtArgs; +use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; @@ -187,7 +187,7 @@ pub trait Write { /// ``` #[stable(feature = "fmt_write_char", since = "1.1.0")] fn write_char(&mut self, c: char) -> Result { - self.write_str(c.encode_utf8(&mut [0; 4])) + self.write_str(c.encode_utf8(&mut [0; MAX_LEN_UTF8])) } /// Glue for usage of the [`write!`] macro with implementors of this trait. @@ -2768,7 +2768,7 @@ impl Display for char { if f.options.width.is_none() && f.options.precision.is_none() { f.write_char(*self) } else { - f.pad(self.encode_utf8(&mut [0; 4])) + f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8])) } } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 0c388115908..8090c98e7ed 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -556,13 +556,13 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe /// * `std::iter::ExactSizeIterator::len` /// * `std::iter::Iterator::__iterator_get_unchecked` /// * `std::iter::TrustedRandomAccessNoCoerce::size` -/// 5. If `T` is a subtype of `Self`, then `self` is allowed to be coerced +/// 5. If `Self` is a subtype of `T`, then `self` is allowed to be coerced /// to `T`. If `self` is coerced to `T` after `self.__iterator_get_unchecked(idx)` has already /// been called, then no methods except for the ones listed under 4. are allowed to be called /// on the resulting value of type `T`, either. Multiple such coercion steps are allowed. /// Regarding 2. and 3., the number of times `__iterator_get_unchecked(idx)` or `next_back()` is /// called on `self` and the resulting value of type `T` (and on further coercion results with -/// sub-subtypes) are added together and their sums must not exceed the specified bounds. +/// super-supertypes) are added together and their sums must not exceed the specified bounds. /// /// Further, given that these conditions are met, it must guarantee that: /// @@ -570,7 +570,7 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe /// * It must be safe to call the methods listed above on `self` after calling /// `self.__iterator_get_unchecked(idx)`, assuming that the required traits are implemented. /// * It must also be safe to drop `self` after calling `self.__iterator_get_unchecked(idx)`. -/// * If `T` is a subtype of `Self`, then it must be safe to coerce `self` to `T`. +/// * If `Self` is a subtype of `T`, then it must be safe to coerce `self` to `T`. // // FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SourceIter::as_inner` // after `__iterator_get_unchecked` is supposed to be allowed. @@ -580,7 +580,7 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {} /// Like [`TrustedRandomAccess`] but without any of the requirements / guarantees around -/// coercions to subtypes after `__iterator_get_unchecked` (they aren’t allowed here!), and +/// coercions to supertypes after `__iterator_get_unchecked` (they aren’t allowed here!), and /// without the requirement that subtypes / supertypes implement `TrustedRandomAccessNoCoerce`. /// /// This trait was created in PR #85874 to fix soundness issue #85873 without performance regressions. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 96a290ad5a0..296b5ebdfaf 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -193,13 +193,13 @@ macro_rules! int_impl { /// Basic usage: /// /// ``` - /// #![feature(integer_sign_cast)] /// #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")] /// ``` - #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 55f4ccd958e..80a38a6013d 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -163,14 +163,14 @@ macro_rules! midpoint_impl { /// # Examples /// /// ``` - /// #![feature(num_midpoint_signed)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[unstable(feature = "num_midpoint_signed", issue = "110840")] + #[stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -215,14 +215,14 @@ macro_rules! midpoint_impl { /// # Examples /// /// ``` - /// #![feature(num_midpoint_signed)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[unstable(feature = "num_midpoint_signed", issue = "110840")] + #[stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 21bad6705ab..b59451d7c75 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1633,14 +1633,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Basic usage: /// /// ``` - /// #![feature(integer_sign_cast)] /// # use std::num::NonZero; /// #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::MAX;")] /// #[doc = concat!("assert_eq!(n.cast_signed(), NonZero::new(-1", stringify!($Sint), ").unwrap());")] /// ``` - #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -2072,14 +2072,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Basic usage: /// /// ``` - /// #![feature(integer_sign_cast)] /// # use std::num::NonZero; /// #[doc = concat!("let n = NonZero::new(-1", stringify!($Int), ").unwrap();")] /// #[doc = concat!("assert_eq!(n.cast_unsigned(), NonZero::<", stringify!($Uint), ">::MAX);")] /// ``` - #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 29f6791ee6a..74d3ae699f6 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -223,13 +223,12 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - /// #![feature(integer_sign_cast)] - /// #[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")] /// #[doc = concat!("assert_eq!(n.cast_signed(), -1", stringify!($SignedT), ");")] /// ``` - #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 45e320e66bc..b1456a1bc1d 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -154,16 +154,39 @@ macro_rules! iterator { #[inline] fn next(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks + // intentionally not using the helpers because this is + // one of the most mono'd things in the library. - // SAFETY: The call to `next_unchecked` is - // safe since we check if the iterator is empty first. + let ptr = self.ptr; + let end_or_len = self.end_or_len; + // SAFETY: See inner comments. (For some reason having multiple + // block breaks inlining this -- if you can fix that please do!) unsafe { - if is_empty!(self) { - None + if T::IS_ZST { + let len = end_or_len.addr(); + if len == 0 { + return None; + } + // SAFETY: just checked that it's not zero, so subtracting one + // cannot wrap. (Ideally this would be `checked_sub`, which + // does the same thing internally, but as of 2025-02 that + // doesn't optimize quite as small in MIR.) + self.end_or_len = without_provenance_mut(len.unchecked_sub(1)); } else { - Some(self.next_unchecked()) + // SAFETY: by type invariant, the `end_or_len` field is always + // non-null for a non-ZST pointee. (This transmute ensures we + // get `!nonnull` metadata on the load of the field.) + if ptr == crate::intrinsics::transmute::<$ptr, NonNull<T>>(end_or_len) { + return None; + } + // SAFETY: since it's not empty, per the check above, moving + // forward one keeps us inside the slice, and this is valid. + self.ptr = ptr.add(1); } + // SAFETY: Now that we know it wasn't empty and we've moved past + // the first one (to avoid giving a duplicate `&mut` next time), + // we can give out a reference to it. + Some({ptr}.$into_ref()) } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ed45e26256e..7b9a76e814a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4796,7 +4796,7 @@ impl<T, const N: usize> [[T; N]] { /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_slice_flatten", issue = "95629")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "CURRENT_RUSTC_VERSION")] pub const fn as_flattened(&self) -> &[T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") @@ -4833,7 +4833,7 @@ impl<T, const N: usize> [[T; N]] { /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_slice_flatten", issue = "95629")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "CURRENT_RUSTC_VERSION")] pub const fn as_flattened_mut(&mut self) -> &mut [T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 09f898309bd..f6dcf42ba60 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -387,7 +387,7 @@ unsafe fn swap_if_less<T, F>(v_base: *mut T, a_pos: usize, b_pos: usize, is_less where F: FnMut(&T, &T) -> bool, { - // SAFETY: the caller must guarantee that `a` and `b` each added to `v_base` yield valid + // SAFETY: the caller must guarantee that `a_pos` and `b_pos` each added to `v_base` yield valid // pointers into `v_base`, and are properly aligned, and part of the same allocation. unsafe { let v_a = v_base.add(a_pos); @@ -404,16 +404,16 @@ where // The equivalent code with a branch would be: // // if should_swap { - // ptr::swap(left, right, 1); + // ptr::swap(v_a, v_b, 1); // } // The goal is to generate cmov instructions here. - let left_swap = if should_swap { v_b } else { v_a }; - let right_swap = if should_swap { v_a } else { v_b }; + let v_a_swap = should_swap.select_unpredictable(v_b, v_a); + let v_b_swap = should_swap.select_unpredictable(v_a, v_b); - let right_swap_tmp = ManuallyDrop::new(ptr::read(right_swap)); - ptr::copy(left_swap, v_a, 1); - ptr::copy_nonoverlapping(&*right_swap_tmp, v_b, 1); + let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap)); + ptr::copy(v_a_swap, v_a, 1); + ptr::copy_nonoverlapping(&*v_b_swap_tmp, v_b, 1); } } @@ -640,26 +640,21 @@ pub unsafe fn sort4_stable<T, F: FnMut(&T, &T) -> bool>( // 1, 1 | c b a d let c3 = is_less(&*c, &*a); let c4 = is_less(&*d, &*b); - let min = select(c3, c, a); - let max = select(c4, b, d); - let unknown_left = select(c3, a, select(c4, c, b)); - let unknown_right = select(c4, d, select(c3, b, c)); + let min = c3.select_unpredictable(c, a); + let max = c4.select_unpredictable(b, d); + let unknown_left = c3.select_unpredictable(a, c4.select_unpredictable(c, b)); + let unknown_right = c4.select_unpredictable(d, c3.select_unpredictable(b, c)); // Sort the last two unknown elements. let c5 = is_less(&*unknown_right, &*unknown_left); - let lo = select(c5, unknown_right, unknown_left); - let hi = select(c5, unknown_left, unknown_right); + let lo = c5.select_unpredictable(unknown_right, unknown_left); + let hi = c5.select_unpredictable(unknown_left, unknown_right); ptr::copy_nonoverlapping(min, dst, 1); ptr::copy_nonoverlapping(lo, dst.add(1), 1); ptr::copy_nonoverlapping(hi, dst.add(2), 1); ptr::copy_nonoverlapping(max, dst.add(3), 1); } - - #[inline(always)] - fn select<T>(cond: bool, if_true: *const T, if_false: *const T) -> *const T { - if cond { if_true } else { if_false } - } } /// SAFETY: The caller MUST guarantee that `v_base` is valid for 8 reads and diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fd2cd59f88e..4754d18b06e 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -198,8 +198,6 @@ impl str { /// Basic usage: /// /// ``` - /// use std::str; - /// /// // some bytes, in a vector /// let sparkle_heart = vec![240, 159, 146, 150]; /// @@ -207,14 +205,12 @@ impl str { /// let sparkle_heart = str::from_utf8(&sparkle_heart)?; /// /// assert_eq!("💖", sparkle_heart); - /// # Ok::<_, str::Utf8Error>(()) + /// # Ok::<_, std::str::Utf8Error>(()) /// ``` /// /// Incorrect bytes: /// /// ``` - /// use std::str; - /// /// // some invalid bytes, in a vector /// let sparkle_heart = vec![0, 159, 146, 150]; /// @@ -227,8 +223,6 @@ impl str { /// A "stack allocated string": /// /// ``` - /// use std::str; - /// /// // some bytes, in a stack-allocated array /// let sparkle_heart = [240, 159, 146, 150]; /// @@ -237,7 +231,8 @@ impl str { /// /// assert_eq!("💖", sparkle_heart); /// ``` - #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "str_inherent_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { converts::from_utf8(v) @@ -250,8 +245,6 @@ impl str { /// Basic usage: /// /// ``` - /// use std::str; - /// /// // "Hello, Rust!" as a mutable vector /// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; /// @@ -264,8 +257,6 @@ impl str { /// Incorrect bytes: /// /// ``` - /// use std::str; - /// /// // Some invalid bytes in a mutable vector /// let mut invalid = vec![128, 223]; /// @@ -273,7 +264,7 @@ impl str { /// ``` /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. - #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] #[rustc_diagnostic_item = "str_inherent_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { @@ -294,8 +285,6 @@ impl str { /// Basic usage: /// /// ``` - /// use std::str; - /// /// // some bytes, in a vector /// let sparkle_heart = vec![240, 159, 146, 150]; /// @@ -307,7 +296,8 @@ impl str { /// ``` #[inline] #[must_use] - #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: converts::from_utf8_unchecked has the same safety requirements as this function. @@ -324,8 +314,6 @@ impl str { /// Basic usage: /// /// ``` - /// use std::str; - /// /// let mut heart = vec![240, 159, 146, 150]; /// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; /// @@ -333,7 +321,8 @@ impl str { /// ``` #[inline] #[must_use] - #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: converts::from_utf8_unchecked_mut has the same safety requirements as this function. diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 52e2364893e..2d941adfd85 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -38,6 +38,7 @@ issue = "27721" )] +use crate::char::MAX_LEN_UTF8; use crate::cmp::Ordering; use crate::convert::TryInto as _; use crate::slice::memchr; @@ -561,8 +562,8 @@ impl Pattern for char { type Searcher<'a> = CharSearcher<'a>; #[inline] - fn into_searcher(self, haystack: &str) -> Self::Searcher<'_> { - let mut utf8_encoded = [0; 4]; + fn into_searcher<'a>(self, haystack: &'a str) -> Self::Searcher<'a> { + let mut utf8_encoded = [0; MAX_LEN_UTF8]; let utf8_size = self .encode_utf8(&mut utf8_encoded) .len() diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index b289f6026ff..9eb71922218 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -65,9 +65,9 @@ macro_rules! assert_unsafe_precondition { #[rustc_nounwind] const fn precondition_check($($name:$ty),*) { if !$e { - ::core::panicking::panic_nounwind( - concat!("unsafe precondition(s) violated: ", $message) - ); + ::core::panicking::panic_nounwind(concat!("unsafe precondition(s) violated: ", $message, + "\n\nThis indicates a bug in the program. \ + This Undefined Behavior check is optional, and cannot be relied on for safety.")); } } diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs index 6422387e956..153fb36925e 100644 --- a/library/coretests/tests/char.rs +++ b/library/coretests/tests/char.rs @@ -1,3 +1,4 @@ +use std::char::MAX_LEN_UTF8; use std::str::FromStr; use std::{char, str}; @@ -259,7 +260,7 @@ fn test_escape_unicode() { #[test] fn test_encode_utf8() { fn check(input: char, expect: &[u8]) { - let mut buf = [0; 4]; + let mut buf = [0; MAX_LEN_UTF8]; let ptr = buf.as_ptr(); let s = input.encode_utf8(&mut buf); assert_eq!(s.as_ptr() as usize, ptr as usize); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 1e1ff29e161..ca58f41d7dd 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -13,6 +13,7 @@ #![feature(bigint_helper_methods)] #![feature(bstr)] #![feature(cell_update)] +#![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] #![feature(const_swap_nonoverlapping)] @@ -62,7 +63,6 @@ #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(never_type)] -#![feature(num_midpoint_signed)] #![feature(numfmt)] #![feature(pattern)] #![feature(pointer_is_aligned_to)] diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs index b763a7c75a5..19d45f4d3b3 100644 --- a/library/portable-simd/crates/core_simd/src/masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks.rs @@ -401,7 +401,6 @@ where LaneCount<N>: SupportedLaneCount, { #[inline] - #[must_use = "method returns a defaulted mask with all elements set to false (0)"] fn default() -> Self { Self::splat(false) } @@ -413,7 +412,6 @@ where LaneCount<N>: SupportedLaneCount, { #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] fn eq(&self, other: &Self) -> bool { self.0 == other.0 } @@ -425,7 +423,6 @@ where LaneCount<N>: SupportedLaneCount, { #[inline] - #[must_use = "method returns a new Ordering and does not mutate the original value"] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) } @@ -451,7 +448,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitand(self, rhs: Self) -> Self { Self(self.0 & rhs.0) } @@ -464,7 +460,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitand(self, rhs: bool) -> Self { self & Self::splat(rhs) } @@ -477,7 +472,6 @@ where { type Output = Mask<T, N>; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitand(self, rhs: Mask<T, N>) -> Mask<T, N> { Mask::splat(self) & rhs } @@ -490,7 +484,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } @@ -503,7 +496,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitor(self, rhs: bool) -> Self { self | Self::splat(rhs) } @@ -516,7 +508,6 @@ where { type Output = Mask<T, N>; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitor(self, rhs: Mask<T, N>) -> Mask<T, N> { Mask::splat(self) | rhs } @@ -529,7 +520,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitxor(self, rhs: Self) -> Self::Output { Self(self.0 ^ rhs.0) } @@ -542,7 +532,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitxor(self, rhs: bool) -> Self::Output { self ^ Self::splat(rhs) } @@ -555,7 +544,6 @@ where { type Output = Mask<T, N>; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitxor(self, rhs: Mask<T, N>) -> Self::Output { Mask::splat(self) ^ rhs } @@ -568,7 +556,6 @@ where { type Output = Mask<T, N>; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn not(self) -> Self::Output { Self(!self.0) } diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs index 2d01946b574..387b508c4b4 100644 --- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs @@ -21,7 +21,6 @@ where LaneCount<N>: SupportedLaneCount, { #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn clone(&self) -> Self { *self } @@ -252,7 +251,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitand(self, rhs: Self) -> Self { // Safety: `self` is an integer vector unsafe { Self(core::intrinsics::simd::simd_and(self.0, rhs.0)) } @@ -266,7 +264,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitor(self, rhs: Self) -> Self { // Safety: `self` is an integer vector unsafe { Self(core::intrinsics::simd::simd_or(self.0, rhs.0)) } @@ -280,7 +277,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn bitxor(self, rhs: Self) -> Self { // Safety: `self` is an integer vector unsafe { Self(core::intrinsics::simd::simd_xor(self.0, rhs.0)) } @@ -294,7 +290,6 @@ where { type Output = Self; #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn not(self) -> Self::Output { Self::splat(true) ^ self } diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs index d3bd14a3402..4ac64a253a3 100644 --- a/library/portable-simd/crates/core_simd/src/ops.rs +++ b/library/portable-simd/crates/core_simd/src/ops.rs @@ -135,7 +135,6 @@ macro_rules! for_base_types { type Output = $out; #[inline] - #[must_use = "operator returns a new vector without mutating the inputs"] // TODO: only useful for int Div::div, but we hope that this // will essentially always get inlined anyway. #[track_caller] diff --git a/library/portable-simd/crates/core_simd/src/ops/deref.rs b/library/portable-simd/crates/core_simd/src/ops/deref.rs index 0ff76cfba39..913cbbe977c 100644 --- a/library/portable-simd/crates/core_simd/src/ops/deref.rs +++ b/library/portable-simd/crates/core_simd/src/ops/deref.rs @@ -18,7 +18,6 @@ macro_rules! deref_lhs { type Output = Simd<T, N>; #[inline] - #[must_use = "operator returns a new vector without mutating the inputs"] fn $call(self, rhs: $simd) -> Self::Output { (*self).$call(rhs) } @@ -39,7 +38,6 @@ macro_rules! deref_rhs { type Output = Simd<T, N>; #[inline] - #[must_use = "operator returns a new vector without mutating the inputs"] fn $call(self, rhs: &$simd) -> Self::Output { self.$call(*rhs) } @@ -71,7 +69,6 @@ macro_rules! deref_ops { type Output = $simd; #[inline] - #[must_use = "operator returns a new vector without mutating the inputs"] fn $call(self, rhs: &'rhs $simd) -> Self::Output { (*self).$call(*rhs) } diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs index bdae96332a3..412a5b80117 100644 --- a/library/portable-simd/crates/core_simd/src/ops/unary.rs +++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs @@ -11,7 +11,6 @@ macro_rules! neg { type Output = Self; #[inline] - #[must_use = "operator returns a new vector without mutating the input"] fn neg(self) -> Self::Output { // Safety: `self` is a signed vector unsafe { core::intrinsics::simd::simd_neg(self) } @@ -46,7 +45,6 @@ macro_rules! not { type Output = Self; #[inline] - #[must_use = "operator returns a new vector without mutating the input"] fn not(self) -> Self::Output { self ^ (Simd::splat(!(0 as $scalar))) } diff --git a/library/portable-simd/crates/core_simd/src/simd/num/float.rs b/library/portable-simd/crates/core_simd/src/simd/num/float.rs index 79954b937b3..db705dfe202 100644 --- a/library/portable-simd/crates/core_simd/src/simd/num/float.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/float.rs @@ -371,7 +371,6 @@ macro_rules! impl_trait { } #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] fn is_normal(self) -> Self::Mask { !(self.abs().simd_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite()) } diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index bdbe3e21994..0af69dff05a 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -1321,12 +1321,14 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_erf)] + /// # #[cfg(reliable_f16_math)] { /// let x: f16 = 0.123; /// /// let one = x.erf() + x.erfc(); /// let abs_difference = (one - 1.0).abs(); /// /// assert!(abs_difference <= f16::EPSILON); + /// # } /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6001a2e2f39..57e235c3efe 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -624,20 +624,20 @@ impl File { self.inner.datasync() } - /// Acquire an exclusive advisory lock on the file. Blocks until the lock can be acquired. + /// Acquire an exclusive lock on the file. Blocks until the lock can be acquired. /// - /// This acquires an exclusive advisory lock; no other file handle to this file may acquire - /// another lock. + /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. /// - /// If this file handle/descriptor, or a clone of it, already holds an advisory lock the exact - /// behavior is unspecified and platform dependent, including the possibility that it will - /// deadlock. However, if this method returns, then an exclusive lock is held. + /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], + /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with + /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not + /// cause non-lockholders to block. /// - /// If the file not open for writing, it is unspecified whether this function returns an error. + /// If this file handle/descriptor, or a clone of it, already holds an lock the exact behavior + /// is unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then an exclusive lock is held. /// - /// Note, this is an advisory lock meant to interact with [`lock_shared`], [`try_lock`], - /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] - /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// If the file not open for writing, it is unspecified whether this function returns an error. /// /// The lock will be released when this file (along with any other file descriptors/handles /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. @@ -648,8 +648,12 @@ impl File { /// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that, /// this [may change in the future][changes]. /// + /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, + /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. + /// /// [changes]: io#platform-specific-behavior /// + /// [`lock`]: File::lock /// [`lock_shared`]: File::lock_shared /// [`try_lock`]: File::try_lock /// [`try_lock_shared`]: File::try_lock_shared @@ -660,7 +664,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -669,23 +672,24 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn lock(&self) -> io::Result<()> { self.inner.lock() } - /// Acquire a shared (non-exclusive) advisory lock on the file. Blocks until the lock can be acquired. + /// Acquire a shared (non-exclusive) lock on the file. Blocks until the lock can be acquired. /// - /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock at the same time. + /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may + /// hold an exclusive lock at the same time. /// - /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact - /// behavior is unspecified and platform dependent, including the possibility that it will - /// deadlock. However, if this method returns, then a shared lock is held. + /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], + /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with + /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not + /// cause non-lockholders to block. /// - /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], - /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] - /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// If this file handle/descriptor, or a clone of it, already holds an lock, the exact behavior + /// is unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then a shared lock is held. /// /// The lock will be released when this file (along with any other file descriptors/handles /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. @@ -696,9 +700,13 @@ impl File { /// and the `LockFileEx` function on Windows. Note that, this /// [may change in the future][changes]. /// + /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, + /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. + /// /// [changes]: io#platform-specific-behavior /// /// [`lock`]: File::lock + /// [`lock_shared`]: File::lock_shared /// [`try_lock`]: File::try_lock /// [`try_lock_shared`]: File::try_lock_shared /// [`unlock`]: File::unlock @@ -708,7 +716,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -717,29 +724,28 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn lock_shared(&self) -> io::Result<()> { self.inner.lock_shared() } - /// Try to acquire an exclusive advisory lock on the file. + /// Try to acquire an exclusive lock on the file. /// /// Returns `Ok(false)` if a different lock is already held on this file (via another /// handle/descriptor). /// - /// This acquires an exclusive advisory lock; no other file handle to this file may acquire - /// another lock. + /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. /// - /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact - /// behavior is unspecified and platform dependent, including the possibility that it will - /// deadlock. However, if this method returns `Ok(true)`, then it has acquired an exclusive - /// lock. + /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], + /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with + /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not + /// cause non-lockholders to block. /// - /// If the file not open for writing, it is unspecified whether this function returns an error. + /// If this file handle/descriptor, or a clone of it, already holds an lock, the exact behavior + /// is unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns `Ok(true)`, then it has acquired an exclusive lock. /// - /// Note, this is an advisory lock meant to interact with [`lock`], [`lock_shared`], - /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] - /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// If the file not open for writing, it is unspecified whether this function returns an error. /// /// The lock will be released when this file (along with any other file descriptors/handles /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. @@ -751,10 +757,14 @@ impl File { /// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this /// [may change in the future][changes]. /// + /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, + /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. + /// /// [changes]: io#platform-specific-behavior /// /// [`lock`]: File::lock /// [`lock_shared`]: File::lock_shared + /// [`try_lock`]: File::try_lock /// [`try_lock_shared`]: File::try_lock_shared /// [`unlock`]: File::unlock /// [`read`]: Read::read @@ -763,7 +773,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -772,27 +781,28 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn try_lock(&self) -> io::Result<bool> { self.inner.try_lock() } - /// Try to acquire a shared (non-exclusive) advisory lock on the file. + /// Try to acquire a shared (non-exclusive) lock on the file. /// /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another /// handle/descriptor). /// - /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock at the same time. + /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may + /// hold an exclusive lock at the same time. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], + /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with + /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not + /// cause non-lockholders to block. + /// + /// If this file handle, or a clone of it, already holds an lock, the exact behavior is /// unspecified and platform dependent, including the possibility that it will deadlock. /// However, if this method returns `Ok(true)`, then it has acquired a shared lock. /// - /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], - /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`] - /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. - /// /// The lock will be released when this file (along with any other file descriptors/handles /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. /// @@ -803,11 +813,15 @@ impl File { /// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this /// [may change in the future][changes]. /// + /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, + /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. + /// /// [changes]: io#platform-specific-behavior /// /// [`lock`]: File::lock /// [`lock_shared`]: File::lock_shared /// [`try_lock`]: File::try_lock + /// [`try_lock_shared`]: File::try_lock_shared /// [`unlock`]: File::unlock /// [`read`]: Read::read /// [`write`]: Write::write @@ -815,7 +829,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -824,7 +837,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn try_lock_shared(&self) -> io::Result<bool> { self.inner.try_lock_shared() } @@ -844,12 +857,14 @@ impl File { /// and the `UnlockFile` function on Windows. Note that, this /// [may change in the future][changes]. /// + /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, + /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. + /// /// [changes]: io#platform-specific-behavior /// /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -859,7 +874,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn unlock(&self) -> io::Result<()> { self.inner.unlock() } @@ -2511,6 +2526,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> /// * `from` does not exist. /// * The current process does not have the permission rights to read /// `from` or write `to`. +/// * The parent directory of `to` doesn't exist. /// /// # Examples /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 8e307f57cf9..1a266f71965 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,5 +1,6 @@ use rand::RngCore; +use crate::char::MAX_LEN_UTF8; use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; @@ -155,7 +156,7 @@ fn file_test_io_non_positional_read() { #[test] fn file_test_io_seek_and_tell_smoke_test() { let message = "ten-four"; - let mut read_mem = [0; 4]; + let mut read_mem = [0; MAX_LEN_UTF8]; let set_cursor = 4 as u64; let tell_pos_pre_read; let tell_pos_post_read; @@ -356,7 +357,7 @@ fn file_test_io_seek_shakedown() { let chunk_one: &str = "qwer"; let chunk_two: &str = "asdf"; let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; + let mut read_mem = [0; MAX_LEN_UTF8]; let tmpdir = tmpdir(); let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); { @@ -621,7 +622,7 @@ fn file_test_directoryinfo_readdir() { check!(w.write(msg)); } let files = check!(fs::read_dir(dir)); - let mut mem = [0; 4]; + let mut mem = [0; MAX_LEN_UTF8]; for f in files { let f = f.unwrap().path(); { diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 318c3508221..661c422811a 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -239,6 +239,7 @@ fn handle_ebadf_lazy<T>(r: io::Result<T>, default: impl FnOnce() -> T) -> io::Re /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Stdin")] pub struct Stdin { inner: &'static Mutex<BufReader<StdinRaw>>, } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 750116c6269..0661b3d770e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -284,6 +284,7 @@ #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] +#![feature(char_max_len)] #![feature(concat_idents)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 42aada131da..34f0e89f2f1 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -162,13 +162,6 @@ pub trait FileExt { Ok(()) } - /// Returns the current position within the file. - /// - /// This corresponds to the `fd_tell` syscall and is similar to - /// `seek` where you offset 0 bytes from the current position. - #[doc(alias = "fd_tell")] - fn tell(&self) -> io::Result<u64>; - /// Adjusts the flags associated with this file. /// /// This corresponds to the `fd_fdstat_set_flags` syscall. @@ -240,10 +233,6 @@ impl FileExt for fs::File { self.as_inner().as_inner().pwrite(bufs, offset) } - fn tell(&self) -> io::Result<u64> { - self.as_inner().as_inner().tell() - } - fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { self.as_inner().as_inner().set_flags(flags) } diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 61801db072a..22776ae2bc4 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -255,6 +255,7 @@ pub use crate::panicking::{set_hook, take_hook}; #[stable(feature = "panic_any", since = "1.51.0")] #[inline] #[track_caller] +#[cfg_attr(not(test), rustc_diagnostic_item = "panic_any")] pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! { crate::panicking::begin_panic(msg); } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index fd0fd1cb755..bdd4844b651 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -217,6 +217,7 @@ use crate::{fmt, fs, str}; /// /// [`wait`]: Child::wait #[stable(feature = "process", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Child")] pub struct Child { pub(crate) handle: imp::Process, @@ -2115,6 +2116,7 @@ impl Child { /// [`ErrorKind`]: io::ErrorKind /// [`InvalidInput`]: io::ErrorKind::InvalidInput #[stable(feature = "process", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "child_kill")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() } @@ -2135,6 +2137,7 @@ impl Child { /// ``` #[must_use] #[stable(feature = "process_id", since = "1.3.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "child_id")] pub fn id(&self) -> u32 { self.handle.id() } @@ -2375,6 +2378,7 @@ pub fn exit(code: i32) -> ! { /// [panic hook]: crate::panic::set_hook #[stable(feature = "process_abort", since = "1.17.0")] #[cold] +#[cfg_attr(not(test), rustc_diagnostic_item = "process_abort")] pub fn abort() -> ! { crate::sys::abort_internal(); } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 5b65d862be1..1d337694944 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -8,7 +8,7 @@ use crate::collections::TryReserveError; use crate::fmt::Write; use crate::rc::Rc; use crate::sync::Arc; -use crate::sys_common::{AsInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, mem, str}; #[cfg(test)] @@ -25,6 +25,37 @@ pub struct Slice { pub inner: [u8], } +impl IntoInner<Vec<u8>> for Buf { + fn into_inner(self) -> Vec<u8> { + self.inner + } +} + +impl FromInner<Vec<u8>> for Buf { + fn from_inner(inner: Vec<u8>) -> Self { + Buf { inner } + } +} + +impl AsInner<[u8]> for Buf { + #[inline] + fn as_inner(&self) -> &[u8] { + &self.inner + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), f) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), f) + } +} + impl fmt::Debug for Slice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner.utf8_chunks().debug(), f) @@ -55,18 +86,6 @@ impl fmt::Display for Slice { } } -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - impl Clone for Buf { #[inline] fn clone(&self) -> Self { @@ -79,19 +98,6 @@ impl Clone for Buf { } } -impl IntoInner<Vec<u8>> for Buf { - fn into_inner(self) -> Vec<u8> { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - #[inline] - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - impl Buf { #[inline] pub fn into_encoded_bytes(self) -> Vec<u8> { @@ -103,6 +109,12 @@ impl Buf { Self { inner: s } } + #[inline] + pub fn into_string(self) -> Result<String, Buf> { + String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() }) + } + + #[inline] pub fn from_string(s: String) -> Buf { Buf { inner: s.into_bytes() } } @@ -123,6 +135,11 @@ impl Buf { } #[inline] + pub fn push_slice(&mut self, s: &Slice) { + self.inner.extend_from_slice(&s.inner) + } + + #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } @@ -157,7 +174,7 @@ impl Buf { // SAFETY: Slice just wraps [u8], // and &*self.inner is &[u8], therefore // transmuting &[u8] to &Slice is safe. - unsafe { mem::transmute(&*self.inner) } + unsafe { mem::transmute(self.inner.as_slice()) } } #[inline] @@ -165,15 +182,7 @@ impl Buf { // SAFETY: Slice just wraps [u8], // and &mut *self.inner is &mut [u8], therefore // transmuting &mut [u8] to &mut Slice is safe. - unsafe { mem::transmute(&mut *self.inner) } - } - - pub fn into_string(self) -> Result<String, Buf> { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() }) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) + unsafe { mem::transmute(self.inner.as_mut_slice()) } } #[inline] @@ -278,18 +287,22 @@ impl Slice { unsafe { Slice::from_encoded_bytes_unchecked(s.as_bytes()) } } + #[inline] pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { str::from_utf8(&self.inner) } + #[inline] pub fn to_string_lossy(&self) -> Cow<'_, str> { String::from_utf8_lossy(&self.inner) } + #[inline] pub fn to_owned(&self) -> Buf { Buf { inner: self.inner.to_vec() } } + #[inline] pub fn clone_into(&self, buf: &mut Buf) { self.inner.clone_into(&mut buf.inner) } @@ -300,6 +313,7 @@ impl Slice { unsafe { mem::transmute(boxed) } } + #[inline] pub fn empty_box() -> Box<Slice> { let boxed: Box<[u8]> = Default::default(); unsafe { mem::transmute(boxed) } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index a4ad5966afe..19728d33990 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -10,11 +10,16 @@ use crate::sys_common::wtf8::{Wtf8, Wtf8Buf, check_utf8_boundary}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, mem}; -#[derive(Clone, Hash)] +#[derive(Hash)] pub struct Buf { pub inner: Wtf8Buf, } +#[repr(transparent)] +pub struct Slice { + pub inner: Wtf8, +} + impl IntoInner<Wtf8Buf> for Buf { fn into_inner(self) -> Wtf8Buf { self.inner @@ -35,31 +40,38 @@ impl AsInner<Wtf8> for Buf { } impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), f) } } impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), f) } } -#[repr(transparent)] -pub struct Slice { - pub inner: Wtf8, -} - impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.inner, formatter) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) } } impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.inner, formatter) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.inner, f) + } +} + +impl Clone for Buf { + #[inline] + fn clone(&self) -> Self { + Buf { inner: self.inner.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.inner.clone_from(&source.inner) } } @@ -74,62 +86,57 @@ impl Buf { unsafe { Self { inner: Wtf8Buf::from_bytes_unchecked(s) } } } - pub fn with_capacity(capacity: usize) -> Buf { - Buf { inner: Wtf8Buf::with_capacity(capacity) } - } - - pub fn clear(&mut self) { - self.inner.clear() - } - - pub fn capacity(&self) -> usize { - self.inner.capacity() + #[inline] + pub fn into_string(self) -> Result<String, Buf> { + self.inner.into_string().map_err(|buf| Buf { inner: buf }) } + #[inline] pub fn from_string(s: String) -> Buf { Buf { inner: Wtf8Buf::from_string(s) } } - pub fn as_slice(&self) -> &Slice { - // SAFETY: Slice is just a wrapper for Wtf8, - // and self.inner.as_slice() returns &Wtf8. - // Therefore, transmuting &Wtf8 to &Slice is safe. - unsafe { mem::transmute(self.inner.as_slice()) } + #[inline] + pub fn with_capacity(capacity: usize) -> Buf { + Buf { inner: Wtf8Buf::with_capacity(capacity) } } - pub fn as_mut_slice(&mut self) -> &mut Slice { - // SAFETY: Slice is just a wrapper for Wtf8, - // and self.inner.as_mut_slice() returns &mut Wtf8. - // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. - // Additionally, care should be taken to ensure the slice - // is always valid Wtf8. - unsafe { mem::transmute(self.inner.as_mut_slice()) } + #[inline] + pub fn clear(&mut self) { + self.inner.clear() } - pub fn into_string(self) -> Result<String, Buf> { - self.inner.into_string().map_err(|buf| Buf { inner: buf }) + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() } + #[inline] pub fn push_slice(&mut self, s: &Slice) { self.inner.push_wtf8(&s.inner) } + #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } + #[inline] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.inner.try_reserve(additional) } + #[inline] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } + #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.inner.try_reserve_exact(additional) } + #[inline] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } @@ -140,6 +147,24 @@ impl Buf { } #[inline] + pub fn as_slice(&self) -> &Slice { + // SAFETY: Slice is just a wrapper for Wtf8, + // and self.inner.as_slice() returns &Wtf8. + // Therefore, transmuting &Wtf8 to &Slice is safe. + unsafe { mem::transmute(self.inner.as_slice()) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Slice { + // SAFETY: Slice is just a wrapper for Wtf8, + // and self.inner.as_mut_slice() returns &mut Wtf8. + // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. + // Additionally, care should be taken to ensure the slice + // is always valid Wtf8. + unsafe { mem::transmute(self.inner.as_mut_slice()) } + } + + #[inline] pub fn leak<'a>(self) -> &'a mut Slice { unsafe { mem::transmute(self.inner.leak()) } } @@ -194,6 +219,7 @@ impl Slice { } #[track_caller] + #[inline] pub fn check_public_boundary(&self, index: usize) { check_utf8_boundary(&self.inner, index); } @@ -203,18 +229,22 @@ impl Slice { unsafe { mem::transmute(Wtf8::from_str(s)) } } + #[inline] pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { self.inner.as_str() } + #[inline] pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() } + #[inline] pub fn to_owned(&self) -> Buf { Buf { inner: self.inner.to_owned() } } + #[inline] pub fn clone_into(&self, buf: &mut Buf) { self.inner.clone_into(&mut buf.inner) } @@ -224,6 +254,7 @@ impl Slice { unsafe { mem::transmute(self.inner.into_box()) } } + #[inline] pub fn empty_box() -> Box<Slice> { unsafe { mem::transmute(Wtf8::empty_box()) } } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 8dc61edb603..4fbdc839939 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -204,7 +204,7 @@ compat_fn_with_fallback! { pub fn NtReleaseKeyedEvent( EventHandle: HANDLE, Key: *const c_void, - Alertable: BOOLEAN, + Alertable: bool, Timeout: *mut i64 ) -> NTSTATUS { panic!("keyed events not available") @@ -213,7 +213,7 @@ compat_fn_with_fallback! { pub fn NtWaitForKeyedEvent( EventHandle: HANDLE, Key: *const c_void, - Alertable: BOOLEAN, + Alertable: bool, Timeout: *mut i64 ) -> NTSTATUS { panic!("keyed events not available") diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index fd3f559ba19..1b245991aa7 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -1,5 +1,6 @@ #![unstable(issue = "none", feature = "windows_stdio")] +use core::char::MAX_LEN_UTF8; use core::str::utf8_char_width; use super::api::{self, WinError}; @@ -426,7 +427,7 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> { impl IncompleteUtf8 { pub const fn new() -> IncompleteUtf8 { - IncompleteUtf8 { bytes: [0; 4], len: 0 } + IncompleteUtf8 { bytes: [0; MAX_LEN_UTF8], len: 0 } } } diff --git a/library/std/src/sys/random/windows.rs b/library/std/src/sys/random/windows.rs index 7566000f9e6..f5da637f56c 100644 --- a/library/std/src/sys/random/windows.rs +++ b/library/std/src/sys/random/windows.rs @@ -14,7 +14,7 @@ pub fn fill_bytes(mut bytes: &mut [u8]) { while !bytes.is_empty() { let len = bytes.len().try_into().unwrap_or(u32::MAX); let ret = unsafe { c::RtlGenRandom(bytes.as_mut_ptr().cast(), len) }; - assert_ne!(ret, 0, "failed to generate random data"); + assert!(ret, "failed to generate random data"); bytes = &mut bytes[len as usize..]; } } diff --git a/library/std/src/sys/sync/mutex/windows7.rs b/library/std/src/sys/sync/mutex/windows7.rs index 689dba10f01..0b57de78ba6 100644 --- a/library/std/src/sys/sync/mutex/windows7.rs +++ b/library/std/src/sys/sync/mutex/windows7.rs @@ -44,7 +44,7 @@ impl Mutex { #[inline] pub fn try_lock(&self) -> bool { - unsafe { c::TryAcquireSRWLockExclusive(raw(self)) != 0 } + unsafe { c::TryAcquireSRWLockExclusive(raw(self)) } } #[inline] diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index f7585e882f0..a1a0f8427cd 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -195,7 +195,7 @@ mod keyed_events { pub unsafe fn park(parker: Pin<&Parker>) { // Wait for unpark() to produce this event. - c::NtWaitForKeyedEvent(keyed_event_handle(), parker.ptr(), 0, ptr::null_mut()); + c::NtWaitForKeyedEvent(keyed_event_handle(), parker.ptr(), false, ptr::null_mut()); // Set the state back to EMPTY (from either PARKED or NOTIFIED). // Note that we don't just write EMPTY, but use swap() to also // include an acquire-ordered read to synchronize with unpark()'s @@ -218,7 +218,7 @@ mod keyed_events { // Wait for unpark() to produce this event. let unparked = - c::NtWaitForKeyedEvent(handle, parker.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; + c::NtWaitForKeyedEvent(handle, parker.ptr(), false, &mut timeout) == c::STATUS_SUCCESS; // Set the state back to EMPTY (from either PARKED or NOTIFIED). let prev_state = parker.state.swap(EMPTY, Acquire); @@ -228,7 +228,7 @@ mod keyed_events { // was set to NOTIFIED, which means we *just* missed an // unpark(), which is now blocked on us to wait for it. // Wait for it to consume the event and unblock that thread. - c::NtWaitForKeyedEvent(handle, parker.ptr(), 0, ptr::null_mut()); + c::NtWaitForKeyedEvent(handle, parker.ptr(), false, ptr::null_mut()); } } pub unsafe fn unpark(parker: Pin<&Parker>) { @@ -239,7 +239,7 @@ mod keyed_events { // To prevent this thread from blocking indefinitely in that case, // park_impl() will, after seeing the state set to NOTIFIED after // waking up, call NtWaitForKeyedEvent again to unblock us. - c::NtReleaseKeyedEvent(keyed_event_handle(), parker.ptr(), 0, ptr::null_mut()); + c::NtReleaseKeyedEvent(keyed_event_handle(), parker.ptr(), false, ptr::null_mut()); } fn keyed_event_handle() -> c::HANDLE { diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 6c60d901ee9..952c39132b0 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -18,7 +18,7 @@ #[cfg(test)] mod tests; -use core::char::{encode_utf8_raw, encode_utf16_raw}; +use core::char::{MAX_LEN_UTF8, MAX_LEN_UTF16, encode_utf8_raw, encode_utf16_raw}; use core::clone::CloneToUninit; use core::str::next_code_point; @@ -156,9 +156,12 @@ impl ops::DerefMut for Wtf8Buf { } } -/// Format the string with double quotes, -/// and surrogates as `\u` followed by four hexadecimal digits. -/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800] +/// Formats the string in double quotes, with characters escaped according to +/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, +/// where each `x` is a hexadecimal digit. +/// +/// For example, the code units [U+0061, U+D800, U+000A] are formatted as +/// `"a\u{D800}\n"`. impl fmt::Debug for Wtf8Buf { #[inline] fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -181,7 +184,7 @@ impl Wtf8Buf { /// Creates a WTF-8 string from a WTF-8 byte vec. /// - /// Since the byte vec is not checked for valid WTF-8, this functions is + /// Since the byte vec is not checked for valid WTF-8, this function is /// marked unsafe. #[inline] pub unsafe fn from_bytes_unchecked(value: Vec<u8>) -> Wtf8Buf { @@ -205,7 +208,7 @@ impl Wtf8Buf { /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] pub fn from_str(s: &str) -> Wtf8Buf { - Wtf8Buf { bytes: <[_]>::to_vec(s.as_bytes()), is_known_utf8: true } + Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true } } pub fn clear(&mut self) { @@ -237,10 +240,11 @@ impl Wtf8Buf { string } - /// Copied from String::push + /// Appends the given `char` to the end of this string. /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. + /// Copied from String::push. fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let mut bytes = [0; 4]; + let mut bytes = [0; MAX_LEN_UTF8]; let bytes = encode_utf8_raw(code_point.value, &mut bytes); self.bytes.extend_from_slice(bytes) } @@ -264,16 +268,16 @@ impl Wtf8Buf { /// /// # Panics /// - /// Panics if the new capacity overflows `usize`. + /// Panics if the new capacity exceeds `isize::MAX` bytes. #[inline] pub fn reserve(&mut self, additional: usize) { self.bytes.reserve(additional) } - /// Tries to reserve capacity for at least `additional` more length units - /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid - /// frequent reallocations. After calling `try_reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if + /// Tries to reserve capacity for at least `additional` more bytes to be + /// inserted in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to + /// avoid frequent reallocations. After calling `try_reserve`, capacity will + /// be greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. This method preserves the contents even /// if an error occurs. /// @@ -291,8 +295,8 @@ impl Wtf8Buf { self.bytes.reserve_exact(additional) } - /// Tries to reserve the minimum capacity for exactly `additional` - /// length units in the given `Wtf8Buf`. After calling + /// Tries to reserve the minimum capacity for exactly `additional` more + /// bytes to be inserted in the given `Wtf8Buf`. After calling /// `try_reserve_exact`, capacity will be greater than or equal to /// `self.len() + additional` if it returns `Ok(())`. /// Does nothing if the capacity is already sufficient. @@ -440,22 +444,17 @@ impl Wtf8Buf { /// /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”) pub fn into_string_lossy(mut self) -> String { - // Fast path: If we already have UTF-8, we can return it immediately. - if self.is_known_utf8 { - return unsafe { String::from_utf8_unchecked(self.bytes) }; - } - - let mut pos = 0; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - pos = surrogate_pos + 3; - self.bytes[surrogate_pos..pos] - .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - } - None => return unsafe { String::from_utf8_unchecked(self.bytes) }, + if !self.is_known_utf8 { + let mut pos = 0; + while let Some((surrogate_pos, _)) = self.next_surrogate(pos) { + pos = surrogate_pos + 3; + // Surrogates and the replacement character are all 3 bytes, so + // they can substituted in-place. + self.bytes[surrogate_pos..pos] + .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); } } + unsafe { String::from_utf8_unchecked(self.bytes) } } /// Converts this `Wtf8Buf` into a boxed `Wtf8`. @@ -535,9 +534,9 @@ impl AsInner<[u8]> for Wtf8 { } } -/// Format the slice with double quotes, -/// and surrogates as `\u` followed by four hexadecimal digits. -/// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800] +/// Formats the string in double quotes, with characters escaped according to +/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, +/// where each `x` is a hexadecimal digit. impl fmt::Debug for Wtf8 { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { @@ -562,6 +561,8 @@ impl fmt::Debug for Wtf8 { } } +/// Formats the string with unpaired surrogates substituted with the replacement +/// character, U+FFFD. impl fmt::Display for Wtf8 { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let wtf8_bytes = &self.bytes; @@ -672,9 +673,8 @@ impl Wtf8 { /// /// This only copies the data if necessary (if it contains any surrogate). pub fn to_string_lossy(&self) -> Cow<'_, str> { - let surrogate_pos = match self.next_surrogate(0) { - None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }), - Some((pos, _)) => pos, + let Some((surrogate_pos, _)) = self.next_surrogate(0) else { + return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }); }; let wtf8_bytes = &self.bytes; let mut utf8_bytes = Vec::with_capacity(self.len()); @@ -964,7 +964,7 @@ pub struct Wtf8CodePoints<'a> { bytes: slice::Iter<'a, u8>, } -impl<'a> Iterator for Wtf8CodePoints<'a> { +impl Iterator for Wtf8CodePoints<'_> { type Item = CodePoint; #[inline] @@ -990,7 +990,7 @@ pub struct EncodeWide<'a> { // Copied from libunicode/u_str.rs #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for EncodeWide<'a> { +impl Iterator for EncodeWide<'_> { type Item = u16; #[inline] @@ -1001,7 +1001,7 @@ impl<'a> Iterator for EncodeWide<'a> { return Some(tmp); } - let mut buf = [0; 2]; + let mut buf = [0; MAX_LEN_UTF16]; self.code_points.next().map(|code_point| { let n = encode_utf16_raw(code_point.value, &mut buf).len(); if n == 2 { diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 88b3e9e0ceb..5ab71413586 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -93,11 +93,17 @@ use crate::sys_common::{FromInner, IntoInner}; /// use std::time::{Instant, Duration}; /// /// let now = Instant::now(); -/// let max_seconds = u64::MAX / 1_000_000_000; -/// let duration = Duration::new(max_seconds, 0); +/// let days_per_10_millennia = 365_2425; +/// let solar_seconds_per_day = 60 * 60 * 24; +/// let millenium_in_solar_seconds = 31_556_952_000; +/// assert_eq!(millenium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10); +/// +/// let duration = Duration::new(millenium_in_solar_seconds, 0); /// println!("{:?}", now + duration); /// ``` /// +/// For cross-platform code, you can comfortably use durations of up to around one hundred years. +/// /// # Underlying System calls /// /// The following system calls are [currently] being used by `now()` to find out diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index fbd0dc3ec30..f25dfaab0f1 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -523,19 +523,31 @@ undesirable, simply delete the `pre-push` file from .git/hooks." /// Handles editor-specific setup differences #[derive(Clone, Debug, Eq, PartialEq)] enum EditorKind { - Vscode, - Vim, Emacs, Helix, + Vim, + VsCode, + Zed, } impl EditorKind { + // Used in `./tests.rs`. + #[allow(dead_code)] + pub const ALL: &[EditorKind] = &[ + EditorKind::Emacs, + EditorKind::Helix, + EditorKind::Vim, + EditorKind::VsCode, + EditorKind::Zed, + ]; + fn prompt_user() -> io::Result<Option<EditorKind>> { let prompt_str = "Available editors: -1. vscode -2. vim -3. emacs -4. helix +1. Emacs +2. Helix +3. Vim +4. VS Code +5. Zed Select which editor you would like to set up [default: None]: "; @@ -543,28 +555,41 @@ Select which editor you would like to set up [default: None]: "; 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), + + let mut modified_input = input.to_lowercase(); + modified_input.retain(|ch| !ch.is_whitespace()); + match modified_input.as_str() { + "1" | "emacs" => return Ok(Some(EditorKind::Emacs)), + "2" | "helix" => return Ok(Some(EditorKind::Helix)), + "3" | "vim" => return Ok(Some(EditorKind::Vim)), + "4" | "vscode" => return Ok(Some(EditorKind::VsCode)), + "5" | "zed" => return Ok(Some(EditorKind::Zed)), + "" | "none" => return Ok(None), _ => { eprintln!("ERROR: unrecognized option '{}'", input.trim()); eprintln!("NOTE: press Ctrl+C to exit"); } - }; + } + + input.clear(); } } /// 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> { + fn hashes(&self) -> &'static [&'static str] { match self { - EditorKind::Vscode | EditorKind::Vim => vec![ + EditorKind::Emacs => &[ + "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", + "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + ], + EditorKind::Helix => &[ + "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", + "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", + ], + EditorKind::Vim | EditorKind::VsCode => &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", @@ -576,12 +601,8 @@ Select which editor you would like to set up [default: None]: "; "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", ], - EditorKind::Emacs => vec![ - "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", - "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", - ], - EditorKind::Helix => { - vec!["2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233"] + EditorKind::Zed => { + &["bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c"] } } } @@ -592,29 +613,31 @@ Select which editor you would like to set up [default: None]: "; 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", + EditorKind::Vim => "coc-settings.json", + EditorKind::VsCode | EditorKind::Zed => "settings.json", }) } 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"), + EditorKind::Vim => PathBuf::from(".vim"), + EditorKind::VsCode => PathBuf::from(".vscode"), + EditorKind::Zed => PathBuf::from(".zed"), } } - fn settings_template(&self) -> &str { + fn settings_template(&self) -> &'static 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"), + EditorKind::Vim | EditorKind::VsCode => { + include_str!("../../../../etc/rust_analyzer_settings.json") + } + EditorKind::Zed => include_str!("../../../../etc/rust_analyzer_zed.json"), } } diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs index f3d4b6aa4db..e8f83ff75e4 100644 --- a/src/bootstrap/src/core/build_steps/setup/tests.rs +++ b/src/bootstrap/src/core/build_steps/setup/tests.rs @@ -5,13 +5,16 @@ use crate::utils::helpers::hex_encode; #[test] fn check_matching_settings_hash() { - let editor = EditorKind::Vscode; - let mut hasher = sha2::Sha256::new(); - hasher.update(&editor.settings_template()); - let hash = hex_encode(hasher.finalize().as_slice()); - assert_eq!( - &hash, - editor.hashes().last().unwrap(), - "Update `EditorKind::hashes()` with the new hash of `src/etc/rust_analyzer_settings.json`" - ); + for editor in EditorKind::ALL { + let mut hasher = sha2::Sha256::new(); + hasher.update(&editor.settings_template()); + let hash = hex_encode(hasher.finalize().as_slice()); + assert_eq!( + &hash, + editor.hashes().last().unwrap(), + "Update `EditorKind::hashes()` with the new hash of `{}` for `EditorKind::{:?}`", + editor.settings_template(), + editor, + ); + } } diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index dbfd6f47dc6..34bf6bb7013 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -6,25 +6,18 @@ pub static CRATES: &[&str] = &[ "annotate-snippets", "anstyle", "basic-toml", - "block-buffer", "bumpalo", - "cfg-if", - "cpufeatures", - "crypto-common", "darling", "darling_core", "derive_builder_core", - "digest", "fluent-bundle", "fluent-langneg", "fluent-syntax", "fnv", - "generic-array", "heck", "ident_case", "intl-memoizer", "intl_pluralrules", - "libc", "log", "memchr", "mime", @@ -32,17 +25,12 @@ pub static CRATES: &[&str] = &[ "minimal-lexical", "nom", "num-conv", - "once_cell", - "pest", - "pest_generator", - "pest_meta", "proc-macro2", "quote", "rinja_parser", "rustc-hash", "self_cell", "serde", - "sha2", "smallvec", "stable_deref_trait", "strsim", @@ -52,15 +40,12 @@ pub static CRATES: &[&str] = &[ "time-core", "tinystr", "type-map", - "typenum", - "ucd-trie", "unic-langid", "unic-langid-impl", "unic-langid-macros", "unicase", "unicode-ident", "unicode-width", - "version_check", "wasm-bindgen-backend", "wasm-bindgen-macro-support", "wasm-bindgen-shared", diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index d2697ac27ab..6658b83efc8 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -236,9 +236,15 @@ args= if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env SCCACHE_BUCKET" args="$args --env SCCACHE_REGION" - args="$args --env AWS_ACCESS_KEY_ID" - args="$args --env AWS_SECRET_ACCESS_KEY" args="$args --env AWS_REGION" + + # Disable S3 authentication for PR builds, because the access keys are missing + if [ "$PR_CI_JOB" != "" ]; then + args="$args --env SCCACHE_S3_NO_CREDENTIALS=1" + else + args="$args --env AWS_ACCESS_KEY_ID" + args="$args --env AWS_SECRET_ACCESS_KEY" + fi else mkdir -p $HOME/.cache/sccache args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache" diff --git a/src/ci/docker/scripts/sccache.sh b/src/ci/docker/scripts/sccache.sh index 6c713e1f861..f66671c64d2 100644 --- a/src/ci/docker/scripts/sccache.sh +++ b/src/ci/docker/scripts/sccache.sh @@ -6,10 +6,10 @@ set -ex case "$(uname -m)" in x86_64) - url="https://ci-mirrors.rust-lang.org/rustc/2021-08-24-sccache-v0.2.15-x86_64-unknown-linux-musl" + url="https://ci-mirrors.rust-lang.org/rustc/2025-01-07-sccache-v0.9.1-x86_64-unknown-linux-musl" ;; aarch64) - url="https://ci-mirrors.rust-lang.org/rustc/2021-08-25-sccache-v0.2.15-aarch64-unknown-linux-musl" + url="https://ci-mirrors.rust-lang.org/rustc/2025-01-07-sccache-v0.9.1-aarch64-unknown-linux-musl" ;; *) echo "unsupported architecture: $(uname -m)" diff --git a/src/ci/run.sh b/src/ci/run.sh index b874f71832d..536754f12bc 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -279,5 +279,5 @@ if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then fi echo "::group::sccache stats" -sccache --show-stats || true +sccache --show-adv-stats || true echo "::endgroup::" diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 91eab2e7a08..c8c501e646a 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -32,6 +32,12 @@ if isWindows && isKnownToBeMingwBuild; then ;; esac + # Stop /msys64/bin from being prepended to PATH by adding the bin directory manually. + # Note that this intentionally uses a Windows style path instead of the msys2 path to + # avoid being auto-translated into `/usr/bin`, which will not have the desired effect. + msys2Path="c:/msys64" + ciCommandAddPath "${msys2Path}/usr/bin" + mingw_dir="mingw${bits}" curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 2c6c3fe1df8..5c041d6cb70 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -154,6 +154,16 @@ You can run `./x setup editor` and select `helix`, which will prompt you to create `languages.toml` with the recommended configuration for Helix. The recommended settings live at [`src/etc/rust_analyzer_helix.toml`]. +### Zed + +Zed comes with built-in LSP and rust-analyzer support. +It can be configured through `.zed/settings.json`, as described +[here](https://zed.dev/docs/configuring-languages). Selecting `zed` +in `./x setup editor` will prompt you to create a `.zed/settings.json` +file which will configure Zed with the recommended configuration. The +recommended `rust-analyzer` settings live +at [`src/etc/rust_analyzer_zed.json`]. + ## Check, check, and check again When doing simple refactoring, it can be useful to run `./x check` @@ -381,4 +391,5 @@ load this completion. [`src/etc/rust_analyzer_settings.json`]: https://github.com/rust-lang/rust/blob/master/src/etc/rust_analyzer_settings.json [`src/etc/rust_analyzer_eglot.el`]: https://github.com/rust-lang/rust/blob/master/src/etc/rust_analyzer_eglot.el [`src/etc/rust_analyzer_helix.toml`]: https://github.com/rust-lang/rust/blob/master/src/etc/rust_analyzer_helix.toml +[`src/etc/rust_analyzer_zed.json`]: https://github.com/rust-lang/rust/blob/master/src/etc/rust_analyzer_zed.json [`src/etc/pre-push.sh`]: https://github.com/rust-lang/rust/blob/master/src/etc/pre-push.sh diff --git a/src/doc/rustc-dev-guide/src/implementing_new_features.md b/src/doc/rustc-dev-guide/src/implementing_new_features.md index 5b67ccd7f4c..fda38ef4fc0 100644 --- a/src/doc/rustc-dev-guide/src/implementing_new_features.md +++ b/src/doc/rustc-dev-guide/src/implementing_new_features.md @@ -167,9 +167,7 @@ a new unstable feature: 1. Prevent usage of the new feature unless the feature gate is set. You can check it in most places in the compiler using the - expression `tcx.features().$feature_name` (or - `sess.features_untracked().$feature_name` if the - tcx is unavailable) + expression `tcx.features().$feature_name()` If the feature gate is not set, you should either maintain the pre-feature behavior or raise an error, depending on diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index b5cd3864620..c4e5c1aac2f 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -301,7 +301,7 @@ target | std | host | notes [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat [`armv7a-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX [`armv7a-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX, hardfloat -`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` +`avr-none` | * | | AVR; requires `-Zbuild-std=core` and `-Ctarget-cpu=...` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) `csky-unknown-linux-gnuabiv2` | ✓ | | C-SKY abiv2 Linux (little endian) @@ -309,10 +309,10 @@ target | std | host | notes [`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3 [`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX) [`i386-apple-ios`](platform-support/apple-ios.md) | ✓ | | 32-bit x86 iOS (Penryn) [^x86_32-floats-return-ABI] -[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI] [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86 (original Pentium) [^x86_32-floats-x87] [`i586-unknown-redox`](platform-support/redox.md) | ✓ | | 32-bit x86 Redox OS (PentiumPro) [^x86_32-floats-x87] [`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI] +[`i686-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI] diff --git a/src/doc/rustc/src/platform-support/avr-none.md b/src/doc/rustc/src/platform-support/avr-none.md new file mode 100644 index 00000000000..9c1836222c1 --- /dev/null +++ b/src/doc/rustc/src/platform-support/avr-none.md @@ -0,0 +1,81 @@ +# `avr-none` + +Series of microcontrollers from Atmel: ATmega8, ATmega328p etc. + +**Tier: 3** + +## Target maintainers + +- [Patryk Wychowaniec](https://github.com/Patryk27) <pwychowaniec@pm.me> + +## Requirements + +This target is only cross-compiled; x86-64 Linux, x86-64 macOS and aarch64 macOS +hosts are confirmed to work, but in principle any machine able to run rustc and +avr-gcc should be good. + +Compiling for this target requires `avr-gcc` installed, because a couple of +intrinsics (like 32-bit multiplication) rely on [`libgcc`](https://github.com/gcc-mirror/gcc/blob/3269a722b7a03613e9c4e2862bc5088c4a17cc11/libgcc/config/avr/lib1funcs.S) +and can't be provided through `compiler-builtins` yet. This is a limitation that +[we hope to lift in the future](https://github.com/rust-lang/compiler-builtins/issues/711). + +You'll also need to setup the `.cargo/config` file - see below for details. + +## Building the target + +Rust comes with AVR support enabled, you don't have to rebuild the compiler. + +## Building Rust programs + +Install `avr-gcc`: + +```console +# Ubuntu: +$ sudo apt-get install gcc-avr + +# Mac: +$ brew tap osx-cross/avr && brew install avr-gcc + +# NixOS (takes a couple of minutes, since it's not provided through Hydra): +$ nix shell nixpkgs#pkgsCross.avr.buildPackages.gcc11 +``` + +... setup `.cargo/config` for your project: + +```toml +[build] +target = "avr-none" +rustflags = ["-C", "target-cpu=atmega328p"] + +[unstable] +build-std = ["core"] +``` + +... and then simply run: + +```console +$ cargo build --release +``` + +The final binary will be placed into +`./target/avr-none/release/your-project.elf`. + +Note that since AVRs have rather small amounts of registers, ROM and RAM, it's +recommended to always use `--release` to avoid running out of space. + +Also, please note that specifying `-C target-cpu` is required - here's a list of +the possible variants: + +https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32 + +## Testing + +You can use [`simavr`](https://github.com/buserror/simavr) to emulate the +resulting firmware on your machine: + +```console +$ simavr -m atmega328p ./target/avr-none/release/your-project.elf +``` + +Alternatively, if you want to write a couple of actual `#[test]`s, you can use +[`avr-tester`](https://github.com/Patryk27/avr-tester). diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 339741f1472..77e8caaee4c 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -31,7 +31,7 @@ Currently, the following QNX versions and compilation targets are supported: | `aarch64-unknown-nto-qnx710_iosock` | QNX Neutrino 7.1 with io-sock | AArch64 | ? | ✓ | | `x86_64-pc-nto-qnx710_iosock` | QNX Neutrino 7.1 with io-sock | x86_64 | ? | ✓ | | `aarch64-unknown-nto-qnx700` | QNX Neutrino 7.0 | AArch64 | ? | ✓ | -| `i586-pc-nto-qnx700` | QNX Neutrino 7.0 | x86 | | ✓ | +| `i686-pc-nto-qnx700` | QNX Neutrino 7.0 | x86 | | ✓ | On QNX Neutrino 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX Neutrino 7.1 includes the optional network stack `io-sock`. diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index 73264aba858..ba95ab7af6d 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -129,6 +129,8 @@ As of the time of this writing the proposals that are enabled by default (the * `mutable-globals` * `reference-types` * `sign-ext` +* `nontrapping-fptoint` (Rust 1.87.0+, LLVM 20+) +* `bulk-memory` (Rust 1.87.0+, LLVM 20+) If you're compiling WebAssembly code for an engine that does not support a feature in LLVM's default feature set then the feature must be disabled at diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md index bc587686111..bfdb579cd35 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md @@ -10,10 +10,11 @@ This feature is incomplete and not yet intended for general use. This implements experimental, Edition-dependent match ergonomics under consideration for inclusion in Rust. -For more information, see the corresponding typing rules for [Editions 2024 and later]. -On earlier Editions, the current behavior is unspecified. +For more information, see the corresponding typing rules for [Editions 2021 and earlier] and for +[Editions 2024 and later]. For alternative experimental match ergonomics, see the feature [`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md). +[Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQEBAAAAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md index 43de1849a5e..0c90cec0dbd 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md @@ -10,10 +10,11 @@ This feature is incomplete and not yet intended for general use. This implements experimental, Edition-dependent match ergonomics under consideration for inclusion in Rust. -For more information, see the corresponding typing rules for [Editions 2024 and later]. -On earlier Editions, the current behavior is unspecified. +For more information, see the corresponding typing rules for [Editions 2021 and earlier] and for +[Editions 2024 and later]. For alternative experimental match ergonomics, see the feature [`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md). +[Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json new file mode 100644 index 00000000000..469ea050621 --- /dev/null +++ b/src/etc/rust_analyzer_zed.json @@ -0,0 +1,52 @@ +{ + "lsp": { + "rust-analyzer": { + "initialization_options": { + "cargo": { + "buildScripts": { + "enable": true, + "invocationLocation": "root", + "invocationStrategy": "once", + "overrideCommand": ["python3", "x.py", "check", "--json-output"] + }, + "extraEnv": { + "RUSTC_BOOTSTRAP": "1" + }, + "sysrootSrc": "./library" + }, + "check": { + "invocationLocation": "root", + "invocationStrategy": "once", + "overrideCommand": ["python3", "x.py", "check", "--json-output"] + }, + "linkedProjects": [ + "Cargo.toml", + "library/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" + ], + "procMacro": { + "enable": true, + "server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + }, + "rustc": { + "source": "./Cargo.toml" + }, + "rustfmt": { + "overrideCommand": [ + "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", + "--edition=2021" + ] + }, + "server": { + "extraEnv": { + "RUSTUP_TOOLCHAIN": "nightly" + } + } + } + } + } +} diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index c593cdcbcd2..c07cc4dc347 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -13,7 +13,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" -minifier = { version = "0.3.4", default-features = false } +minifier = { version = "0.3.5", default-features = false } pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 92ef3ab7a1d..dcc5fd12d81 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1150,9 +1150,9 @@ fn clean_args_from_types_and_body_id<'tcx>( Arguments { values: types .iter() - .enumerate() - .map(|(i, ty)| Argument { - name: name_from_pat(body.params[i].pat), + .zip(body.params) + .map(|(ty, param)| Argument { + name: name_from_pat(param.pat), type_: clean_ty(ty, cx), is_const: false, }) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 6b1d1a2fcdd..34656b26ce2 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,5 +1,5 @@ use std::assert_matches::debug_assert_matches; -use std::fmt::Write as _; +use std::fmt::{self, Display, Write as _}; use std::mem; use std::sync::LazyLock as Lazy; @@ -24,6 +24,7 @@ use crate::clean::{ clean_middle_ty, inline, }; use crate::core::DocContext; +use crate::display::Joined as _; #[cfg(test)] mod tests; @@ -250,16 +251,20 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String { hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(), }; - let mut s = String::new(); - for (i, seg) in segments.iter().enumerate() { - if i > 0 { - s.push_str("::"); - } - if seg.ident.name != kw::PathRoot { - s.push_str(seg.ident.as_str()); - } - } - s + fmt::from_fn(|f| { + segments + .iter() + .map(|seg| { + fmt::from_fn(|f| { + if seg.ident.name != kw::PathRoot { + write!(f, "{}", seg.ident)?; + } + Ok(()) + }) + }) + .joined("::", f) + }) + .to_string() } pub(crate) fn build_deref_target_impls( @@ -299,35 +304,49 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { Symbol::intern(&match p.kind { // FIXME(never_patterns): does this make sense? - PatKind::Wild | PatKind::Err(_) | PatKind::Never | PatKind::Struct(..) => { + PatKind::Wild + | PatKind::Err(_) + | PatKind::Never + | PatKind::Struct(..) + | PatKind::Range(..) => { return kw::Underscore; } PatKind::Binding(_, _, ident, _) => return ident.name, + PatKind::Box(p) | PatKind::Ref(p, _) | PatKind::Guard(p, _) => return name_from_pat(p), PatKind::TupleStruct(ref p, ..) | PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p), PatKind::Or(pats) => { - pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ") + fmt::from_fn(|f| pats.iter().map(|p| name_from_pat(p)).joined(" | ", f)).to_string() + } + PatKind::Tuple(elts, _) => { + format!("({})", fmt::from_fn(|f| elts.iter().map(|p| name_from_pat(p)).joined(", ", f))) } - PatKind::Tuple(elts, _) => format!( - "({})", - elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ") - ), - PatKind::Box(p) => return name_from_pat(p), PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)), - PatKind::Ref(p, _) => return name_from_pat(p), PatKind::Expr(..) => { warn!( "tried to get argument name from PatKind::Expr, which is silly in function arguments" ); return Symbol::intern("()"); } - PatKind::Guard(p, _) => return name_from_pat(p), - PatKind::Range(..) => return kw::Underscore, - PatKind::Slice(begin, ref mid, end) => { - let begin = begin.iter().map(|p| name_from_pat(p).to_string()); - let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(p))).into_iter(); - let end = end.iter().map(|p| name_from_pat(p).to_string()); - format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", ")) + PatKind::Slice(begin, mid, end) => { + fn print_pat<'a>(pat: &'a Pat<'a>, wild: bool) -> impl Display + 'a { + fmt::from_fn(move |f| { + if wild { + f.write_str("..")?; + } + name_from_pat(pat).fmt(f) + }) + } + + format!( + "[{}]", + fmt::from_fn(|f| { + let begin = begin.iter().map(|p| print_pat(p, false)); + let mid = mid.map(|p| print_pat(p, true)); + let end = end.iter().map(|p| print_pat(p, false)); + begin.chain(mid).chain(end).joined(", ", f) + }) + ) } }) } diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d89caabefe3..4792bc525a5 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -1,6 +1,7 @@ //! Logic for transforming the raw code given by the user into something actually //! runnable, e.g. by adding a `main` function if it doesn't already exist. +use std::fmt::{self, Write as _}; use std::io; use std::sync::Arc; @@ -17,6 +18,7 @@ use rustc_span::symbol::sym; use tracing::debug; use super::GlobalTestOptions; +use crate::display::Joined as _; use crate::html::markdown::LangString; /// This struct contains information about the doctest itself which is then used to generate @@ -232,13 +234,15 @@ impl DocTestBuilder { // add extra 4 spaces for each line to offset the code block if opts.insert_indent_space { - prog.push_str( - &everything_else + write!( + prog, + "{}", + fmt::from_fn(|f| everything_else .lines() - .map(|line| format!(" {}", line)) - .collect::<Vec<String>>() - .join("\n"), - ); + .map(|line| fmt::from_fn(move |f| write!(f, " {line}"))) + .joined("\n", f)) + ) + .unwrap(); } else { prog.push_str(everything_else); }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d2d7415261b..f3201147039 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2,7 +2,6 @@ use std::cmp::Ordering; use std::fmt; use std::fmt::Display; -use itertools::Itertools; use rinja::Template; use rustc_abi::VariantIdx; use rustc_data_structures::captures::Captures; @@ -514,11 +513,7 @@ fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[cl class = myitem.type_(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), - title = [myitem.type_().to_string(), full_path(cx, myitem)] - .iter() - .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None }) - .collect::<Vec<_>>() - .join(" "), + title = format_args!("{} {}", myitem.type_(), full_path(cx, myitem)), ), ); } @@ -915,7 +910,7 @@ fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra w, format_args!( "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>", - list.iter().join("`, `") + fmt::from_fn(|f| list.iter().joined("`, `", f)) ), ); } @@ -1168,17 +1163,18 @@ fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra js_src_path.extend(cx.current.iter().copied()); js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap())); } - let extern_crates = extern_crates - .into_iter() - .map(|cnum| tcx.crate_name(cnum).to_string()) - .collect::<Vec<_>>() - .join(","); - let (extern_before, extern_after) = - if extern_crates.is_empty() { ("", "") } else { (" data-ignore-extern-crates=\"", "\"") }; + let extern_crates = fmt::from_fn(|f| { + if !extern_crates.is_empty() { + f.write_str(" data-ignore-extern-crates=\"")?; + extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?; + f.write_str("\"")?; + } + Ok(()) + }); write_str( w, format_args!( - "<script src=\"{src}\"{extern_before}{extern_crates}{extern_after} async></script>", + "<script src=\"{src}\"{extern_crates} async></script>", src = js_src_path.finish() ), ); @@ -1400,7 +1396,7 @@ fn item_type_alias(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean .collect(); js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied()); js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap())); - let self_path = self_fqp.iter().map(Symbol::as_str).collect::<Vec<&str>>().join("::"); + let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f)); write_str( w, format_args!( diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 50c09b98db4..64dbaf9083e 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::cmp::Ordering; use rinja::Template; use rustc_data_structures::fx::FxHashSet; @@ -12,6 +13,7 @@ use crate::clean; use crate::formats::Impl; use crate::formats::item_type::ItemType; use crate::html::markdown::{IdMap, MarkdownWithToc}; +use crate::html::render::print_item::compare_names; #[derive(Clone, Copy)] pub(crate) enum ModuleLike { @@ -77,7 +79,7 @@ impl<'a> LinkBlock<'a> { } /// A link to an item. Content should not be escaped. -#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone)] +#[derive(Ord, PartialEq, Eq, Hash, Clone)] pub(crate) struct Link<'a> { /// The content for the anchor tag and title attr name: Cow<'a, str>, @@ -89,6 +91,20 @@ pub(crate) struct Link<'a> { children: Vec<Link<'a>>, } +impl PartialOrd for Link<'_> { + fn partial_cmp(&self, other: &Link<'_>) -> Option<Ordering> { + match compare_names(&self.name, &other.name) { + Ordering::Equal => (), + result => return Some(result), + } + (&self.name_html, &self.href, &self.children).partial_cmp(&( + &other.name_html, + &other.href, + &other.children, + )) + } +} + impl<'a> Link<'a> { pub fn new(href: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> Self { Self { href: href.into(), name: name.into(), children: vec![], name_html: None } diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 3cb47d8ef91..960b9aa032b 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -94,7 +94,6 @@ impl Finiteness { } impl From<bool> for Finiteness { - #[must_use] fn from(b: bool) -> Self { if b { Infinite } else { Finite } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 4f707e34abf..dd149c4a29b 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -351,21 +351,18 @@ pub enum FullInt { } impl PartialEq for FullInt { - #[must_use] fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal } } impl PartialOrd for FullInt { - #[must_use] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } impl Ord for FullInt { - #[must_use] fn cmp(&self, other: &Self) -> Ordering { use FullInt::{S, U}; diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 55292c46bba..c65f10a52bd 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -465,7 +465,10 @@ fn profiler_runtime() { #[test] fn asm_support() { let asms = [ + #[cfg(bootstrap)] ("avr-unknown-gnu-atmega328", false), + #[cfg(not(bootstrap))] + ("avr-none", false), ("i686-unknown-netbsd", true), ("riscv32gc-unknown-linux-gnu", true), ("riscv64imac-unknown-none-elf", true), diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index f4dac6e947e..54fe7f6eb5a 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -2,6 +2,7 @@ name = "error_index_generator" version = "0.0.0" edition = "2021" +workspace = "../rustbook" [dependencies] mdbook = { version = "0.4", default-features = false, features = ["search"] } diff --git a/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs b/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs index fdbf6171c53..608c6605304 100644 --- a/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs +++ b/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs @@ -27,6 +27,10 @@ pub struct Args { #[arg(long)] target_cpu: Option<String>, + /// The target features + #[arg(long)] + target_feature: Option<String>, + /// Write output to the filename #[arg(short, long)] output: PathBuf, @@ -49,7 +53,7 @@ fn main() -> anyhow::Result<()> { let args = Args::parse(); - let mut linker = Session::new(args.target, args.target_cpu, args.output); + let mut linker = Session::new(args.target, args.target_cpu, args.target_feature, args.output); linker.add_exported_symbols(args.export_symbol); diff --git a/src/tools/llvm-bitcode-linker/src/linker.rs b/src/tools/llvm-bitcode-linker/src/linker.rs index 9f579d10094..dafd847e768 100644 --- a/src/tools/llvm-bitcode-linker/src/linker.rs +++ b/src/tools/llvm-bitcode-linker/src/linker.rs @@ -8,6 +8,7 @@ use crate::{Optimization, Target}; pub struct Session { target: Target, cpu: Option<String>, + feature: Option<String>, symbols: Vec<String>, /// A file that `llvm-link` supports, like a bitcode file or an archive. @@ -21,7 +22,12 @@ pub struct Session { } impl Session { - pub fn new(target: crate::Target, cpu: Option<String>, out_path: PathBuf) -> Self { + pub fn new( + target: crate::Target, + cpu: Option<String>, + feature: Option<String>, + out_path: PathBuf, + ) -> Self { let link_path = out_path.with_extension("o"); let opt_path = out_path.with_extension("optimized.o"); let sym_path = out_path.with_extension("symbols.txt"); @@ -29,6 +35,7 @@ impl Session { Session { target, cpu, + feature, symbols: Vec::new(), files: Vec::new(), link_path, @@ -134,6 +141,10 @@ impl Session { lcc_command.arg("--mcpu").arg(mcpu); } + if let Some(mattr) = &self.feature { + lcc_command.arg(&format!("--mattr={}", mattr)); + } + let lcc_output = lcc_command .arg(&self.opt_path) .arg("-o").arg(&self.out_path) diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index 782303d5f3f..80dd2f39b42 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -1,6 +1,8 @@ thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: unsafe precondition(s) violated: ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap + +This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread caused non-unwinding panic. aborting. diff --git a/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.rs b/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.rs new file mode 100644 index 00000000000..7de4aef422a --- /dev/null +++ b/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.rs @@ -0,0 +1,30 @@ +// Test that transmuting from `&dyn Trait<fn(&'static ())>` to `&dyn Trait<for<'a> fn(&'a ())>` is UB. +// +// The vtable of `() as Trait<fn(&'static ())>` and `() as Trait<for<'a> fn(&'a ())>` can have +// different entries and, because in the former the entry for `foo` is vacant, this test will +// segfault at runtime. + +trait Trait<U> { + fn foo(&self) + where + U: HigherRanked, + { + } +} +impl<T, U> Trait<U> for T {} + +trait HigherRanked {} +impl HigherRanked for for<'a> fn(&'a ()) {} + +// 2nd candidate is required so that selecting `(): Trait<fn(&'static ())>` will +// evaluate the candidates and fail the leak check instead of returning the +// only applicable candidate. +trait Unsatisfied {} +impl<T: Unsatisfied> HigherRanked for T {} + +fn main() { + let x: &dyn Trait<fn(&'static ())> = &(); + let y: &dyn Trait<for<'a> fn(&'a ())> = unsafe { std::mem::transmute(x) }; + //~^ ERROR: wrong trait in wide pointer vtable + y.foo(); +} diff --git a/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr b/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr new file mode 100644 index 00000000000..cfdf279a605 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<for<'a> fn(&'a ())>`, but encountered `Trait<fn(&())>` + --> tests/fail/validity/dyn-transmute-inner-binder.rs:LL:CC + | +LL | let y: &dyn Trait<for<'a> fn(&'a ())> = unsafe { std::mem::transmute(x) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<for<'a> fn(&'a ())>`, but encountered `Trait<fn(&())>` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/validity/dyn-transmute-inner-binder.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 6f8adc09640..875891df233 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -9,6 +9,7 @@ fn main() { drop_principal(); modulo_binder(); modulo_assoc(); + bidirectional_subtyping(); } fn vtable_nop_cast() { @@ -531,3 +532,32 @@ fn modulo_assoc() { (&() as &dyn Trait as &dyn Middle<()>).say_hello(&0); } + +fn bidirectional_subtyping() { + // Test that transmuting between subtypes of dyn traits is fine, even in the + // "wrong direction", i.e. going from a lower-ranked to a higher-ranked dyn trait. + // Note that compared to the `dyn-transmute-inner-binder` test, the `for` is on the + // *outside* here! + + trait Trait<U: ?Sized> {} + impl<T, U: ?Sized> Trait<U> for T {} + + struct Wrapper<T: ?Sized>(T); + + let x: &dyn Trait<fn(&'static ())> = &(); + let _y: &dyn for<'a> Trait<fn(&'a ())> = unsafe { std::mem::transmute(x) }; + + let x: &dyn for<'a> Trait<fn(&'a ())> = &(); + let _y: &dyn Trait<fn(&'static ())> = unsafe { std::mem::transmute(x) }; + + let x: &dyn Trait<dyn Trait<fn(&'static ())>> = &(); + let _y: &dyn for<'a> Trait<dyn Trait<fn(&'a ())>> = unsafe { std::mem::transmute(x) }; + + let x: &dyn for<'a> Trait<dyn Trait<fn(&'a ())>> = &(); + let _y: &dyn Trait<dyn Trait<fn(&'static ())>> = unsafe { std::mem::transmute(x) }; + + // This lowers to a ptr-to-ptr cast (which behaves like a transmute) + // and not an unsizing coercion: + let x: *const dyn for<'a> Trait<&'a ()> = &(); + let _y: *const Wrapper<dyn Trait<&'static ()>> = x as _; +} diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index fd4a20278ad..710ba025830 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -253,6 +253,13 @@ impl Rustc { self } + /// Specify the target CPU. + pub fn target_cpu<S: AsRef<str>>(&mut self, target_cpu: S) -> &mut Self { + let target_cpu = target_cpu.as_ref(); + self.cmd.arg(format!("-Ctarget-cpu={target_cpu}")); + self + } + /// Specify the crate type. pub fn crate_type(&mut self, crate_type: &str) -> &mut Self { self.cmd.arg("--crate-type"); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index b6f7c44c2ae..f5a7b658123 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -194,6 +194,7 @@ fn layout_of_simd_ty( fields, backend_repr: BackendRepr::Vector { element: e_abi, count: e_len }, largest_niche: e_ly.largest_niche, + uninhabited: false, size, align, max_repr_align: None, @@ -297,20 +298,17 @@ pub fn layout_of_ty_query( .checked_mul(count, dl) .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; - let backend_repr = - if count != 0 && matches!(element.backend_repr, BackendRepr::Uninhabited) { - BackendRepr::Uninhabited - } else { - BackendRepr::Memory { sized: true } - }; + let backend_repr = BackendRepr::Memory { sized: true }; let largest_niche = if count != 0 { element.largest_niche } else { None }; + let uninhabited = if count != 0 { element.uninhabited } else { false }; Layout { variants: Variants::Single { index: struct_variant_idx() }, fields: FieldsShape::Array { stride: element.size, count }, backend_repr, largest_niche, + uninhabited, align: element.align, size, max_repr_align: None, @@ -325,6 +323,7 @@ pub fn layout_of_ty_query( fields: FieldsShape::Array { stride: element.size, count: 0 }, backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, + uninhabited: false, align: element.align, size: Size::ZERO, max_repr_align: None, @@ -337,6 +336,7 @@ pub fn layout_of_ty_query( fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, + uninhabited: false, align: dl.i8_align, size: Size::ZERO, max_repr_align: None, diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index b31bf61a6fb..ddcf315a267 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -447,6 +447,13 @@ dependencies = [ ] [[package]] +name = "error_index_generator" +version = "0.0.0" +dependencies = [ + "mdbook", +] + +[[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -867,9 +874,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9da1e54401fe5d45a664c57e112e70f18e8c5a73e268c179305b932ee864574" +checksum = "b07d36d96ffe1b5b16ddf2bc80b3b26bb7a498b2a6591061250bf0af8e8095ad" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 9f9846cdee0..6aec0bec0fa 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +members = ["../error_index_generator"] [package] name = "rustbook" @@ -14,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.44" +version = "0.4.45" default-features = false features = ["search"] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index e8e7dfe0d84..51e58b4e4fc 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -99,7 +99,6 @@ const EXCEPTIONS: ExceptionList = &[ ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) ("foldhash", "Zlib"), // rustc - ("mdbook", "MPL-2.0"), // mdbook ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses) ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde) @@ -667,7 +666,7 @@ pub static CRATES: &[&str] = &[ for extra in expected.difference(&proc_macro_deps) { tidy_error!( bad, - "`{extra}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency", + "`{extra}` is registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency", ); } if *bad != old_bad { diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 39c9a148e9e..1cb47353469 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3619,7 +3619,6 @@ ui/resolve/issue-21221-1.rs ui/resolve/issue-21221-2.rs ui/resolve/issue-21221-3.rs ui/resolve/issue-21221-4.rs -ui/resolve/issue-22692.rs ui/resolve/issue-2330.rs ui/resolve/issue-23305.rs ui/resolve/issue-2356.rs diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs index 776221d3062..b2681934417 100644 --- a/src/tools/tidy/src/target_policy.rs +++ b/src/tools/tidy/src/target_policy.rs @@ -21,6 +21,7 @@ const EXCEPTIONS: &[&str] = &[ "xtensa_esp32s2_espidf", "xtensa_esp32s3_none_elf", "xtensa_esp32s3_espidf", + "i586_pc_nto_qnx700", // Renamed to i686-pc-nto-qnx700, see https://github.com/rust-lang/rust/issues/136495 ]; pub fn check(root_path: &Path, bad: &mut bool) { diff --git a/tests/assembly/asm/avr-modifiers.rs b/tests/assembly/asm/avr-modifiers.rs index 585fdd7b725..124cad9bef6 100644 --- a/tests/assembly/asm/avr-modifiers.rs +++ b/tests/assembly/asm/avr-modifiers.rs @@ -1,6 +1,6 @@ //@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --target avr-unknown-gnu-atmega328 +//@ compile-flags: --target avr-none -C target-cpu=atmega328p //@ needs-llvm-components: avr #![feature(no_core, asm_experimental_arch)] diff --git a/tests/assembly/asm/avr-types.rs b/tests/assembly/asm/avr-types.rs index 25cf3ec3b4b..309405f4d51 100644 --- a/tests/assembly/asm/avr-types.rs +++ b/tests/assembly/asm/avr-types.rs @@ -1,6 +1,6 @@ //@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --target avr-unknown-gnu-atmega328 +//@ compile-flags: --target avr-none -C target-cpu=atmega328p //@ needs-llvm-components: avr #![feature(no_core, asm_experimental_arch)] diff --git a/tests/assembly/closure-inherit-target-feature.rs b/tests/assembly/closure-inherit-target-feature.rs index b629d8769ed..069204bbd34 100644 --- a/tests/assembly/closure-inherit-target-feature.rs +++ b/tests/assembly/closure-inherit-target-feature.rs @@ -8,8 +8,9 @@ use std::arch::x86_64::{__m128, _mm_blend_ps}; +// Use an explicit return pointer to prevent tail call optimization. #[no_mangle] -pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128) -> __m128 { +pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128, ret: *mut __m128) { let f = { // check that _mm_blend_ps is not being inlined into the closure // CHECK-LABEL: {{sse41_blend_nofeature.*closure.*:}} @@ -18,9 +19,9 @@ pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128) -> __m128 { // CHECK-NOT: blendps // CHECK: ret #[inline(never)] - |x, y| _mm_blend_ps(x, y, 0b0101) + |x, y, ret: *mut __m128| unsafe { *ret = _mm_blend_ps(x, y, 0b0101) } }; - f(x, y) + f(x, y, ret); } #[no_mangle] diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index b5c0ee5a107..3e73d2c6eb7 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -216,9 +216,9 @@ //@ revisions: hexagon_unknown_none_elf //@ [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf //@ [hexagon_unknown_none_elf] needs-llvm-components: hexagon -//@ revisions: i586_pc_nto_qnx700 -//@ [i586_pc_nto_qnx700] compile-flags: --target i586-pc-nto-qnx700 -//@ [i586_pc_nto_qnx700] needs-llvm-components: x86 +//@ revisions: i686_pc_nto_qnx700 +//@ [i686_pc_nto_qnx700] compile-flags: --target i686-pc-nto-qnx700 +//@ [i686_pc_nto_qnx700] needs-llvm-components: x86 //@ revisions: i586_unknown_linux_gnu //@ [i586_unknown_linux_gnu] compile-flags: --target i586-unknown-linux-gnu //@ [i586_unknown_linux_gnu] needs-llvm-components: x86 diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs index 1fa4dc821dd..b74d0181c4d 100644 --- a/tests/assembly/targets/targets-pe.rs +++ b/tests/assembly/targets/targets-pe.rs @@ -15,9 +15,9 @@ //@ revisions: arm64ec_pc_windows_msvc //@ [arm64ec_pc_windows_msvc] compile-flags: --target arm64ec-pc-windows-msvc //@ [arm64ec_pc_windows_msvc] needs-llvm-components: aarch64 -//@ revisions: avr_unknown_gnu_atmega328 -//@ [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328 -//@ [avr_unknown_gnu_atmega328] needs-llvm-components: avr +//@ revisions: avr_none +//@ [avr_none] compile-flags: --target avr-none -C target-cpu=atmega328p +//@ [avr_none] needs-llvm-components: avr //@ revisions: bpfeb_unknown_none //@ [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none //@ [bpfeb_unknown_none] needs-llvm-components: bpf diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs index ad760627b3a..2c39c830684 100644 --- a/tests/assembly/x86-return-float.rs +++ b/tests/assembly/x86-return-float.rs @@ -33,19 +33,18 @@ use minicore::*; // CHECK-LABEL: return_f32: #[no_mangle] pub fn return_f32(x: f32) -> f32 { - // CHECK: movl {{.*}}(%ebp), %eax - // CHECK-NOT: ax - // CHECK: retl + // CHECK: movss {{.*}}(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // CHECK-NEXT: retl x } // CHECK-LABEL: return_f64: #[no_mangle] pub fn return_f64(x: f64) -> f64 { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL:.*]] - // CHECK-NEXT: movsd %[[VAL]], (%[[PTR]]) - // CHECK: retl + // CHECK: movsd {{.*}}(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // CHECK-NEXT: retl x } @@ -157,7 +156,7 @@ pub unsafe fn call_f32(x: &mut f32) { } // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] // CHECK: calll {{()|_}}get_f32 - // CHECK-NEXT: movl %eax, (%[[PTR]]) + // CHECK-NEXT: movss %xmm0, (%[[PTR]]) *x = get_f32(); } @@ -169,8 +168,7 @@ pub unsafe fn call_f64(x: &mut f64) { } // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] // CHECK: calll {{()|_}}get_f64 - // CHECK: movsd {{.*}}(%{{ebp|esp}}), %[[VAL:.*]] - // CHECK-NEXT: movsd %[[VAL:.*]], (%[[PTR]]) + // CHECK-NEXT: movlps %xmm0, (%[[PTR]]) *x = get_f64(); } @@ -315,25 +313,21 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) { #[no_mangle] pub fn return_f16(x: f16) -> f16 { // CHECK: pushl %ebp - // CHECK: movl %esp, %ebp - // CHECK: movzwl 8(%ebp), %eax - // CHECK: popl %ebp - // CHECK: retl + // CHECK-NEXT: movl %esp, %ebp + // CHECK-NEXT: pinsrw $0, 8(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // CHECK-NEXT: retl x } // CHECK-LABEL: return_f128: #[no_mangle] pub fn return_f128(x: f128) -> f128 { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]] - // CHECK-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]]) - // CHECK-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]]) - // CHECK-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]]) - // CHECK-NEXT: movl %[[VAL1:.*]] (%[[PTR]]) - // CHECK: retl + // CHECK: pushl %ebp + // CHECK-NEXT: movl %esp, %ebp + // linux-NEXT: movaps 8(%ebp), %xmm0 + // win-NEXT: movups 8(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // CHECK-NEXT: retl x } diff --git a/tests/assembly/x86_64-windows-i128-abi.rs b/tests/assembly/x86_64-windows-i128-abi.rs new file mode 100644 index 00000000000..d2aefb7daa6 --- /dev/null +++ b/tests/assembly/x86_64-windows-i128-abi.rs @@ -0,0 +1,26 @@ +//@ assembly-output: emit-asm +//@ add-core-stubs +//@ revisions: msvc softfloat +//@ compile-flags: -Copt-level=3 +//@[msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[msvc] needs-llvm-components: x86 +//@[softfloat] compile-flags: --target x86_64-unknown-uefi +//@[softfloat] needs-llvm-components: x86 + +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: ret_i128 +// Hardfloat targets return via xmm0, softfloat targets via rax and rdx. +// msvc: movaps {{.*}}, %xmm0 +// softfloat: movq (%[[INPUT:.*]]), %rax +// softfloat-NEXT: movq 8(%[[INPUT]]), %rdx +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn ret_i128(x: &i128) -> i128 { + *x +} diff --git a/tests/codegen/abi-x86-sse.rs b/tests/codegen/abi-x86-sse.rs new file mode 100644 index 00000000000..837bf6134b0 --- /dev/null +++ b/tests/codegen/abi-x86-sse.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -Z merge-functions=disabled + +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 + +//@ revisions: x86-32 +//@[x86-32] compile-flags: --target i686-unknown-linux-gnu +//@[x86-32] needs-llvm-components: x86 + +//@ revisions: x86-32-nosse +//@[x86-32-nosse] compile-flags: --target i586-unknown-linux-gnu +//@[x86-32-nosse] needs-llvm-components: x86 + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +// Ensure this type is passed without ptr indirection on targets that +// require SSE2. +#[repr(simd)] +pub struct Sse([f32; 4]); + +// x86-64: <4 x float> @sse_id(<4 x float> {{[^,]*}}) +// x86-32: <4 x float> @sse_id(<4 x float> {{[^,]*}}) +// x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) +#[no_mangle] +pub fn sse_id(x: Sse) -> Sse { + x +} diff --git a/tests/codegen/asm/avr-clobbers.rs b/tests/codegen/asm/avr-clobbers.rs index 56218cd7bcf..9451127bf04 100644 --- a/tests/codegen/asm/avr-clobbers.rs +++ b/tests/codegen/asm/avr-clobbers.rs @@ -1,6 +1,6 @@ //@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --target avr-unknown-gnu-atmega328 +//@ compile-flags: --target avr-none -C target-cpu=atmega328p //@ needs-llvm-components: avr #![crate_type = "rlib"] diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index ed8acccb1ad..2ec7c86b5f4 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Copt-level=3 --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort +//@ compile-flags: -Copt-level=3 --target=avr-none -C target-cpu=atmega328p --crate-type=rlib -C panic=abort //@ needs-llvm-components: avr // This test validates that function pointers can be stored in global variables diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 562a8e6c9e9..d87bab1172a 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -1,8 +1,11 @@ // 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. // Emscripten aligns f128 to 8 bytes, not 16. -//@ revisions: x86 bit32 bit64 emscripten -//@[x86] only-x86 +//@ revisions: x86-sse x86-nosse bit32 bit64 emscripten +//@[x86-sse] only-x86 +//@[x86-sse] only-rustc_abi-x86-sse2 +//@[x86-nosse] only-x86 +//@[x86-nosse] ignore-rustc_abi-x86-sse2 //@[bit32] ignore-x86 //@[bit32] ignore-emscripten //@[bit32] only-32bit @@ -60,7 +63,8 @@ pub fn f128_le(a: f128, b: f128) -> bool { a <= b } -// x86-LABEL: void @f128_neg({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_neg({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_neg(fp128 // bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_neg( // emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8]) @@ -70,7 +74,8 @@ pub fn f128_neg(a: f128) -> f128 { -a } -// x86-LABEL: void @f128_add({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_add({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_add(fp128 // bit32-LABEL: void @f128_add({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_add( // emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8]) @@ -80,7 +85,8 @@ pub fn f128_add(a: f128, b: f128) -> f128 { a + b } -// x86-LABEL: void @f128_sub({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_sub({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_sub(fp128 // bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_sub( // emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8]) @@ -90,7 +96,8 @@ pub fn f128_sub(a: f128, b: f128) -> f128 { a - b } -// x86-LABEL: void @f128_mul({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_mul({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_mul(fp128 // bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_mul( // emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8]) @@ -100,7 +107,8 @@ pub fn f128_mul(a: f128, b: f128) -> f128 { a * b } -// x86-LABEL: void @f128_div({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_div({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_div(fp128 // bit32-LABEL: void @f128_div({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_div( // emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8]) @@ -110,7 +118,8 @@ pub fn f128_div(a: f128, b: f128) -> f128 { a / b } -// x86-LABEL: void @f128_rem({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_rem({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_rem(fp128 // bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_rem( // emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8]) @@ -162,7 +171,8 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) { /* float to float conversions */ -// x86-LABEL: i16 @f128_as_f16( +// x86-sse-LABEL: <2 x i8> @f128_as_f16( +// x86-nosse-LABEL: i16 @f128_as_f16( // bits32-LABEL: half @f128_as_f16( // bits64-LABEL: half @f128_as_f16( #[no_mangle] @@ -171,7 +181,8 @@ pub fn f128_as_f16(a: f128) -> f16 { a as f16 } -// x86-LABEL: i32 @f128_as_f32( +// x86-sse-LABEL: <4 x i8> @f128_as_f32( +// x86-nosse-LABEL: i32 @f128_as_f32( // bit32-LABEL: float @f128_as_f32( // bit64-LABEL: float @f128_as_f32( // emscripten-LABEL: float @f128_as_f32( @@ -181,7 +192,8 @@ pub fn f128_as_f32(a: f128) -> f32 { a as f32 } -// x86-LABEL: void @f128_as_f64( +// x86-sse-LABEL: <8 x i8> @f128_as_f64( +// x86-nosse-LABEL: void @f128_as_f64({{.*}}sret([8 x i8]) // bit32-LABEL: double @f128_as_f64( // bit64-LABEL: double @f128_as_f64( // emscripten-LABEL: double @f128_as_f64( @@ -191,7 +203,8 @@ pub fn f128_as_f64(a: f128) -> f64 { a as f64 } -// x86-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_as_self( +// x86-nosse-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_as_self( // emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) @@ -204,7 +217,8 @@ pub fn f128_as_self(a: f128) -> f128 { a as f128 } -// x86-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f16_as_f128( +// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f16_as_f128( // emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) @@ -214,7 +228,8 @@ pub fn f16_as_f128(a: f16) -> f128 { a as f128 } -// x86-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f32_as_f128( +// x86-nosse-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f32_as_f128( // emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) @@ -224,7 +239,8 @@ pub fn f32_as_f128(a: f32) -> f128 { a as f128 } -// x86-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f64_as_f128( +// x86-nosse-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f64_as_f128( // emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) @@ -263,7 +279,8 @@ pub fn f128_as_u64(a: f128) -> u64 { a as u64 } -// x86-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) // bit64-LABEL: i128 @f128_as_u128( // emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) @@ -300,7 +317,8 @@ pub fn f128_as_i64(a: f128) -> i64 { a as i64 } -// x86-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) // bit64-LABEL: i128 @f128_as_i128( // emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) @@ -312,7 +330,8 @@ pub fn f128_as_i128(a: f128) -> i128 { /* int to float conversions */ -// x86-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @u8_as_f128( +// x86-nosse-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u8_as_f128( // emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) @@ -322,7 +341,8 @@ pub fn u8_as_f128(a: u8) -> f128 { a as f128 } -// x86-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @u16_as_f128( +// x86-nosse-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u16_as_f128( // emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) @@ -332,7 +352,8 @@ pub fn u16_as_f128(a: u16) -> f128 { a as f128 } -// x86-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @u32_as_f128( +// x86-nosse-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u32_as_f128( // emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) @@ -342,7 +363,8 @@ pub fn u32_as_f128(a: u32) -> f128 { a as f128 } -// x86-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @u64_as_f128( +// x86-nosse-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u64_as_f128( // emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) @@ -352,7 +374,8 @@ pub fn u64_as_f128(a: u64) -> f128 { a as f128 } -// x86-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @u128_as_f128( +// x86-nosse-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u128_as_f128( // emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) @@ -362,7 +385,8 @@ pub fn u128_as_f128(a: u128) -> f128 { a as f128 } -// x86-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @i8_as_f128( +// x86-nosse-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i8_as_f128( // emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) @@ -372,7 +396,8 @@ pub fn i8_as_f128(a: i8) -> f128 { a as f128 } -// x86-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @i16_as_f128( +// x86-nosse-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i16_as_f128( // emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) @@ -382,7 +407,8 @@ pub fn i16_as_f128(a: i16) -> f128 { a as f128 } -// x86-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @i32_as_f128( +// x86-nosse-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i32_as_f128( // emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) @@ -392,7 +418,8 @@ pub fn i32_as_f128(a: i32) -> f128 { a as f128 } -// x86-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @i64_as_f128( +// x86-nosse-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i64_as_f128( // emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) @@ -402,7 +429,8 @@ pub fn i64_as_f128(a: i64) -> f128 { a as f128 } -// x86-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @i128_as_f128( +// x86-nosse-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i128_as_f128( // emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs index 5c3a5893b9d..0c40606ad8a 100644 --- a/tests/codegen/float/f16.rs +++ b/tests/codegen/float/f16.rs @@ -1,7 +1,10 @@ // 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: x86 bit32 bit64 -//@[x86] only-x86 +//@ revisions: x86-sse x86-nosse bit32 bit64 +//@[x86-sse] only-x86 +//@[x86-sse] only-rustc_abi-x86-sse2 +//@[x86-nosse] only-x86 +//@[x86-nosse] ignore-rustc_abi-x86-sse2 //@[bit32] ignore-x86 //@[bit32] only-32bit //@[bit64] ignore-x86 @@ -59,8 +62,10 @@ pub fn f16_le(a: f16, b: f16) -> bool { } // This is where we check the argument and return ABI for f16. -// other-LABEL: half @f16_neg(half -// x86-LABEL: i16 @f16_neg(half +// bit32-LABEL: half @f16_neg(half +// bit64-LABEL: half @f16_neg(half +// x86-sse-LABEL: <2 x i8> @f16_neg(half +// x86-nosse-LABEL: i16 @f16_neg(half #[no_mangle] pub fn f16_neg(a: f16) -> f16 { // CHECK: fneg half %{{.+}} @@ -144,17 +149,23 @@ pub fn f16_rem_assign(a: &mut f16, b: f16) { /* float to float conversions */ -// other-LABEL: half @f16_as_self( -// x86-LABEL: i16 @f16_as_self( +// bit32-LABEL: half @f16_as_self( +// bit64-LABEL: half @f16_as_self( +// x86-sse-LABEL: <2 x i8> @f16_as_self( +// x86-nosse-LABEL: i16 @f16_as_self( #[no_mangle] pub fn f16_as_self(a: f16) -> f16 { - // other-CHECK: ret half %{{.+}} - // x86-CHECK: bitcast half - // x86-CHECK: ret i16 + // bit32-CHECK: ret half %{{.+}} + // bit64-CHECK: ret half %{{.+}} + // x86-sse-CHECK: bitcast half + // x86-nosse-CHECK: bitcast half + // x86-sse-CHECK: ret i16 + // x86-nosse-CHECK: ret i16 a as f16 } -// x86-LABEL: i32 @f16_as_f32( +// x86-sse-LABEL: <4 x i8> @f16_as_f32( +// x86-nosse-LABEL: i32 @f16_as_f32( // bit32-LABEL: float @f16_as_f32( // bit64-LABEL: float @f16_as_f32( #[no_mangle] @@ -163,7 +174,8 @@ pub fn f16_as_f32(a: f16) -> f32 { a as f32 } -// x86-LABEL: void @f16_as_f64( +// x86-sse-LABEL: <8 x i8> @f16_as_f64( +// x86-nosse-LABEL: void @f16_as_f64({{.*}}sret([8 x i8]) // bit32-LABEL: double @f16_as_f64( // bit64-LABEL: double @f16_as_f64( #[no_mangle] @@ -172,7 +184,8 @@ pub fn f16_as_f64(a: f16) -> f64 { a as f64 } -// x86-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f16_as_f128( +// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f16_as_f128( #[no_mangle] @@ -231,7 +244,8 @@ pub fn f16_as_u64(a: f16) -> u64 { a as u64 } -// x86-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) // bit64-LABEL: i128 @f16_as_u128( #[no_mangle] @@ -267,7 +281,8 @@ pub fn f16_as_i64(a: f16) -> i64 { a as i64 } -// x86-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) +// x86-sse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) // bit64-LABEL: i128 @f16_as_i128( #[no_mangle] diff --git a/tests/codegen/i128-x86-callconv.rs b/tests/codegen/i128-x86-callconv.rs index 9a9c9002fc0..41c30c09c1a 100644 --- a/tests/codegen/i128-x86-callconv.rs +++ b/tests/codegen/i128-x86-callconv.rs @@ -4,13 +4,18 @@ //@ compile-flags: -Copt-level=1 //@ add-core-stubs -//@ revisions: MSVC MINGW +//@ revisions: MSVC MINGW softfloat //@ [MSVC] needs-llvm-components: x86 -//@ [MINGW] needs-llvm-components: x86 //@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc -//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu +// Use `WIN` as a common prefix for MSVC and MINGW but *not* the softfloat test. //@ [MSVC] filecheck-flags: --check-prefix=WIN +//@ [MINGW] needs-llvm-components: x86 +//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu //@ [MINGW] filecheck-flags: --check-prefix=WIN +// The `x86_64-unknown-uefi` target also uses the Windows calling convention, +// but does not have SSE registers available. +//@ [softfloat] needs-llvm-components: x86 +//@ [softfloat] compile-flags: --target x86_64-unknown-uefi #![crate_type = "lib"] #![no_std] @@ -28,24 +33,26 @@ extern "C" { pub extern "C" fn pass(_arg0: u32, arg1: i128) { // CHECK-LABEL: @pass( // i128 is passed indirectly on Windows. It should load the pointer to the stack and pass - // a pointer to that allocation. - // WIN-SAME: %_arg0, ptr{{.*}} %arg1) - // WIN: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16 - // WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 - // WIN: store i128 [[LOADED]], ptr [[PASS]] - // WIN: call void @extern_call + // a pointer to that allocation. The softfloat ABI works the same. + // CHECK-SAME: %_arg0, ptr{{.*}} %arg1) + // CHECK: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16 + // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 + // CHECK: store i128 [[LOADED]], ptr [[PASS]] + // CHECK: call void @extern_call unsafe { extern_call(arg1) }; } // Check that we produce the correct return ABI #[no_mangle] pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 { - // CHECK-LABEL: @ret( + // WIN-LABEL: @ret( // i128 is returned in xmm0 on Windows // FIXME(#134288): This may change for the `-msvc` targets in the future. // WIN-SAME: i32{{.*}} %_arg0, ptr{{.*}} %arg1) // WIN: [[LOADED:%[_0-9]+]] = load <16 x i8>, ptr %arg1 // WIN-NEXT: ret <16 x i8> [[LOADED]] + // The softfloat ABI returns this indirectly. + // softfloat-LABEL: i128 @ret(i32{{.*}} %_arg0, ptr{{.*}} %arg1) arg1 } @@ -57,6 +64,7 @@ pub extern "C" fn forward(dst: *mut i128) { // WIN: [[RETURNED:%[_0-9]+]] = tail call <16 x i8> @extern_ret() // WIN: store <16 x i8> [[RETURNED]], ptr %dst // WIN: ret void + // softfloat: [[RETURNED:%[_0-9]+]] = tail call {{.*}}i128 @extern_ret() unsafe { *dst = extern_ret() }; } @@ -70,10 +78,10 @@ struct RetAggregate { pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate { // CHECK-LABEL: @ret_aggregate( // Aggregates should also be returned indirectly - // WIN-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1) - // WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 - // WIN: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]] - // WIN: store i128 [[LOADED]], ptr [[GEP]] - // WIN: ret void + // CHECK-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1) + // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 + // CHECK: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]] + // CHECK: store i128 [[LOADED]], ptr [[GEP]] + // CHECK: ret void RetAggregate { a: 1, b: arg1 } } diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs index 5ded0e192fa..8ff5cc8ee4f 100644 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ b/tests/codegen/intrinsics/transmute-niched.rs @@ -170,7 +170,7 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { // OPT: call void @llvm.assume(i1 %2) // CHECK-NOT: icmp // CHECK-NOT: assume - // CHECK: %[[R:.+]] = trunc i8 %x to i1 + // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1 // CHECK: ret i1 %[[R]] transmute(x) diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs index fe68f183667..be45e4db90f 100644 --- a/tests/codegen/intrinsics/transmute-x64.rs +++ b/tests/codegen/intrinsics/transmute-x64.rs @@ -6,15 +6,6 @@ use std::arch::x86_64::{__m128, __m128i, __m256i}; use std::mem::transmute; -// CHECK-LABEL: @check_sse_float_to_int( -#[no_mangle] -pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i { - // CHECK-NOT: alloca - // CHECK: %0 = load <4 x float>, ptr %x, align 16 - // CHECK: store <4 x float> %0, ptr %_0, align 16 - transmute(x) -} - // CHECK-LABEL: @check_sse_pair_to_avx( #[no_mangle] pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 5b40a6a12c0..ff297b27065 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -11,6 +11,9 @@ use std::intrinsics::mir::*; use std::intrinsics::{transmute, transmute_unchecked}; use std::mem::MaybeUninit; +// FIXME(LLVM18REMOVED): `trunc nuw` doesn't exist in LLVM 18, so once we no +// longer support it the optional flag checks can be changed to required. + pub enum ZstNever {} #[repr(align(2))] @@ -153,7 +156,7 @@ pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool { // CHECK: %x = alloca [1 x i8], align 1 // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1 - // CHECK: %[[BOOL:.+]] = trunc i8 %[[BYTE]] to i1 + // CHECK: %[[BOOL:.+]] = trunc{{( nuw)?}} i8 %[[BYTE]] to i1 // CHECK: ret i1 %[[BOOL]] transmute(x) } @@ -171,7 +174,7 @@ pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 { #[no_mangle] pub unsafe fn check_byte_to_bool(x: u8) -> bool { // CHECK-NOT: alloca - // CHECK: %[[R:.+]] = trunc i8 %x to i1 + // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1 // CHECK: ret i1 %[[R]] transmute(x) } @@ -284,7 +287,7 @@ pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { #[no_mangle] pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) { // CHECK-NOT: alloca - // CHECK: trunc i8 %x.0 to i1 + // CHECK: trunc{{( nuw)?}} i8 %x.0 to i1 // CHECK: zext i1 %x.1 to i8 transmute(x) } @@ -338,7 +341,7 @@ pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) { // CHECK: store i8 %[[WIDER]] // CHECK: %[[BYTE:.+]] = load i8 - // CHECK: trunc i8 %[[BYTE:.+]] to i1 + // CHECK: trunc{{( nuw)?}} i8 %[[BYTE:.+]] to i1 // CHECK: load i32 transmute(x) } diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs index 4d6895166f1..559e8d947fb 100644 --- a/tests/codegen/issues/issue-32031.rs +++ b/tests/codegen/issues/issue-32031.rs @@ -1,7 +1,7 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 // 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. //@ revisions: x86 other -//@[x86] only-x86 +//@[x86] only-rustc_abi-x86-sse2 //@[other] ignore-x86 #![crate_type = "lib"] @@ -10,7 +10,7 @@ pub struct F32(f32); // other: define{{.*}}float @add_newtype_f32(float %a, float %b) -// x86: define{{.*}}i32 @add_newtype_f32(float %a, float %b) +// x86: define{{.*}}<4 x i8> @add_newtype_f32(float %a, float %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f32(a: F32, b: F32) -> F32 { @@ -21,7 +21,7 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 { pub struct F64(f64); // other: define{{.*}}double @add_newtype_f64(double %a, double %b) -// x86: define{{.*}}void @add_newtype_f64(ptr{{.*}}sret([8 x i8]){{.*}}%_0, double %a, double %b) +// x86: define{{.*}}<8 x i8> @add_newtype_f64(double %a, double %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f64(a: F64, b: F64) -> F64 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 75f989d6e12..0d21d510557 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -1,5 +1,14 @@ // //@ compile-flags: -C no-prepopulate-passes +// LLVM IR isn't very portable and the one tested here depends on the ABI +// which is different between x86 (where we use SSE registers) and others. +// `x86-64` and `x86-32-sse2` are identical, but compiletest does not support +// taking the union of multiple `only` annotations. +//@ revisions: x86-64 x86-32-sse2 other +//@[x86-64] only-x86_64 +//@[x86-32-sse2] only-rustc_abi-x86-sse2 +//@[other] ignore-rustc_abi-x86-sse2 +//@[other] ignore-x86_64 #![crate_type = "lib"] #![allow(non_camel_case_types)] @@ -38,7 +47,9 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> { #[no_mangle] pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // x86-32: ret <4 x float> %[[VAL:.+]] + // x86-64: ret <4 x float> %[[VAL:.+]] + // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } @@ -53,6 +64,8 @@ pub fn build_array_t(x: [f32; 4]) -> T { #[no_mangle] pub fn build_array_transmute_t(x: [f32; 4]) -> T { // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // x86-32: ret <4 x float> %[[VAL:.+]] + // x86-64: ret <4 x float> %[[VAL:.+]] + // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index 1df09c96e6c..a27d5e3af45 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -1,4 +1,5 @@ //@ revisions:opt3 noopt +//@ only-x86_64 //@[opt3] compile-flags: -Copt-level=3 //@[noopt] compile-flags: -Cno-prepopulate-passes @@ -14,14 +15,14 @@ use core::{mem, ptr}; #[repr(simd, packed)] #[derive(Copy, Clone)] -pub struct Simd<T, const N: usize>([T; N]); +pub struct PackedSimd<T, const N: usize>([T; N]); #[repr(simd)] #[derive(Copy, Clone)] pub struct FullSimd<T, const N: usize>([T; N]); // non-powers-of-two have padding and need to be expanded to full vectors -fn load<T, const N: usize>(v: Simd<T, N>) -> FullSimd<T, N> { +fn load<T, const N: usize>(v: PackedSimd<T, N>) -> FullSimd<T, N> { unsafe { let mut tmp = mem::MaybeUninit::<FullSimd<T, N>>::uninit(); ptr::copy_nonoverlapping(&v as *const _, tmp.as_mut_ptr().cast(), 1); @@ -29,18 +30,16 @@ fn load<T, const N: usize>(v: Simd<T, N>) -> FullSimd<T, N> { } } -// CHECK-LABEL: square_packed_full -// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] -// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 +// CHECK-LABEL: define <3 x float> @square_packed_full(ptr{{[a-z_ ]*}} align 4 {{[^,]*}}) #[no_mangle] -pub fn square_packed_full(x: Simd<f32, 3>) -> FullSimd<f32, 3> { - // CHECK-NEXT: start - // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] - // CHECK: load <3 x float> +pub fn square_packed_full(x: PackedSimd<f32, 3>) -> FullSimd<f32, 3> { + // The unoptimized version of this is not very interesting to check + // since `load` does not get inlined. + // opt3-NEXT: start: + // opt3-NEXT: load <3 x float> let x = load(x); - // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> - // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] - // CHECK-NEXT: ret void + // opt3-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // opt3-NEXT: ret <3 x float> [[VREG:%[a-z0-9_]+]] unsafe { intrinsics::simd_mul(x, x) } } @@ -48,7 +47,7 @@ pub fn square_packed_full(x: Simd<f32, 3>) -> FullSimd<f32, 3> { // CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] // CHECK-SAME: ptr{{[a-z_ ]*}} align 4 #[no_mangle] -pub fn square_packed(x: Simd<f32, 3>) -> Simd<f32, 3> { +pub fn square_packed(x: PackedSimd<f32, 3>) -> PackedSimd<f32, 3> { // CHECK-NEXT: start // CHECK-NEXT: load <3 x float> // noopt-NEXT: load <3 x float> diff --git a/tests/codegen/simd/project-to-simd-array-field.rs b/tests/codegen/simd/project-to-simd-array-field.rs new file mode 100644 index 00000000000..29fab640633 --- /dev/null +++ b/tests/codegen/simd/project-to-simd-array-field.rs @@ -0,0 +1,31 @@ +//@compile-flags: -Copt-level=3 + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy)] +#[repr(simd)] +struct i32x4([i32; 4]); + +#[inline(always)] +fn to_array4(a: i32x4) -> [i32; 4] { + a.0 +} + +// CHECK-LABEL: simd_add_self_then_return_array( +// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], +// CHECK-SAME: ptr{{.+}}%a) +#[no_mangle] +pub fn simd_add_self_then_return_array(a: &i32x4) -> [i32; 4] { + // It would be nice to just ban `.0` into simd types, + // but until we do this has to keep working. + // See also <https://github.com/rust-lang/rust/issues/105439> + + // CHECK: %[[T1:.+]] = load <4 x i32>, ptr %a + // CHECK: %[[T2:.+]] = shl <4 x i32> %[[T1]], {{splat \(i32 1\)|<i32 1, i32 1, i32 1, i32 1>}} + // CHECK: store <4 x i32> %[[T2]], ptr %[[RET]] + let a = *a; + let b = unsafe { core::intrinsics::simd::simd_add(a, a) }; + to_array4(b) +} diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs index 98a1b961a64..87907e7ad0a 100644 --- a/tests/codegen/slice-iter-nonnull.rs +++ b/tests/codegen/slice-iter-nonnull.rs @@ -14,11 +14,11 @@ // CHECK-LABEL: @slice_iter_next( #[no_mangle] pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { - // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} - // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK: %[[START:.+]] = load ptr, ptr %it, // CHECK-SAME: !nonnull // CHECK-SAME: !noundef - // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] // CHECK-SAME: !nonnull // CHECK-SAME: !noundef // CHECK: icmp eq ptr %[[START]], %[[END]] diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 43da7c1781e..c080259a917 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -26,7 +26,7 @@ pub fn bool_to_byte(b: bool) -> u8 { } // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) -// CHECK: %_0 = trunc i8 %byte to i1 +// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1 // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs index b27eb73c0cc..9fccaf2252e 100644 --- a/tests/codegen/unchecked_shifts.rs +++ b/tests/codegen/unchecked_shifts.rs @@ -1,4 +1,10 @@ -//@ compile-flags: -Copt-level=3 +//@ revisions: LLVM18 LLVM19PLUS +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@[LLVM18] exact-llvm-major-version: 18 +//@[LLVM19PLUS] min-llvm-version: 19 + +// This runs mir-opts to inline the standard library call, but doesn't run LLVM +// optimizations so it doesn't need to worry about them adding more flags. #![crate_type = "lib"] #![feature(unchecked_shifts)] @@ -17,13 +23,10 @@ pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 { // CHECK-LABEL: @unchecked_shl_unsigned_smaller #[no_mangle] pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16 - // CHECK-DAG: shl i16 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i32 %b to i16 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 + // CHECK: shl i16 %a, %[[TRUNC]] a.unchecked_shl(b) } @@ -31,7 +34,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { #[no_mangle] pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i32 %b to i64 + // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: shl i64 %a, %[[EXT]] a.unchecked_shl(b) } @@ -49,13 +52,10 @@ pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 { // CHECK-LABEL: @unchecked_shr_signed_smaller #[no_mangle] pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16 - // CHECK-DAG: ashr i16 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i32 %b to i16 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 + // CHECK: ashr i16 %a, %[[TRUNC]] a.unchecked_shr(b) } @@ -63,7 +63,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { #[no_mangle] pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i32 %b to i64 + // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: ashr i64 %a, %[[EXT]] a.unchecked_shr(b) } @@ -72,7 +72,7 @@ pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { #[no_mangle] pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128 + // CHECK: %[[EXT:.+]] = zext i8 %b to i128 // CHECK: lshr i128 %a, %[[EXT]] std::intrinsics::unchecked_shr(a, b) } @@ -81,7 +81,7 @@ pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 { #[no_mangle] pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128 + // CHECK: %[[EXT:.+]] = zext i8 %b to i128 // CHECK: shl i128 %a, %[[EXT]] std::intrinsics::unchecked_shl(a, b) } @@ -89,25 +89,19 @@ pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 { // CHECK-LABEL: @unchecked_shl_u8_i128 #[no_mangle] pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8 - // CHECK-DAG: shl i8 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i128 %b to i8 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 + // CHECK: shl i8 %a, %[[TRUNC]] std::intrinsics::unchecked_shl(a, b) } // CHECK-LABEL: @unchecked_shr_i8_u128 #[no_mangle] pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8 - // CHECK-DAG: ashr i8 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i128 %b to i8 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 + // CHECK: ashr i8 %a, %[[TRUNC]] std::intrinsics::unchecked_shr(a, b) } diff --git a/tests/codegen/uninhabited-transparent-return-abi.rs b/tests/codegen/uninhabited-transparent-return-abi.rs new file mode 100644 index 00000000000..6e8b1683163 --- /dev/null +++ b/tests/codegen/uninhabited-transparent-return-abi.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Copt-level=3 + +// See https://github.com/rust-lang/rust/issues/135802 + +#![crate_type = "lib"] + +enum Void {} + +// Should be ABI-compatible with T, but wasn't prior to the PR adding this test. +#[repr(transparent)] +struct NoReturn<T>(T, Void); + +// Returned by invisible reference (in most ABIs) +#[allow(dead_code)] +struct Large(u64, u64, u64); + +extern "Rust" { + fn opaque() -> NoReturn<Large>; + fn opaque_with_arg(rsi: u32) -> NoReturn<Large>; +} + +// CHECK-LABEL: @test_uninhabited_ret_by_ref +#[no_mangle] +pub fn test_uninhabited_ret_by_ref() { + // CHECK: %_1 = alloca [24 x i8], align {{8|4}} + // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_1) + // CHECK-NEXT: call void @opaque(ptr noalias nocapture noundef nonnull sret([24 x i8]) align {{8|4}} dereferenceable(24) %_1) #2 + // CHECK-NEXT: unreachable + unsafe { + opaque(); + } +} + +// CHECK-LABEL: @test_uninhabited_ret_by_ref_with_arg +#[no_mangle] +pub fn test_uninhabited_ret_by_ref_with_arg(rsi: u32) { + // CHECK: %_2 = alloca [24 x i8], align {{8|4}} + // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_2) + // CHECK-NEXT: call void @opaque_with_arg(ptr noalias nocapture noundef nonnull sret([24 x i8]) align {{8|4}} dereferenceable(24) %_2, i32 noundef %rsi) #2 + // CHECK-NEXT: unreachable + unsafe { + opaque_with_arg(rsi); + } +} diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index 92d40d8ac14..28acc4de2f3 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -2,8 +2,11 @@ //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes // 32-bit x86 returns `f32` differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: x86 bit32 bit64 -//@[x86] only-x86 +//@ revisions: x86-sse x86-nosse bit32 bit64 +//@[x86-sse] only-x86 +//@[x86-sse] only-rustc_abi-x86-sse2 +//@[x86-nosse] only-x86 +//@[x86-nosse] ignore-rustc_abi-x86-sse2 //@[bit32] ignore-x86 //@[bit32] only-32bit //@[bit64] ignore-x86 @@ -75,7 +78,8 @@ pub union UnionF32 { a: f32, } -// x86: define {{(dso_local )?}}i32 @test_UnionF32(float %_1) +// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32(float %_1) +// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32(float %_1) // bit32: define {{(dso_local )?}}float @test_UnionF32(float %_1) // bit64: define {{(dso_local )?}}float @test_UnionF32(float %_1) #[no_mangle] @@ -88,7 +92,8 @@ pub union UnionF32F32 { b: f32, } -// x86: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1) +// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32F32(float %_1) +// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1) // bit32: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) // bit64: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) #[no_mangle] @@ -110,7 +115,8 @@ pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { pub union UnionU128 { a: u128, } -// x86: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) +// x86-sse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) +// x86-nosse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) // bit32: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) // bit64: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1) #[no_mangle] @@ -136,4 +142,4 @@ pub union UnionBool { pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } } -// CHECK: %_0 = trunc i8 %b to i1 +// CHECK: %_0 = trunc{{( nuw)?}} i8 %b to i1 diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 3c740d80ea0..3deacbc8e12 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -1,52 +1,57 @@ Function name: <holes::main::MyStruct>::_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 25, 09, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 2b, 09, 00, 1d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 37, 9) to (start + 0, 29) +- Code(Zero) at (prev + 43, 9) to (start + 0, 29) Highest counter ID seen: (none) Function name: holes::main -Raw bytes (44): 0x[01, 01, 00, 08, 01, 08, 01, 06, 11, 01, 0f, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 01, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 12, 01, 05, 05, 00, 12, 01, 07, 09, 00, 11, 01, 09, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 04, 05, 00, 12, 01, 04, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 0c, 0d, 01, 0f, 0e, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 8, 1) to (start + 6, 17) -- Code(Counter(0)) at (prev + 15, 5) to (start + 0, 18) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 18) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 7, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 7, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 6, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 10, 5) to (start + 12, 13) +- Code(Counter(0)) at (prev + 15, 14) to (start + 5, 2) Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 05, 00, 17] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 5) to (start + 0, 23) +- Code(Zero) at (prev + 31, 5) to (start + 0, 23) Highest counter ID seen: (none) Function name: holes::main::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 09, 02, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 18, 9) to (start + 2, 10) +- Code(Zero) at (prev + 24, 9) to (start + 2, 10) Highest counter ID seen: (none) Function name: holes::main::{closure#1} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 3d, 09, 02, 0a] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 4b, 09, 02, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 61, 9) to (start + 2, 10) +- Code(Zero) at (prev + 75, 9) to (start + 2, 10) Highest counter ID seen: (none) diff --git a/tests/coverage/holes.coverage b/tests/coverage/holes.coverage index 6e65435f7e3..1b45c12156a 100644 --- a/tests/coverage/holes.coverage +++ b/tests/coverage/holes.coverage @@ -7,10 +7,16 @@ LL| | LL| 1|fn main() { LL| 1| black_box(()); - LL| 1| - LL| 1| // Splitting this across multiple lines makes it easier to see where the - LL| 1| // coverage mapping regions begin and end. - LL| 1| #[rustfmt::skip] + LL| | + LL| | static MY_STATIC: () = (); + LL| | + LL| 1| black_box(()); + LL| | + LL| | const MY_CONST: () = (); + LL| | + LL| | // Splitting this across multiple lines makes it easier to see where the + LL| | // coverage mapping regions begin and end. + LL| | #[rustfmt::skip] LL| 1| let _closure = LL| | | LL| | _arg: (), @@ -39,6 +45,14 @@ LL| | LL| 1| black_box(()); LL| | + LL| | trait MyTrait {} + LL| | + LL| 1| black_box(()); + LL| | + LL| | impl MyTrait for MyStruct {} + LL| | + LL| 1| black_box(()); + LL| | LL| | macro_rules! _my_macro { LL| | () => {}; LL| | } @@ -64,5 +78,24 @@ LL| | ; LL| | LL| 1| black_box(()); + LL| 1| + LL| 1| // This tests the edge case of a const block nested inside an "anon const", + LL| 1| // such as the length of an array literal. Handling this case requires + LL| 1| // `nested_filter::OnlyBodies` or equivalent. + LL| 1| #[rustfmt::skip] + LL| 1| let _const_block_inside_anon_const = + LL| 1| [ + LL| 1| 0 + LL| 1| ; + LL| 1| 7 + LL| 1| + + LL| 1| const + LL| | { + LL| | 3 + LL| 1| } + LL| 1| ] + LL| 1| ; + LL| 1| + LL| 1| black_box(()); LL| 1|} diff --git a/tests/coverage/holes.rs b/tests/coverage/holes.rs index b3a71e759c8..7f6671772c3 100644 --- a/tests/coverage/holes.rs +++ b/tests/coverage/holes.rs @@ -8,6 +8,12 @@ use core::hint::black_box; fn main() { black_box(()); + static MY_STATIC: () = (); + + black_box(()); + + const MY_CONST: () = (); + // Splitting this across multiple lines makes it easier to see where the // coverage mapping regions begin and end. #[rustfmt::skip] @@ -39,6 +45,14 @@ fn main() { black_box(()); + trait MyTrait {} + + black_box(()); + + impl MyTrait for MyStruct {} + + black_box(()); + macro_rules! _my_macro { () => {}; } @@ -64,4 +78,23 @@ fn main() { ; black_box(()); + + // This tests the edge case of a const block nested inside an "anon const", + // such as the length of an array literal. Handling this case requires + // `nested_filter::OnlyBodies` or equivalent. + #[rustfmt::skip] + let _const_block_inside_anon_const = + [ + 0 + ; + 7 + + + const + { + 3 + } + ] + ; + + black_box(()); } diff --git a/tests/crashes/103899.rs b/tests/crashes/103899.rs deleted file mode 100644 index 39c2d72bd35..00000000000 --- a/tests/crashes/103899.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ known-bug: #103899 - -trait BaseWithAssoc { - type Assoc; -} - -trait WrapperWithAssoc { - type BaseAssoc: BaseWithAssoc; -} - -struct Wrapper<B> { - inner: B, -} - -struct ProjectToBase<T: BaseWithAssoc> { - data_type_h: T::Assoc, -} - -struct DoubleProject<L: WrapperWithAssoc> { - buffer: Wrapper<ProjectToBase<L::BaseAssoc>>, -} - -fn trigger<L: WrapperWithAssoc<BaseAssoc = ()>>() -> DoubleProject<L> { - loop {} -} - -fn main() {} diff --git a/tests/crashes/105299.rs b/tests/crashes/105299.rs deleted file mode 100644 index 8e3aafa47bc..00000000000 --- a/tests/crashes/105299.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ known-bug: #105299 - -pub trait Foo: Clone {} - -pub struct Bar<'a, T: Clone> { - pub cow: std::borrow::Cow<'a, [T]>, - - pub THIS_CAUSES_ICE: (), // #1 -} - -impl<T> Bar<'_, T> -where - T: Clone, - [T]: Foo, -{ - pub fn MOVES_SELF(self) {} // #2 -} - -pub fn main() {} diff --git a/tests/crashes/project-to-simd-array-field.rs b/tests/crashes/project-to-simd-array-field.rs new file mode 100644 index 00000000000..6dc916c41db --- /dev/null +++ b/tests/crashes/project-to-simd-array-field.rs @@ -0,0 +1,33 @@ +//@ known-bug: #137108 +//@compile-flags: -Copt-level=3 + +// If you fix this, put it in the corresponding codegen test, +// not in a UI test like the readme says. + +#![crate_type = "lib"] + +#![feature(repr_simd, core_intrinsics)] + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy)] +#[repr(simd)] +struct i32x3([i32; 3]); + +const _: () = { assert!(size_of::<i32x3>() == 16) }; + +#[inline(always)] +fn to_array3(a: i32x3) -> [i32; 3] { + a.0 +} + +// CHECK-LABEL: simd_add_self_then_return_array_packed( +// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], +// CHECK-SAME: ptr{{.+}}%a) +#[no_mangle] +pub fn simd_add_self_then_return_array_packed(a: i32x3) -> [i32; 3] { + // CHECK: %[[T1:.+]] = load <3 x i32>, ptr %a + // CHECK: %[[T2:.+]] = shl <3 x i32> %[[T1]], <i32 1, i32 1, i32 1> + // CHECK: store <3 x i32> %[[T2]], ptr %[[RET]] + let b = unsafe { core::intrinsics::simd::simd_add(a, a) }; + to_array3(b) +} diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff index 727efe4b0d9..267a4c1cf6b 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff @@ -47,6 +47,7 @@ + Deinit(_8); + copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7); + StorageDead(_4); ++ nop; StorageDead(_2); - _0 = move _1; + StorageLive(_12); @@ -61,6 +62,7 @@ + Deinit(_16); + copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15); + StorageDead(_12); ++ nop; StorageDead(_1); return; } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff index 8d0cd97f786..8e5c403cd7e 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff @@ -47,6 +47,7 @@ + Deinit(_8); + copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7); + StorageDead(_4); ++ nop; StorageDead(_2); - _0 = move _1; + StorageLive(_12); @@ -61,6 +62,7 @@ + Deinit(_16); + copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15); + StorageDead(_12); ++ nop; StorageDead(_1); return; } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff index 6d1e2a72fdb..96c5aadd85f 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff @@ -47,6 +47,7 @@ + Deinit(_8); + copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7); + StorageDead(_4); ++ nop; StorageDead(_2); - _0 = move _1; + StorageLive(_12); @@ -61,6 +62,7 @@ + Deinit(_16); + copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15); + StorageDead(_12); ++ nop; StorageDead(_1); return; } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff index 4b1406d0d62..d20e2e08eaa 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff @@ -47,6 +47,7 @@ + Deinit(_8); + copy_nonoverlapping(dst = copy _9, src = copy _11, count = copy _7); + StorageDead(_4); ++ nop; StorageDead(_2); - _0 = move _1; + StorageLive(_12); @@ -61,6 +62,7 @@ + Deinit(_16); + copy_nonoverlapping(dst = copy _17, src = copy _19, count = copy _15); + StorageDead(_12); ++ nop; StorageDead(_1); return; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index b7a9b4a1fe0..7ef532d222d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -4,28 +4,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::slice::Iter<'_, T>; - let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _21: std::option::Option<(usize, &T)>; - let mut _24: &impl Fn(usize, &T); - let mut _25: (usize, &T); - let _26: (); + let mut _11: std::ptr::NonNull<T>; + let mut _12: *const T; + let mut _13: usize; + let mut _32: std::option::Option<(usize, &T)>; + let mut _35: &impl Fn(usize, &T); + let mut _36: (usize, &T); + let _37: (); scope 1 { - debug iter => _13; - let _22: usize; - let _23: &T; + debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11; + debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _12; + debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; + debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _13; + let _33: usize; + let _34: &T; scope 2 { - debug i => _22; - debug x => _23; + debug i => _33; + debug x => _34; } scope 19 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) { - let mut _14: &mut std::slice::Iter<'_, T>; - let mut _15: std::option::Option<&T>; - let mut _19: (usize, bool); - let mut _20: (usize, &T); + let mut _27: std::option::Option<&T>; + let mut _30: (usize, bool); + let mut _31: (usize, &T); scope 20 { - let _18: usize; + let _29: usize; scope 25 { } } @@ -40,11 +42,59 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 26 (inlined <Option<&T> as Try>::branch) { - let mut _16: isize; - let _17: &T; + let _28: &T; scope 27 { } } + scope 29 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { + let _14: std::ptr::NonNull<T>; + let _16: std::ptr::NonNull<T>; + let mut _19: bool; + let mut _22: std::ptr::NonNull<T>; + let mut _24: usize; + let _26: &T; + scope 30 { + let _15: *const T; + scope 31 { + let _23: usize; + scope 32 { + scope 35 (inlined core::num::<impl usize>::unchecked_sub) { + scope 36 (inlined core::ub_checks::check_language_ub) { + scope 37 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 38 (inlined without_provenance_mut::<T>) { + } + } + scope 33 (inlined std::ptr::const_ptr::<impl *const T>::addr) { + scope 34 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) { + } + } + scope 39 (inlined <NonNull<T> as PartialEq>::eq) { + let mut _17: *mut T; + let mut _18: *mut T; + scope 40 (inlined NonNull::<T>::as_ptr) { + } + scope 41 (inlined NonNull::<T>::as_ptr) { + } + } + scope 42 (inlined NonNull::<T>::add) { + let mut _20: *const T; + let mut _21: *const T; + scope 43 (inlined NonNull::<T>::as_ptr) { + } + } + scope 44 (inlined NonNull::<T>::as_ref::<'_>) { + let _25: *const T; + scope 45 (inlined NonNull::<T>::as_ptr) { + } + scope 46 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { + } + } + } + } + } } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -89,9 +139,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - StorageLive(_11); StorageLive(_3); - StorageLive(_6); StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); @@ -120,86 +168,150 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb3: { - StorageLive(_10); _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_10); StorageDead(_9); StorageDead(_4); - StorageDead(_6); StorageDead(_3); - _12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize }; - StorageDead(_11); + StorageLive(_11); + StorageLive(_12); StorageLive(_13); - _13 = copy _12; + _11 = copy _6; + _12 = copy _10; + _13 = const 0_usize; goto -> bb4; } bb4: { - StorageLive(_21); - StorageLive(_18); - StorageLive(_19); - StorageLive(_15); + StorageLive(_32); + StorageLive(_29); + StorageLive(_30); + StorageLive(_27); StorageLive(_14); - _14 = &mut (_13.0: std::slice::Iter<'_, T>); - _15 = <std::slice::Iter<'_, T> as Iterator>::next(move _14) -> [return: bb5, unwind unreachable]; + StorageLive(_15); + StorageLive(_23); + StorageLive(_24); + StorageLive(_16); + StorageLive(_26); + _14 = copy _11; + _15 = copy _12; + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8]; } bb5: { - StorageDead(_14); - StorageLive(_16); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb11]; + StorageLive(_19); + _16 = copy _15 as std::ptr::NonNull<T> (Transmute); + StorageLive(_17); + _17 = copy _14 as *mut T (Transmute); + StorageLive(_18); + _18 = copy _16 as *mut T (Transmute); + _19 = Eq(move _17, move _18); + StorageDead(_18); + StorageDead(_17); + switchInt(move _19) -> [0: bb6, otherwise: bb7]; } bb6: { - StorageDead(_16); - StorageDead(_15); StorageDead(_19); - StorageDead(_18); + StorageLive(_22); + StorageLive(_21); + StorageLive(_20); + _20 = copy _14 as *const T (Transmute); + _21 = Offset(move _20, const 1_usize); + StorageDead(_20); + _22 = NonNull::<T> { pointer: move _21 }; StorageDead(_21); - StorageDead(_13); - drop(_2) -> [return: bb7, unwind unreachable]; + _11 = move _22; + StorageDead(_22); + goto -> bb13; } bb7: { - return; + StorageDead(_19); + StorageDead(_26); + StorageDead(_16); + StorageDead(_24); + StorageDead(_23); + StorageDead(_15); + StorageDead(_14); + goto -> bb10; } bb8: { - _17 = move ((_15 as Some).0: &T); - StorageDead(_16); - StorageDead(_15); - _18 = copy (_13.1: usize); - _19 = AddWithOverflow(copy (_13.1: usize), const 1_usize); - assert(!move (_19.1: bool), "attempt to compute `{} + {}`, which would overflow", copy (_13.1: usize), const 1_usize) -> [success: bb9, unwind unreachable]; + _23 = copy _15 as usize (Transmute); + switchInt(copy _23) -> [0: bb9, otherwise: bb12]; } bb9: { - (_13.1: usize) = move (_19.0: usize); - StorageLive(_20); - _20 = (copy _18, copy _17); - _21 = Option::<(usize, &T)>::Some(move _20); - StorageDead(_20); - StorageDead(_19); - StorageDead(_18); - _22 = copy (((_21 as Some).0: (usize, &T)).0: usize); - _23 = copy (((_21 as Some).0: (usize, &T)).1: &T); - StorageLive(_24); - _24 = &_2; - StorageLive(_25); - _25 = (copy _22, copy _23); - _26 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _24, move _25) -> [return: bb10, unwind unreachable]; + StorageDead(_26); + StorageDead(_16); + StorageDead(_24); + StorageDead(_23); + StorageDead(_15); + StorageDead(_14); + goto -> bb10; } bb10: { + StorageDead(_27); + StorageDead(_30); + StorageDead(_29); + StorageDead(_32); + StorageDead(_11); + StorageDead(_12); + StorageDead(_13); + drop(_2) -> [return: bb11, unwind unreachable]; + } + + bb11: { + return; + } + + bb12: { + _24 = SubUnchecked(copy _23, const 1_usize); + _12 = copy _24 as *const T (Transmute); + goto -> bb13; + } + + bb13: { + StorageLive(_25); + _25 = copy _14 as *const T (Transmute); + _26 = &(*_25); StorageDead(_25); + _27 = Option::<&T>::Some(copy _26); + StorageDead(_26); + StorageDead(_16); StorageDead(_24); - StorageDead(_21); - goto -> bb4; + StorageDead(_23); + StorageDead(_15); + StorageDead(_14); + _28 = move ((_27 as Some).0: &T); + StorageDead(_27); + _29 = copy _13; + _30 = AddWithOverflow(copy _13, const 1_usize); + assert(!move (_30.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _13, const 1_usize) -> [success: bb14, unwind unreachable]; } - bb11: { - unreachable; + bb14: { + _13 = move (_30.0: usize); + StorageLive(_31); + _31 = (copy _29, copy _28); + _32 = Option::<(usize, &T)>::Some(move _31); + StorageDead(_31); + StorageDead(_30); + StorageDead(_29); + _33 = copy (((_32 as Some).0: (usize, &T)).0: usize); + _34 = copy (((_32 as Some).0: (usize, &T)).1: &T); + StorageLive(_35); + _35 = &_2; + StorageLive(_36); + _36 = (copy _33, copy _34); + _37 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _35, move _36) -> [return: bb15, unwind unreachable]; + } + + bb15: { + StorageDead(_36); + StorageDead(_35); + StorageDead(_32); + goto -> bb4; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index dc13bb23c31..62787f3447c 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -4,19 +4,68 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::slice::Iter<'_, T>; - let mut _12: std::slice::Iter<'_, T>; - let mut _13: &mut std::slice::Iter<'_, T>; - let mut _14: std::option::Option<&T>; - let mut _15: isize; - let mut _17: &impl Fn(&T); - let mut _18: (&T,); - let _19: (); + let mut _11: std::ptr::NonNull<T>; + let mut _12: *const T; + let mut _26: std::option::Option<&T>; + let mut _28: &impl Fn(&T); + let mut _29: (&T,); + let _30: (); scope 1 { - debug iter => _12; - let _16: &T; + debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11; + debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _12; + debug ((iter: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; + let _27: &T; scope 2 { - debug x => _16; + debug x => _27; + } + scope 17 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { + let _13: std::ptr::NonNull<T>; + let _15: std::ptr::NonNull<T>; + let mut _18: bool; + let mut _21: std::ptr::NonNull<T>; + let mut _23: usize; + let _25: &T; + scope 18 { + let _14: *const T; + scope 19 { + let _22: usize; + scope 20 { + scope 23 (inlined core::num::<impl usize>::unchecked_sub) { + scope 24 (inlined core::ub_checks::check_language_ub) { + scope 25 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 26 (inlined without_provenance_mut::<T>) { + } + } + scope 21 (inlined std::ptr::const_ptr::<impl *const T>::addr) { + scope 22 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) { + } + } + scope 27 (inlined <NonNull<T> as PartialEq>::eq) { + let mut _16: *mut T; + let mut _17: *mut T; + scope 28 (inlined NonNull::<T>::as_ptr) { + } + scope 29 (inlined NonNull::<T>::as_ptr) { + } + } + scope 30 (inlined NonNull::<T>::add) { + let mut _19: *const T; + let mut _20: *const T; + scope 31 (inlined NonNull::<T>::as_ptr) { + } + } + scope 32 (inlined NonNull::<T>::as_ref::<'_>) { + let _24: *const T; + scope 33 (inlined NonNull::<T>::as_ptr) { + } + scope 34 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { + } + } + } + } } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -58,7 +107,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb0: { StorageLive(_3); - StorageLive(_6); StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); @@ -87,57 +135,125 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb3: { - StorageLive(_10); _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_10); StorageDead(_9); StorageDead(_4); - StorageDead(_6); StorageDead(_3); + StorageLive(_11); StorageLive(_12); - _12 = copy _11; + _11 = copy _6; + _12 = copy _10; goto -> bb4; } bb4: { + StorageLive(_26); + StorageLive(_13); StorageLive(_14); - _13 = &mut _12; - _14 = <std::slice::Iter<'_, T> as Iterator>::next(move _13) -> [return: bb5, unwind unreachable]; + StorageLive(_22); + StorageLive(_23); + StorageLive(_15); + StorageLive(_25); + _13 = copy _11; + _14 = copy _12; + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8]; } bb5: { - _15 = discriminant(_14); - switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageLive(_18); + _15 = copy _14 as std::ptr::NonNull<T> (Transmute); + StorageLive(_16); + _16 = copy _13 as *mut T (Transmute); + StorageLive(_17); + _17 = copy _15 as *mut T (Transmute); + _18 = Eq(move _16, move _17); + StorageDead(_17); + StorageDead(_16); + switchInt(move _18) -> [0: bb6, otherwise: bb7]; } bb6: { - StorageDead(_14); - StorageDead(_12); - drop(_2) -> [return: bb7, unwind unreachable]; + StorageDead(_18); + StorageLive(_21); + StorageLive(_20); + StorageLive(_19); + _19 = copy _13 as *const T (Transmute); + _20 = Offset(move _19, const 1_usize); + StorageDead(_19); + _21 = NonNull::<T> { pointer: move _20 }; + StorageDead(_20); + _11 = move _21; + StorageDead(_21); + goto -> bb13; } bb7: { - return; + StorageDead(_18); + StorageDead(_25); + StorageDead(_15); + StorageDead(_23); + StorageDead(_22); + StorageDead(_14); + StorageDead(_13); + goto -> bb10; } bb8: { - _16 = copy ((_14 as Some).0: &T); - StorageLive(_17); - _17 = &_2; - StorageLive(_18); - _18 = (copy _16,); - _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind unreachable]; + _22 = copy _14 as usize (Transmute); + switchInt(copy _22) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_18); - StorageDead(_17); + StorageDead(_25); + StorageDead(_15); + StorageDead(_23); + StorageDead(_22); StorageDead(_14); - goto -> bb4; + StorageDead(_13); + goto -> bb10; } bb10: { - unreachable; + StorageDead(_26); + StorageDead(_11); + StorageDead(_12); + drop(_2) -> [return: bb11, unwind unreachable]; + } + + bb11: { + return; + } + + bb12: { + _23 = SubUnchecked(copy _22, const 1_usize); + _12 = copy _23 as *const T (Transmute); + goto -> bb13; + } + + bb13: { + StorageLive(_24); + _24 = copy _13 as *const T (Transmute); + _25 = &(*_24); + StorageDead(_24); + _26 = Option::<&T>::Some(copy _25); + StorageDead(_25); + StorageDead(_15); + StorageDead(_23); + StorageDead(_22); + StorageDead(_14); + StorageDead(_13); + _27 = copy ((_26 as Some).0: &T); + StorageLive(_28); + _28 = &_2; + StorageLive(_29); + _29 = (copy _27,); + _30 = <impl Fn(&T) as Fn<(&T,)>>::call(move _28, move _29) -> [return: bb14, unwind unreachable]; + } + + bb14: { + StorageDead(_29); + StorageDead(_28); + StorageDead(_26); + goto -> bb4; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 3f1e0e0f746..e5478e27918 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -4,19 +4,68 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::slice::Iter<'_, T>; - let mut _12: std::slice::Iter<'_, T>; - let mut _13: &mut std::slice::Iter<'_, T>; - let mut _14: std::option::Option<&T>; - let mut _15: isize; - let mut _17: &impl Fn(&T); - let mut _18: (&T,); - let _19: (); + let mut _11: std::ptr::NonNull<T>; + let mut _12: *const T; + let mut _26: std::option::Option<&T>; + let mut _28: &impl Fn(&T); + let mut _29: (&T,); + let _30: (); scope 1 { - debug iter => _12; - let _16: &T; + debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11; + debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _12; + debug ((iter: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; + let _27: &T; scope 2 { - debug x => _16; + debug x => _27; + } + scope 17 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { + let _13: std::ptr::NonNull<T>; + let _15: std::ptr::NonNull<T>; + let mut _18: bool; + let mut _21: std::ptr::NonNull<T>; + let mut _23: usize; + let _25: &T; + scope 18 { + let _14: *const T; + scope 19 { + let _22: usize; + scope 20 { + scope 23 (inlined core::num::<impl usize>::unchecked_sub) { + scope 24 (inlined core::ub_checks::check_language_ub) { + scope 25 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 26 (inlined without_provenance_mut::<T>) { + } + } + scope 21 (inlined std::ptr::const_ptr::<impl *const T>::addr) { + scope 22 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) { + } + } + scope 27 (inlined <NonNull<T> as PartialEq>::eq) { + let mut _16: *mut T; + let mut _17: *mut T; + scope 28 (inlined NonNull::<T>::as_ptr) { + } + scope 29 (inlined NonNull::<T>::as_ptr) { + } + } + scope 30 (inlined NonNull::<T>::add) { + let mut _19: *const T; + let mut _20: *const T; + scope 31 (inlined NonNull::<T>::as_ptr) { + } + } + scope 32 (inlined NonNull::<T>::as_ref::<'_>) { + let _24: *const T; + scope 33 (inlined NonNull::<T>::as_ptr) { + } + scope 34 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { + } + } + } + } } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -58,7 +107,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb0: { StorageLive(_3); - StorageLive(_6); StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); @@ -87,65 +135,133 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb3: { - StorageLive(_10); _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_10); StorageDead(_9); StorageDead(_4); - StorageDead(_6); StorageDead(_3); + StorageLive(_11); StorageLive(_12); - _12 = copy _11; + _11 = copy _6; + _12 = copy _10; goto -> bb4; } bb4: { + StorageLive(_26); + StorageLive(_13); StorageLive(_14); - _13 = &mut _12; - _14 = <std::slice::Iter<'_, T> as Iterator>::next(move _13) -> [return: bb5, unwind: bb11]; + StorageLive(_22); + StorageLive(_23); + StorageLive(_15); + StorageLive(_25); + _13 = copy _11; + _14 = copy _12; + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8]; } bb5: { - _15 = discriminant(_14); - switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageLive(_18); + _15 = copy _14 as std::ptr::NonNull<T> (Transmute); + StorageLive(_16); + _16 = copy _13 as *mut T (Transmute); + StorageLive(_17); + _17 = copy _15 as *mut T (Transmute); + _18 = Eq(move _16, move _17); + StorageDead(_17); + StorageDead(_16); + switchInt(move _18) -> [0: bb6, otherwise: bb7]; } bb6: { - StorageDead(_14); - StorageDead(_12); - drop(_2) -> [return: bb7, unwind continue]; + StorageDead(_18); + StorageLive(_21); + StorageLive(_20); + StorageLive(_19); + _19 = copy _13 as *const T (Transmute); + _20 = Offset(move _19, const 1_usize); + StorageDead(_19); + _21 = NonNull::<T> { pointer: move _20 }; + StorageDead(_20); + _11 = move _21; + StorageDead(_21); + goto -> bb13; } bb7: { - return; + StorageDead(_18); + StorageDead(_25); + StorageDead(_15); + StorageDead(_23); + StorageDead(_22); + StorageDead(_14); + StorageDead(_13); + goto -> bb10; } bb8: { - _16 = copy ((_14 as Some).0: &T); - StorageLive(_17); - _17 = &_2; - StorageLive(_18); - _18 = (copy _16,); - _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind: bb11]; + _22 = copy _14 as usize (Transmute); + switchInt(copy _22) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_18); - StorageDead(_17); + StorageDead(_25); + StorageDead(_15); + StorageDead(_23); + StorageDead(_22); StorageDead(_14); - goto -> bb4; + StorageDead(_13); + goto -> bb10; } bb10: { - unreachable; + StorageDead(_26); + StorageDead(_11); + StorageDead(_12); + drop(_2) -> [return: bb11, unwind continue]; + } + + bb11: { + return; + } + + bb12: { + _23 = SubUnchecked(copy _22, const 1_usize); + _12 = copy _23 as *const T (Transmute); + goto -> bb13; + } + + bb13: { + StorageLive(_24); + _24 = copy _13 as *const T (Transmute); + _25 = &(*_24); + StorageDead(_24); + _26 = Option::<&T>::Some(copy _25); + StorageDead(_25); + StorageDead(_15); + StorageDead(_23); + StorageDead(_22); + StorageDead(_14); + StorageDead(_13); + _27 = copy ((_26 as Some).0: &T); + StorageLive(_28); + _28 = &_2; + StorageLive(_29); + _29 = (copy _27,); + _30 = <impl Fn(&T) as Fn<(&T,)>>::call(move _28, move _29) -> [return: bb14, unwind: bb15]; + } + + bb14: { + StorageDead(_29); + StorageDead(_28); + StorageDead(_26); + goto -> bb4; } - bb11 (cleanup): { - drop(_2) -> [return: bb12, unwind terminate(cleanup)]; + bb15 (cleanup): { + drop(_2) -> [return: bb16, unwind terminate(cleanup)]; } - bb12 (cleanup): { + bb16 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir index 8edac638ccd..b6df2300efb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir @@ -3,12 +3,134 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { debug it => _1; let mut _0: std::option::Option<&T>; + scope 1 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { + let _2: std::ptr::NonNull<T>; + let _4: std::ptr::NonNull<T>; + let mut _7: bool; + let mut _10: std::ptr::NonNull<T>; + let mut _12: usize; + let _14: &T; + scope 2 { + let _3: *const T; + scope 3 { + let _11: usize; + scope 4 { + scope 7 (inlined core::num::<impl usize>::unchecked_sub) { + scope 8 (inlined core::ub_checks::check_language_ub) { + scope 9 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 10 (inlined without_provenance_mut::<T>) { + } + } + scope 5 (inlined std::ptr::const_ptr::<impl *const T>::addr) { + scope 6 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) { + } + } + scope 11 (inlined <NonNull<T> as PartialEq>::eq) { + let mut _5: *mut T; + let mut _6: *mut T; + scope 12 (inlined NonNull::<T>::as_ptr) { + } + scope 13 (inlined NonNull::<T>::as_ptr) { + } + } + scope 14 (inlined NonNull::<T>::add) { + let mut _8: *const T; + let mut _9: *const T; + scope 15 (inlined NonNull::<T>::as_ptr) { + } + } + scope 16 (inlined NonNull::<T>::as_ref::<'_>) { + let _13: *const T; + scope 17 (inlined NonNull::<T>::as_ptr) { + } + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { + } + } + } + } + } bb0: { - _0 = <std::slice::Iter<'_, T> as Iterator>::next(move _1) -> [return: bb1, unwind unreachable]; + StorageLive(_2); + StorageLive(_3); + StorageLive(_11); + StorageLive(_12); + StorageLive(_4); + StorageLive(_14); + _2 = copy ((*_1).0: std::ptr::NonNull<T>); + _3 = copy ((*_1).1: *const T); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb4]; } bb1: { + StorageLive(_7); + _4 = copy _3 as std::ptr::NonNull<T> (Transmute); + StorageLive(_5); + _5 = copy _2 as *mut T (Transmute); + StorageLive(_6); + _6 = copy _4 as *mut T (Transmute); + _7 = Eq(move _5, move _6); + StorageDead(_6); + StorageDead(_5); + switchInt(move _7) -> [0: bb2, otherwise: bb3]; + } + + bb2: { + StorageDead(_7); + StorageLive(_10); + StorageLive(_9); + StorageLive(_8); + _8 = copy _2 as *const T (Transmute); + _9 = Offset(move _8, const 1_usize); + StorageDead(_8); + _10 = NonNull::<T> { pointer: move _9 }; + StorageDead(_9); + ((*_1).0: std::ptr::NonNull<T>) = move _10; + StorageDead(_10); + goto -> bb7; + } + + bb3: { + _0 = const {transmute(0x0000000000000000): Option<&T>}; + StorageDead(_7); + goto -> bb8; + } + + bb4: { + _11 = copy _3 as usize (Transmute); + switchInt(copy _11) -> [0: bb5, otherwise: bb6]; + } + + bb5: { + _0 = const {transmute(0x0000000000000000): Option<&T>}; + goto -> bb8; + } + + bb6: { + _12 = SubUnchecked(copy _11, const 1_usize); + ((*_1).1: *const T) = copy _12 as *const T (Transmute); + goto -> bb7; + } + + bb7: { + StorageLive(_13); + _13 = copy _2 as *const T (Transmute); + _14 = &(*_13); + StorageDead(_13); + _0 = Option::<&T>::Some(copy _14); + goto -> bb8; + } + + bb8: { + StorageDead(_14); + StorageDead(_4); + StorageDead(_12); + StorageDead(_11); + StorageDead(_3); + StorageDead(_2); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir index fdde0717343..b6df2300efb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir @@ -3,12 +3,134 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { debug it => _1; let mut _0: std::option::Option<&T>; + scope 1 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { + let _2: std::ptr::NonNull<T>; + let _4: std::ptr::NonNull<T>; + let mut _7: bool; + let mut _10: std::ptr::NonNull<T>; + let mut _12: usize; + let _14: &T; + scope 2 { + let _3: *const T; + scope 3 { + let _11: usize; + scope 4 { + scope 7 (inlined core::num::<impl usize>::unchecked_sub) { + scope 8 (inlined core::ub_checks::check_language_ub) { + scope 9 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 10 (inlined without_provenance_mut::<T>) { + } + } + scope 5 (inlined std::ptr::const_ptr::<impl *const T>::addr) { + scope 6 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) { + } + } + scope 11 (inlined <NonNull<T> as PartialEq>::eq) { + let mut _5: *mut T; + let mut _6: *mut T; + scope 12 (inlined NonNull::<T>::as_ptr) { + } + scope 13 (inlined NonNull::<T>::as_ptr) { + } + } + scope 14 (inlined NonNull::<T>::add) { + let mut _8: *const T; + let mut _9: *const T; + scope 15 (inlined NonNull::<T>::as_ptr) { + } + } + scope 16 (inlined NonNull::<T>::as_ref::<'_>) { + let _13: *const T; + scope 17 (inlined NonNull::<T>::as_ptr) { + } + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { + } + } + } + } + } bb0: { - _0 = <std::slice::Iter<'_, T> as Iterator>::next(move _1) -> [return: bb1, unwind continue]; + StorageLive(_2); + StorageLive(_3); + StorageLive(_11); + StorageLive(_12); + StorageLive(_4); + StorageLive(_14); + _2 = copy ((*_1).0: std::ptr::NonNull<T>); + _3 = copy ((*_1).1: *const T); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb4]; } bb1: { + StorageLive(_7); + _4 = copy _3 as std::ptr::NonNull<T> (Transmute); + StorageLive(_5); + _5 = copy _2 as *mut T (Transmute); + StorageLive(_6); + _6 = copy _4 as *mut T (Transmute); + _7 = Eq(move _5, move _6); + StorageDead(_6); + StorageDead(_5); + switchInt(move _7) -> [0: bb2, otherwise: bb3]; + } + + bb2: { + StorageDead(_7); + StorageLive(_10); + StorageLive(_9); + StorageLive(_8); + _8 = copy _2 as *const T (Transmute); + _9 = Offset(move _8, const 1_usize); + StorageDead(_8); + _10 = NonNull::<T> { pointer: move _9 }; + StorageDead(_9); + ((*_1).0: std::ptr::NonNull<T>) = move _10; + StorageDead(_10); + goto -> bb7; + } + + bb3: { + _0 = const {transmute(0x0000000000000000): Option<&T>}; + StorageDead(_7); + goto -> bb8; + } + + bb4: { + _11 = copy _3 as usize (Transmute); + switchInt(copy _11) -> [0: bb5, otherwise: bb6]; + } + + bb5: { + _0 = const {transmute(0x0000000000000000): Option<&T>}; + goto -> bb8; + } + + bb6: { + _12 = SubUnchecked(copy _11, const 1_usize); + ((*_1).1: *const T) = copy _12 as *const T (Transmute); + goto -> bb7; + } + + bb7: { + StorageLive(_13); + _13 = copy _2 as *const T (Transmute); + _14 = &(*_13); + StorageDead(_13); + _0 = Option::<&T>::Some(copy _14); + goto -> bb8; + } + + bb8: { + StorageDead(_14); + StorageDead(_4); + StorageDead(_12); + StorageDead(_11); + StorageDead(_3); + StorageDead(_2); return; } } diff --git a/tests/run-make/avr-rjmp-offset/rmake.rs b/tests/run-make/avr-rjmp-offset/rmake.rs index de64b724eed..da314f26ca7 100644 --- a/tests/run-make/avr-rjmp-offset/rmake.rs +++ b/tests/run-make/avr-rjmp-offset/rmake.rs @@ -22,7 +22,12 @@ fn main() { .input("avr-rjmp-offsets.rs") .opt_level("s") .panic("abort") - .target("avr-unknown-gnu-atmega328") + .target("avr-none") + // rust-lld has some troubles understanding the -mmcu flag, so for the + // time being let's tell rustc to emit binary that's compatible with the + // target CPU that lld defaults to, i.e. just `avr` (that's simply the + // minimal common instruction set across all AVRs) + .target_cpu("avr") // normally one links with `avr-gcc`, but this is not available in CI, // hence this test diverges from the default behavior to enable linking // at all, which is necessary for the test (to resolve the labels). To @@ -49,6 +54,7 @@ fn main() { // of the Rust compiler did produce a label `rjmp .-4` (misses the first // instruction in the loop). assert!(disassembly.contains("<main>"), "no main function in output"); + disassembly .trim() .lines() diff --git a/tests/rustdoc-gui/sidebar-foreign-impl-sort.goml b/tests/rustdoc-gui/sidebar-foreign-impl-sort.goml new file mode 100644 index 00000000000..f09f0971351 --- /dev/null +++ b/tests/rustdoc-gui/sidebar-foreign-impl-sort.goml @@ -0,0 +1,15 @@ +// Checks sidebar resizing close the Settings popover +go-to: "file://" + |DOC_PATH| + "/test_docs/SidebarSort/trait.Sort.html#foreign-impls" + +// Check that the sidebar contains the expected foreign implementations +assert-text: (".sidebar-elems section ul > li:nth-child(1)", "&'a str") +assert-text: (".sidebar-elems section ul > li:nth-child(2)", "AtomicBool") +assert-text: (".sidebar-elems section ul > li:nth-child(3)", "AtomicU8") +assert-text: (".sidebar-elems section ul > li:nth-child(4)", "AtomicU16") +assert-text: (".sidebar-elems section ul > li:nth-child(5)", "AtomicU32") +assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Cell<u8>") +assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Cell<u16>") +assert-text: (".sidebar-elems section ul > li:nth-child(8)", "u8") +assert-text: (".sidebar-elems section ul > li:nth-child(9)", "u16") +assert-text: (".sidebar-elems section ul > li:nth-child(10)", "u32") +assert-text: (".sidebar-elems section ul > li:nth-child(11)", "usize") diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 1a9ffbe8898..f9c20ab22b8 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -713,3 +713,21 @@ pub trait ItemsTrait { /// blablala fn bar(); } + +pub mod SidebarSort { + use std::cell::Cell; + use std::sync::atomic::*; + pub trait Sort {} + + impl Sort for u32 {} + impl Sort for u8 {} + impl Sort for u16 {} + impl Sort for usize {} + impl Sort for AtomicU32 {} + impl Sort for AtomicU16 {} + impl Sort for AtomicU8 {} + impl Sort for AtomicBool {} + impl Sort for Cell<u16> {} + impl Sort for Cell<u8> {} + impl<'a> Sort for &'a str {} +} diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index c8f7d0a517c..57cc48aa9cf 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -45,6 +46,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index 1015f7d8898..67380176730 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -56,6 +57,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index 1015f7d8898..67380176730 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -56,6 +57,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index 1015f7d8898..67380176730 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -56,6 +57,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index c8f7d0a517c..57cc48aa9cf 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -45,6 +46,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index 1015f7d8898..67380176730 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -56,6 +57,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index e550e5bfcf3..5f73ff7d6bd 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -20,6 +20,7 @@ error: fn_abi_of(test) = FnAbi { ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -67,6 +68,7 @@ error: fn_abi_of(test) = FnAbi { valid_range: 0..=1, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -125,6 +127,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { valid_range: 0..=1, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -163,6 +166,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -213,6 +217,7 @@ error: fn_abi_of(test_generic) = FnAbi { ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -248,6 +253,7 @@ error: fn_abi_of(test_generic) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -297,6 +303,7 @@ error: ABIs are not compatible ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -332,6 +339,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -369,6 +377,7 @@ error: ABIs are not compatible ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -404,6 +413,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -444,6 +454,7 @@ error: ABIs are not compatible count: 32, }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -483,6 +494,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -517,6 +529,7 @@ error: ABIs are not compatible count: 32, }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -556,6 +569,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -598,6 +612,7 @@ error: ABIs are not compatible ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -633,6 +648,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -670,6 +686,7 @@ error: ABIs are not compatible ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -705,6 +722,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -748,6 +766,7 @@ error: ABIs are not compatible ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -783,6 +802,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -820,6 +840,7 @@ error: ABIs are not compatible ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -855,6 +876,7 @@ error: ABIs are not compatible memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -923,6 +945,7 @@ error: fn_abi_of(assoc_test) = FnAbi { valid_range: $NON_NULL, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -960,6 +983,7 @@ error: fn_abi_of(assoc_test) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 781e9b2f4c9..ec85030c106 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -17,6 +17,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -45,6 +46,7 @@ error: fn_abi_of(pass_zst) = FnAbi { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr index 28e7975c7a2..305fbbd275f 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied - --> $DIR/as_expression.rs:55:15 + --> $DIR/as_expression.rs:56:15 | LL | SelectInt.check("bar"); | ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 4f685c508c7..90bb715a052 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied - --> $DIR/as_expression.rs:55:21 + --> $DIR/as_expression.rs:56:21 | LL | SelectInt.check("bar"); | ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str` @@ -8,7 +8,7 @@ LL | SelectInt.check("bar"); | = help: the trait `AsExpression<Text>` is implemented for `&str` note: required by a bound in `Foo::check` - --> $DIR/as_expression.rs:46:12 + --> $DIR/as_expression.rs:47:12 | LL | fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression | ----- required by a bound in this associated function @@ -17,7 +17,7 @@ LL | T: AsExpression<Self::SqlType>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text` - --> $DIR/as_expression.rs:55:5 + --> $DIR/as_expression.rs:56:5 | LL | SelectInt.check("bar"); | ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 48c1ed2b02d..73a238ddf50 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro pub trait Expression { type SqlType; diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr index 47597a5d405..8a478a5c733 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:10:1 + --> $DIR/does_not_acccept_args.rs:11:1 | LL | #[diagnostic::do_not_recommend(not_accepted)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | #[diagnostic::do_not_recommend(not_accepted)] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:14:1 + --> $DIR/does_not_acccept_args.rs:15:1 | LL | #[diagnostic::do_not_recommend(not_accepted = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:18:1 + --> $DIR/does_not_acccept_args.rs:19:1 | LL | #[diagnostic::do_not_recommend(not_accepted(42))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr index 47597a5d405..8a478a5c733 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:10:1 + --> $DIR/does_not_acccept_args.rs:11:1 | LL | #[diagnostic::do_not_recommend(not_accepted)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | #[diagnostic::do_not_recommend(not_accepted)] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:14:1 + --> $DIR/does_not_acccept_args.rs:15:1 | LL | #[diagnostic::do_not_recommend(not_accepted = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:18:1 + --> $DIR/does_not_acccept_args.rs:19:1 | LL | #[diagnostic::do_not_recommend(not_accepted(42))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs index eeff5e2e6e8..5c21c045e10 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs @@ -2,6 +2,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.syntax trait Foo {} trait Bar {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr index ee6ebabadd9..e348f0c8902 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:6:1 + --> $DIR/incorrect-locations.rs:7:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,49 +7,49 @@ LL | #[diagnostic::do_not_recommend] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:10:1 + --> $DIR/incorrect-locations.rs:11:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:14:1 + --> $DIR/incorrect-locations.rs:15:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:18:1 + --> $DIR/incorrect-locations.rs:19:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:22:1 + --> $DIR/incorrect-locations.rs:23:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:26:1 + --> $DIR/incorrect-locations.rs:27:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:30:1 + --> $DIR/incorrect-locations.rs:31:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:34:1 + --> $DIR/incorrect-locations.rs:35:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:38:1 + --> $DIR/incorrect-locations.rs:39:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr index ee6ebabadd9..e348f0c8902 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:6:1 + --> $DIR/incorrect-locations.rs:7:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,49 +7,49 @@ LL | #[diagnostic::do_not_recommend] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:10:1 + --> $DIR/incorrect-locations.rs:11:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:14:1 + --> $DIR/incorrect-locations.rs:15:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:18:1 + --> $DIR/incorrect-locations.rs:19:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:22:1 + --> $DIR/incorrect-locations.rs:23:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:26:1 + --> $DIR/incorrect-locations.rs:27:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:30:1 + --> $DIR/incorrect-locations.rs:31:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:34:1 + --> $DIR/incorrect-locations.rs:35:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:38:1 + --> $DIR/incorrect-locations.rs:39:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs index 1cf436aa2af..e716457eaed 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs @@ -2,6 +2,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.allowed-positions #[diagnostic::do_not_recommend] //~^WARN `#[diagnostic::do_not_recommend]` can only be placed diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr index b14c68d6897..cb1da8ff8be 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `(): Root` is not satisfied - --> $DIR/nested.rs:21:18 + --> $DIR/nested.rs:22:18 | LL | needs_root::<()>(); | ^^ the trait `Root` is not implemented for `()` | note: required by a bound in `needs_root` - --> $DIR/nested.rs:18:18 + --> $DIR/nested.rs:19:18 | LL | fn needs_root<T: Root>() {} | ^^^^ required by this bound in `needs_root` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr index b14c68d6897..cb1da8ff8be 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `(): Root` is not satisfied - --> $DIR/nested.rs:21:18 + --> $DIR/nested.rs:22:18 | LL | needs_root::<()>(); | ^^ the trait `Root` is not implemented for `()` | note: required by a bound in `needs_root` - --> $DIR/nested.rs:18:18 + --> $DIR/nested.rs:19:18 | LL | fn needs_root<T: Root>() {} | ^^^^ required by this bound in `needs_root` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs b/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs index 6534157d1fb..3c96c760dfb 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro trait Root {} trait DontRecommend {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr index 884b13c17b8..dd425f1e6ee 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `*mut (): Foo` is not satisfied - --> $DIR/simple.rs:15:17 + --> $DIR/simple.rs:16:17 | LL | needs_foo::<*mut ()>(); | ^^^^^^^ the trait `Foo` is not implemented for `*mut ()` | note: required by a bound in `needs_foo` - --> $DIR/simple.rs:10:17 + --> $DIR/simple.rs:11:17 | LL | fn needs_foo<T: Foo>() {} | ^^^ required by this bound in `needs_foo` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr index 884b13c17b8..dd425f1e6ee 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `*mut (): Foo` is not satisfied - --> $DIR/simple.rs:15:17 + --> $DIR/simple.rs:16:17 | LL | needs_foo::<*mut ()>(); | ^^^^^^^ the trait `Foo` is not implemented for `*mut ()` | note: required by a bound in `needs_foo` - --> $DIR/simple.rs:10:17 + --> $DIR/simple.rs:11:17 | LL | fn needs_foo<T: Foo>() {} | ^^^ required by this bound in `needs_foo` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs index 6bca2b724d2..a6fa7ac7949 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro trait Foo {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr index d8605806395..d940c3fd477 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `(): Root` is not satisfied - --> $DIR/stacked.rs:17:18 + --> $DIR/stacked.rs:18:18 | LL | needs_root::<()>(); | ^^ the trait `Root` is not implemented for `()` | note: required by a bound in `needs_root` - --> $DIR/stacked.rs:14:18 + --> $DIR/stacked.rs:15:18 | LL | fn needs_root<T: Root>() {} | ^^^^ required by this bound in `needs_root` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr index d8605806395..d940c3fd477 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `(): Root` is not satisfied - --> $DIR/stacked.rs:17:18 + --> $DIR/stacked.rs:18:18 | LL | needs_root::<()>(); | ^^ the trait `Root` is not implemented for `()` | note: required by a bound in `needs_root` - --> $DIR/stacked.rs:14:18 + --> $DIR/stacked.rs:15:18 | LL | fn needs_root<T: Root>() {} | ^^^^ required by this bound in `needs_root` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs index 842e04b9d90..fd7be35ff84 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro trait Root {} trait DontRecommend {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr index 95ccbb92a89..0b07b073172 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/supress_suggestions_in_help.rs:21:11 + --> $DIR/supress_suggestions_in_help.rs:22:11 | LL | check(()); | ----- ^^ the trait `Foo` is not implemented for `()` @@ -8,7 +8,7 @@ LL | check(()); | = help: the trait `Foo` is implemented for `i32` note: required by a bound in `check` - --> $DIR/supress_suggestions_in_help.rs:18:18 + --> $DIR/supress_suggestions_in_help.rs:19:18 | LL | fn check(a: impl Foo) {} | ^^^ required by this bound in `check` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr index 95ccbb92a89..0b07b073172 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/supress_suggestions_in_help.rs:21:11 + --> $DIR/supress_suggestions_in_help.rs:22:11 | LL | check(()); | ----- ^^ the trait `Foo` is not implemented for `()` @@ -8,7 +8,7 @@ LL | check(()); | = help: the trait `Foo` is implemented for `i32` note: required by a bound in `check` - --> $DIR/supress_suggestions_in_help.rs:18:18 + --> $DIR/supress_suggestions_in_help.rs:19:18 | LL | fn check(a: impl Foo) {} | ^^^ required by this bound in `check` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs index 2c7c1516123..04cf8243a67 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro trait Foo {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr index b53febbb71a..31a1ae991ec 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr @@ -1,11 +1,11 @@ error[E0277]: Very important message! - --> $DIR/type_mismatch.rs:23:14 + --> $DIR/type_mismatch.rs:24:14 | LL | verify::<u8>(); | ^^ the trait `TheImportantOne` is not implemented for `u8` | note: required by a bound in `verify` - --> $DIR/type_mismatch.rs:20:14 + --> $DIR/type_mismatch.rs:21:14 | LL | fn verify<T: TheImportantOne>() {} | ^^^^^^^^^^^^^^^ required by this bound in `verify` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr index b53febbb71a..31a1ae991ec 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr @@ -1,11 +1,11 @@ error[E0277]: Very important message! - --> $DIR/type_mismatch.rs:23:14 + --> $DIR/type_mismatch.rs:24:14 | LL | verify::<u8>(); | ^^ the trait `TheImportantOne` is not implemented for `u8` | note: required by a bound in `verify` - --> $DIR/type_mismatch.rs:20:14 + --> $DIR/type_mismatch.rs:21:14 | LL | fn verify<T: TheImportantOne>() {} | ^^^^^^^^^^^^^^^ required by this bound in `verify` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs index 7f30fdb06c7..b5bd14745cd 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro #[diagnostic::on_unimplemented(message = "Very important message!")] trait TheImportantOne {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr index a8429ff60f8..7e348842e19 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/with_lifetime.rs:17:5 + --> $DIR/with_lifetime.rs:18:5 | LL | fn foo<'a>(a: &'a ()) { | -- lifetime `'a` defined here diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr index a8429ff60f8..7e348842e19 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/with_lifetime.rs:17:5 + --> $DIR/with_lifetime.rs:18:5 | LL | fn foo<'a>(a: &'a ()) { | -- lifetime `'a` defined here diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs index 6a67d83d5fe..98916ed061f 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs @@ -1,6 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ reference: attributes.diagnostic.do_not_recommend.intro trait Root {} trait DontRecommend {} diff --git a/tests/ui/dropck/dropck-only-error-ambiguity.rs b/tests/ui/dropck/dropck-only-error-ambiguity.rs new file mode 100644 index 00000000000..ddba2af7070 --- /dev/null +++ b/tests/ui/dropck/dropck-only-error-ambiguity.rs @@ -0,0 +1,23 @@ +// Test that we don't ICE for a typeck error that only shows up in dropck +// Version where the normalization error is an ambiguous trait implementation. +// <[T] as ToOwned>::Owned is ambiguous on whether to use T: Clone or [T]::Clone. +// Regression test for #105299 + +pub trait Foo: Clone {} + +pub struct Bar<'a, T: Clone> { + pub cow: std::borrow::Cow<'a, [T]>, + + pub THIS_CAUSES_ICE: (), +} + +impl<T> Bar<'_, T> +where + T: Clone, + [T]: Foo, +{ + pub fn MOVES_SELF(self) {} + //~^ ERROR type annotations needed +} + +pub fn main() {} diff --git a/tests/ui/dropck/dropck-only-error-ambiguity.stderr b/tests/ui/dropck/dropck-only-error-ambiguity.stderr new file mode 100644 index 00000000000..de19bd49f4e --- /dev/null +++ b/tests/ui/dropck/dropck-only-error-ambiguity.stderr @@ -0,0 +1,11 @@ +error[E0284]: type annotations needed + --> $DIR/dropck-only-error-ambiguity.rs:19:23 + | +LL | pub fn MOVES_SELF(self) {} + | ^^^^ cannot infer type + | + = note: cannot satisfy `<[T] as ToOwned>::Owned == _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/crashes/135039.rs b/tests/ui/dropck/dropck-only-error-async.rs index c4c5336fd4f..71158e3c6ef 100644 --- a/tests/crashes/135039.rs +++ b/tests/ui/dropck/dropck-only-error-async.rs @@ -1,7 +1,6 @@ -//@ known-bug: #135039 -//@ edition:2021 - -pub type UserId<Backend> = <<Backend as AuthnBackend>::User as AuthUser>::Id; +// Test that we don't ICE for a typeck error that only shows up in dropck +// issue #135039 +//@ edition:2018 pub trait AuthUser { type Id; @@ -13,7 +12,7 @@ pub trait AuthnBackend { pub struct AuthSession<Backend: AuthnBackend> { user: Option<Backend::User>, - data: Option<UserId<Backend>>, + data: Option<<<Backend as AuthnBackend>::User as AuthUser>::Id>, } pub trait Authz: Sized { @@ -27,8 +26,12 @@ pub trait Query<User: Authz> { pub async fn run_query<User: Authz, Q: Query<User> + 'static>( auth: AuthSession<User::AuthnBackend>, + //~^ ERROR the trait bound `User: AuthUser` is not satisfied [E0277] + //~| ERROR the trait bound `User: AuthUser` is not satisfied [E0277] query: Q, ) -> Result<Q::Output, ()> { let user = auth.user; query.run().await } + +fn main() {} diff --git a/tests/ui/dropck/dropck-only-error-async.stderr b/tests/ui/dropck/dropck-only-error-async.stderr new file mode 100644 index 00000000000..4a069c8ac33 --- /dev/null +++ b/tests/ui/dropck/dropck-only-error-async.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `User: AuthUser` is not satisfied + --> $DIR/dropck-only-error-async.rs:28:5 + | +LL | auth: AuthSession<User::AuthnBackend>, + | ^^^^ the trait `AuthUser` is not implemented for `User` + +error[E0277]: the trait bound `User: AuthUser` is not satisfied + --> $DIR/dropck-only-error-async.rs:28:5 + | +LL | auth: AuthSession<User::AuthnBackend>, + | ^^^^ the trait `AuthUser` is not implemented for `User` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/crashes/91985.rs b/tests/ui/dropck/dropck-only-error-gat.rs index 338550430e1..dadcf76a43f 100644 --- a/tests/crashes/91985.rs +++ b/tests/ui/dropck/dropck-only-error-gat.rs @@ -1,6 +1,6 @@ -//@ known-bug: #91985 - -#![feature(generic_associated_types)] +// Test that we don't ICE for a typeck error that only shows up in dropck +// Version that uses a generic associated type +// Regression test for #91985 pub trait Trait1 { type Associated: Ord; @@ -22,7 +22,7 @@ impl GatTrait for GatStruct { pub struct OuterStruct<T1: Trait1, T2: Trait2> { inner: InnerStruct<T2, GatStruct>, - t1: T1, + t1: T1, } pub struct InnerStruct<T: Trait2, G: GatTrait> { @@ -35,6 +35,7 @@ where T2: Trait2<Associated = T1::Associated>, { pub fn new() -> Self { + //~^ ERROR the trait bound `<T1 as Trait1>::Associated: Clone` is not satisfied todo!() } } diff --git a/tests/ui/dropck/dropck-only-error-gat.stderr b/tests/ui/dropck/dropck-only-error-gat.stderr new file mode 100644 index 00000000000..53982c0826a --- /dev/null +++ b/tests/ui/dropck/dropck-only-error-gat.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `<T1 as Trait1>::Associated: Clone` is not satisfied + --> $DIR/dropck-only-error-gat.rs:37:21 + | +LL | pub fn new() -> Self { + | ^^^^ the trait `Clone` is not implemented for `<T1 as Trait1>::Associated` + | +note: required by a bound in `GatTrait::Gat` + --> $DIR/dropck-only-error-gat.rs:14:17 + | +LL | type Gat<T: Clone>; + | ^^^^^ required by this bound in `GatTrait::Gat` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dropck/dropck-only-error.rs b/tests/ui/dropck/dropck-only-error.rs new file mode 100644 index 00000000000..e85eeb82e00 --- /dev/null +++ b/tests/ui/dropck/dropck-only-error.rs @@ -0,0 +1,23 @@ +// Test that we don't ICE for a typeck error that only shows up in dropck +// issue #135039 + +pub trait AuthUser { + type Id; +} + +pub trait AuthnBackend { + type User: AuthUser; +} + +pub struct AuthSession<Backend: AuthnBackend> { + data: Option<<<Backend as AuthnBackend>::User as AuthUser>::Id>, +} + +pub trait Authz: Sized { + type AuthnBackend: AuthnBackend<User = Self>; +} + +pub fn run_query<User: Authz>(auth: AuthSession<User::AuthnBackend>) {} +//~^ ERROR the trait bound `User: AuthUser` is not satisfied [E0277] + +fn main() {} diff --git a/tests/ui/dropck/dropck-only-error.stderr b/tests/ui/dropck/dropck-only-error.stderr new file mode 100644 index 00000000000..6c7cd5d296c --- /dev/null +++ b/tests/ui/dropck/dropck-only-error.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `User: AuthUser` is not satisfied + --> $DIR/dropck-only-error.rs:20:31 + | +LL | pub fn run_query<User: Authz>(auth: AuthSession<User::AuthnBackend>) {} + | ^^^^ the trait `AuthUser` is not implemented for `User` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs b/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs index 5386628a8e0..ce3d3fc645d 100644 --- a/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs +++ b/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs @@ -1,5 +1,5 @@ //@ needs-llvm-components: avr -//@ compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib +//@ compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib #![no_core] #![feature(no_core, lang_items)] #[lang="sized"] diff --git a/tests/ui/generic-associated-types/issue-91883.stderr b/tests/ui/generic-associated-types/issue-91883.current.stderr index ac636ebb648..0741cf9581d 100644 --- a/tests/ui/generic-associated-types/issue-91883.stderr +++ b/tests/ui/generic-associated-types/issue-91883.current.stderr @@ -1,5 +1,5 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/issue-91883.rs:30:24 + --> $DIR/issue-91883.rs:34:24 | LL | type Cursor<'tx>: Cursor<'tx> | ----------------------------- definition of `Cursor` from trait @@ -8,12 +8,12 @@ LL | type Cursor<'tx> = CursorImpl<'tx>; | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'db` as defined here - --> $DIR/issue-91883.rs:29:6 + --> $DIR/issue-91883.rs:33:6 | LL | impl<'db> Transaction<'db> for TransactionImpl<'db> { | ^^^ note: but lifetime parameter must outlive the lifetime `'tx` as defined here - --> $DIR/issue-91883.rs:30:17 + --> $DIR/issue-91883.rs:34:17 | LL | type Cursor<'tx> = CursorImpl<'tx>; | ^^^ diff --git a/tests/ui/generic-associated-types/issue-91883.next.stderr b/tests/ui/generic-associated-types/issue-91883.next.stderr new file mode 100644 index 00000000000..b3ed2d81b63 --- /dev/null +++ b/tests/ui/generic-associated-types/issue-91883.next.stderr @@ -0,0 +1,20 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/issue-91883.rs:34:24 + | +LL | type Cursor<'tx> = CursorImpl<'tx>; + | ^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'db` as defined here + --> $DIR/issue-91883.rs:33:6 + | +LL | impl<'db> Transaction<'db> for TransactionImpl<'db> { + | ^^^ +note: but lifetime parameter must outlive the lifetime `'tx` as defined here + --> $DIR/issue-91883.rs:34:17 + | +LL | type Cursor<'tx> = CursorImpl<'tx>; + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/generic-associated-types/issue-91883.rs b/tests/ui/generic-associated-types/issue-91883.rs index e870e08a3a2..d31e1736cf2 100644 --- a/tests/ui/generic-associated-types/issue-91883.rs +++ b/tests/ui/generic-associated-types/issue-91883.rs @@ -1,3 +1,7 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + use std::fmt::Debug; use std::marker::PhantomData; diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs index c1a78bc2388..1bbff839ffa 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs @@ -1,5 +1,8 @@ //@ edition:2021 //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver use std::fmt::Debug; diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs index 10c2a811243..6954a7d8067 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver use std::ops::Deref; diff --git a/tests/ui/implied-bounds/bevy_world_query.rs b/tests/ui/implied-bounds/bevy_world_query.rs index e36be26d003..6548c03d1b0 100644 --- a/tests/ui/implied-bounds/bevy_world_query.rs +++ b/tests/ui/implied-bounds/bevy_world_query.rs @@ -1,3 +1,5 @@ +#![crate_name = "bevy_ecs"] + //@ check-pass // We currently special case bevy from erroring on incorrect implied bounds diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr index f498257e12f..f8ee6fef824 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr @@ -1,4 +1,4 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { @@ -25,4 +25,4 @@ LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/issues/issue-20831-debruijn.stderr b/tests/ui/issues/issue-20831-debruijn.stderr index fe310998f09..bed75ed6ba2 100644 --- a/tests/ui/issues/issue-20831-debruijn.stderr +++ b/tests/ui/issues/issue-20831-debruijn.stderr @@ -1,4 +1,4 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/issue-20831-debruijn.rs:28:33 | LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) { @@ -48,4 +48,4 @@ LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs index 81dc7285254..b87a1d2031d 100644 --- a/tests/ui/layout/debug.rs +++ b/tests/ui/layout/debug.rs @@ -82,3 +82,8 @@ type Impossible = (str, str); //~ ERROR: cannot be known at compilation time #[rustc_layout(debug)] union EmptyUnion {} //~ ERROR: has an unknown layout //~^ ERROR: unions cannot have zero fields + +// Test the error message of `LayoutError::TooGeneric` +// (this error is never emitted to users). +#[rustc_layout(debug)] +type TooGeneric<T> = T; //~ ERROR: does not have a fixed layout diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 319c0de26a9..07cad776692 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -31,6 +31,7 @@ error: layout_of(E) = Layout { valid_range: 0..=0, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -56,6 +57,7 @@ error: layout_of(E) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -69,7 +71,9 @@ error: layout_of(E) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Memory { + sized: true, + }, fields: Arbitrary { offsets: [ Size(4 bytes), @@ -83,6 +87,7 @@ error: layout_of(E) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 1, }, @@ -136,6 +141,7 @@ error: layout_of(S) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -161,6 +167,7 @@ error: layout_of(U) = Layout { 2, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -213,6 +220,7 @@ error: layout_of(Result<i32, i32>) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -255,6 +263,7 @@ error: layout_of(Result<i32, i32>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -293,6 +302,7 @@ error: layout_of(Result<i32, i32>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -328,6 +338,7 @@ error: layout_of(i32) = Layout { ), fields: Primitive, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -353,6 +364,7 @@ error: layout_of(V) = Layout { 2, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -378,6 +390,7 @@ error: layout_of(W) = Layout { 2, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -403,6 +416,7 @@ error: layout_of(Y) = Layout { 2, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -428,6 +442,7 @@ error: layout_of(P1) = Layout { 1, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -453,6 +468,7 @@ error: layout_of(P2) = Layout { 1, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -478,6 +494,7 @@ error: layout_of(P3) = Layout { 1, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -503,6 +520,7 @@ error: layout_of(P4) = Layout { 1, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -533,6 +551,7 @@ error: layout_of(P5) = Layout { 2, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -563,6 +582,7 @@ error: layout_of(MaybeUninit<u8>) = Layout { 2, ), largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -596,12 +616,18 @@ error: the type has an unknown layout LL | union EmptyUnion {} | ^^^^^^^^^^^^^^^^ +error: the type `T` does not have a fixed layout + --> $DIR/debug.rs:89:1 + | +LL | type TooGeneric<T> = T; + | ^^^^^^^^^^^^^^^^^^ + error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases --> $DIR/debug.rs:75:5 | LL | const C: () = (); | ^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index 96f0a8c8740..90c06ba1f83 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -31,6 +31,7 @@ error: layout_of(A) = Layout { valid_range: 0..=0, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -56,6 +57,7 @@ error: layout_of(A) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -107,6 +109,7 @@ error: layout_of(B) = Layout { valid_range: 255..=255, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -132,6 +135,7 @@ error: layout_of(B) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -183,6 +187,7 @@ error: layout_of(C) = Layout { valid_range: 256..=256, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -208,6 +213,7 @@ error: layout_of(C) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -259,6 +265,7 @@ error: layout_of(P) = Layout { valid_range: 268435456..=268435456, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -284,6 +291,7 @@ error: layout_of(P) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -335,6 +343,7 @@ error: layout_of(T) = Layout { valid_range: 2164260864..=2164260864, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -360,6 +369,7 @@ error: layout_of(T) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index cd9e4c02781..3bdb9c5c143 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -37,6 +37,7 @@ error: layout_of(MissingPayloadField) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -78,6 +79,7 @@ error: layout_of(MissingPayloadField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -99,6 +101,7 @@ error: layout_of(MissingPayloadField) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -157,6 +160,7 @@ error: layout_of(CommonPayloadField) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -199,6 +203,7 @@ error: layout_of(CommonPayloadField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -237,6 +242,7 @@ error: layout_of(CommonPayloadField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -294,6 +300,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -335,6 +342,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -372,6 +380,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -429,6 +438,7 @@ error: layout_of(NicheFirst) = Layout { valid_range: 0..=4, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -486,6 +496,7 @@ error: layout_of(NicheFirst) = Layout { valid_range: 0..=2, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -507,6 +518,7 @@ error: layout_of(NicheFirst) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -528,6 +540,7 @@ error: layout_of(NicheFirst) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 2, }, @@ -585,6 +598,7 @@ error: layout_of(NicheSecond) = Layout { valid_range: 0..=4, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -642,6 +656,7 @@ error: layout_of(NicheSecond) = Layout { valid_range: 0..=2, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -663,6 +678,7 @@ error: layout_of(NicheSecond) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -684,6 +700,7 @@ error: layout_of(NicheSecond) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 2, }, diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index 15a3f6004f5..1d4e4436448 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -25,6 +25,7 @@ error: layout_of(Aligned1) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -50,6 +51,7 @@ error: layout_of(Aligned1) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -73,6 +75,7 @@ error: layout_of(Aligned1) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -128,6 +131,7 @@ error: layout_of(Aligned2) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -153,6 +157,7 @@ error: layout_of(Aligned2) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -176,6 +181,7 @@ error: layout_of(Aligned2) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/layout/normalization-failure.rs b/tests/ui/layout/normalization-failure.rs new file mode 100644 index 00000000000..c0f8710c03c --- /dev/null +++ b/tests/ui/layout/normalization-failure.rs @@ -0,0 +1,57 @@ +//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why +//! it is necessary. +//! +//! This code does not cause an immediate normalization error in typeck, because we +//! don't reveal the hidden type returned by `opaque<T>` in the analysis typing mode. +//! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know +//! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound, +//! but cannot normalize `<{opaque} as Project2>::Assoc2` any further. +//! +//! However, in the post-analysis typing mode, which is used for the layout computation, +//! the opaque's hidden type is revealed to be `PhantomData<T>`, and now we fail to +//! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound +//! in the param env! This happens, because `PhantomData<T>: Project2` only holds if +//! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the +//! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not +//! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead. +//! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing +//! `<PhantomData<T> as Project2>::Assoc2` fails. +//! +//! Note that this layout error can only happen when computing the layout in a generic +//! context, which is not required for codegen, but may happen for lints, MIR optimizations, +//! and the transmute check. + +use std::marker::PhantomData; + +trait Project1 { + type Assoc1; +} + +impl<T> Project1 for T { + type Assoc1 = (); +} + +trait Project2 { + type Assoc2; + fn get(self) -> Self::Assoc2; +} + +impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> { + type Assoc2 = (); + fn get(self) -> Self::Assoc2 {} +} + +fn opaque<T>() -> impl Project2 { + PhantomData::<T> +} + +fn check<T: Project1>() { + unsafe { + std::mem::transmute::<_, ()>(opaque::<T>().get()); + //~^ ERROR: cannot transmute + //~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized) + //~| NOTE: (0 bits) + } +} + +fn main() {} diff --git a/tests/ui/layout/normalization-failure.stderr b/tests/ui/layout/normalization-failure.stderr new file mode 100644 index 00000000000..5fe38d4403a --- /dev/null +++ b/tests/ui/layout/normalization-failure.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/normalization-failure.rs:50:9 + | +LL | std::mem::transmute::<_, ()>(opaque::<T>().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `<impl Project2 as Project2>::Assoc2` (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized) + = note: target type: `()` (0 bits) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 120081d193c..0c343318564 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -31,6 +31,7 @@ error: layout_of(A) = Layout { valid_range: 0..=0, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -56,6 +57,7 @@ error: layout_of(A) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -107,6 +109,7 @@ error: layout_of(B) = Layout { valid_range: 255..=255, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -132,6 +135,7 @@ error: layout_of(B) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -183,6 +187,7 @@ error: layout_of(C) = Layout { valid_range: 256..=256, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -208,6 +213,7 @@ error: layout_of(C) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -259,6 +265,7 @@ error: layout_of(P) = Layout { valid_range: 268435456..=268435456, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -284,6 +291,7 @@ error: layout_of(P) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -335,6 +343,7 @@ error: layout_of(T) = Layout { valid_range: 2164260864..=2164260864, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -360,6 +369,7 @@ error: layout_of(T) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index b6fcc14c063..33d2eede220 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -25,6 +25,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -54,6 +55,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -88,6 +90,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Single { index: 1, }, @@ -133,6 +136,7 @@ error: layout_of(MultipleAlignments) = Layout { valid_range: 0..=2, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -162,6 +166,7 @@ error: layout_of(MultipleAlignments) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -187,6 +192,7 @@ error: layout_of(MultipleAlignments) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -221,6 +227,7 @@ error: layout_of(MultipleAlignments) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Single { index: 2, }, @@ -266,6 +273,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -295,6 +303,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -329,6 +338,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout { valid_range: 1..=65535, }, ), + uninhabited: false, variants: Single { index: 1, }, @@ -374,6 +384,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -407,6 +418,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -441,6 +453,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout { valid_range: 0..=0, }, ), + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index 8f8000fe34d..87a906761c0 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(concat_bytes)] -#![feature(inherent_str_constructors)] #![warn(invalid_from_utf8_unchecked)] #![warn(invalid_from_utf8)] diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 715ecf56f21..3cd4d227fc2 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,5 +1,5 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:22:9 + --> $DIR/invalid_from_utf8.rs:21:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -7,13 +7,13 @@ LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112 | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:5:9 + --> $DIR/invalid_from_utf8.rs:4:9 | LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:24:9 + --> $DIR/invalid_from_utf8.rs:23:9 | LL | str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -21,7 +21,7 @@ LL | str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121 | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:26:9 + --> $DIR/invalid_from_utf8.rs:25:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -29,7 +29,7 @@ LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8_unchecked_mut` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:28:9 + --> $DIR/invalid_from_utf8.rs:27:9 | LL | str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -37,7 +37,7 @@ LL | str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:50:9 + --> $DIR/invalid_from_utf8.rs:49:9 | LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -45,7 +45,7 @@ LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:52:9 + --> $DIR/invalid_from_utf8.rs:51:9 | LL | str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -53,7 +53,7 @@ LL | str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:54:9 + --> $DIR/invalid_from_utf8.rs:53:9 | LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -61,7 +61,7 @@ LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:56:9 + --> $DIR/invalid_from_utf8.rs:55:9 | LL | str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -69,7 +69,7 @@ LL | str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:58:9 + --> $DIR/invalid_from_utf8.rs:57:9 | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -77,7 +77,7 @@ LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:60:9 + --> $DIR/invalid_from_utf8.rs:59:9 | LL | str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -85,7 +85,7 @@ LL | str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:62:9 + --> $DIR/invalid_from_utf8.rs:61:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -93,7 +93,7 @@ LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8_unchecked` with an invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:64:9 + --> $DIR/invalid_from_utf8.rs:63:9 | LL | str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -101,7 +101,7 @@ LL | str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:84:9 + --> $DIR/invalid_from_utf8.rs:83:9 | LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -109,13 +109,13 @@ LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:6:9 + --> $DIR/invalid_from_utf8.rs:5:9 | LL | #![warn(invalid_from_utf8)] | ^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:86:9 + --> $DIR/invalid_from_utf8.rs:85:9 | LL | str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -123,7 +123,7 @@ LL | str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:88:9 + --> $DIR/invalid_from_utf8.rs:87:9 | LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -131,7 +131,7 @@ LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:90:9 + --> $DIR/invalid_from_utf8.rs:89:9 | LL | str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -139,7 +139,7 @@ LL | str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:112:9 + --> $DIR/invalid_from_utf8.rs:111:9 | LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -147,7 +147,7 @@ LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:114:9 + --> $DIR/invalid_from_utf8.rs:113:9 | LL | str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^----------------------------------^ @@ -155,7 +155,7 @@ LL | str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:116:9 + --> $DIR/invalid_from_utf8.rs:115:9 | LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -163,7 +163,7 @@ LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']) | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:118:9 + --> $DIR/invalid_from_utf8.rs:117:9 | LL | str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -171,7 +171,7 @@ LL | str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:120:9 + --> $DIR/invalid_from_utf8.rs:119:9 | LL | std::str::from_utf8(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^-------------^ @@ -179,7 +179,7 @@ LL | std::str::from_utf8(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:122:9 + --> $DIR/invalid_from_utf8.rs:121:9 | LL | str::from_utf8(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^-------------^ @@ -187,7 +187,7 @@ LL | str::from_utf8(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:124:9 + --> $DIR/invalid_from_utf8.rs:123:9 | LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -195,7 +195,7 @@ LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:126:9 + --> $DIR/invalid_from_utf8.rs:125:9 | LL | str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^---------------------------------^ @@ -203,7 +203,7 @@ LL | str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:133:5 + --> $DIR/invalid_from_utf8.rs:132:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -211,7 +211,7 @@ LL | std::str::from_utf8_mut(&mut a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:135:5 + --> $DIR/invalid_from_utf8.rs:134:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -220,7 +220,7 @@ LL | str::from_utf8_mut(&mut a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:139:5 + --> $DIR/invalid_from_utf8.rs:138:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -229,7 +229,7 @@ LL | std::str::from_utf8_mut(c); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:141:5 + --> $DIR/invalid_from_utf8.rs:140:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -238,7 +238,7 @@ LL | str::from_utf8_mut(c); | ^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:144:5 + --> $DIR/invalid_from_utf8.rs:143:5 | LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -246,7 +246,7 @@ LL | std::str::from_utf8(c); | ^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:146:5 + --> $DIR/invalid_from_utf8.rs:145:5 | LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -255,7 +255,7 @@ LL | str::from_utf8(c); | ^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:149:5 + --> $DIR/invalid_from_utf8.rs:148:5 | LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -263,7 +263,7 @@ LL | std::str::from_utf8(&INVALID_1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:151:5 + --> $DIR/invalid_from_utf8.rs:150:5 | LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -272,7 +272,7 @@ LL | str::from_utf8(&INVALID_1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:154:5 + --> $DIR/invalid_from_utf8.rs:153:5 | LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -280,7 +280,7 @@ LL | std::str::from_utf8(&INVALID_2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:156:5 + --> $DIR/invalid_from_utf8.rs:155:5 | LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -289,7 +289,7 @@ LL | str::from_utf8(&INVALID_2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:159:5 + --> $DIR/invalid_from_utf8.rs:158:5 | LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -297,7 +297,7 @@ LL | std::str::from_utf8(INVALID_3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:161:5 + --> $DIR/invalid_from_utf8.rs:160:5 | LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -306,7 +306,7 @@ LL | str::from_utf8(INVALID_3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:164:5 + --> $DIR/invalid_from_utf8.rs:163:5 | LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -314,7 +314,7 @@ LL | std::str::from_utf8(INVALID_4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:166:5 + --> $DIR/invalid_from_utf8.rs:165:5 | LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index 51f868706b6..860fc5046d1 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -79,6 +79,11 @@ trait Use { #[must_use] //~ ERROR `#[must_use]` has no effect impl Use for () { type AssocTy = (); + + #[must_use] //~ ERROR `#[must_use]` has no effect + fn get_four(&self) -> usize { + 4 + } } #[must_use] //~ ERROR `#[must_use]` has no effect diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 9633767c442..28fd8eeb8cb 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -76,43 +76,43 @@ LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a trait alias - --> $DIR/unused_attributes-must_use.rs:84:1 + --> $DIR/unused_attributes-must_use.rs:89:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a macro def - --> $DIR/unused_attributes-must_use.rs:87:1 + --> $DIR/unused_attributes-must_use.rs:92:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a statement - --> $DIR/unused_attributes-must_use.rs:95:5 + --> $DIR/unused_attributes-must_use.rs:100:5 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a closure - --> $DIR/unused_attributes-must_use.rs:99:13 + --> $DIR/unused_attributes-must_use.rs:104:13 | LL | let x = #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an match arm - --> $DIR/unused_attributes-must_use.rs:121:9 + --> $DIR/unused_attributes-must_use.rs:126:9 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a struct field - --> $DIR/unused_attributes-must_use.rs:129:28 + --> $DIR/unused_attributes-must_use.rs:134:28 | LL | let s = PatternField { #[must_use] foo: 123 }; | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a pattern field - --> $DIR/unused_attributes-must_use.rs:130:24 + --> $DIR/unused_attributes-must_use.rs:135:24 | LL | let PatternField { #[must_use] foo } = s; | ^^^^^^^^^^^ @@ -129,6 +129,12 @@ error: `#[must_use]` has no effect when applied to an associated type LL | #[must_use] | ^^^^^^^^^^^ +error: `#[must_use]` has no effect when applied to a provided trait method + --> $DIR/unused_attributes-must_use.rs:83:5 + | +LL | #[must_use] + | ^^^^^^^^^^^ + error: `#[must_use]` has no effect when applied to a foreign static item --> $DIR/unused_attributes-must_use.rs:50:5 | @@ -136,7 +142,7 @@ LL | #[must_use] | ^^^^^^^^^^^ error: unused `X` that must be used - --> $DIR/unused_attributes-must_use.rs:103:5 + --> $DIR/unused_attributes-must_use.rs:108:5 | LL | X; | ^ @@ -152,7 +158,7 @@ LL | let _ = X; | +++++++ error: unused `Y` that must be used - --> $DIR/unused_attributes-must_use.rs:104:5 + --> $DIR/unused_attributes-must_use.rs:109:5 | LL | Y::Z; | ^^^^ @@ -163,7 +169,7 @@ LL | let _ = Y::Z; | +++++++ error: unused `U` that must be used - --> $DIR/unused_attributes-must_use.rs:105:5 + --> $DIR/unused_attributes-must_use.rs:110:5 | LL | U { unit: () }; | ^^^^^^^^^^^^^^ @@ -174,7 +180,7 @@ LL | let _ = U { unit: () }; | +++++++ error: unused return value of `U::method` that must be used - --> $DIR/unused_attributes-must_use.rs:106:5 + --> $DIR/unused_attributes-must_use.rs:111:5 | LL | U::method(); | ^^^^^^^^^^^ @@ -185,7 +191,7 @@ LL | let _ = U::method(); | +++++++ error: unused return value of `foo` that must be used - --> $DIR/unused_attributes-must_use.rs:107:5 + --> $DIR/unused_attributes-must_use.rs:112:5 | LL | foo(); | ^^^^^ @@ -196,7 +202,7 @@ LL | let _ = foo(); | +++++++ error: unused return value of `foreign_foo` that must be used - --> $DIR/unused_attributes-must_use.rs:110:9 + --> $DIR/unused_attributes-must_use.rs:115:9 | LL | foreign_foo(); | ^^^^^^^^^^^^^ @@ -207,7 +213,7 @@ LL | let _ = foreign_foo(); | +++++++ error: unused return value of `Use::get_four` that must be used - --> $DIR/unused_attributes-must_use.rs:118:5 + --> $DIR/unused_attributes-must_use.rs:123:5 | LL | ().get_four(); | ^^^^^^^^^^^^^ @@ -217,5 +223,5 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = ().get_four(); | +++++++ -error: aborting due to 28 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/nll/normalization-bounds-error.stderr b/tests/ui/nll/normalization-bounds-error.stderr index d4254881863..47d2663313d 100644 --- a/tests/ui/nll/normalization-bounds-error.stderr +++ b/tests/ui/nll/normalization-bounds-error.stderr @@ -1,4 +1,4 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements --> $DIR/normalization-bounds-error.rs:12:31 | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} @@ -36,4 +36,4 @@ LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/parser/doc-before-bad-variant.rs b/tests/ui/parser/doc-before-bad-variant.rs new file mode 100644 index 00000000000..bfede28c108 --- /dev/null +++ b/tests/ui/parser/doc-before-bad-variant.rs @@ -0,0 +1,6 @@ +enum TestEnum { + Works, + /// Some documentation + Self, //~ ERROR expected identifier, found keyword `Self` + //~^ HELP enum variants can be +} diff --git a/tests/ui/parser/doc-before-bad-variant.stderr b/tests/ui/parser/doc-before-bad-variant.stderr new file mode 100644 index 00000000000..5e4d4116f25 --- /dev/null +++ b/tests/ui/parser/doc-before-bad-variant.stderr @@ -0,0 +1,13 @@ +error: expected identifier, found keyword `Self` + --> $DIR/doc-before-bad-variant.rs:4:5 + | +LL | enum TestEnum { + | -------- while parsing this enum +... +LL | Self, + | ^^^^ expected identifier, found keyword + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/doc-before-syntax-error.rs b/tests/ui/parser/doc-before-syntax-error.rs new file mode 100644 index 00000000000..435f497d186 --- /dev/null +++ b/tests/ui/parser/doc-before-syntax-error.rs @@ -0,0 +1,2 @@ +/// Some documentation +<> //~ ERROR expected identifier diff --git a/tests/ui/parser/doc-before-syntax-error.stderr b/tests/ui/parser/doc-before-syntax-error.stderr new file mode 100644 index 00000000000..93e39d63000 --- /dev/null +++ b/tests/ui/parser/doc-before-syntax-error.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `<` + --> $DIR/doc-before-syntax-error.rs:2:1 + | +LL | <> + | ^ expected identifier + +error: aborting due to 1 previous error + diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs index daa9b7368fd..b18f87fd569 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs @@ -9,3 +9,10 @@ macro_rules! mixed_edition_pat { Some(mut $foo) }; } + +#[macro_export] +macro_rules! bind_ref { + ($foo:ident) => { + ref $foo + }; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/auxiliary/mixed-editions-macros.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/auxiliary/mixed-editions-macros.rs new file mode 100644 index 00000000000..14d26be91a0 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/auxiliary/mixed-editions-macros.rs @@ -0,0 +1,48 @@ +//@[classic2021] edition: 2024 +//@[structural2021] edition: 2024 +//@[classic2024] edition: 2021 +//@[structural2024] edition: 2021 +//! This contains macros in an edition *different* to the one used in `../mixed-editions.rs`, in +//! order to test typing mixed-edition patterns. + +#[macro_export] +macro_rules! match_ctor { + ($p:pat) => { + [$p] + }; +} + +#[macro_export] +macro_rules! match_ref { + ($p:pat) => { + &$p + }; +} + +#[macro_export] +macro_rules! bind { + ($i:ident) => { + $i + } +} + +#[macro_export] +macro_rules! bind_ref { + ($i:ident) => { + ref $i + } +} + +#[macro_export] +macro_rules! bind_mut { + ($i:ident) => { + mut $i + } +} + +#[macro_export] +macro_rules! bind_ref_mut { + ($i:ident) => { + ref mut $i + } +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr new file mode 100644 index 00000000000..355a8af6760 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr @@ -0,0 +1,37 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-errors.rs:31:29 + | +LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { + | - ^^^^^^^^^^^^^^^^^^^ + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) { +LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:36:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:41:23 + | +LL | if let &Some(Some(x)) = &Some(&mut Some(0)) { + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:46:11 + | +LL | let &[x] = &&mut [0]; + | ^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr index 1c446178308..d40bdb9111b 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr @@ -1,25 +1,25 @@ -error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array - --> $DIR/borrowck-errors.rs:13:16 +error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array + --> $DIR/borrowck-errors.rs:15:16 | LL | let [&x] = &[&mut 0]; | - ^^^^^^^^^ cannot move out of here | | | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | LL | let [&ref x] = &[&mut 0]; | +++ -error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array - --> $DIR/borrowck-errors.rs:19:16 +error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array + --> $DIR/borrowck-errors.rs:22:16 | LL | let [&x] = &mut [&mut 0]; | - ^^^^^^^^^^^^^ cannot move out of here | | | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -27,7 +27,7 @@ LL | let [&ref x] = &mut [&mut 0]; | +++ error[E0507]: cannot move out of a shared reference - --> $DIR/borrowck-errors.rs:27:29 + --> $DIR/borrowck-errors.rs:31:29 | LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ @@ -42,25 +42,25 @@ LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { | error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:32:10 + --> $DIR/borrowck-errors.rs:36:10 | LL | let &ref mut x = &0; | ^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:37:23 + --> $DIR/borrowck-errors.rs:41:23 | LL | if let &Some(Some(x)) = &Some(&mut Some(0)) { | ^ cannot borrow as mutable error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:42:11 + --> $DIR/borrowck-errors.rs:46:11 | LL | let &[x] = &&mut [0]; | ^ cannot borrow as mutable error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array - --> $DIR/borrowck-errors.rs:46:20 + --> $DIR/borrowck-errors.rs:50:20 | LL | let [&mut x] = &mut [&mut 0]; | - ^^^^^^^^^^^^^ cannot move out of here diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs index 59cafc50d86..621ca7cc792 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs @@ -1,11 +1,13 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //! Tests for pattern errors not handled by the pattern typing rules, but by borrowck. #![allow(incomplete_features)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] /// These patterns additionally use `&` to match a `&mut` reference type, which causes compilation /// to fail in HIR typeck on stable. As such, they need to be separate from the other tests. @@ -14,13 +16,15 @@ fn errors_caught_in_hir_typeck_on_stable() { //[stable2021]~^ mismatched types //[stable2021]~| types differ in mutability //[classic2024]~^^^ ERROR: cannot move out of type - let _: &u32 = x; + #[cfg(any(classic2021, structural2021))] let _: u32 = x; + #[cfg(structural2024)] let _: &u32 = x; let [&x] = &mut [&mut 0]; //[stable2021]~^ mismatched types //[stable2021]~| types differ in mutability //[classic2024]~^^^ ERROR: cannot move out of type - let _: &u32 = x; + #[cfg(any(classic2021, structural2021))] let _: u32 = x; + #[cfg(structural2024)] let _: &u32 = x; } pub fn main() { @@ -35,16 +39,16 @@ pub fn main() { // For 2021 edition, this is also a regression test for #136223 // since the maximum mutability is downgraded during the pattern check process. if let &Some(Some(x)) = &Some(&mut Some(0)) { - //[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable - let _: &u32 = x; + //[stable2021,classic2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + #[cfg(any(structural2021, structural2024))] let _: &u32 = x; } let &[x] = &&mut [0]; - //[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable - let _: &u32 = x; + //[stable2021,classic2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + #[cfg(any(structural2021, structural2024))] let _: &u32 = x; let [&mut x] = &mut [&mut 0]; //[classic2024]~^ ERROR: cannot move out of type - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(structural2024)] let _: &mut u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr index deefe21ca7d..edcf9f30357 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/borrowck-errors.rs:13:10 + --> $DIR/borrowck-errors.rs:15:10 | LL | let [&x] = &[&mut 0]; | ^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -15,7 +15,7 @@ LL + let [x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/borrowck-errors.rs:19:10 + --> $DIR/borrowck-errors.rs:22:10 | LL | let [&x] = &mut [&mut 0]; | ^^ ------------- this expression has type `&mut [&mut {integer}; 1]` @@ -31,7 +31,7 @@ LL + let [x] = &mut [&mut 0]; | error[E0507]: cannot move out of a shared reference - --> $DIR/borrowck-errors.rs:27:29 + --> $DIR/borrowck-errors.rs:31:29 | LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ @@ -46,19 +46,19 @@ LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { | error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:32:10 + --> $DIR/borrowck-errors.rs:36:10 | LL | let &ref mut x = &0; | ^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:37:23 + --> $DIR/borrowck-errors.rs:41:23 | LL | if let &Some(Some(x)) = &Some(&mut Some(0)) { | ^ cannot borrow as mutable error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:42:11 + --> $DIR/borrowck-errors.rs:46:11 | LL | let &[x] = &&mut [0]; | ^ cannot borrow as mutable diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr new file mode 100644 index 00000000000..208f6c8bbed --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr @@ -0,0 +1,25 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-errors.rs:31:29 + | +LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { + | - ^^^^^^^^^^^^^^^^^^^ + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) { +LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:36:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr index 30d2f9f3d70..208f6c8bbed 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/borrowck-errors.rs:27:29 + --> $DIR/borrowck-errors.rs:31:29 | LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { | error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:32:10 + --> $DIR/borrowck-errors.rs:36:10 | LL | let &ref mut x = &0; | ^^^^^^^^^ cannot borrow as mutable diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr new file mode 100644 index 00000000000..7e3caaf9797 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr @@ -0,0 +1,103 @@ +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mixed-editions.rs:41:10 + | +LL | let [bind_mut!(y)] = &[0]; + | ^^^^^^^^^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: this error originates in the macro `bind_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:76:21 + | +LL | let match_ref!([x]) = &mut &mut [0]; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:80:22 + | +LL | let &match_ctor!(y) = &mut &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:84:17 + | +LL | let &[bind!(z)] = &mut &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:110:28 + | +LL | let match_ref!(ref mut x) = &mut 0; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:112:24 + | +LL | let &bind_ref_mut!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:116:29 + | +LL | let [match_ref!(ref mut x)] = &mut [0]; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:118:25 + | +LL | let [&bind_ref_mut!(x)] = &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: binding modifiers may only be written when the default binding mode is `move` + --> $DIR/mixed-editions.rs:30:10 + | +LL | let [bind_ref!(y)] = &[0]; + | ^^^^^^^^^^^^ occurs within macro expansion + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +note: matching on a reference type with a non-reference pattern changes the default binding mode + --> $DIR/mixed-editions.rs:30:9 + | +LL | let [bind_ref!(y)] = &[0]; + | ^^^^^^^^^^^^^^ this matches on type `&_` + = note: this error originates in the macro `bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: make the implied reference pattern explicit + | +LL | let &[bind_ref!(y)] = &[0]; + | + + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mixed-editions.rs:61:21 + | +LL | let match_ref!([x]) = &&mut [0]; + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mixed-editions.rs:65:22 + | +LL | let &match_ctor!(y) = &&mut [0]; + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mixed-editions.rs:69:11 + | +LL | let &[bind!(z)] = &&mut [0]; + | ^^^^^^^^ cannot borrow as mutable + | + = note: this error originates in the macro `bind` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0596, E0658. +For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr new file mode 100644 index 00000000000..466993a1671 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr @@ -0,0 +1,97 @@ +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mixed-editions.rs:37:21 + | +LL | let match_ctor!(mut x) = &[0]; + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` 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[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:76:21 + | +LL | let match_ref!([x]) = &mut &mut [0]; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:80:22 + | +LL | let &match_ctor!(y) = &mut &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:84:17 + | +LL | let &[bind!(z)] = &mut &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:110:28 + | +LL | let match_ref!(ref mut x) = &mut 0; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:112:24 + | +LL | let &bind_ref_mut!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:116:29 + | +LL | let [match_ref!(ref mut x)] = &mut [0]; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:118:25 + | +LL | let [&bind_ref_mut!(x)] = &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: binding modifiers may only be written when the default binding mode is `move` + --> $DIR/mixed-editions.rs:26:21 + | +LL | let match_ctor!(ref x) = &[0]; + | ^^^ binding modifier not allowed under `ref` default binding mode + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + --> $DIR/auxiliary/mixed-editions-macros.rs:11:9 + | +LL | &[$p] + | + + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mixed-editions.rs:61:21 + | +LL | let match_ref!([x]) = &&mut [0]; + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mixed-editions.rs:65:22 + | +LL | let &match_ctor!(y) = &&mut [0]; + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mixed-editions.rs:69:11 + | +LL | let &[bind!(z)] = &&mut [0]; + | ^^^^^^^^ cannot borrow as mutable + | + = note: this error originates in the macro `bind` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0596, E0658. +For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs new file mode 100644 index 00000000000..0a22b55ab63 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs @@ -0,0 +1,122 @@ +//@ revisions: classic2021 structural2021 classic2024 structural2024 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//@ aux-build:mixed-editions-macros.rs +//! Tests for typing mixed-edition patterns under the `ref_pat_eat_one_layer_2024` and +//! `ref_pat_eat_one_layer_2024_structural` feature gates. +//! This is meant both to check that patterns are typed with edition-appropriate typing rules and +//! that we keep our internal state consistent when mixing editions. +#![allow(incomplete_features, unused)] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] + +extern crate mixed_editions_macros; +use mixed_editions_macros::*; + +// Tests type equality in a way that avoids coercing `&&T` to `&T`. +trait Eq<T> {} +impl<T> Eq<T> for T {} +fn assert_type_eq<T, U: Eq<T>>(_: T, _: U) {} + +/// Make sure binding with `ref` in the presence of an inherited reference is forbidden when and +/// only when the binding is from edition 2024. +fn ref_binding_tests() { + let match_ctor!(ref x) = &[0]; + //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + #[cfg(any(classic2021, structural2021))] assert_type_eq(x, &0u32); + + let [bind_ref!(y)] = &[0]; + //[classic2021,structural2021]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + #[cfg(any(classic2024, structural2024))] assert_type_eq(y, &0u32); +} + +/// Likewise, when binding with `mut`. +fn mut_binding_tests() { + let match_ctor!(mut x) = &[0]; + //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference + #[cfg(any(classic2021, structural2021))] assert_type_eq(x, 0u32); + + let [bind_mut!(y)] = &[0]; + //[classic2021,structural2021]~^ ERROR: binding cannot be both mutable and by-reference + #[cfg(any(classic2024, structural2024))] assert_type_eq(y, 0u32); +} + +/// Make sure reference patterns correspond to one deref on edition 2024 and two on edition 2021. +fn layers_eaten_tests() { + let match_ctor!(&x) = &[&0]; + #[cfg(any(classic2021, structural2021))] assert_type_eq(x, 0u32); + #[cfg(any(classic2024, structural2024))] assert_type_eq(x, &0u32); + + let [match_ref!(y)] = &[&0]; + #[cfg(any(classic2021, structural2021))] assert_type_eq(y, &0u32); + #[cfg(any(classic2024, structural2024))] assert_type_eq(y, 0u32); +} + +/// Make sure downgrading mutable binding modes inside shared refs ("Rule 3") doesn't break. +/// This only applies to `ref_pat_eat_one_layer_2024_structural`, which has Rule 3 in all editions; +/// under `ref_pat_eat_one_layer_2024`, these should be errors. +fn rule_3_tests() { + let match_ref!([x]) = &&mut [0]; + //[classic2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + #[cfg(any(structural2021, structural2024))] assert_type_eq(x, &0u32); + + let &match_ctor!(y) = &&mut [0]; + //[classic2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + #[cfg(any(structural2021, structural2024))] assert_type_eq(y, &0u32); + + let &[bind!(z)] = &&mut [0]; + //[classic2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + #[cfg(any(structural2021, structural2024))] assert_type_eq(z, &0u32); +} + +/// Test that the interaction between Rules 3 and 5 doesn't break. +fn rules_3_and_5_tests() { + let match_ref!([x]) = &mut &mut [0]; + //[classic2021,classic2024]~^ ERROR: cannot borrow as mutable inside an `&` pattern + #[cfg(any(structural2021, structural2024))] assert_type_eq(x, &0u32); + + let &match_ctor!(y) = &mut &mut [0]; + //[classic2021,classic2024]~^ ERROR: cannot borrow as mutable inside an `&` pattern + #[cfg(any(structural2021, structural2024))] assert_type_eq(y, &0u32); + + let &[bind!(z)] = &mut &mut [0]; + //[classic2021,classic2024]~^ ERROR: cannot borrow as mutable inside an `&` pattern + #[cfg(any(structural2021, structural2024))] assert_type_eq(z, &0u32); +} + +/// Make sure matching a lone shared reference with a `&` ("Rule 4") doesn't break. +fn rule_4_tests() { + let match_ref!([x]) = &[0]; + assert_type_eq(x, 0u32); + + let &match_ctor!(y) = &[0]; + assert_type_eq(y, 0u32); +} + +/// Make sure matching a `&mut` reference with a `&` pattern ("Rule 5") doesn't break. +fn rule_5_tests() { + let match_ref!(x) = &mut 0; + assert_type_eq(x, 0u32); + + // also test inherited references (assumes rule 4) + let [match_ref!(y)] = &mut [0]; + assert_type_eq(y, 0u32); +} + +/// Make sure binding with `ref mut` is an error within a `&` pattern matching a `&mut` reference. +fn rule_5_mutability_error_tests() { + let match_ref!(ref mut x) = &mut 0; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let &bind_ref_mut!(x) = &mut 0; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + + // also test inherited references (assumes rule 4) + let [match_ref!(ref mut x)] = &mut [0]; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let [&bind_ref_mut!(x)] = &mut [0]; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern +} + +fn main() {} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr new file mode 100644 index 00000000000..4075dc9529d --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr @@ -0,0 +1,61 @@ +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mixed-editions.rs:41:10 + | +LL | let [bind_mut!(y)] = &[0]; + | ^^^^^^^^^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: this error originates in the macro `bind_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:110:28 + | +LL | let match_ref!(ref mut x) = &mut 0; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:112:24 + | +LL | let &bind_ref_mut!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:116:29 + | +LL | let [match_ref!(ref mut x)] = &mut [0]; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:118:25 + | +LL | let [&bind_ref_mut!(x)] = &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: binding modifiers may only be written when the default binding mode is `move` + --> $DIR/mixed-editions.rs:30:10 + | +LL | let [bind_ref!(y)] = &[0]; + | ^^^^^^^^^^^^ occurs within macro expansion + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +note: matching on a reference type with a non-reference pattern changes the default binding mode + --> $DIR/mixed-editions.rs:30:9 + | +LL | let [bind_ref!(y)] = &[0]; + | ^^^^^^^^^^^^^^ this matches on type `&_` + = note: this error originates in the macro `bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: make the implied reference pattern explicit + | +LL | let &[bind_ref!(y)] = &[0]; + | + + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0596, E0658. +For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr new file mode 100644 index 00000000000..819a54299ea --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr @@ -0,0 +1,55 @@ +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mixed-editions.rs:37:21 + | +LL | let match_ctor!(mut x) = &[0]; + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` 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[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:110:28 + | +LL | let match_ref!(ref mut x) = &mut 0; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:112:24 + | +LL | let &bind_ref_mut!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:116:29 + | +LL | let [match_ref!(ref mut x)] = &mut [0]; + | ^ + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/mixed-editions.rs:118:25 + | +LL | let [&bind_ref_mut!(x)] = &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: binding modifiers may only be written when the default binding mode is `move` + --> $DIR/mixed-editions.rs:26:21 + | +LL | let match_ctor!(ref x) = &[0]; + | ^^^ binding modifier not allowed under `ref` default binding mode + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + --> $DIR/auxiliary/mixed-editions-macros.rs:11:9 + | +LL | &[$p] + | + + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0596, E0658. +For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr index fa95b2b5a57..6ddced3d168 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr @@ -1,5 +1,5 @@ error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:14:13 + --> $DIR/mut-ref-mut.rs:18:13 | LL | let Foo(mut a) = &Foo(0); | ^^^^ @@ -9,7 +9,7 @@ LL | let Foo(mut a) = &Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:19:13 + --> $DIR/mut-ref-mut.rs:23:13 | LL | let Foo(mut a) = &mut Foo(0); | ^^^^ @@ -19,7 +19,7 @@ LL | let Foo(mut a) = &mut Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0308]: mismatched types - --> $DIR/mut-ref-mut.rs:24:10 + --> $DIR/mut-ref-mut.rs:28:10 | LL | let [&mut mut x] = &[&mut 0]; | ^^^^^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs index fbd6514df73..c8e988ad76d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs @@ -1,29 +1,33 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //@[stable2021] run-pass +//@[classic2021] run-pass +//@[structural2021] run-pass //! Test diagnostics for binding with `mut` when the default binding mode is by-ref. #![allow(incomplete_features, unused_assignments, unused_variables)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { struct Foo(u8); let Foo(mut a) = &Foo(0); //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference - #[cfg(stable2021)] { a = 42 } + #[cfg(any(stable2021, classic2021, structural2021))] { a = 42 } #[cfg(any(classic2024, structural2024))] { a = &42 } let Foo(mut a) = &mut Foo(0); //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference - #[cfg(stable2021)] { a = 42 } + #[cfg(any(stable2021, classic2021, structural2021))] { a = 42 } #[cfg(any(classic2024, structural2024))] { a = &mut 42 } let [&mut mut x] = &[&mut 0]; //[classic2024]~^ ERROR: mismatched types //[classic2024]~| cannot match inherited `&` with `&mut` pattern //[structural2024]~^^^ binding cannot be both mutable and by-reference - #[cfg(stable2021)] { x = 0 } + #[cfg(any(stable2021, classic2021, structural2021))] { x = 0 } } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr index fd82da70a18..c0c0f966b68 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr @@ -1,5 +1,5 @@ error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:14:13 + --> $DIR/mut-ref-mut.rs:18:13 | LL | let Foo(mut a) = &Foo(0); | ^^^^ @@ -9,7 +9,7 @@ LL | let Foo(mut a) = &Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:19:13 + --> $DIR/mut-ref-mut.rs:23:13 | LL | let Foo(mut a) = &mut Foo(0); | ^^^^ @@ -19,7 +19,7 @@ LL | let Foo(mut a) = &mut Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:24:15 + --> $DIR/mut-ref-mut.rs:28:15 | LL | let [&mut mut x] = &[&mut 0]; | ^^^^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2021.stderr new file mode 100644 index 00000000000..a856a0eaf2a --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2021.stderr @@ -0,0 +1,219 @@ +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:20:27 + | +LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { + | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { +LL + if let Some(&mut Some(x)) = &Some(&mut Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:33:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected reference `&Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:38:23 + | +LL | if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { + | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-errors.rs:38:23 + | +LL | if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { +LL + if let Some(&Some(x)) = &Some(&mut Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:45:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:56:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - if let Some(&mut Some(x)) = &Some(Some(0)) { +LL + if let Some(&Some(x)) = &Some(Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:114:11 + | +LL | let [&&mut x] = &[&mut 0]; + | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut x] = &[&mut 0]; +LL + let [&x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:121:11 + | +LL | let [&&mut x] = &mut [&mut 0]; + | ^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut x] = &mut [&mut 0]; +LL + let [&x] = &mut [&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:128:11 + | +LL | let [&&mut ref x] = &[&mut 0]; + | ^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut ref x] = &[&mut 0]; +LL + let [&ref x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:135:11 + | +LL | let [&&mut ref x] = &mut [&mut 0]; + | ^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut ref x] = &mut [&mut 0]; +LL + let [&ref x] = &mut [&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:142:11 + | +LL | let [&&mut mut x] = &[&mut 0]; + | ^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut mut x] = &[&mut 0]; +LL + let [&mut x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:149:11 + | +LL | let [&&mut mut x] = &mut [&mut 0]; + | ^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut mut x] = &mut [&mut 0]; +LL + let [&mut x] = &mut [&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:164:15 + | +LL | let [&mut &x] = &[&mut 0]; + | ^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &x] = &[&mut 0]; +LL + let [&mut x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:170:15 + | +LL | let [&mut &ref x] = &[&mut 0]; + | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &ref x] = &[&mut 0]; +LL + let [&mut ref x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:176:15 + | +LL | let [&mut &(mut x)] = &[&mut 0]; + | ^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &(mut x)] = &[&mut 0]; +LL + let [&mut mut x)] = &[&mut 0]; + | + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr index 6726a726315..90510d23e66 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:12:17 + --> $DIR/pattern-errors.rs:14:17 | LL | if let Some(&mut x) = &Some(&mut 0) { | ^^^^^ @@ -12,7 +12,7 @@ LL + if let Some(&x) = &Some(&mut 0) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:18:17 + --> $DIR/pattern-errors.rs:20:17 | LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { | ^^^^^ @@ -25,7 +25,7 @@ LL + if let Some(&Some(&x)) = &Some(&mut Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:24:22 + --> $DIR/pattern-errors.rs:26:22 | LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { | ^^^^^ @@ -38,7 +38,7 @@ LL + if let Some(Some(&x)) = &Some(Some(&mut 0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:31:17 + --> $DIR/pattern-errors.rs:33:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { | ^^^^^ @@ -51,7 +51,7 @@ LL + if let Some(&Some(&_)) = &Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:41:23 + --> $DIR/pattern-errors.rs:45:23 | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { | ^^^^^ @@ -64,7 +64,7 @@ LL + if let Some(&Some(&_)) = &mut Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:51:17 + --> $DIR/pattern-errors.rs:56:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { | ^^^^^ @@ -77,7 +77,7 @@ LL + if let Some(&Some(x)) = &Some(Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:147:10 + --> $DIR/pattern-errors.rs:158:10 | LL | let [&mut x] = &[&mut 0]; | ^^^^^ @@ -90,7 +90,7 @@ LL + let [&x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:153:10 + --> $DIR/pattern-errors.rs:164:10 | LL | let [&mut &x] = &[&mut 0]; | ^^^^^ @@ -103,7 +103,7 @@ LL + let [&&x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:159:10 + --> $DIR/pattern-errors.rs:170:10 | LL | let [&mut &ref x] = &[&mut 0]; | ^^^^^ @@ -116,7 +116,7 @@ LL + let [&&ref x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:165:10 + --> $DIR/pattern-errors.rs:176:10 | LL | let [&mut &(mut x)] = &[&mut 0]; | ^^^^^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs index c07c2972cd0..5e677445644 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs @@ -1,170 +1,181 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //! Test cases for poorly-typed patterns in edition 2024 which are caught by HIR typeck. These must //! be separate from cases caught by MIR borrowck or the latter errors may not be emitted. #![allow(incomplete_features)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&mut x) = &Some(&mut 0) { //[classic2024]~^ ERROR: mismatched types //[classic2024]~| cannot match inherited `&` with `&mut` pattern - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(structural2024)] let _: &u32 = x; } if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { - //[stable2021,classic2024]~^ ERROR: mismatched types - //[stable2021]~| expected integer, found `&_` + //[stable2021,classic2021,structural2021,classic2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021]~| expected integer, found `&_` //[classic2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(structural2024)] let _: u32 = x; } if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { //[classic2024]~^ ERROR: mismatched types //[classic2024]~| cannot match inherited `&` with `&mut` pattern - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(structural2024)] let _: &u32 = x; } if let Some(&mut Some(&_)) = &Some(&Some(0)) { //~^ ERROR: mismatched types - //[stable2021]~| types differ in mutability + //[stable2021,classic2021,structural2021]~| types differ in mutability //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern } - if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - //[stable2021,structural2024]~^ ERROR: mismatched types + if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021]~| expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(classic2024)] let _: u32 = x; } if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { //~^ ERROR: mismatched types - //[stable2021]~| expected integer, found `&mut _` + //[stable2021,classic2021,structural2021]~| expected integer, found `&mut _` //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern } - if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { - //[stable2021,structural2024]~^ ERROR: mismatched types + if let Some(&Some(Some(&mut x))) = &Some(Some(&mut Some(0))) { + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_` - //[structural2024]~| cannot match inherited `&` with `&mut` pattern + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: u32 = x; } if let Some(&mut Some(x)) = &Some(Some(0)) { //~^ ERROR: mismatched types //[stable2021]~| expected `Option<{integer}>`, found `&mut _` - //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern + //[classic2021,structural2021,classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern } } fn structural_errors_0() { let &[&mut x] = &&mut [0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| expected integer, found `&mut _` - //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: u32 = x; let &[&mut x] = &mut &mut [0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability - //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: u32 = x; let &[&mut ref x] = &&mut [0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| expected integer, found `&mut _` - //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: &u32 = x; + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: &u32 = x; let &[&mut ref x] = &mut &mut [0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability - //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: &u32 = x; + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: &u32 = x; let &[&mut mut x] = &&mut [0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| expected integer, found `&mut _` - //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: u32 = x; let &[&mut mut x] = &mut &mut [0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability - //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + //[structural2021,structural2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(any(classic2021, classic2024))] let _: u32 = x; } fn structural_errors_1() { let [&(mut x)] = &[&0]; //[structural2024]~^ ERROR: binding cannot be both mutable and by-reference - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(classic2024)] let _: &u32 = x; let [&(mut x)] = &mut [&0]; //[structural2024]~^ ERROR: binding cannot be both mutable and by-reference - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(classic2024)] let _: &u32 = x; } fn structural_errors_2() { let [&&mut x] = &[&mut 0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021] expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(classic2024)] let _: u32 = x; let [&&mut x] = &mut [&mut 0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021] expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(classic2024)] let _: u32 = x; let [&&mut ref x] = &[&mut 0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021] expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: &u32 = x; + #[cfg(classic2024)] let _: &u32 = x; let [&&mut ref x] = &mut [&mut 0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021] expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: &u32 = x; + #[cfg(classic2024)] let _: &u32 = x; let [&&mut mut x] = &[&mut 0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021] expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(classic2024)] let _: u32 = x; let [&&mut mut x] = &mut [&mut 0]; - //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,structural2024]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability + //[classic2021,structural2021] expected integer, found `&mut _` //[structural2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(classic2024)] let _: u32 = x; } fn classic_errors_0() { let [&mut x] = &[&mut 0]; //[classic2024]~^ ERROR: mismatched types //[classic2024]~| cannot match inherited `&` with `&mut` pattern - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(structural2024)] let _: &u32 = x; let [&mut &x] = &[&mut 0]; - //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,classic2024]~^ ERROR: mismatched types //[stable2021]~| expected integer, found `&_` //[classic2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(structural2024)] let _: u32 = x; let [&mut &ref x] = &[&mut 0]; - //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,classic2024]~^ ERROR: mismatched types //[stable2021]~| expected integer, found `&_` //[classic2024]~| cannot match inherited `&` with `&mut` pattern - let _: &u32 = x; + #[cfg(structural2024)] let _: &u32 = x; let [&mut &(mut x)] = &[&mut 0]; - //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021,classic2021,structural2021,classic2024]~^ ERROR: mismatched types //[stable2021]~| expected integer, found `&_` //[classic2024]~| cannot match inherited `&` with `&mut` pattern - let _: u32 = x; + #[cfg(structural2024)] let _: u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr index ad19b122c20..76e6d2f562a 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:18:27 + --> $DIR/pattern-errors.rs:20:27 | LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` @@ -15,7 +15,7 @@ LL + if let Some(&mut Some(x)) = &Some(&mut Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:31:17 + --> $DIR/pattern-errors.rs:33:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -26,9 +26,9 @@ LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:36:17 + --> $DIR/pattern-errors.rs:38:17 | -LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { +LL | if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { | ^^^^^^^^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` | | | types differ in mutability @@ -37,7 +37,7 @@ LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:41:23 + --> $DIR/pattern-errors.rs:45:23 | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` @@ -48,9 +48,9 @@ LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:46:17 + --> $DIR/pattern-errors.rs:50:17 | -LL | if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { +LL | if let Some(&Some(Some(&mut x))) = &Some(Some(&mut Some(0))) { | ^^^^^^^^^^^^^^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>` | | | expected `Option<&mut Option<{integer}>>`, found `&_` @@ -59,7 +59,7 @@ LL | if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:51:17 + --> $DIR/pattern-errors.rs:56:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { | ^^^^^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` @@ -70,7 +70,7 @@ LL | if let Some(&mut Some(x)) = &Some(Some(0)) { found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:59:11 + --> $DIR/pattern-errors.rs:64:11 | LL | let &[&mut x] = &&mut [0]; | ^^^^^^ --------- this expression has type `&&mut [{integer}; 1]` @@ -80,7 +80,7 @@ LL | let &[&mut x] = &&mut [0]; = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/pattern-errors.rs:59:11 + --> $DIR/pattern-errors.rs:64:11 | LL | let &[&mut x] = &&mut [0]; | ^^^^^^ @@ -91,7 +91,7 @@ LL + let &[x] = &&mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:65:9 + --> $DIR/pattern-errors.rs:70:9 | LL | let &[&mut x] = &mut &mut [0]; | ^^^^^^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` @@ -102,7 +102,7 @@ LL | let &[&mut x] = &mut &mut [0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:71:11 + --> $DIR/pattern-errors.rs:76:11 | LL | let &[&mut ref x] = &&mut [0]; | ^^^^^^^^^^ --------- this expression has type `&&mut [{integer}; 1]` @@ -112,7 +112,7 @@ LL | let &[&mut ref x] = &&mut [0]; = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/pattern-errors.rs:71:11 + --> $DIR/pattern-errors.rs:76:11 | LL | let &[&mut ref x] = &&mut [0]; | ^^^^^^^^^^ @@ -123,7 +123,7 @@ LL + let &[ref x] = &&mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:77:9 + --> $DIR/pattern-errors.rs:82:9 | LL | let &[&mut ref x] = &mut &mut [0]; | ^^^^^^^^^^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` @@ -134,7 +134,7 @@ LL | let &[&mut ref x] = &mut &mut [0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:83:11 + --> $DIR/pattern-errors.rs:88:11 | LL | let &[&mut mut x] = &&mut [0]; | ^^^^^^^^^^ --------- this expression has type `&&mut [{integer}; 1]` @@ -144,7 +144,7 @@ LL | let &[&mut mut x] = &&mut [0]; = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/pattern-errors.rs:83:11 + --> $DIR/pattern-errors.rs:88:11 | LL | let &[&mut mut x] = &&mut [0]; | ^^^^^^^^^^ @@ -155,7 +155,7 @@ LL + let &[mut x] = &&mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:89:9 + --> $DIR/pattern-errors.rs:94:9 | LL | let &[&mut mut x] = &mut &mut [0]; | ^^^^^^^^^^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` @@ -166,7 +166,7 @@ LL | let &[&mut mut x] = &mut &mut [0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:109:10 + --> $DIR/pattern-errors.rs:114:10 | LL | let [&&mut x] = &[&mut 0]; | ^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -177,7 +177,7 @@ LL | let [&&mut x] = &[&mut 0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:115:10 + --> $DIR/pattern-errors.rs:121:10 | LL | let [&&mut x] = &mut [&mut 0]; | ^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` @@ -188,7 +188,7 @@ LL | let [&&mut x] = &mut [&mut 0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:121:10 + --> $DIR/pattern-errors.rs:128:10 | LL | let [&&mut ref x] = &[&mut 0]; | ^^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -199,7 +199,7 @@ LL | let [&&mut ref x] = &[&mut 0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:127:10 + --> $DIR/pattern-errors.rs:135:10 | LL | let [&&mut ref x] = &mut [&mut 0]; | ^^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` @@ -210,7 +210,7 @@ LL | let [&&mut ref x] = &mut [&mut 0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:133:10 + --> $DIR/pattern-errors.rs:142:10 | LL | let [&&mut mut x] = &[&mut 0]; | ^^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -221,7 +221,7 @@ LL | let [&&mut mut x] = &[&mut 0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:139:10 + --> $DIR/pattern-errors.rs:149:10 | LL | let [&&mut mut x] = &mut [&mut 0]; | ^^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` @@ -232,7 +232,7 @@ LL | let [&&mut mut x] = &mut [&mut 0]; found reference `&_` error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:153:15 + --> $DIR/pattern-errors.rs:164:15 | LL | let [&mut &x] = &[&mut 0]; | ^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -248,7 +248,7 @@ LL + let [&mut x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:159:15 + --> $DIR/pattern-errors.rs:170:15 | LL | let [&mut &ref x] = &[&mut 0]; | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -264,7 +264,7 @@ LL + let [&mut ref x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:165:15 + --> $DIR/pattern-errors.rs:176:15 | LL | let [&mut &(mut x)] = &[&mut 0]; | ^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2021.stderr new file mode 100644 index 00000000000..1ca6bff3f38 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2021.stderr @@ -0,0 +1,310 @@ +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:20:27 + | +LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { + | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { +LL + if let Some(&mut Some(x)) = &Some(&mut Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:33:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected reference `&Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:38:23 + | +LL | if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { + | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-errors.rs:38:23 + | +LL | if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { +LL + if let Some(&Some(x)) = &Some(&mut Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:45:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:50:28 + | +LL | if let Some(&Some(Some(&mut x))) = &Some(Some(&mut Some(0))) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - if let Some(&Some(Some(&mut x))) = &Some(Some(&mut Some(0))) { +LL + if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:56:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - if let Some(&mut Some(x)) = &Some(Some(0)) { +LL + if let Some(&Some(x)) = &Some(Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:64:11 + | +LL | let &[&mut x] = &&mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - let &[&mut x] = &&mut [0]; +LL + let &[&x] = &&mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:70:11 + | +LL | let &[&mut x] = &mut &mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - let &[&mut x] = &mut &mut [0]; +LL + let &[&x] = &mut &mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:76:11 + | +LL | let &[&mut ref x] = &&mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - let &[&mut ref x] = &&mut [0]; +LL + let &[&ref x] = &&mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:82:11 + | +LL | let &[&mut ref x] = &mut &mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - let &[&mut ref x] = &mut &mut [0]; +LL + let &[&ref x] = &mut &mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:88:11 + | +LL | let &[&mut mut x] = &&mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - let &[&mut mut x] = &&mut [0]; +LL + let &[&mut x] = &&mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:94:11 + | +LL | let &[&mut mut x] = &mut &mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL - let &[&mut mut x] = &mut &mut [0]; +LL + let &[&mut x] = &mut &mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:114:11 + | +LL | let [&&mut x] = &[&mut 0]; + | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut x] = &[&mut 0]; +LL + let [&x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:121:11 + | +LL | let [&&mut x] = &mut [&mut 0]; + | ^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut x] = &mut [&mut 0]; +LL + let [&x] = &mut [&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:128:11 + | +LL | let [&&mut ref x] = &[&mut 0]; + | ^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut ref x] = &[&mut 0]; +LL + let [&ref x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:135:11 + | +LL | let [&&mut ref x] = &mut [&mut 0]; + | ^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut ref x] = &mut [&mut 0]; +LL + let [&ref x] = &mut [&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:142:11 + | +LL | let [&&mut mut x] = &[&mut 0]; + | ^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut mut x] = &[&mut 0]; +LL + let [&mut x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:149:11 + | +LL | let [&&mut mut x] = &mut [&mut 0]; + | ^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +help: consider removing `&mut` from the pattern + | +LL - let [&&mut mut x] = &mut [&mut 0]; +LL + let [&mut x] = &mut [&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:164:15 + | +LL | let [&mut &x] = &[&mut 0]; + | ^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &x] = &[&mut 0]; +LL + let [&mut x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:170:15 + | +LL | let [&mut &ref x] = &[&mut 0]; + | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &ref x] = &[&mut 0]; +LL + let [&mut ref x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:176:15 + | +LL | let [&mut &(mut x)] = &[&mut 0]; + | ^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &(mut x)] = &[&mut 0]; +LL + let [&mut mut x)] = &[&mut 0]; + | + +error: aborting due to 21 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr index fdf48a5a71b..3658893df9c 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:31:17 + --> $DIR/pattern-errors.rs:33:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { | ^^^^^ @@ -12,20 +12,20 @@ LL + if let Some(&Some(&_)) = &Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:36:23 + --> $DIR/pattern-errors.rs:38:23 | -LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { +LL | if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL - if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { -LL + if let Some(&Some(&_)) = &Some(&mut Some(0)) { +LL - if let Some(&Some(&mut x)) = &Some(&mut Some(0)) { +LL + if let Some(&Some(&x)) = &Some(&mut Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:41:23 + --> $DIR/pattern-errors.rs:45:23 | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { | ^^^^^ @@ -38,20 +38,20 @@ LL + if let Some(&Some(&_)) = &mut Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:46:28 + --> $DIR/pattern-errors.rs:50:28 | -LL | if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { +LL | if let Some(&Some(Some(&mut x))) = &Some(Some(&mut Some(0))) { | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL - if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { -LL + if let Some(&Some(Some(&_))) = &Some(Some(&mut Some(0))) { +LL - if let Some(&Some(Some(&mut x))) = &Some(Some(&mut Some(0))) { +LL + if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:51:17 + --> $DIR/pattern-errors.rs:56:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { | ^^^^^ @@ -64,7 +64,7 @@ LL + if let Some(&Some(x)) = &Some(Some(0)) { | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:59:11 + --> $DIR/pattern-errors.rs:64:11 | LL | let &[&mut x] = &&mut [0]; | ^^^^^ @@ -77,7 +77,7 @@ LL + let &[&x] = &&mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:65:11 + --> $DIR/pattern-errors.rs:70:11 | LL | let &[&mut x] = &mut &mut [0]; | ^^^^^ @@ -90,7 +90,7 @@ LL + let &[&x] = &mut &mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:71:11 + --> $DIR/pattern-errors.rs:76:11 | LL | let &[&mut ref x] = &&mut [0]; | ^^^^^ @@ -103,7 +103,7 @@ LL + let &[&ref x] = &&mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:77:11 + --> $DIR/pattern-errors.rs:82:11 | LL | let &[&mut ref x] = &mut &mut [0]; | ^^^^^ @@ -116,7 +116,7 @@ LL + let &[&ref x] = &mut &mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:83:11 + --> $DIR/pattern-errors.rs:88:11 | LL | let &[&mut mut x] = &&mut [0]; | ^^^^^ @@ -129,7 +129,7 @@ LL + let &[&mut x] = &&mut [0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:89:11 + --> $DIR/pattern-errors.rs:94:11 | LL | let &[&mut mut x] = &mut &mut [0]; | ^^^^^ @@ -142,7 +142,7 @@ LL + let &[&mut x] = &mut &mut [0]; | error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/pattern-errors.rs:97:12 + --> $DIR/pattern-errors.rs:102:12 | LL | let [&(mut x)] = &[&0]; | ^^^^ @@ -152,7 +152,7 @@ LL | let [&(mut x)] = &[&0]; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/pattern-errors.rs:102:12 + --> $DIR/pattern-errors.rs:107:12 | LL | let [&(mut x)] = &mut [&0]; | ^^^^ @@ -162,7 +162,7 @@ LL | let [&(mut x)] = &mut [&0]; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:109:11 + --> $DIR/pattern-errors.rs:114:11 | LL | let [&&mut x] = &[&mut 0]; | ^^^^^ @@ -175,7 +175,7 @@ LL + let [&&x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:115:11 + --> $DIR/pattern-errors.rs:121:11 | LL | let [&&mut x] = &mut [&mut 0]; | ^^^^^ @@ -188,7 +188,7 @@ LL + let [&&x] = &mut [&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:121:11 + --> $DIR/pattern-errors.rs:128:11 | LL | let [&&mut ref x] = &[&mut 0]; | ^^^^^ @@ -201,7 +201,7 @@ LL + let [&&ref x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:127:11 + --> $DIR/pattern-errors.rs:135:11 | LL | let [&&mut ref x] = &mut [&mut 0]; | ^^^^^ @@ -214,7 +214,7 @@ LL + let [&&ref x] = &mut [&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:133:11 + --> $DIR/pattern-errors.rs:142:11 | LL | let [&&mut mut x] = &[&mut 0]; | ^^^^^ @@ -227,7 +227,7 @@ LL + let [&&mut x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:139:11 + --> $DIR/pattern-errors.rs:149:11 | LL | let [&&mut mut x] = &mut [&mut 0]; | ^^^^^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2021.stderr new file mode 100644 index 00000000000..1dda2dca4a4 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2021.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr index 56125be2d6f..44cb005a748 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/ref-binding-on-inh-ref-errors.rs:54:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:58:10 | LL | let [&mut ref x] = &[&mut 0]; | ^^^^^ @@ -12,14 +12,14 @@ LL + let [&ref x] = &[&mut 0]; | error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 | LL | let [ref mut x] = &[0]; | ^^^^^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:9 | LL | let [ref mut x] = &[0]; | ^^^^^^^^^^^ this matches on type `&_` @@ -29,20 +29,20 @@ LL | let &[ref mut x] = &[0]; | + error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 | LL | let [ref mut x] = &[0]; | ^^^^^^^^^ cannot borrow as mutable error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:75:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:79:10 | LL | let [ref x] = &[0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:75:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:79:9 | LL | let [ref x] = &[0]; | ^^^^^^^ this matches on type `&_` @@ -52,14 +52,14 @@ LL | let &[ref x] = &[0]; | + error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:79:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10 | LL | let [ref x] = &mut [0]; | ^^^ binding modifier not allowed under `ref mut` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:79:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:83:9 | LL | let [ref x] = &mut [0]; | ^^^^^^^ this matches on type `&mut _` @@ -69,14 +69,14 @@ LL | let &mut [ref x] = &mut [0]; | ++++ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:87:10 | LL | let [ref mut x] = &mut [0]; | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:83:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:87:9 | LL | let [ref mut x] = &mut [0]; | ^^^^^^^^^^^ this matches on type `&mut _` diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs index 4e048570c33..ea6f028fe4b 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs @@ -1,35 +1,37 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //! Tests for errors from binding with `ref x` under a by-ref default binding mode in edition 2024. //! These can't be in the same body as tests for other errors, since they're emitted during THIR //! construction. The errors on stable edition 2021 Rust are unrelated. #![allow(incomplete_features)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] /// These only fail on the eat-inner variant of the new edition 2024 pattern typing rules. /// The eat-outer variant eats the inherited reference, so binding with `ref` isn't a problem. fn errors_from_eating_the_real_reference() { let [&ref x] = &[&0]; //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&u32 = x; let [&ref x] = &mut [&0]; //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&u32 = x; let [&mut ref x] = &mut [&mut 0]; //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&mut u32 = x; let [&mut ref mut x] = &mut [&mut 0]; //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &mut u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &mut u32 = x; #[cfg(classic2024)] let _: &mut &mut u32 = x; } @@ -40,12 +42,14 @@ fn errors_from_eating_the_real_reference_caught_in_hir_typeck_on_stable() { //[stable2021]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move` + #[cfg(any(classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&mut u32 = x; let [&ref x] = &mut [&mut 0]; //[stable2021]~^ ERROR: mismatched types //[stable2021]~| types differ in mutability //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move` + #[cfg(any(classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&mut u32 = x; } @@ -55,7 +59,7 @@ fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() { //[classic2024]~^ ERROR: mismatched types //[classic2024]~| cannot match inherited `&` with `&mut` pattern //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; } /// These should be errors in all editions. In edition 2024, they should be caught by the pattern @@ -74,13 +78,13 @@ fn borrowck_errors_in_old_editions() { pub fn main() { let [ref x] = &[0]; //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; let [ref x] = &mut [0]; //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; let [ref mut x] = &mut [0]; //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` - #[cfg(stable2021)] let _: &mut u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: &mut u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr index 26095d84605..2ec6650dd7d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/ref-binding-on-inh-ref-errors.rs:39:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:41:10 | LL | let [&ref x] = &[&mut 0]; | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` @@ -15,7 +15,7 @@ LL + let [ref x] = &[&mut 0]; | error[E0308]: mismatched types - --> $DIR/ref-binding-on-inh-ref-errors.rs:45:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:48:10 | LL | let [&ref x] = &mut [&mut 0]; | ^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` @@ -31,7 +31,7 @@ LL + let [ref x] = &mut [&mut 0]; | error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 | LL | let [ref mut x] = &[0]; | ^^^^^^^^^ cannot borrow as mutable diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2021.stderr new file mode 100644 index 00000000000..1dda2dca4a4 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2021.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr index 31930e8c033..6f62ad06cc4 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr @@ -1,12 +1,12 @@ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:15:11 + --> $DIR/ref-binding-on-inh-ref-errors.rs:17:11 | LL | let [&ref x] = &[&0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:15:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:17:9 | LL | let [&ref x] = &[&0]; | ^^^^^^^^ this matches on type `&_` @@ -16,14 +16,14 @@ LL | let &[&ref x] = &[&0]; | + error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:20:11 + --> $DIR/ref-binding-on-inh-ref-errors.rs:22:11 | LL | let [&ref x] = &mut [&0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:20:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:22:9 | LL | let [&ref x] = &mut [&0]; | ^^^^^^^^ this matches on type `&mut _` @@ -33,14 +33,14 @@ LL | let &mut [&ref x] = &mut [&0]; | ++++ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:25:15 + --> $DIR/ref-binding-on-inh-ref-errors.rs:27:15 | LL | let [&mut ref x] = &mut [&mut 0]; | ^^^ binding modifier not allowed under `ref mut` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:25:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:27:9 | LL | let [&mut ref x] = &mut [&mut 0]; | ^^^^^^^^^^^^ this matches on type `&mut _` @@ -50,14 +50,14 @@ LL | let &mut [&mut ref x] = &mut [&mut 0]; | ++++ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:30:15 + --> $DIR/ref-binding-on-inh-ref-errors.rs:32:15 | LL | let [&mut ref mut x] = &mut [&mut 0]; | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:30:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:32:9 | LL | let [&mut ref mut x] = &mut [&mut 0]; | ^^^^^^^^^^^^^^^^ this matches on type `&mut _` @@ -67,14 +67,14 @@ LL | let &mut [&mut ref mut x] = &mut [&mut 0]; | ++++ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:39:11 + --> $DIR/ref-binding-on-inh-ref-errors.rs:41:11 | LL | let [&ref x] = &[&mut 0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:39:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:41:9 | LL | let [&ref x] = &[&mut 0]; | ^^^^^^^^ this matches on type `&_` @@ -84,14 +84,14 @@ LL | let &[&ref x] = &[&mut 0]; | + error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:45:11 + --> $DIR/ref-binding-on-inh-ref-errors.rs:48:11 | LL | let [&ref x] = &mut [&mut 0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:45:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:48:9 | LL | let [&ref x] = &mut [&mut 0]; | ^^^^^^^^ this matches on type `&mut _` @@ -101,14 +101,14 @@ LL | let &mut [&ref x] = &mut [&mut 0]; | ++++ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:54:15 + --> $DIR/ref-binding-on-inh-ref-errors.rs:58:15 | LL | let [&mut ref x] = &[&mut 0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:54:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:58:9 | LL | let [&mut ref x] = &[&mut 0]; | ^^^^^^^^^^^^ this matches on type `&_` @@ -118,14 +118,14 @@ LL | let &[&mut ref x] = &[&mut 0]; | + error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 | LL | let [ref mut x] = &[0]; | ^^^^^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:9 | LL | let [ref mut x] = &[0]; | ^^^^^^^^^^^ this matches on type `&_` @@ -135,20 +135,20 @@ LL | let &[ref mut x] = &[0]; | + error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:71:10 | LL | let [ref mut x] = &[0]; | ^^^^^^^^^ cannot borrow as mutable error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:75:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:79:10 | LL | let [ref x] = &[0]; | ^^^ binding modifier not allowed under `ref` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:75:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:79:9 | LL | let [ref x] = &[0]; | ^^^^^^^ this matches on type `&_` @@ -158,14 +158,14 @@ LL | let &[ref x] = &[0]; | + error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:79:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10 | LL | let [ref x] = &mut [0]; | ^^^ binding modifier not allowed under `ref mut` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:79:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:83:9 | LL | let [ref x] = &mut [0]; | ^^^^^^^ this matches on type `&mut _` @@ -175,14 +175,14 @@ LL | let &mut [ref x] = &mut [0]; | ++++ error: binding modifiers may only be written when the default binding mode is `move` - --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10 + --> $DIR/ref-binding-on-inh-ref-errors.rs:87:10 | LL | let [ref mut x] = &mut [0]; | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode | = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> note: matching on a reference type with a non-reference pattern changes the default binding mode - --> $DIR/ref-binding-on-inh-ref-errors.rs:83:9 + --> $DIR/ref-binding-on-inh-ref-errors.rs:87:9 | LL | let [ref mut x] = &mut [0]; | ^^^^^^^^^^^ this matches on type `&mut _` diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2021.stderr new file mode 100644 index 00000000000..8127ca92e02 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2021.stderr @@ -0,0 +1,51 @@ +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 + | +LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:22:31 + | +LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:31:15 + | +LL | let &pat!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:19 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:30 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:43:11 + | +LL | let &[x] = &mut &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed index c01784d5076..57de9cb4c10 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed @@ -1,5 +1,7 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //@[classic2024] run-rustfix @@ -7,19 +9,19 @@ //! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts //! to bind by mutable reference. #![allow(incomplete_features)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } @@ -28,18 +30,18 @@ pub fn main() { } let &mut pat!(x) = &mut 0; //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; let &mut (ref mut a, ref mut b) = &mut (true, false); //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern - //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut bool = a; let _: &mut bool = b; let &mut [x] = &mut &mut [0]; //[stable2021]~^ ERROR: mismatched types - //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr index 5e98b77be40..8127ca92e02 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -7,7 +7,7 @@ LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:22:31 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -15,7 +15,7 @@ LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:15 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:31:15 | LL | let &pat!(x) = &mut 0; | - ^ @@ -23,7 +23,7 @@ LL | let &pat!(x) = &mut 0; | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:19 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:19 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ @@ -31,7 +31,7 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:30 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:30 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ @@ -39,7 +39,7 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:41:11 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:43:11 | LL | let &[x] = &mut &mut [0]; | - ^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs index fe40dabb553..277ff90b673 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs @@ -1,5 +1,7 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //@[classic2024] run-rustfix @@ -7,19 +9,19 @@ //! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts //! to bind by mutable reference. #![allow(incomplete_features)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } @@ -28,18 +30,18 @@ pub fn main() { } let &pat!(x) = &mut 0; //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; let &(ref mut a, ref mut b) = &mut (true, false); //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern - //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut bool = a; let _: &mut bool = b; let &[x] = &mut &mut [0]; //[stable2021]~^ ERROR: mismatched types - //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr index 72c6c05e184..5fbaacd7281 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:17 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:17 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | ^^^^^^^^^^^^^^^^ ------------------ this expression has type `&mut Option<Option<{integer}>>` @@ -10,7 +10,7 @@ LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:12 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:22:12 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | ^^^^^^^^^^^^^^^^^^^^^^ ------------------ this expression has type `&mut Option<Option<{integer}>>` @@ -21,7 +21,7 @@ LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:9 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:31:9 | LL | let &pat!(x) = &mut 0; | ^^^^^^^^ ------ this expression has type `&mut {integer}` @@ -32,7 +32,7 @@ LL | let &pat!(x) = &mut 0; found reference `&_` error[E0308]: mismatched types - --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:9 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:9 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | ^^^^^^^^^^^^^^^^^^^^^^^ ------------------ this expression has type `&mut (bool, bool)` @@ -43,7 +43,7 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); found reference `&_` error[E0308]: mismatched types - --> $DIR/ref-mut-inside-shared-ref-pat.rs:41:9 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:43:9 | LL | let &[x] = &mut &mut [0]; | ^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2021.stderr new file mode 100644 index 00000000000..e735cfed249 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2021.stderr @@ -0,0 +1,43 @@ +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 + | +LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:22:31 + | +LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:31:15 + | +LL | let &pat!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:19 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:30 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed index 4ee849b38c5..bcde4b90f59 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed @@ -1,5 +1,7 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //@[classic2024] run-rustfix @@ -7,19 +9,19 @@ //! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts //! to bind by mutable reference. #![allow(incomplete_features)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } @@ -28,18 +30,18 @@ pub fn main() { } let &mut pat!(x) = &mut 0; //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; let &mut (ref mut a, ref mut b) = &mut (true, false); //[stable2021]~^ ERROR: mismatched types - //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern - //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,structural2021,classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut bool = a; let _: &mut bool = b; let &[x] = &mut &mut [0]; //[stable2021]~^ ERROR: mismatched types - //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2021,classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr index 69cb6c438b6..e735cfed249 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -7,7 +7,7 @@ LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:22:31 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -15,7 +15,7 @@ LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:15 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:31:15 | LL | let &pat!(x) = &mut 0; | - ^ @@ -23,7 +23,7 @@ LL | let &pat!(x) = &mut 0; | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:19 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:19 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ @@ -31,7 +31,7 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:30 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:36:30 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs deleted file mode 100644 index ab3264704ac..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass -//@ edition: 2021 -//@ revisions: classic structural -#![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] - -pub fn main() { - #[cfg(structural)] - if let &Some(Some(x)) = &Some(&mut Some(0)) { - let _: &u32 = x; - } - - if let Some(&x) = Some(&mut 0) { - let _: u32 = x; - } -} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs deleted file mode 100644 index d28567f2859..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ edition: 2021 -#![allow(incomplete_features)] -#![feature(ref_pat_eat_one_layer_2024)] -pub fn main() { - if let Some(Some(&x)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } - if let Some(Some(&x)) = &Some(Some(&0)) { - let _: &u32 = x; - //~^ ERROR: mismatched types - } - if let Some(Some(&&x)) = &Some(Some(&0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } - if let Some(&Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } - if let Some(Some(&x)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } - if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } - if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { - //~^ ERROR: mismatched types - let _: u32 = x; - } -} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr deleted file mode 100644 index 0158ed0f423..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr +++ /dev/null @@ -1,133 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:5:22 - | -LL | if let Some(Some(&x)) = &Some(&Some(0)) { - | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL - if let Some(Some(&x)) = &Some(&Some(0)) { -LL + if let Some(Some(x)) = &Some(&Some(0)) { - | - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:10:23 - | -LL | let _: &u32 = x; - | ---- ^ expected `&u32`, found integer - | | - | expected due to this - | -help: consider borrowing here - | -LL | let _: &u32 = &x; - | + - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:13:23 - | -LL | if let Some(Some(&&x)) = &Some(Some(&0)) { - | ^^ --------------- this expression has type `&Option<Option<&{integer}>>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL - if let Some(Some(&&x)) = &Some(Some(&0)) { -LL + if let Some(Some(&x)) = &Some(Some(&0)) { - | - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:17:17 - | -LL | if let Some(&Some(x)) = &Some(Some(0)) { - | ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&_` - | - = note: expected enum `Option<{integer}>` - found reference `&_` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:21:22 - | -LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:21:22 - | -LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { -LL + if let Some(Some(x)) = &mut Some(&mut Some(0)) { - | - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:25:22 - | -LL | if let Some(Some(&x)) = &Some(&Some(0)) { - | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL - if let Some(Some(&x)) = &Some(&Some(0)) { -LL + if let Some(Some(x)) = &Some(&Some(0)) { - | - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:29:27 - | -LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { - | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL - if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { -LL + if let Some(&mut Some(x)) = &Some(&mut Some(0)) { - | - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:33:23 - | -LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { - | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:33:23 - | -LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL - if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { -LL + if let Some(&Some(x)) = &mut Some(&Some(0)) { - | - -error: aborting due to 8 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr new file mode 100644 index 00000000000..f8c2bd9a921 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.classic2021.stderr @@ -0,0 +1,122 @@ +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:32:23 + | +LL | if let Some(Some(&&x)) = &Some(Some(&0)) { + | ^^ --------------- this expression has type `&Option<Option<&{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(Some(&&x)) = &Some(Some(&0)) { +LL + if let Some(Some(&x)) = &Some(Some(&0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:63:23 + | +LL | if let Some(&Some(&x)) = &Some(&Some(0)) { + | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&Some(&x)) = &Some(&Some(0)) { +LL + if let Some(&Some(x)) = &Some(&Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:82:23 + | +LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { + | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&Some(&x)) = &Some(&mut Some(0)) { +LL + if let Some(&Some(x)) = &Some(&mut Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:88:23 + | +LL | if let Some(&Some(&x)) = &mut Some(&Some(0)) { + | ^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&Some(&x)) = &mut Some(&Some(0)) { +LL + if let Some(&Some(x)) = &mut Some(&Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:123:15 + | +LL | let [&mut &x] = &mut [&0]; + | ^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &x] = &mut [&0]; +LL + let [&mut x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:129:15 + | +LL | let [&mut &ref x] = &mut [&0]; + | ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &ref x] = &mut [&0]; +LL + let [&mut ref x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:135:15 + | +LL | let [&mut &(mut x)] = &mut [&0]; + | ^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &(mut x)] = &mut [&0]; +LL + let [&mut mut x)] = &mut [&0]; + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/well-typed-edition-2024.rs:109:19 + | +LL | let [&mut ref mut x] = &mut [&0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0308, E0596. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs index 3114b9d3bf8..62c1c28022b 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs @@ -1,5 +1,7 @@ -//@ revisions: stable2021 classic2024 structural2024 +//@ revisions: stable2021 classic2021 structural2021 classic2024 structural2024 //@[stable2021] edition: 2021 +//@[classic2021] edition: 2021 +//@[structural2021] edition: 2021 //@[classic2024] edition: 2024 //@[structural2024] edition: 2024 //@[classic2024] run-pass @@ -7,8 +9,8 @@ //! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we //! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests. #![allow(incomplete_features, unused_mut)] -#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(any(classic2021, classic2024), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural2021, structural2024), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { // Tests not using match ergonomics. These should always succeed with the same bindings. @@ -18,110 +20,121 @@ pub fn main() { // Tests for differences in how many layers of reference are eaten by reference patterns if let Some(Some(&x)) = &Some(Some(&0)) { - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x; } if let Some(&Some(x)) = &mut Some(&Some(0)) { // This additionally tests that `&` patterns can eat inherited `&mut` refs. // This is possible on stable when the real reference being eaten is of a `&` type. - #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(stable2021, classic2021, structural2021))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x; } if let Some(Some(&&x)) = &Some(Some(&0)) { - //[stable2021]~^ mismatched types - //[stable2021]~| expected integer, found `&_` - let _: u32 = x; + //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: u32 = x; } // Tests for eating a lone inherited reference if let Some(Some(&x)) = &Some(&Some(0)) { //[stable2021]~^ mismatched types //[stable2021]~| expected integer, found `&_` - let _: u32 = x; + #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } if let Some(&Some(x)) = &Some(Some(0)) { //[stable2021]~^ mismatched types //[stable2021]~| expected `Option<{integer}>`, found `&_` - let _: u32 = x; + #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { //[stable2021]~^ mismatched types //[stable2021]~| expected integer, found `&mut _` - let _: u32 = x; + #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } // Tests for `&` patterns matching real `&mut` reference types if let Some(&Some(&x)) = Some(&Some(&mut 0)) { //[stable2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: u32 = x; + #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } // Tests for eating only one layer and also eating a lone inherited reference if let Some(&Some(&x)) = &Some(&Some(0)) { - //[stable2021]~^ mismatched types - //[stable2021]~| expected integer, found `&_` - let _: u32 = x; + //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: u32 = x; } // Tests for `&` matching a lone inherited possibly-`&mut` reference if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { //[stable2021]~^ mismatched types //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_` - let _: u32 = x; + #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } if let Some(&Some(x)) = &mut Some(Some(0)) { //[stable2021]~^ mismatched types //[stable2021]~| expected `Option<{integer}>`, found `&_` - let _: u32 = x; + #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } // Tests eating one layer, eating a lone inherited ref, and `&` eating `&mut` (realness varies) if let Some(&Some(&x)) = &Some(&mut Some(0)) { - //[stable2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: u32 = x; + //[classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: u32 = x; } if let Some(&Some(&x)) = &mut Some(&Some(0)) { - //[stable2021]~^ mismatched types - //[stable2021]~| expected integer, found `&_` - let _: u32 = x; + //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: u32 = x; } - // Tests for eat-inner rulesets matching on the outer reference if matching on the inner - // reference causes a mutability mismatch, i.e. `Deref(EatInner, FallbackToOuter)`: + // Tests for eat-inner and eat-both rulesets matching on the outer reference if matching on the + // inner reference causes a mutability mismatch. i.e. tests for "fallback-to-outer" deref rules. let [&mut x] = &mut [&0]; //[stable2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: &u32 = x; + #[cfg(any(classic2021, structural2021))] let _: u32 = x; + #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut ref x] = &mut [&0]; //[stable2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: &&u32 = x; + #[cfg(any(classic2021, structural2021))] let _: &u32 = x; + #[cfg(any(classic2024, structural2024))] let _: &&u32 = x; - let [&mut ref mut x] = &mut [&0]; - //[stable2021]~^ mismatched types - //[stable2021]~| types differ in mutability - let _: &mut &u32 = x; + fn borrowck_error_on_structural2021() { + let [&mut ref mut x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + //[classic2021,structural2021]~^^^ cannot borrow data in a `&` reference as mutable + #[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x; + } + borrowck_error_on_structural2021(); let [&mut mut x] = &mut [&0]; //[stable2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: &u32 = x; + #[cfg(any(classic2021, structural2021))] let _: u32 = x; + #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut &x] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: u32 = x; + //[classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: u32 = x; let [&mut &ref x] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: &u32 = x; + //[classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut &(mut x)] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ mismatched types //[stable2021]~| types differ in mutability - let _: u32 = x; + //[classic2021,structural2021]~| expected integer, found `&_` + #[cfg(any(classic2024, structural2024))] let _: u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr index b1a8024397b..adb47172f34 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:30:23 + --> $DIR/well-typed-edition-2024.rs:32:23 | LL | if let Some(Some(&&x)) = &Some(Some(&0)) { | ^^ --------------- this expression has type `&Option<Option<&{integer}>>` @@ -15,7 +15,7 @@ LL + if let Some(Some(&x)) = &Some(Some(&0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:37:22 + --> $DIR/well-typed-edition-2024.rs:39:22 | LL | if let Some(Some(&x)) = &Some(&Some(0)) { | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -31,7 +31,7 @@ LL + if let Some(Some(x)) = &Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:42:17 + --> $DIR/well-typed-edition-2024.rs:44:17 | LL | if let Some(&Some(x)) = &Some(Some(0)) { | ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` @@ -42,7 +42,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:47:22 + --> $DIR/well-typed-edition-2024.rs:49:22 | LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` @@ -52,7 +52,7 @@ LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/well-typed-edition-2024.rs:47:22 + --> $DIR/well-typed-edition-2024.rs:49:22 | LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { | ^^^^^^ @@ -63,7 +63,7 @@ LL + if let Some(Some(x)) = &mut Some(&mut Some(0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:54:23 + --> $DIR/well-typed-edition-2024.rs:56:23 | LL | if let Some(&Some(&x)) = Some(&Some(&mut 0)) { | ^^ ------------------- this expression has type `Option<&Option<&mut {integer}>>` @@ -79,7 +79,7 @@ LL + if let Some(&Some(x)) = Some(&Some(&mut 0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:61:23 + --> $DIR/well-typed-edition-2024.rs:63:23 | LL | if let Some(&Some(&x)) = &Some(&Some(0)) { | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -95,7 +95,7 @@ LL + if let Some(&Some(x)) = &Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:68:17 + --> $DIR/well-typed-edition-2024.rs:70:17 | LL | if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { | ^^^^^^^^^^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>` @@ -106,7 +106,7 @@ LL | if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { found reference `&_` error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:73:17 + --> $DIR/well-typed-edition-2024.rs:75:17 | LL | if let Some(&Some(x)) = &mut Some(Some(0)) { | ^^^^^^^^ ------------------ this expression has type `&mut Option<Option<{integer}>>` @@ -117,7 +117,7 @@ LL | if let Some(&Some(x)) = &mut Some(Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:80:17 + --> $DIR/well-typed-edition-2024.rs:82:17 | LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { | ^^^^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` @@ -128,7 +128,7 @@ LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:85:23 + --> $DIR/well-typed-edition-2024.rs:88:23 | LL | if let Some(&Some(&x)) = &mut Some(&Some(0)) { | ^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` @@ -144,7 +144,7 @@ LL + if let Some(&Some(x)) = &mut Some(&Some(0)) { | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:93:10 + --> $DIR/well-typed-edition-2024.rs:96:10 | LL | let [&mut x] = &mut [&0]; | ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` @@ -154,7 +154,7 @@ LL | let [&mut x] = &mut [&0]; = note: expected reference `&{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/well-typed-edition-2024.rs:93:10 + --> $DIR/well-typed-edition-2024.rs:96:10 | LL | let [&mut x] = &mut [&0]; | ^^^^^^ @@ -165,7 +165,7 @@ LL + let [x] = &mut [&0]; | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:98:10 + --> $DIR/well-typed-edition-2024.rs:102:10 | LL | let [&mut ref x] = &mut [&0]; | ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` @@ -175,7 +175,7 @@ LL | let [&mut ref x] = &mut [&0]; = note: expected reference `&{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/well-typed-edition-2024.rs:98:10 + --> $DIR/well-typed-edition-2024.rs:102:10 | LL | let [&mut ref x] = &mut [&0]; | ^^^^^^^^^^ @@ -186,28 +186,7 @@ LL + let [ref x] = &mut [&0]; | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:103:10 - | -LL | let [&mut ref mut x] = &mut [&0]; - | ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` - | | - | types differ in mutability - | - = note: expected reference `&{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/well-typed-edition-2024.rs:103:10 - | -LL | let [&mut ref mut x] = &mut [&0]; - | ^^^^^^^^^^^^^^ -help: consider removing `&mut` from the pattern - | -LL - let [&mut ref mut x] = &mut [&0]; -LL + let [ref mut x] = &mut [&0]; - | - -error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:108:10 + --> $DIR/well-typed-edition-2024.rs:117:10 | LL | let [&mut mut x] = &mut [&0]; | ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` @@ -217,7 +196,7 @@ LL | let [&mut mut x] = &mut [&0]; = note: expected reference `&{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/well-typed-edition-2024.rs:108:10 + --> $DIR/well-typed-edition-2024.rs:117:10 | LL | let [&mut mut x] = &mut [&0]; | ^^^^^^^^^^ @@ -228,7 +207,7 @@ LL + let [mut x] = &mut [&0]; | error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:113:10 + --> $DIR/well-typed-edition-2024.rs:123:10 | LL | let [&mut &x] = &mut [&0]; | ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` @@ -239,7 +218,7 @@ LL | let [&mut &x] = &mut [&0]; found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:118:10 + --> $DIR/well-typed-edition-2024.rs:129:10 | LL | let [&mut &ref x] = &mut [&0]; | ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` @@ -250,7 +229,7 @@ LL | let [&mut &ref x] = &mut [&0]; found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/well-typed-edition-2024.rs:123:10 + --> $DIR/well-typed-edition-2024.rs:135:10 | LL | let [&mut &(mut x)] = &mut [&0]; | ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` @@ -260,6 +239,27 @@ LL | let [&mut &(mut x)] = &mut [&0]; = note: expected reference `&{integer}` found mutable reference `&mut _` +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:109:14 + | +LL | let [&mut ref mut x] = &mut [&0]; + | ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/well-typed-edition-2024.rs:109:14 + | +LL | let [&mut ref mut x] = &mut [&0]; + | ^^^^^^^^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let [&mut ref mut x] = &mut [&0]; +LL + let [ref mut x] = &mut [&0]; + | + error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.structural2021.stderr new file mode 100644 index 00000000000..f8c2bd9a921 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.structural2021.stderr @@ -0,0 +1,122 @@ +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:32:23 + | +LL | if let Some(Some(&&x)) = &Some(Some(&0)) { + | ^^ --------------- this expression has type `&Option<Option<&{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(Some(&&x)) = &Some(Some(&0)) { +LL + if let Some(Some(&x)) = &Some(Some(&0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:63:23 + | +LL | if let Some(&Some(&x)) = &Some(&Some(0)) { + | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&Some(&x)) = &Some(&Some(0)) { +LL + if let Some(&Some(x)) = &Some(&Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:82:23 + | +LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { + | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&Some(&x)) = &Some(&mut Some(0)) { +LL + if let Some(&Some(x)) = &Some(&mut Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:88:23 + | +LL | if let Some(&Some(&x)) = &mut Some(&Some(0)) { + | ^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(&Some(&x)) = &mut Some(&Some(0)) { +LL + if let Some(&Some(x)) = &mut Some(&Some(0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:123:15 + | +LL | let [&mut &x] = &mut [&0]; + | ^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &x] = &mut [&0]; +LL + let [&mut x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:129:15 + | +LL | let [&mut &ref x] = &mut [&0]; + | ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &ref x] = &mut [&0]; +LL + let [&mut ref x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:135:15 + | +LL | let [&mut &(mut x)] = &mut [&0]; + | ^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &(mut x)] = &mut [&0]; +LL + let [&mut mut x)] = &mut [&0]; + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/well-typed-edition-2024.rs:109:19 + | +LL | let [&mut ref mut x] = &mut [&0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0308, E0596. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed index 0a22e939496..bb4ecc09063 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed @@ -239,4 +239,15 @@ fn main() { assert_type_eq(b, &0u32); assert_type_eq(c, &[0u32]); assert_type_eq(d, 0u32); + + // Test that we use the correct message and suggestion style when pointing inside expansions. + let &[migration_lint_macros::bind_ref!(a)] = &[0]; + //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + assert_type_eq(a, &0u32); + + // Test that we use the correct span when labeling a `&` whose subpattern is from an expansion. + let &[&migration_lint_macros::bind_ref!(a)] = &[&0]; + //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, &0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs index 7a6f2269d44..2837c8d81db 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs @@ -239,4 +239,15 @@ fn main() { assert_type_eq(b, &0u32); assert_type_eq(c, &[0u32]); assert_type_eq(d, 0u32); + + // Test that we use the correct message and suggestion style when pointing inside expansions. + let [migration_lint_macros::bind_ref!(a)] = &[0]; + //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + assert_type_eq(a, &0u32); + + // Test that we use the correct span when labeling a `&` whose subpattern is from an expansion. + let [&migration_lint_macros::bind_ref!(a)] = &[&0]; + //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, &0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr index 191800df07a..6efda4f757f 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -562,5 +562,41 @@ help: make the implied reference patterns explicit LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | + + -error: aborting due to 29 previous errors +error: binding modifiers may only be written when the default binding mode is `move` + --> $DIR/migration_lint.rs:244:10 + | +LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ occurs within macro expansion + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +note: matching on a reference type with a non-reference pattern changes the default binding mode + --> $DIR/migration_lint.rs:244:9 + | +LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` + = note: this error originates in the macro `migration_lint_macros::bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: make the implied reference pattern explicit + | +LL | let &[migration_lint_macros::bind_ref!(a)] = &[0]; + | + + +error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + --> $DIR/migration_lint.rs:249:10 + | +LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; + | ^ reference pattern not allowed under `ref` default binding mode + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +note: matching on a reference type with a non-reference pattern changes the default binding mode + --> $DIR/migration_lint.rs:249:9 + | +LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` +help: make the implied reference pattern explicit + | +LL | let &[&migration_lint_macros::bind_ref!(a)] = &[&0]; + | + + +error: aborting due to 31 previous errors diff --git a/tests/ui/process/process-sigpipe.rs b/tests/ui/process/process-sigpipe.rs index 453e53379fc..3ecf271599d 100644 --- a/tests/ui/process/process-sigpipe.rs +++ b/tests/ui/process/process-sigpipe.rs @@ -9,9 +9,9 @@ // Make sure that these behaviors don't get inherited to children // spawned via std::process, since they're needed for traditional UNIX // filter behavior. -// This test checks that `while echo y ; do : ; done | head` terminates -// (instead of running forever), and that it does not print an error -// message about a broken pipe. +// This test checks that `yes` or `while echo y ; do : ; done | head` +// terminates (instead of running forever), and that it does not print an +// error message about a broken pipe. //@ ignore-vxworks no 'sh' //@ ignore-fuchsia no 'sh' @@ -22,14 +22,21 @@ use std::process; use std::thread; fn main() { - // Just in case `yes` doesn't check for EPIPE... + // Just in case `yes` or `while-echo` doesn't check for EPIPE... thread::spawn(|| { thread::sleep_ms(5000); process::exit(1); }); + // QNX Neutrino does not have `yes`. Therefore, use `while-echo` for `nto` + // and `yes` for other platforms. + let command = if cfg!(target_os = "nto") { + "while echo y ; do : ; done | head" + } else { + "yes | head" + }; let output = process::Command::new("sh") .arg("-c") - .arg("while echo y ; do : ; done | head") + .arg(command) .output() .unwrap(); assert!(output.status.success()); diff --git a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr index 2e76333e26f..ca9ceeeeff3 100644 --- a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -1,4 +1,4 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:24:4 | LL | fn bar<'a, 'b>() @@ -24,4 +24,4 @@ LL | fn bar<'a, 'b>() error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/regions/resolve-re-error-ice.stderr b/tests/ui/regions/resolve-re-error-ice.stderr index 41c5f0fa92e..f463a97c5bc 100644 --- a/tests/ui/regions/resolve-re-error-ice.stderr +++ b/tests/ui/regions/resolve-re-error-ice.stderr @@ -1,4 +1,4 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements --> $DIR/resolve-re-error-ice.rs:12:5 | LL | fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> { @@ -34,4 +34,4 @@ LL | struct Subject<'a, T, V, R>(PhantomData<(&'a T, V, R)>); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs index 2b6bbf12650..011076882d2 100644 --- a/tests/ui/repr/16-bit-repr-c-enum.rs +++ b/tests/ui/repr/16-bit-repr-c-enum.rs @@ -2,7 +2,7 @@ //@ revisions: avr msp430 // //@ [avr] needs-llvm-components: avr -//@ [avr] compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib +//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib //@ [msp430] needs-llvm-components: msp430 //@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib #![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)] diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr index 8e8f1d159b7..204db30786e 100644 --- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -4,7 +4,15 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(0 bytes), @@ -23,6 +31,7 @@ error: layout_of(Univariant) = Layout { valid_range: 0..=0, }, ), + uninhabited: true, variants: Multiple { tag: Initialized { value: Int( @@ -40,7 +49,15 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(4 bytes), @@ -50,6 +67,7 @@ error: layout_of(Univariant) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -107,6 +125,7 @@ error: layout_of(TwoVariants) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -119,12 +138,26 @@ error: layout_of(TwoVariants) = Layout { tag_field: 0, variants: [ Layout { - size: Size(4 bytes), + size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), fields: Arbitrary { offsets: [ Size(4 bytes), @@ -134,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -171,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -216,6 +251,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -233,7 +269,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Memory { + sized: true, + }, fields: Arbitrary { offsets: [ Size(8 bytes), @@ -245,6 +283,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -272,6 +311,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr index 2cd0960ce3e..1fab00bf50c 100644 --- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -4,7 +4,15 @@ error: layout_of(Univariant) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(0 bytes), @@ -23,6 +31,7 @@ error: layout_of(Univariant) = Layout { valid_range: 0..=0, }, ), + uninhabited: true, variants: Multiple { tag: Initialized { value: Int( @@ -40,7 +49,15 @@ error: layout_of(Univariant) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(1 bytes), @@ -50,6 +67,7 @@ error: layout_of(Univariant) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -107,6 +125,7 @@ error: layout_of(TwoVariants) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -119,12 +138,26 @@ error: layout_of(TwoVariants) = Layout { tag_field: 0, variants: [ Layout { - size: Size(1 bytes), + size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: ScalarPair( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), fields: Arbitrary { offsets: [ Size(1 bytes), @@ -134,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -171,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -216,6 +251,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -233,7 +269,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Memory { + sized: true, + }, fields: Arbitrary { offsets: [ Size(8 bytes), @@ -245,6 +283,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -272,6 +311,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr index 8e8f1d159b7..204db30786e 100644 --- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -4,7 +4,15 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(0 bytes), @@ -23,6 +31,7 @@ error: layout_of(Univariant) = Layout { valid_range: 0..=0, }, ), + uninhabited: true, variants: Multiple { tag: Initialized { value: Int( @@ -40,7 +49,15 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(4 bytes), @@ -50,6 +67,7 @@ error: layout_of(Univariant) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -107,6 +125,7 @@ error: layout_of(TwoVariants) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -119,12 +138,26 @@ error: layout_of(TwoVariants) = Layout { tag_field: 0, variants: [ Layout { - size: Size(4 bytes), + size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), fields: Arbitrary { offsets: [ Size(4 bytes), @@ -134,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -171,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -216,6 +251,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -233,7 +269,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Memory { + sized: true, + }, fields: Arbitrary { offsets: [ Size(8 bytes), @@ -245,6 +283,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -272,6 +311,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr index 8e8f1d159b7..204db30786e 100644 --- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -4,7 +4,15 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(0 bytes), @@ -23,6 +31,7 @@ error: layout_of(Univariant) = Layout { valid_range: 0..=0, }, ), + uninhabited: true, variants: Multiple { tag: Initialized { value: Int( @@ -40,7 +49,15 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(4 bytes), @@ -50,6 +67,7 @@ error: layout_of(Univariant) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -107,6 +125,7 @@ error: layout_of(TwoVariants) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -119,12 +138,26 @@ error: layout_of(TwoVariants) = Layout { tag_field: 0, variants: [ Layout { - size: Size(4 bytes), + size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), fields: Arbitrary { offsets: [ Size(4 bytes), @@ -134,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -171,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -216,6 +251,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -233,7 +269,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Memory { + sized: true, + }, fields: Arbitrary { offsets: [ Size(8 bytes), @@ -245,6 +283,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -272,6 +311,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr index fa08b323dec..f852212deb9 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.stderr +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -4,7 +4,15 @@ error: layout_of(UnivariantU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(0 bytes), @@ -23,6 +31,7 @@ error: layout_of(UnivariantU8) = Layout { valid_range: 0..=0, }, ), + uninhabited: true, variants: Multiple { tag: Initialized { value: Int( @@ -40,7 +49,15 @@ error: layout_of(UnivariantU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), fields: Arbitrary { offsets: [ Size(1 bytes), @@ -50,6 +67,7 @@ error: layout_of(UnivariantU8) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -107,6 +125,7 @@ error: layout_of(TwoVariantsU8) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -119,12 +138,26 @@ error: layout_of(TwoVariantsU8) = Layout { tag_field: 0, variants: [ Layout { - size: Size(1 bytes), + size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: ScalarPair( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), fields: Arbitrary { offsets: [ Size(1 bytes), @@ -134,6 +167,7 @@ error: layout_of(TwoVariantsU8) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -171,6 +205,7 @@ error: layout_of(TwoVariantsU8) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, @@ -216,6 +251,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { valid_range: 0..=1, }, ), + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -233,7 +269,9 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Uninhabited, + abi: Memory { + sized: true, + }, fields: Arbitrary { offsets: [ Size(8 bytes), @@ -245,6 +283,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { ], }, largest_niche: None, + uninhabited: true, variants: Single { index: 0, }, @@ -272,6 +311,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Single { index: 1, }, diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs new file mode 100644 index 00000000000..432e3c0b77e --- /dev/null +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs @@ -0,0 +1,123 @@ +// see also https://github.com/rust-lang/rust/issues/22692 + +type Alias = Vec<u32>; + +mod foo { + fn bar() {} +} + +fn main() { + let _ = String.new(); + //~^ ERROR expected value, found struct `String` + //~| HELP use the path separator + + let _ = String.default; + //~^ ERROR expected value, found struct `String` + //~| HELP use the path separator + + let _ = Vec::<()>.with_capacity(1); + //~^ ERROR expected value, found struct `Vec` + //~| HELP use the path separator + + let _ = Alias.new(); + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + + let _ = Alias.default; + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + + let _ = foo.bar; + //~^ ERROR expected value, found module `foo` + //~| HELP use the path separator +} + +macro_rules! Type { + () => { + ::std::cell::Cell + //~^ ERROR expected value, found struct `std::cell::Cell` + //~| ERROR expected value, found struct `std::cell::Cell` + //~| ERROR expected value, found struct `std::cell::Cell` + }; + (alias) => { + Alias + //~^ ERROR expected value, found type alias `Alias` + //~| ERROR expected value, found type alias `Alias` + //~| ERROR expected value, found type alias `Alias` + }; +} + +macro_rules! create { + (type method) => { + Vec.new() + //~^ ERROR expected value, found struct `Vec` + //~| HELP use the path separator + }; + (type field) => { + Vec.new + //~^ ERROR expected value, found struct `Vec` + //~| HELP use the path separator + }; + (macro method) => { + Type!().new(0) + //~^ HELP use the path separator + }; + (macro method alias) => { + Type!(alias).new(0) + //~^ HELP use the path separator + }; +} + +macro_rules! check_ty { + ($Ty:ident) => { + $Ty.foo + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + }; +} +macro_rules! check_ident { + ($Ident:ident) => { + Alias.$Ident + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + }; +} +macro_rules! check_ty_ident { + ($Ty:ident, $Ident:ident) => { + $Ty.$Ident + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + }; +} + +fn interaction_with_macros() { + // + // Verify that we do not only suggest to replace `.` with `::` if the receiver is a + // macro call but that we also correctly suggest to surround it with angle brackets. + // + + Type!().get(); + //~^ HELP use the path separator + + Type! {}.get; + //~^ HELP use the path separator + + Type!(alias).get(); + //~^ HELP use the path separator + + Type! {alias}.get; + //~^ HELP use the path separator + + // + // Ensure that the suggestion is shown for expressions inside of macro definitions. + // + + let _ = create!(type method); + let _ = create!(type field); + let _ = create!(macro method); + let _ = create!(macro method alias); + + let _ = check_ty!(Alias); + let _ = check_ident!(foo); + let _ = check_ty_ident!(Alias, foo); +} diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr new file mode 100644 index 00000000000..d74814dd876 --- /dev/null +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr @@ -0,0 +1,251 @@ +error[E0423]: expected value, found struct `String` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:10:13 + | +LL | let _ = String.new(); + | ^^^^^^ + | +help: use the path separator to refer to an item + | +LL - let _ = String.new(); +LL + let _ = String::new(); + | + +error[E0423]: expected value, found struct `String` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:14:13 + | +LL | let _ = String.default; + | ^^^^^^ + | +help: use the path separator to refer to an item + | +LL - let _ = String.default; +LL + let _ = String::default; + | + +error[E0423]: expected value, found struct `Vec` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:18:13 + | +LL | let _ = Vec::<()>.with_capacity(1); + | ^^^^^^^^^ + | +help: use the path separator to refer to an item + | +LL - let _ = Vec::<()>.with_capacity(1); +LL + let _ = Vec::<()>::with_capacity(1); + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:22:13 + | +LL | let _ = Alias.new(); + | ^^^^^ + | +help: use the path separator to refer to an item + | +LL - let _ = Alias.new(); +LL + let _ = Alias::new(); + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:26:13 + | +LL | let _ = Alias.default; + | ^^^^^ + | +help: use the path separator to refer to an item + | +LL - let _ = Alias.default; +LL + let _ = Alias::default; + | + +error[E0423]: expected value, found module `foo` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:30:13 + | +LL | let _ = foo.bar; + | ^^^ + | +help: use the path separator to refer to an item + | +LL - let _ = foo.bar; +LL + let _ = foo::bar; + | + +error[E0423]: expected value, found struct `std::cell::Cell` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 + | +LL | ::std::cell::Cell + | ^^^^^^^^^^^^^^^^^ +... +LL | Type!().get(); + | ------- in this macro invocation + | + = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Type!().get(); +LL + <Type!()>::get(); + | + +error[E0423]: expected value, found struct `std::cell::Cell` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 + | +LL | ::std::cell::Cell + | ^^^^^^^^^^^^^^^^^ +... +LL | Type! {}.get; + | -------- in this macro invocation + | + = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Type! {}.get; +LL + <Type! {}>::get; + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 + | +LL | Alias + | ^^^^^ +... +LL | Type!(alias).get(); + | ------------ in this macro invocation + | + = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Type!(alias).get(); +LL + <Type!(alias)>::get(); + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 + | +LL | Alias + | ^^^^^ +... +LL | Type! {alias}.get; + | ------------- in this macro invocation + | + = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Type! {alias}.get; +LL + <Type! {alias}>::get; + | + +error[E0423]: expected value, found struct `Vec` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:52:9 + | +LL | Vec.new() + | ^^^ +... +LL | let _ = create!(type method); + | -------------------- in this macro invocation + | + = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Vec.new() +LL + Vec::new() + | + +error[E0423]: expected value, found struct `Vec` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:57:9 + | +LL | Vec.new + | ^^^ +... +LL | let _ = create!(type field); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Vec.new +LL + Vec::new + | + +error[E0423]: expected value, found struct `std::cell::Cell` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 + | +LL | ::std::cell::Cell + | ^^^^^^^^^^^^^^^^^ +... +LL | let _ = create!(macro method); + | --------------------- in this macro invocation + | + = note: this error originates in the macro `Type` which comes from the expansion of the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Type!().new(0) +LL + <Type!()>::new(0) + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 + | +LL | Alias + | ^^^^^ +... +LL | let _ = create!(macro method alias); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `Type` which comes from the expansion of the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Type!(alias).new(0) +LL + <Type!(alias)>::new(0) + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:73:9 + | +LL | $Ty.foo + | ^^^ +... +LL | let _ = check_ty!(Alias); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `check_ty` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - $Ty.foo +LL + $Ty::foo + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:80:9 + | +LL | Alias.$Ident + | ^^^^^ +... +LL | let _ = check_ident!(foo); + | ----------------- in this macro invocation + | + = note: this error originates in the macro `check_ident` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - Alias.$Ident +LL + <Alias>::$Ident + | + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:87:9 + | +LL | $Ty.$Ident + | ^^^ +... +LL | let _ = check_ty_ident!(Alias, foo); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `check_ty_ident` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL - $Ty.$Ident +LL + <$Ty>::$Ident + | + +error: aborting due to 17 previous errors + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/resolve/enum-expected-value-suggest-variants.rs b/tests/ui/resolve/enum-expected-value-suggest-variants.rs new file mode 100644 index 00000000000..9f86a0a1ecc --- /dev/null +++ b/tests/ui/resolve/enum-expected-value-suggest-variants.rs @@ -0,0 +1,58 @@ +enum Foo { + //~^ HELP consider importing this tuple variant + A(u32), + B(u32), +} + +enum Bar { + C(u32), + D(u32), + E, + F, +} + +fn main() { + let _: Foo = Foo(0); + //~^ ERROR expected function + //~| HELP try to construct one of the enum's variants + + let _: Foo = Foo.A(0); + //~^ ERROR expected value, found enum `Foo` + //~| HELP use the path separator to refer to a variant + + let _: Foo = Foo.Bad(0); + //~^ ERROR expected value, found enum `Foo` + //~| HELP the following enum variants are available + + let _: Bar = Bar(0); + //~^ ERROR expected function + //~| HELP try to construct one of the enum's variants + //~| HELP you might have meant to construct one of the enum's non-tuple variants + + let _: Bar = Bar.C(0); + //~^ ERROR expected value, found enum `Bar` + //~| HELP use the path separator to refer to a variant + + let _: Bar = Bar.E; + //~^ ERROR expected value, found enum `Bar` + //~| HELP use the path separator to refer to a variant + + let _: Bar = Bar.Bad(0); + //~^ ERROR expected value, found enum `Bar` + //~| HELP you might have meant to use one of the following enum variants + //~| HELP alternatively, the following enum variants are also available + + let _: Bar = Bar.Bad; + //~^ ERROR expected value, found enum `Bar` + //~| HELP you might have meant to use one of the following enum variants + //~| HELP alternatively, the following enum variants are also available + + match Foo::A(42) { + A(..) => {} + //~^ ERROR cannot find tuple struct or tuple variant `A` in this scope + Foo(..) => {} + //~^ ERROR expected tuple struct or tuple variant + //~| HELP try to match against one of the enum's variants + _ => {} + } +} diff --git a/tests/ui/resolve/enum-expected-value-suggest-variants.stderr b/tests/ui/resolve/enum-expected-value-suggest-variants.stderr new file mode 100644 index 00000000000..548a4c0e593 --- /dev/null +++ b/tests/ui/resolve/enum-expected-value-suggest-variants.stderr @@ -0,0 +1,234 @@ +error[E0423]: expected value, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:19:18 + | +LL | let _: Foo = Foo.A(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: use the path separator to refer to a variant + | +LL - let _: Foo = Foo.A(0); +LL + let _: Foo = Foo::A(0); + | + +error[E0423]: expected value, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:23:18 + | +LL | let _: Foo = Foo.Bad(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: the following enum variants are available + | +LL - let _: Foo = Foo.Bad(0); +LL + let _: Foo = (Foo::A(/* fields */)).Bad(0); + | +LL - let _: Foo = Foo.Bad(0); +LL + let _: Foo = (Foo::B(/* fields */)).Bad(0); + | + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:32:18 + | +LL | let _: Bar = Bar.C(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: use the path separator to refer to a variant + | +LL - let _: Bar = Bar.C(0); +LL + let _: Bar = Bar::C(0); + | + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:36:18 + | +LL | let _: Bar = Bar.E; + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: use the path separator to refer to a variant + | +LL - let _: Bar = Bar.E; +LL + let _: Bar = Bar::E; + | + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:40:18 + | +LL | let _: Bar = Bar.Bad(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants + | +LL | let _: Bar = Bar::E.Bad(0); + | +++ +LL | let _: Bar = Bar::F.Bad(0); + | +++ +help: alternatively, the following enum variants are also available + | +LL - let _: Bar = Bar.Bad(0); +LL + let _: Bar = (Bar::C(/* fields */)).Bad(0); + | +LL - let _: Bar = Bar.Bad(0); +LL + let _: Bar = (Bar::D(/* fields */)).Bad(0); + | + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:45:18 + | +LL | let _: Bar = Bar.Bad; + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants + | +LL | let _: Bar = Bar::E.Bad; + | +++ +LL | let _: Bar = Bar::F.Bad; + | +++ +help: alternatively, the following enum variants are also available + | +LL - let _: Bar = Bar.Bad; +LL + let _: Bar = (Bar::C(/* fields */)).Bad; + | +LL - let _: Bar = Bar.Bad; +LL + let _: Bar = (Bar::D(/* fields */)).Bad; + | + +error[E0531]: cannot find tuple struct or tuple variant `A` in this scope + --> $DIR/enum-expected-value-suggest-variants.rs:51:9 + | +LL | A(..) => {} + | ^ not found in this scope + | +help: consider importing this tuple variant + | +LL + use Foo::A; + | + +error[E0532]: expected tuple struct or tuple variant, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:53:9 + | +LL | Foo(..) => {} + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: try to match against one of the enum's variants + | +LL | Foo::A(..) => {} + | +++ +LL | Foo::B(..) => {} + | +++ + +error[E0423]: expected function, tuple struct or tuple variant, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:15:18 + | +LL | let _: Foo = Foo(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: try to construct one of the enum's variants + | +LL | let _: Foo = Foo::A(0); + | +++ +LL | let _: Foo = Foo::B(0); + | +++ + +error[E0423]: expected function, tuple struct or tuple variant, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:27:18 + | +LL | let _: Bar = Bar(0); + | ^^^ + | + = help: you might have meant to construct one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: try to construct one of the enum's variants + | +LL | let _: Bar = Bar::C(0); + | +++ +LL | let _: Bar = Bar::D(0); + | +++ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0423, E0531, E0532. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/resolve/issue-22692.rs b/tests/ui/resolve/issue-22692.rs deleted file mode 100644 index 31a76261408..00000000000 --- a/tests/ui/resolve/issue-22692.rs +++ /dev/null @@ -1,60 +0,0 @@ -fn main() { - let _ = String.new(); - //~^ ERROR expected value, found struct `String` - //~| HELP use the path separator - - let _ = String.default; - //~^ ERROR expected value, found struct `String` - //~| HELP use the path separator - - let _ = Vec::<()>.with_capacity(1); - //~^ ERROR expected value, found struct `Vec` - //~| HELP use the path separator -} - -macro_rules! Type { - () => { - ::std::cell::Cell - //~^ ERROR expected value, found struct `std::cell::Cell` - //~| ERROR expected value, found struct `std::cell::Cell` - //~| ERROR expected value, found struct `std::cell::Cell` - }; -} - -macro_rules! create { - (type method) => { - Vec.new() - //~^ ERROR expected value, found struct `Vec` - //~| HELP use the path separator - }; - (type field) => { - Vec.new - //~^ ERROR expected value, found struct `Vec` - //~| HELP use the path separator - }; - (macro method) => { - Type!().new(0) - //~^ HELP use the path separator - }; -} - -fn interaction_with_macros() { - // - // Verify that we do not only suggest to replace `.` with `::` if the receiver is a - // macro call but that we also correctly suggest to surround it with angle brackets. - // - - Type!().get(); - //~^ HELP use the path separator - - Type! {}.get; - //~^ HELP use the path separator - - // - // Ensure that the suggestion is shown for expressions inside of macro definitions. - // - - let _ = create!(type method); - let _ = create!(type field); - let _ = create!(macro method); -} diff --git a/tests/ui/resolve/issue-22692.stderr b/tests/ui/resolve/issue-22692.stderr deleted file mode 100644 index 546f12b35c1..00000000000 --- a/tests/ui/resolve/issue-22692.stderr +++ /dev/null @@ -1,119 +0,0 @@ -error[E0423]: expected value, found struct `String` - --> $DIR/issue-22692.rs:2:13 - | -LL | let _ = String.new(); - | ^^^^^^ - | -help: use the path separator to refer to an item - | -LL - let _ = String.new(); -LL + let _ = String::new(); - | - -error[E0423]: expected value, found struct `String` - --> $DIR/issue-22692.rs:6:13 - | -LL | let _ = String.default; - | ^^^^^^ - | -help: use the path separator to refer to an item - | -LL - let _ = String.default; -LL + let _ = String::default; - | - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-22692.rs:10:13 - | -LL | let _ = Vec::<()>.with_capacity(1); - | ^^^^^^^^^ - | -help: use the path separator to refer to an item - | -LL - let _ = Vec::<()>.with_capacity(1); -LL + let _ = Vec::<()>::with_capacity(1); - | - -error[E0423]: expected value, found struct `std::cell::Cell` - --> $DIR/issue-22692.rs:17:9 - | -LL | ::std::cell::Cell - | ^^^^^^^^^^^^^^^^^ -... -LL | Type!().get(); - | ------- in this macro invocation - | - = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) -help: use the path separator to refer to an item - | -LL - Type!().get(); -LL + <Type!()>::get(); - | - -error[E0423]: expected value, found struct `std::cell::Cell` - --> $DIR/issue-22692.rs:17:9 - | -LL | ::std::cell::Cell - | ^^^^^^^^^^^^^^^^^ -... -LL | Type! {}.get; - | -------- in this macro invocation - | - = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) -help: use the path separator to refer to an item - | -LL - Type! {}.get; -LL + <Type! {}>::get; - | - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-22692.rs:26:9 - | -LL | Vec.new() - | ^^^ -... -LL | let _ = create!(type method); - | -------------------- in this macro invocation - | - = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) -help: use the path separator to refer to an item - | -LL - Vec.new() -LL + Vec::new() - | - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-22692.rs:31:9 - | -LL | Vec.new - | ^^^ -... -LL | let _ = create!(type field); - | ------------------- in this macro invocation - | - = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) -help: use the path separator to refer to an item - | -LL - Vec.new -LL + Vec::new - | - -error[E0423]: expected value, found struct `std::cell::Cell` - --> $DIR/issue-22692.rs:17:9 - | -LL | ::std::cell::Cell - | ^^^^^^^^^^^^^^^^^ -... -LL | let _ = create!(macro method); - | --------------------- in this macro invocation - | - = note: this error originates in the macro `Type` which comes from the expansion of the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) -help: use the path separator to refer to an item - | -LL - Type!().new(0) -LL + <Type!()>::new(0) - | - -error: aborting due to 8 previous errors - -For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/sse-abi-checks.rs b/tests/ui/sse-simd-abi-checks.rs index cb3128a890f..396e9bf1318 100644 --- a/tests/ui/sse-abi-checks.rs +++ b/tests/ui/sse-simd-abi-checks.rs @@ -1,7 +1,8 @@ //! Ensure we trigger abi_unsupported_vector_types for target features that are usually enabled -//! on a target, but disabled in this file via a `-C` flag. +//! on a target via the base CPU, but disabled in this file via a `-C` flag. +//@ compile-flags: --crate-type=rlib --target=i586-unknown-linux-gnu +//@ compile-flags: -Ctarget-cpu=pentium4 -C target-feature=-sse,-sse2 //@ add-core-stubs -//@ compile-flags: --crate-type=rlib --target=i586-unknown-linux-gnu -C target-feature=-sse,-sse2 //@ build-pass //@ ignore-pass (test emits codegen-time warnings) //@ needs-llvm-components: x86 diff --git a/tests/ui/sse-abi-checks.stderr b/tests/ui/sse-simd-abi-checks.stderr index 9944aa093b4..95486f480d2 100644 --- a/tests/ui/sse-abi-checks.stderr +++ b/tests/ui/sse-simd-abi-checks.stderr @@ -1,5 +1,5 @@ warning: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled - --> $DIR/sse-abi-checks.rs:19:1 + --> $DIR/sse-simd-abi-checks.rs:20:1 | LL | pub unsafe extern "C" fn f(_: SseVector) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -13,7 +13,7 @@ warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: warning: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled - --> $DIR/sse-abi-checks.rs:19:1 + --> $DIR/sse-simd-abi-checks.rs:20:1 | LL | pub unsafe extern "C" fn f(_: SseVector) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here diff --git a/tests/ui/static/static-lifetime.stderr b/tests/ui/static/static-lifetime.stderr index 7a956dbfeef..9b5869fd0dc 100644 --- a/tests/ui/static/static-lifetime.stderr +++ b/tests/ui/static/static-lifetime.stderr @@ -11,7 +11,7 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} | ^^ = note: but lifetime parameter must outlive the static lifetime -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/static-lifetime.rs:3:34 | LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} @@ -38,5 +38,5 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} error: aborting due to 2 previous errors -Some errors have detailed explanations: E0478, E0495. +Some errors have detailed explanations: E0478, E0803. For more information about an error, try `rustc --explain E0478`. diff --git a/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs new file mode 100644 index 00000000000..71d90ddd935 --- /dev/null +++ b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.rs @@ -0,0 +1,6 @@ +#![feature(default_field_values)] +struct A<'a> { //~ ERROR lifetime parameter `'a` is never used + x: Vec<A> = Vec::new(), //~ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr new file mode 100644 index 00000000000..20b9afe80cd --- /dev/null +++ b/tests/ui/structs/default-field-values/do-not-ice-on-invalid-lifetime.stderr @@ -0,0 +1,23 @@ +error[E0106]: missing lifetime specifier + --> $DIR/do-not-ice-on-invalid-lifetime.rs:3:12 + | +LL | x: Vec<A> = Vec::new(), + | ^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | x: Vec<A<'a>> = Vec::new(), + | ++++ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/do-not-ice-on-invalid-lifetime.rs:2:10 + | +LL | struct A<'a> { + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0106, E0392. +For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.rs b/tests/ui/traits/const-traits/predicate-entailment-passes.rs index 9c8d5a5e3f6..28ae21891f3 100644 --- a/tests/ui/traits/const-traits/predicate-entailment-passes.rs +++ b/tests/ui/traits/const-traits/predicate-entailment-passes.rs @@ -6,32 +6,21 @@ #[const_trait] trait Bar {} impl const Bar for () {} - #[const_trait] trait TildeConst { - type Bar<T> where T: ~const Bar; - fn foo<T>() where T: ~const Bar; } impl TildeConst for () { - type Bar<T> = () where T: Bar; - fn foo<T>() where T: Bar {} } #[const_trait] trait AlwaysConst { - type Bar<T> where T: const Bar; - fn foo<T>() where T: const Bar; } impl AlwaysConst for i32 { - type Bar<T> = () where T: Bar; - fn foo<T>() where T: Bar {} } impl const AlwaysConst for u32 { - type Bar<T> = () where T: ~const Bar; - fn foo<T>() where T: ~const Bar {} } diff --git a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr index 8bf8536c74e..4e324209fe9 100644 --- a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr +++ b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr @@ -1,4 +1,4 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28 | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { @@ -24,4 +24,4 @@ LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr index 1d42dbdfe00..294fa0d7613 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr @@ -1,18 +1,8 @@ -error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc: Sized` +error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc == _` --> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18 | LL | type Assoc = <T as Overflow>::Assoc; | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `Overflow::Assoc` - --> $DIR/trait_ref_is_knowable-norm-overflow.rs:7:5 - | -LL | type Assoc; - | ^^^^^^^^^^^ required by this bound in `Overflow::Assoc` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assoc: ?Sized; - | ++++++++ error[E0119]: conflicting implementations of trait `Trait` --> $DIR/trait_ref_is_knowable-norm-overflow.rs:18:1 diff --git a/tests/ui/traits/next-solver/gat-wf.rs b/tests/ui/traits/next-solver/gat-wf.rs new file mode 100644 index 00000000000..ff6e2665ef3 --- /dev/null +++ b/tests/ui/traits/next-solver/gat-wf.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Znext-solver + +// Make sure that, like the old trait solver, we end up requiring that the WC of +// impl GAT matches that of the trait. This is not a restriction that we *need*, +// but is a side-effect of registering the where clauses when normalizing the GAT +// when proving it satisfies its item bounds. + +trait Foo { + type T<'a>: Sized where Self: 'a; +} + +impl Foo for &() { + type T<'a> = (); //~ the type `&()` does not fulfill the required lifetime +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/gat-wf.stderr b/tests/ui/traits/next-solver/gat-wf.stderr new file mode 100644 index 00000000000..620bca77e4b --- /dev/null +++ b/tests/ui/traits/next-solver/gat-wf.stderr @@ -0,0 +1,15 @@ +error[E0477]: the type `&()` does not fulfill the required lifetime + --> $DIR/gat-wf.rs:13:18 + | +LL | type T<'a> = (); + | ^^ + | +note: type must outlive the lifetime `'a` as defined here + --> $DIR/gat-wf.rs:13:12 + | +LL | type T<'a> = (); + | ^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0477`. diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index 0ca18b5b0dd..df1d5105a34 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -1,3 +1,4 @@ +#![feature(try_trait_v2)] fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this let test = String::from("one,two"); let x = test diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index bad325a6720..0f83c9e73a3 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -1,5 +1,5 @@ error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:14:22 + --> $DIR/question-mark-result-err-mismatch.rs:15:22 | LL | fn foo() -> Result<String, String> { | ---------------------- expected `String` because of this @@ -17,7 +17,7 @@ LL | .map(|()| "")?; = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:28:25 + --> $DIR/question-mark-result-err-mismatch.rs:29:25 | LL | fn bar() -> Result<(), String> { | ------------------ expected `String` because of this @@ -40,7 +40,7 @@ LL | .map_err(|_| ())?; = note: required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:48:11 + --> $DIR/question-mark-result-err-mismatch.rs:49:11 | LL | fn baz() -> Result<String, String> { | ---------------------- expected `String` because of this diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index c67ad762a83..818ab499306 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -10,7 +10,6 @@ LL | Err("")?; = help: the trait `From<&str>` is not implemented for `TryFromSliceError` but trait `From<Infallible>` is implemented for it = help: for that trait implementation, expected `Infallible`, found `&str` - = note: required for `Result<u32, TryFromSliceError>` to implement `FromResidual<Result<Infallible, &str>>` error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str` --> $DIR/try-block-bad-type.rs:12:9 diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index bb5e5646ad2..45422be946e 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -12,7 +12,6 @@ LL | Ok(Err(123_i32)?) = help: the following other types implement trait `From<T>`: `u8` implements `From<Char>` `u8` implements `From<bool>` - = note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` --> $DIR/bad-interconversion.rs:9:12 diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 475bd1ff3ac..20454e12de5 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -19,7 +19,6 @@ LL | Err(5)?; `(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>` `(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>` and 4 others - = note: required for `Result<i32, ()>` to implement `FromResidual<Result<Infallible, {integer}>>` error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr index 04288112fa8..ae00d3fc667 100644 --- a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr +++ b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr @@ -15,7 +15,7 @@ note: but lifetime parameter must outlive the lifetime `'b` as defined here LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b; | ^^ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0803]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/closure_wf_outlives.rs:34:9 | LL | || {} @@ -63,5 +63,5 @@ LL | type Opaque<T: 'static> = impl Sized; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0310, E0478, E0495. +Some errors have detailed explanations: E0310, E0478, E0803. For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index 7da8cfd4dbc..690592ba0b8 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -31,6 +31,7 @@ error: layout_of(NonZero<u32>) = Layout { valid_range: 1..=4294967295, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -69,6 +70,7 @@ error: layout_of((u32) is 1..=) = Layout { valid_range: 1..=4294967295, }, ), + uninhabited: false, variants: Single { index: 0, }, @@ -105,6 +107,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -134,6 +137,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -174,6 +178,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { valid_range: 1..=4294967295, }, ), + uninhabited: false, variants: Single { index: 1, }, @@ -216,6 +221,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout { ], }, largest_niche: None, + uninhabited: false, variants: Multiple { tag: Initialized { value: Int( @@ -245,6 +251,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout { memory_index: [], }, largest_niche: None, + uninhabited: false, variants: Single { index: 0, }, @@ -285,6 +292,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout { valid_range: 1..=4294967295, }, ), + uninhabited: false, variants: Single { index: 1, }, @@ -336,6 +344,7 @@ error: layout_of(NonZeroU32New) = Layout { valid_range: 1..=4294967295, }, ), + uninhabited: false, variants: Single { index: 0, }, diff --git a/tests/ui/typeck/issue-103899.current.stderr b/tests/ui/typeck/issue-103899.current.stderr new file mode 100644 index 00000000000..a3a164907be --- /dev/null +++ b/tests/ui/typeck/issue-103899.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): BaseWithAssoc` is not satisfied + --> $DIR/issue-103899.rs:24:54 + | +LL | fn trigger<L: WrapperWithAssoc<BaseAssoc = ()>>() -> DoubleProject<L> { + | ^^^^^^^^^^^^^^^^ the trait `BaseWithAssoc` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-103899.rs:4:1 + | +LL | trait BaseWithAssoc { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-103899.next.stderr b/tests/ui/typeck/issue-103899.next.stderr new file mode 100644 index 00000000000..a3a164907be --- /dev/null +++ b/tests/ui/typeck/issue-103899.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): BaseWithAssoc` is not satisfied + --> $DIR/issue-103899.rs:24:54 + | +LL | fn trigger<L: WrapperWithAssoc<BaseAssoc = ()>>() -> DoubleProject<L> { + | ^^^^^^^^^^^^^^^^ the trait `BaseWithAssoc` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-103899.rs:4:1 + | +LL | trait BaseWithAssoc { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-103899.rs b/tests/ui/typeck/issue-103899.rs index 81ab92a8994..92356ecf288 100644 --- a/tests/ui/typeck/issue-103899.rs +++ b/tests/ui/typeck/issue-103899.rs @@ -1,9 +1,5 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) -//@ check-fail -//@ failure-status: 101 -//@ dont-check-compiler-stderr -//@ known-bug: #103899 trait BaseWithAssoc { type Assoc; @@ -26,6 +22,7 @@ struct DoubleProject<L: WrapperWithAssoc> { } fn trigger<L: WrapperWithAssoc<BaseAssoc = ()>>() -> DoubleProject<L> { + //~^ ERROR the trait bound `(): BaseWithAssoc` is not satisfied [E0277] loop {} } diff --git a/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs new file mode 100644 index 00000000000..2c2788a3e56 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-transparent-return-abi.rs @@ -0,0 +1,33 @@ +//@ run-pass +//@ needs-unwind +// See https://github.com/rust-lang/rust/issues/135802 + +enum Void {} + +// Should be ABI-compatible with T, but wasn't prior to the PR adding this test. +#[repr(transparent)] +struct NoReturn<T>(T, Void); + +// Returned by invisible reference (in most ABIs) +#[allow(dead_code)] +struct Large(u64, u64, u64); + +// Prior to the PR adding this test, this function had a different ABI than +// `fn() -> Large` (on `x86_64-unknown-linux-gnu` at least), so calling it as `fn() -> Large` +// would pass the return place pointer in rdi and `correct` in rsi, but the function +// would expect `correct` in rdi. +fn never(correct: &mut bool) -> NoReturn<Large> { + *correct = true; + panic!("catch this") +} + +fn main() { + let mut correct = false; + let never: fn(&mut bool) -> NoReturn<Large> = never; + // Safety: `NoReturn<Large>` is a `repr(transparent)` wrapper around `Large`, + // so they should be ABI-compatible. + let never: fn(&mut bool) -> Large = unsafe { std::mem::transmute(never) }; + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| never(&mut correct))); + assert!(result.is_err(), "function should have panicked"); + assert!(correct, "function should have stored `true` into `correct`"); +} diff --git a/tests/ui/wf/hir-wf-check-erase-regions.rs b/tests/ui/wf/hir-wf-check-erase-regions.rs index 01893044c27..20cc1cfe730 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.rs +++ b/tests/ui/wf/hir-wf-check-erase-regions.rs @@ -8,7 +8,9 @@ impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> { //~^ ERROR `&'a T` is not an iterator type Item = &'a T; - fn into_iter(self) -> Self::IntoIter { //~ ERROR `&'a T` is not an iterator + fn into_iter(self) -> Self::IntoIter { + //~^ ERROR `&'a T` is not an iterator + //~| ERROR `&T` is not an iterator unimplemented!() } } diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.stderr index 4b696dc1d1d..e4d48bf82c0 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.stderr +++ b/tests/ui/wf/hir-wf-check-erase-regions.stderr @@ -34,6 +34,16 @@ LL | fn into_iter(self) -> Self::IntoIter { note: required by a bound in `Flatten` --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL -error: aborting due to 3 previous errors +error[E0277]: `&T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:11:27 + | +LL | fn into_iter(self) -> Self::IntoIter { + | ^^^^^^^^^^^^^^ `&T` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&T` + = help: the trait `Iterator` is implemented for `&mut I` + = note: required for `&T` to implement `IntoIterator` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. |
