From 076064f3129863e7b568570588bd893017535f03 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 26 Nov 2025 06:02:20 -0500 Subject: [PATCH 01/55] Mark method receivers in builtin derives as being from the derive. --- compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 2 +- compiler/rustc_expand/src/build.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index baffc525d95a0..66a22ff16b193 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1055,7 +1055,7 @@ impl<'a> MethodDef<'a> { let args = { let self_arg = explicit_self.map(|explicit_self| { - let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span); + let ident = Ident::new(kw::SelfLower, span); ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident) }); let nonself_args = diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6be65b0fff16f..c5ffcfd6e04dd 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -315,7 +315,7 @@ impl<'a> ExtCtxt<'a> { self.expr_path(self.path_ident(span, id)) } pub fn expr_self(&self, span: Span) -> Box { - self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower)) + self.expr_ident(span, Ident::new(kw::SelfLower, span)) } pub fn expr_macro_call(&self, span: Span, call: Box) -> Box { From f78cbce6484b76886e5849e8f0c5372cba5223fe Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 1 Feb 2026 10:13:36 +0800 Subject: [PATCH 02/55] refactor: remove `Adjust::ReborrowPin` --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 13 +--- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 -- .../rustc_hir_typeck/src/method/confirm.rs | 11 +++- compiler/rustc_lint/src/autorefs.rs | 1 - compiler/rustc_middle/src/ty/adjustment.rs | 4 -- compiler/rustc_mir_build/src/thir/cx/expr.rs | 62 ------------------- 6 files changed, 9 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index b6dfda33142c5..9587b774c4ff2 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -751,16 +751,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::Borrow(ref autoref) => { self.walk_autoref(expr, &place_with_id, autoref); } - - adjustment::Adjust::ReborrowPin(mutbl) => { - // Reborrowing a Pin is like a combinations of a deref and a borrow, so we do - // both. - let bk = match mutbl { - ty::Mutability::Not => ty::BorrowKind::Immutable, - ty::Mutability::Mut => ty::BorrowKind::Mutable, - }; - self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); - } } place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?; } @@ -1292,8 +1282,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) - | adjustment::Adjust::Borrow(_) - | adjustment::Adjust::ReborrowPin(..) => { + | adjustment::Adjust::Borrow(_) => { // Result is an rvalue. Ok(self.cat_rvalue(expr.hir_id, target)) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f817ca8421473..d50ac8dbaa742 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -337,10 +337,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Adjust::Pointer(_pointer_coercion) => { // FIXME(const_trait_impl): We should probably enforce these. } - Adjust::ReborrowPin(_mutability) => { - // FIXME(const_trait_impl): We could enforce these; they correspond to - // `&mut T: DerefMut` tho, so it's kinda moot. - } Adjust::Borrow(_) => { // No effects to enforce here. } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 608bc7dffd9c0..add67bd826b1c 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -18,7 +18,8 @@ use rustc_lint::builtin::{ }; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, DerefAdjustKind, + PointerCoercion, }; use rustc_middle::ty::{ self, AssocContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, @@ -243,12 +244,16 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ty::Ref(_, ty, _) => *ty, _ => bug!("Expected a reference type for argument to Pin"), }; + adjustments.push(Adjustment { + kind: Adjust::Deref(DerefAdjustKind::Pin), + target: inner_ty, + }); Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl) } _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"), }; - - adjustments.push(Adjustment { kind: Adjust::ReborrowPin(mutbl), target }); + adjustments + .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Pin(mutbl)), target }); } None => {} } diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 910a2918f9f71..9a374488ab6fa 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -172,7 +172,6 @@ fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Muta &Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some((mutbl.into(), false)), Adjust::NeverToAny | Adjust::Pointer(..) - | Adjust::ReborrowPin(..) | Adjust::Deref(DerefAdjustKind::Builtin | DerefAdjustKind::Pin) | Adjust::Borrow(AutoBorrow::RawPtr(..) | AutoBorrow::Pin(..)) => None, } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 58687be7440b5..3802bde088a54 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -103,10 +103,6 @@ pub enum Adjust { Borrow(AutoBorrow), Pointer(PointerCoercion), - - /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. - // FIXME(pin_ergonomics): This can be replaced with a `Deref(Pin)` followed by a `Borrow(Pin)` - ReborrowPin(hir::Mutability), } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index c646b0fc45ea1..21d1551af6a5b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -218,68 +218,6 @@ impl<'tcx> ThirBuildCx<'tcx> { base: AdtExprBase::None, })); - debug!(?kind); - kind - } - Adjust::ReborrowPin(mutbl) => { - debug!("apply ReborrowPin adjustment"); - // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }` - - // We'll need these types later on - let pin_ty_args = match expr.ty.kind() { - ty::Adt(_, args) => args, - _ => bug!("ReborrowPin with non-Pin type"), - }; - let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty(); - let ptr_target_ty = match pin_ty.kind() { - ty::Ref(_, ty, _) => *ty, - _ => bug!("ReborrowPin with non-Ref type"), - }; - - // pointer = ($expr).__pointer - let pointer_target = ExprKind::Field { - lhs: self.thir.exprs.push(expr), - variant_index: FIRST_VARIANT, - name: FieldIdx::ZERO, - }; - let arg = Expr { temp_scope_id, ty: pin_ty, span, kind: pointer_target }; - let arg = self.thir.exprs.push(arg); - - // arg = *pointer - let expr = ExprKind::Deref { arg }; - let arg = self.thir.exprs.push(Expr { - temp_scope_id, - ty: ptr_target_ty, - span, - kind: expr, - }); - - // expr = &mut target - let borrow_kind = match mutbl { - hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, - hir::Mutability::Not => BorrowKind::Shared, - }; - let new_pin_target = - Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, ptr_target_ty, mutbl); - let expr = self.thir.exprs.push(Expr { - temp_scope_id, - ty: new_pin_target, - span, - kind: ExprKind::Borrow { borrow_kind, arg }, - }); - - // kind = Pin { __pointer: pointer } - let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span); - let args = self.tcx.mk_args(&[new_pin_target.into()]); - let kind = ExprKind::Adt(Box::new(AdtExpr { - adt_def: self.tcx.adt_def(pin_did), - variant_index: FIRST_VARIANT, - args, - fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]), - user_ty: None, - base: AdtExprBase::None, - })); - debug!(?kind); kind } From d81cc6846c6aee24270390ed9c0df229d3ce488a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Wed, 11 Mar 2026 20:41:57 +0800 Subject: [PATCH 03/55] fix: add EII function aliases to exported symbols --- compiler/rustc_codegen_ssa/src/back/symbol_export.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 557b00b911aa9..3269fc5c9c1d5 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -199,6 +199,14 @@ fn exported_non_generic_symbols_provider_local<'tcx>( })) } + symbols.extend(sorted.iter().flat_map(|&(&def_id, &info)| { + tcx.codegen_fn_attrs(def_id).foreign_item_symbol_aliases.iter().map( + move |&(foreign_item, _linkage, _visibility)| { + (ExportedSymbol::NonGeneric(foreign_item), info) + }, + ) + })); + if tcx.entry_fn(()).is_some() { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); From 69d9576b37dc62b9af763204dd7df8fff7935efe Mon Sep 17 00:00:00 2001 From: randomicon00 <20146907+randomicon00@users.noreply.github.com> Date: Mon, 16 Mar 2026 22:09:53 -0400 Subject: [PATCH 04/55] refactor: move doc(rust_logo) check to parser --- .../rustc_attr_parsing/src/attributes/doc.rs | 23 ++++++++++++++++++- compiler/rustc_passes/src/check_attr.rs | 15 ++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index f8968639f98c2..3a8de4f1a3c21 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,10 +1,12 @@ use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; +use rustc_errors::msg; use rustc_feature::template; use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, }; use rustc_hir::lints::AttributeLintKind; +use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; @@ -553,7 +555,26 @@ impl DocParser { ), Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic), Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox), - Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo), + Some(sym::rust_logo) => { + if let Err(span) = args.no_args() { + expected_no_args(cx, span); + return; + } + let span = path.span(); + if !check_attr_crate_level(cx, span) { + return; + } + if !cx.features().rustdoc_internals() { + feature_err( + cx.sess(), + sym::rustdoc_internals, + span, + msg!("the `#[doc(rust_logo)]` attribute is used for Rust branding"), + ) + .emit(); + } + self.attribute.rust_logo = Some(span); + } Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.list() else { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bec6ab7e83551..5b6b214a09abe 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1145,7 +1145,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { html_no_source: _, // already checked in attr_parsing issue_tracker_base_url: _, - rust_logo, + // already checked in attr_parsing + rust_logo: _, // allowed anywhere test_attrs: _, // already checked in attr_parsing @@ -1174,18 +1175,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_doc_inline(hir_id, target, inline); - if let Some(span) = rust_logo - && !self.tcx.features().rustdoc_internals() - { - feature_err( - &self.tcx.sess, - sym::rustdoc_internals, - *span, - msg!("the `#[doc(rust_logo)]` attribute is used for Rust branding"), - ) - .emit(); - } - if let Some(span) = masked { self.check_doc_masked(*span, hir_id, target); } From 48987fdba7ccb3815bfa05d239f0f7b0deab1c0a Mon Sep 17 00:00:00 2001 From: randomicon00 <20146907+randomicon00@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:06:40 -0400 Subject: [PATCH 05/55] refactor: reuse doc attr helper for rust_logo --- .../rustc_attr_parsing/src/attributes/doc.rs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 3a8de4f1a3c21..099a75e11f3af 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -483,15 +483,19 @@ impl DocParser { } macro_rules! no_args_and_crate_level { ($ident: ident) => {{ + no_args_and_crate_level!($ident, |span| {}); + }}; + ($ident: ident, |$span:ident| $extra_validation:block) => {{ if let Err(span) = args.no_args() { expected_no_args(cx, span); return; } - let span = path.span(); - if !check_attr_crate_level(cx, span) { + let $span = path.span(); + if !check_attr_crate_level(cx, $span) { return; } - self.attribute.$ident = Some(span); + $extra_validation + self.attribute.$ident = Some($span); }}; } macro_rules! string_arg_and_crate_level { @@ -555,15 +559,7 @@ impl DocParser { ), Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic), Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox), - Some(sym::rust_logo) => { - if let Err(span) = args.no_args() { - expected_no_args(cx, span); - return; - } - let span = path.span(); - if !check_attr_crate_level(cx, span) { - return; - } + Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo, |span| { if !cx.features().rustdoc_internals() { feature_err( cx.sess(), @@ -573,8 +569,7 @@ impl DocParser { ) .emit(); } - self.attribute.rust_logo = Some(span); - } + }), Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.list() else { From de1b0ac73a5701f1c3916e27938df22139e7b939 Mon Sep 17 00:00:00 2001 From: Embers-of-the-Fire Date: Fri, 20 Mar 2026 18:02:43 +0800 Subject: [PATCH 06/55] fix: guard paren-sugar pretty-printing on short trait args --- compiler/rustc_middle/src/ty/print/pretty.rs | 3 ++- .../paren-sugar-non-fn-trait-issue-153855.rs | 12 ++++++++++ ...ren-sugar-non-fn-trait-issue-153855.stderr | 15 +++++++++++++ ...en-sugar-non-fn-trait-ufcs-issue-153855.rs | 16 ++++++++++++++ ...ugar-non-fn-trait-ufcs-issue-153855.stderr | 22 +++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.rs create mode 100644 tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.stderr create mode 100644 tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.rs create mode 100644 tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.stderr diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2c14c37609d41..deef3065c3455 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3314,7 +3314,8 @@ define_print_and_forward_display! { TraitRefPrintSugared<'tcx> { if !with_reduced_queries() && p.tcx().trait_def(self.0.def_id).paren_sugar - && let ty::Tuple(args) = self.0.args.type_at(1).kind() + && let Some(args_ty) = self.0.args.get(1).and_then(|arg| arg.as_type()) + && let ty::Tuple(args) = args_ty.kind() { write!(p, "{}(", p.tcx().item_name(self.0.def_id))?; for (i, arg) in args.iter().enumerate() { diff --git a/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.rs b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.rs new file mode 100644 index 0000000000000..40816c39e6683 --- /dev/null +++ b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.rs @@ -0,0 +1,12 @@ +#![feature(rustc_attrs, unboxed_closures)] +#![allow(internal_features)] + +#[rustc_paren_sugar] +trait Tr { + fn method(); +} + +fn main() { + ::method(); + //~^ ERROR the trait bound `u8: Tr` is not satisfied +} diff --git a/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.stderr b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.stderr new file mode 100644 index 0000000000000..99699d8cb482e --- /dev/null +++ b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-issue-153855.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `u8: Tr` is not satisfied + --> $DIR/paren-sugar-non-fn-trait-issue-153855.rs:10:6 + | +LL | ::method(); + | ^^ the trait `Tr` is not implemented for `u8` + | +help: this trait has no implementations, consider adding one + --> $DIR/paren-sugar-non-fn-trait-issue-153855.rs:5:1 + | +LL | trait Tr { + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.rs b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.rs new file mode 100644 index 0000000000000..c49a2fe34c78d --- /dev/null +++ b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.rs @@ -0,0 +1,16 @@ +#![feature(rustc_attrs, unboxed_closures)] +#![allow(internal_features)] + +// Regression test for #153855: diagnostics should not ICE when a +// `#[rustc_paren_sugar]` trait is used with parenthesized syntax but does not +// have an `Fn`-family generic layout. +#[rustc_paren_sugar] +trait Tr<'a, 'b, T> { + fn method() {} +} + +fn main() { + ::method; + //~^ ERROR associated item constraints are not allowed here + //~| ERROR the trait bound `u8: Tr<'_, '_, (&u8,)>` is not satisfied +} diff --git a/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.stderr b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.stderr new file mode 100644 index 0000000000000..c4ce9047cd30b --- /dev/null +++ b/tests/ui/unboxed-closures/paren-sugar-non-fn-trait-ufcs-issue-153855.stderr @@ -0,0 +1,22 @@ +error[E0229]: associated item constraints are not allowed here + --> $DIR/paren-sugar-non-fn-trait-ufcs-issue-153855.rs:13:12 + | +LL | ::method; + | ^^^^^^^ associated item constraint not allowed here + +error[E0277]: the trait bound `u8: Tr<'_, '_, (&u8,)>` is not satisfied + --> $DIR/paren-sugar-non-fn-trait-ufcs-issue-153855.rs:13:6 + | +LL | ::method; + | ^^ the trait `Tr<'_, '_, (&u8,)>` is not implemented for `u8` + | +help: this trait has no implementations, consider adding one + --> $DIR/paren-sugar-non-fn-trait-ufcs-issue-153855.rs:8:1 + | +LL | trait Tr<'a, 'b, T> { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0229, E0277. +For more information about an error, try `rustc --explain E0229`. From 125cefc89ae8e55d8b1a2635ab4d5c653490f9d9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 21 Mar 2026 06:45:55 +0000 Subject: [PATCH 07/55] freebsd sync: fix _umtx_time flags check to use bitwise operation. The `_umtx_time` flags check in `read_umtx_time` used equality (`flags == abs_time`) instead of bitwise AND (`flags & abs_time != 0`) to detect `UMTX_ABSTIME`. While functionally equivalent for current valid inputs (0 or `UMTX_ABSTIME` alone), the equality check would silently treat an absolute timeout as relative if `flags` had `UMTX_ABSTIME` set alongside other bits. Additionally, unknown flags were silently accepted, whereas the FreeBSD kernel (`umtx_copyin_umtx_time()` in `kern_umtx.c`) rejects them with `EINVAL`. The fix adds validation that rejects unsupported flags and switches to the standard bitwise AND pattern used elsewhere in the codebase (e.g. `O_APPEND`/`O_TRUNC` checks in `fs.rs`). --- src/tools/miri/src/shims/unix/freebsd/sync.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs index 8cf4464389631..8c585c7ec2641 100644 --- a/src/tools/miri/src/shims/unix/freebsd/sync.rs +++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs @@ -216,7 +216,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let flags_place = this.project_field(ut, FieldIdx::from_u32(1))?; let flags = this.read_scalar(&flags_place)?.to_u32()?; - let abs_time_flag = flags == abs_time; + + if flags & !abs_time != 0 { + throw_unsup_format!("unsupported `_umtx_time` flags: {:#x}", flags); + } + + let abs_time_flag = flags & abs_time != 0; let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?; let clock_id = this.read_scalar(&clock_id_place)?; From 69fcf2675911b70b969441856c04a3439a419c00 Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Sun, 22 Mar 2026 22:11:07 +0100 Subject: [PATCH 08/55] Unblock all threads with expired timeouts in single scheduler run --- src/tools/miri/src/concurrency/thread.rs | 145 +++++++++++------------ 1 file changed, 66 insertions(+), 79 deletions(-) diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index d6d6449df32bf..ee74e06815945 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -656,64 +656,10 @@ impl<'tcx> ThreadManager<'tcx> { // We should only switch stacks between steps. self.yield_active_thread = true; } - - /// Get the wait time for the next timeout, or `None` if no timeout is pending. - fn next_callback_wait_time(&self, clock: &MonotonicClock) -> Option { - self.threads - .iter() - .filter_map(|t| { - match &t.state { - ThreadState::Blocked { timeout: Some(timeout), .. } => - Some(timeout.get_wait_time(clock)), - _ => None, - } - }) - .min() - } } impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { - /// Execute a timeout callback on the callback's thread. - #[inline] - fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let mut found_callback = None; - // Find a blocked thread that has timed out. - for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() { - match &thread.state { - ThreadState::Blocked { timeout: Some(timeout), .. } - if timeout.get_wait_time(&this.machine.monotonic_clock) == Duration::ZERO => - { - let old_state = mem::replace(&mut thread.state, ThreadState::Enabled); - let ThreadState::Blocked { callback, .. } = old_state else { unreachable!() }; - found_callback = Some((id, callback)); - // Run the fallback (after the loop because borrow-checking). - break; - } - _ => {} - } - } - if let Some((thread, callback)) = found_callback { - // This back-and-forth with `set_active_thread` is here because of two - // design decisions: - // 1. Make the caller and not the callback responsible for changing - // thread. - // 2. Make the scheduler the only place that can change the active - // thread. - let old_thread = this.machine.threads.set_active_thread_id(thread); - callback.call(this, UnblockKind::TimedOut)?; - this.machine.threads.set_active_thread_id(old_thread); - } - // found_callback can remain None if the computer's clock - // was shifted after calling the scheduler and before the call - // to get_ready_callback (see issue - // https://github.com/rust-lang/miri/issues/1763). In this case, - // just do nothing, which effectively just returns to the - // scheduler. - interp_ok(()) - } - #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); @@ -790,19 +736,12 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { this.poll_and_unblock(Some(Duration::ZERO))?; } - let thread_manager = &this.machine.threads; - let clock = &this.machine.monotonic_clock; - // We also check timeouts before running any other thread, to ensure that timeouts // "in the past" fire before any other thread can take an action. This ensures that for // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by // abstime has already been passed at the time of the call". // - let potential_sleep_time = thread_manager.next_callback_wait_time(clock); - if potential_sleep_time == Some(Duration::ZERO) { - // The timeout exceeded for some thread so we unblock the thread and execute its timeout callback. - this.run_timeout_callback()?; - } + let potential_sleep_time = this.unblock_expired_timeouts()?; let thread_manager = &mut this.machine.threads; let rng = this.machine.rng.get_mut(); @@ -868,6 +807,71 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { throw_machine_stop!(TerminationInfo::GlobalDeadlock); } } + + /// Poll for I/O events until either an I/O event happened or the timeout expired. + /// The different timeout values are described in [`BlockingIoManager::poll`]. + fn poll_and_unblock(&mut self, timeout: Option) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let ready = match this.machine.blocking_io.poll(timeout) { + Ok(ready) => ready, + // We can ignore errors originating from interrupts; that's just a spurious wakeup. + Err(e) if e.kind() == io::ErrorKind::Interrupted => return interp_ok(()), + // For other errors we panic. On Linux and BSD hosts this should only be + // reachable when a system resource error (e.g. ENOMEM or ENOSPC) occurred. + Err(e) => panic!("unexpected error while polling: {e}"), + }; + + ready.into_iter().try_for_each(|thread_id| this.unblock_thread(thread_id, BlockReason::IO)) + } + + /// Find all threads with expired timeouts, unblock them and execute their timeout callbacks. + /// + /// This method returns the minimum duration until the next thread timeout expires. + /// If all ready threads have no timeout set, [`None`] is returned. + fn unblock_expired_timeouts(&mut self) -> InterpResult<'tcx, Option> { + let this = self.eval_context_mut(); + let clock = &this.machine.monotonic_clock; + + let mut min_wait_time = Option::::None; + let mut callbacks = Vec::new(); + + for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() { + match &thread.state { + ThreadState::Blocked { timeout: Some(timeout), .. } => { + let wait_time = timeout.get_wait_time(clock); + if wait_time.is_zero() { + // The timeout expired for this thread. + let old_state = mem::replace(&mut thread.state, ThreadState::Enabled); + let ThreadState::Blocked { callback, .. } = old_state else { + unreachable!() + }; + // Add callback to list to be run after this loop because of borrow-checking. + callbacks.push((id, callback)); + } else { + // Update `min_wait_time` to contain the smallest duration until + // the next timeout expires. + min_wait_time = Some(wait_time.min(min_wait_time.unwrap_or(Duration::MAX))); + } + } + _ => {} + } + } + + for (thread, callback) in callbacks { + // This back-and-forth with `set_active_thread` is here because of two + // design decisions: + // 1. Make the caller and not the callback responsible for changing + // thread. + // 2. Make the scheduler the only place that can change the active + // thread. + let old_thread = this.machine.threads.set_active_thread_id(thread); + callback.call(this, UnblockKind::TimedOut)?; + this.machine.threads.set_active_thread_id(old_thread); + } + + interp_ok(min_wait_time) + } } // Public interface to thread management. @@ -1348,21 +1352,4 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } - - /// Poll for I/O events until either an I/O event happened or the timeout expired. - /// The different timeout values are described in [`BlockingIoManager::poll`]. - fn poll_and_unblock(&mut self, timeout: Option) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let ready = match this.machine.blocking_io.poll(timeout) { - Ok(ready) => ready, - // We can ignore errors originating from interrupts; that's just a spurious wakeup. - Err(e) if e.kind() == io::ErrorKind::Interrupted => return interp_ok(()), - // For other errors we panic. On Linux and BSD hosts this should only be - // reachable when a system resource error (e.g. ENOMEM or ENOSPC) occurred. - Err(e) => panic!("{e}"), - }; - - ready.into_iter().try_for_each(|thread_id| this.unblock_thread(thread_id, BlockReason::IO)) - } } From 365d2bc033731cd8d56a006a3ff1c8c81e4b7577 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2026 08:08:38 +0100 Subject: [PATCH 09/55] Prepare for merging from rust-lang/rust This updates the rust-version file to 212b0d480f337082bbe1132d2b62be20e7e61f8a. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e281dad8ef1ee..78136929d4459 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -fd0c901b00ee1e08a250039cdb90258603497e20 +212b0d480f337082bbe1132d2b62be20e7e61f8a From 65f28d1e9e32e4884b9808a8353d459e6740d1f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2026 08:35:37 +0100 Subject: [PATCH 10/55] support looking up extern statics via dlsym --- src/tools/miri/src/machine.rs | 2 +- src/tools/miri/src/shims/unix/foreign_items.rs | 9 ++++++--- src/tools/miri/tests/pass-dep/libc/libc-misc.rs | 11 +++++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index d8224f1878f05..566a775b90108 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -569,7 +569,7 @@ pub struct MiriMachine<'tcx> { pub(crate) user_relevant_crates: Vec, /// Mapping extern static names to their pointer. - extern_statics: FxHashMap, + pub(crate) extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index f2e16e75892ec..bce091537f587 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -727,11 +727,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; - if let Ok(name) = str::from_utf8(name) - && is_dyn_sym(name, &this.tcx.sess.target.os) - { + let Ok(name) = str::from_utf8(name) else { + throw_unsup_format!("dlsym: non UTF-8 symbol name not supported") + }; + if is_dyn_sym(name, &this.tcx.sess.target.os) { let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; + } else if let Some(&ptr) = this.machine.extern_statics.get(&Symbol::intern(name)) { + this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs index d1c0085b024a5..36ed470b353fe 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs @@ -63,15 +63,22 @@ fn test_sigrt() { } fn test_dlsym() { - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) }; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"notasymbol".as_ptr()) }; assert!(addr as usize == 0); - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) }; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"isatty".as_ptr()) }; assert!(addr as usize != 0); let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) }; assert_eq!(isatty(999), 0); let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); assert_eq!(errno, libc::EBADF); + + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"environ".as_ptr()) }; + assert!(addr as usize != 0); + extern "C" { + static mut environ: *const *const u8; + } + assert!(addr as usize == &raw const environ as usize); } fn test_getuid() { From fd9670b7af5ef3af0c8d9d0f42000ca46cd99036 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2026 08:50:21 +0100 Subject: [PATCH 11/55] make better use of CStr/CString --- .../fail-dep/libc/env-set_var-data-race.rs | 2 +- .../libc/env-set_var-data-race.stderr | 6 ++-- .../fail-dep/libc/fs/mkstemp_immutable_arg.rs | 2 +- .../fs/unix_open_missing_required_mode.rs | 5 ++- .../fs/unix_open_missing_required_mode.stderr | 4 +-- .../concurrency/env-cleanup-data-race.rs | 2 +- .../miri/tests/pass-dep/extra_fn_ptr_gc.rs | 4 +-- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 34 +++++++------------ 8 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index 5c80f6425eaae..b1929e3f27ed2 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -7,7 +7,7 @@ fn main() { let t = thread::spawn(|| unsafe { // Access the environment in another thread without taking the env lock. // This represents some C code that queries the environment. - libc::getenv(b"TZ\0".as_ptr().cast()); //~ERROR: Data race detected + libc::getenv(c"TZ".as_ptr()); //~ERROR: Data race detected }); // Meanwhile, the main thread uses the "safe" Rust env accessor. env::set_var("MY_RUST_VAR", "Ferris"); diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr index 635091cc0173d..b4cd31b4ddaba 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `unnamed-ID` at ALLOC --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC | -LL | libc::getenv(b"TZ/0".as_ptr().cast()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (2) just happened here +LL | libc::getenv(c"TZ".as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (2) just happened here | help: and (1) occurred earlier here --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC @@ -19,7 +19,7 @@ LL | let t = thread::spawn(|| unsafe { | _____________^ LL | | // Access the environment in another thread without taking the env lock. LL | | // This represents some C code that queries the environment. -LL | | libc::getenv(b"TZ/0".as_ptr().cast()); +LL | | libc::getenv(c"TZ".as_ptr()); LL | | }); | |______^ diff --git a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs index 2c676f12b4f0e..abdafe2b0fb38 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs @@ -6,6 +6,6 @@ fn main() { } fn test_mkstemp_immutable_arg() { - let s: *mut libc::c_char = b"fooXXXXXX\0" as *const _ as *mut _; + let s: *mut libc::c_char = c"fooXXXXXX".as_ptr().cast_mut(); let _fd = unsafe { libc::mkstemp(s) }; //~ ERROR: Undefined Behavior: writing to alloc1 which is read-only } diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs index 457f32e55446e..29548c17443a6 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs @@ -6,7 +6,6 @@ fn main() { } fn test_file_open_missing_needed_mode() { - let name = b"missing_arg.txt\0"; - let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: not enough variadic arguments + let name = c"missing_arg.txt".as_ptr(); + let _fd = unsafe { libc::open(name, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: not enough variadic arguments } diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr index a85fae9c7dd27..186ca4ccdd406 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not enough variadic arguments for `open(pathname, O_CREAT, ...)`: got 0, expected at least 1 --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC | -LL | let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | let _fd = unsafe { libc::open(name, libc::O_CREAT) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index 91cf24a944ad6..44e969578989b 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -8,7 +8,7 @@ fn main() { unsafe { thread::spawn(|| { // Access the environment in another thread without taking the env lock - let s = libc::getenv("MIRI_ENV_VAR_TEST\0".as_ptr().cast()); + let s = libc::getenv(c"MIRI_ENV_VAR_TEST".as_ptr()); if s.is_null() { panic!("null"); } diff --git a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs index 9e5627c75a97a..70fa6c183c84a 100644 --- a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs +++ b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs @@ -7,8 +7,8 @@ mod utils; type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; fn main() { - let name = "getentropy\0"; - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize }; + let name = c"getentropy"; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize }; // If the GC does not account for the extra_fn_ptr entry that this dlsym just added, this GC // run will delete our entry for the base addr of the function pointer we will transmute to, // and the call through the function pointer will report UB. diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index f5e9a56d7d039..9dc1af1be299f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -54,29 +54,23 @@ fn main() { fn test_file_open_unix_allow_two_args() { let path = utils::prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY) }; + let _fd = unsafe { libc::open(name.as_ptr(), libc::O_RDONLY) }; } fn test_file_open_unix_needs_three_args() { let path = utils::prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT, 0o666) }; + let _fd = unsafe { libc::open(name.as_ptr(), libc::O_CREAT, 0o666) }; } fn test_file_open_unix_extra_third_arg() { let path = utils::prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 42) }; + let _fd = unsafe { libc::open(name.as_ptr(), libc::O_RDONLY, 42) }; } fn test_dup_stdout_stderr() { @@ -92,12 +86,10 @@ fn test_dup_stdout_stderr() { fn test_dup() { let bytes = b"dup and dup2"; let path = utils::prepare_with_content("miri_test_libc_dup.txt", bytes); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); unsafe { - let fd = libc::open(name_ptr, libc::O_RDONLY); + let fd = libc::open(name.as_ptr(), libc::O_RDONLY); let new_fd = libc::dup(fd); let new_fd2 = libc::dup2(fd, 8); @@ -519,7 +511,7 @@ fn test_read_and_uninit() { { // We test that libc::read initializes its buffer. let path = utils::prepare_with_content("pass-libc-read-and-uninit.txt", &[1u8, 2, 3]); - let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + let cpath = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); unsafe { let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); assert_ne!(fd, -1); @@ -528,8 +520,8 @@ fn test_read_and_uninit() { let buf = buf.assume_init(); assert_eq!(buf, 1); assert_eq!(libc::close(fd), 0); + assert_eq!(libc::unlink(cpath.as_ptr()), 0); } - remove_file(&path).unwrap(); } { // We test that if we requested to read 4 bytes, but actually read 3 bytes, then @@ -567,17 +559,15 @@ fn test_nofollow_not_symlink() { #[cfg(target_os = "macos")] fn test_ioctl() { let path = utils::prepare_with_content("miri_test_libc_ioctl.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); unsafe { // 100 surely is an invalid FD. assert_eq!(libc::ioctl(100, libc::FIOCLEX), -1); let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); assert_eq!(errno, libc::EBADF); - let fd = libc::open(name_ptr, libc::O_RDONLY); + let fd = libc::open(name.as_ptr(), libc::O_RDONLY); assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } From b32f9cbda1a4a0af2f4502225e882d3dd5f6f381 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2026 17:27:47 +0100 Subject: [PATCH 12/55] CONTRIBUTING: explain how to build miri against a locally built rustc --- src/tools/miri/CONTRIBUTING.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 852ea26ab89e0..ad8b2b09b6ba8 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -171,8 +171,8 @@ MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/pass/v ``` Note that you will only get `info`, `warn` or `error` messages if you use a prebuilt compiler. -In order to get `debug` and `trace` level messages, you need to build miri with a locally built -compiler that has `debug=true` set in `bootstrap.toml`. +In order to get `debug` and `trace` level messages, you need to build miri with a [locally built +compiler](#advanced-topic-building-miri-against-a-locally-compiled-rustc) that has `debug=true` set in `bootstrap.toml`. #### Debugging error messages @@ -320,6 +320,33 @@ You can also directly run Miri on a Rust source file: ./x.py run miri --stage 1 --args src/tools/miri/tests/pass/hello.rs ``` +## Advanced topic: Building Miri against a locally compiled rustc + +Very rarely, it can be necessary to work with an out-of-tree Miri but build it against a rustc that +was locally compiled. (Usually, you should instead work on the Miri that's in the Rust tree, as +described in the previous subsection.) + +This requires a fully bootstrapped build: + +```sh +# Build rustc, then build rustc with that rustc. This can take a while. +./x build library --stage 3 +``` + +You also need to set up a linked toolchain with rustup: + +```sh +rustup toolchain link stage2 build/host/stage2 +``` + +Then in the Miri folder, you can set this as the current toolchain and build against it: + +```sh +rustup override set stage2 +# Prevent `./miri` from reseting the toolchain. +export MIRI_AUTO_OPS=no +``` + ## Advanced topic: Syncing with the rustc repo We use the [`josh-sync`](https://github.com/rust-lang/josh-sync) tool to transmit changes between the From 63a2011abb695a45df4002a66a585a8947b7a16a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2026 22:19:21 +0100 Subject: [PATCH 13/55] test miri_start with and without std --- .../pass/{no_std_miri_start.rs => miri_start_no_std.rs} | 0 ...{no_std_miri_start.stdout => miri_start_no_std.stdout} | 0 src/tools/miri/tests/pass/miri_start_with_std.rs | 8 ++++++++ src/tools/miri/tests/pass/miri_start_with_std.stdout | 1 + 4 files changed, 9 insertions(+) rename src/tools/miri/tests/pass/{no_std_miri_start.rs => miri_start_no_std.rs} (100%) rename src/tools/miri/tests/pass/{no_std_miri_start.stdout => miri_start_no_std.stdout} (100%) create mode 100644 src/tools/miri/tests/pass/miri_start_with_std.rs create mode 100644 src/tools/miri/tests/pass/miri_start_with_std.stdout diff --git a/src/tools/miri/tests/pass/no_std_miri_start.rs b/src/tools/miri/tests/pass/miri_start_no_std.rs similarity index 100% rename from src/tools/miri/tests/pass/no_std_miri_start.rs rename to src/tools/miri/tests/pass/miri_start_no_std.rs diff --git a/src/tools/miri/tests/pass/no_std_miri_start.stdout b/src/tools/miri/tests/pass/miri_start_no_std.stdout similarity index 100% rename from src/tools/miri/tests/pass/no_std_miri_start.stdout rename to src/tools/miri/tests/pass/miri_start_no_std.stdout diff --git a/src/tools/miri/tests/pass/miri_start_with_std.rs b/src/tools/miri/tests/pass/miri_start_with_std.rs new file mode 100644 index 0000000000000..510b9d4196226 --- /dev/null +++ b/src/tools/miri/tests/pass/miri_start_with_std.rs @@ -0,0 +1,8 @@ +#![no_main] + +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _b = Box::new(0); + println!("hello, world!"); + 0 +} diff --git a/src/tools/miri/tests/pass/miri_start_with_std.stdout b/src/tools/miri/tests/pass/miri_start_with_std.stdout new file mode 100644 index 0000000000000..270c611ee72c5 --- /dev/null +++ b/src/tools/miri/tests/pass/miri_start_with_std.stdout @@ -0,0 +1 @@ +hello, world! From a2856a7f700c0880e963062f04d48ef04160f948 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 25 Mar 2026 05:20:05 +0000 Subject: [PATCH 14/55] Prepare for merging from rust-lang/rust This updates the rust-version file to 8a703520e80d87d4423c01f9d4fbc9e5f6533a02. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 78136929d4459..effc9080877a2 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -212b0d480f337082bbe1132d2b62be20e7e61f8a +8a703520e80d87d4423c01f9d4fbc9e5f6533a02 From f0c2bb026172ce0e98dac2f9d6c4ee7d1a7fc5fb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2026 12:18:54 +0100 Subject: [PATCH 15/55] ./miri toolchain: support overwriting the to-be-installed commit --- src/tools/miri/miri-script/src/commands.rs | 11 +++++++---- src/tools/miri/miri-script/src/main.rs | 7 +++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 86f6253d4558a..d469502c243f4 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -80,7 +80,7 @@ impl Command { // `toolchain` goes first as it could affect the others if auto_toolchain { - Self::toolchain(vec![])?; + Self::toolchain(None, vec![])?; } if auto_fmt { Self::fmt(vec![])?; @@ -121,15 +121,18 @@ impl Command { Command::Clippy { features, flags } => Self::clippy(features, flags), Command::Bench { target, no_install, save_baseline, load_baseline, benches } => Self::bench(target, no_install, save_baseline, load_baseline, benches), - Command::Toolchain { flags } => Self::toolchain(flags), + Command::Toolchain { commit, flags } => Self::toolchain(commit, flags), Command::Squash => Self::squash(), } } - fn toolchain(flags: Vec) -> Result<()> { + fn toolchain(new_commit: Option, flags: Vec) -> Result<()> { let sh = Shell::new()?; sh.change_dir(miri_dir()?); - let new_commit = sh.read_file("rust-version")?.trim().to_owned(); + let new_commit = match new_commit { + Some(c) => c, + None => sh.read_file("rust-version")?.trim().to_owned(), + }; let current_commit = { let rustc_info = cmd!(sh, "rustc +miri --version -v").read(); if let Ok(rustc_info) = rustc_info { diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index e307014496886..419c128e5b72f 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -138,6 +138,9 @@ pub enum Command { /// The `rust-version` file is used to determine the commit that will be intsalled. /// `rustup-toolchain-install-master` must be installed for this to work. Toolchain { + /// Overwrite the commit to install. + #[arg(long)] + commit: Option, /// Flags that are passed through to `rustup-toolchain-install-master`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, @@ -157,8 +160,8 @@ impl Command { | Self::Build { flags, .. } | Self::Check { flags, .. } | Self::Doc { flags, .. } - | Self::Fmt { flags } - | Self::Toolchain { flags } + | Self::Fmt { flags, .. } + | Self::Toolchain { flags, .. } | Self::Clippy { flags, .. } | Self::Run { flags, .. } | Self::Test { flags, .. } => { From d0db8c29b1abc29314524ed9a412a9c1fb46f9db Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Mon, 23 Mar 2026 00:00:47 +0100 Subject: [PATCH 16/55] Add socket `getpeername` shim --- .../miri/src/shims/unix/foreign_items.rs | 10 ++ src/tools/miri/src/shims/unix/socket.rs | 42 ++++++ .../miri/tests/pass-dep/libc/libc-socket.rs | 130 +++++++++++++++++- src/tools/miri/tests/pass/shims/socket.rs | 20 +++ 4 files changed, 201 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index f2e16e75892ec..471a91515d859 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -633,6 +633,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.getsockname(socket, address, address_len)?; this.write_scalar(result, dest)?; } + "getpeername" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + link_name, + abi, + args, + )?; + let result = this.getpeername(socket, address, address_len)?; + this.write_scalar(result, dest)?; + } // Time "gettimeofday" => { diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index f9b3ca479b799..8f2ab69261ce7 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -620,6 +620,48 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Err(e) => this.set_last_error_and_return_i32(e), } } + + fn getpeername( + &mut self, + socket: &OpTy<'tcx>, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let address_ptr = this.read_pointer(address)?; + let address_len_ptr = this.read_pointer(address_len)?; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return_i32(LibcError("ENOTSOCK")); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + let state = socket.state.borrow(); + + let SocketState::Connected(stream) = &*state else { + // We can only read the peer address of connected sockets. + return this.set_last_error_and_return_i32(LibcError("ENOTCONN")); + }; + + let address = match stream.peer_addr() { + Ok(address) => address, + Err(e) => return this.set_last_error_and_return_i32(e), + }; + + match this.write_socket_address(&address, address_ptr, address_len_ptr, "getpeername")? { + Ok(_) => interp_ok(Scalar::from_i32(0)), + Err(e) => this.set_last_error_and_return_i32(e), + } + } } impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs index e3c14e60b25e6..8dd00e60200a5 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socket.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs @@ -38,6 +38,9 @@ fn main() { test_getsockname_ipv4_random_port(); test_getsockname_ipv4_unbound(); test_getsockname_ipv6(); + + test_getpeername_ipv4(); + test_getpeername_ipv6(); } fn test_socket_close() { @@ -183,7 +186,6 @@ fn test_listen() { /// - Connecting when the server is already accepting /// - Accepting when there is already an incoming connection fn test_accept_connect() { - // Create a new non-blocking server socket. let server_sockfd = unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; let client_sockfd = @@ -379,6 +381,132 @@ fn test_getsockname_ipv6() { assert_eq!(addr.sin6_addr.s6_addr, sock_addr.sin6_addr.s6_addr); } +/// Test the `getpeername` syscall on an IPv4 socket. +/// For a connected socket, the `getpeername` syscall should +/// return the same address as the socket was connected to. +fn test_getpeername_ipv4() { + let server_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + server_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(server_sockfd, 16)); + } + + // Retrieve actual listener address because we used a randomized port. + let (_, server_addr) = + sockname(|storage, len| unsafe { libc::getsockname(server_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(addr) = server_addr else { + // We bound an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + // Spawn the server thread. + let server_thread = thread::spawn(move || { + let (_peerfd, _peer_addr) = + sockname(|storage, len| unsafe { libc::accept(server_sockfd, storage, len) }).unwrap(); + }); + + // Test connecting to an already accepting server. + unsafe { + errno_check(libc::connect( + client_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + let (_, peer_addr) = + sockname(|storage, len| unsafe { libc::getpeername(client_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(peer_addr) = peer_addr else { + // We connected to an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + assert_eq!(addr.sin_family, peer_addr.sin_family); + assert_eq!(addr.sin_port, peer_addr.sin_port); + assert_eq!(addr.sin_addr.s_addr, peer_addr.sin_addr.s_addr); + + server_thread.join().unwrap(); +} + +/// Test the `getpeername` syscall on an IPv6 socket. +/// For a connected socket, the `getpeername` syscall should +/// return the same address as the socket was connected to. +fn test_getpeername_ipv6() { + let server_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET6, libc::SOCK_STREAM, 0)).unwrap() }; + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET6, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv6_sock_addr(net::IPV6_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + server_sockfd, + (&addr as *const libc::sockaddr_in6).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(server_sockfd, 16)); + } + + // Retrieve actual listener address because we used a randomized port. + let (_, server_addr) = + sockname(|storage, len| unsafe { libc::getsockname(server_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V6(addr) = server_addr else { + // We bound an IPv6 address so we also expect + // an IPv6 address to be returned. + panic!() + }; + + // Spawn the server thread. + let server_thread = thread::spawn(move || { + let (_peerfd, _peer_addr) = + sockname(|storage, len| unsafe { libc::accept(server_sockfd, storage, len) }).unwrap(); + }); + + // Test connecting to an already accepting server. + unsafe { + errno_check(libc::connect( + client_sockfd, + (&addr as *const libc::sockaddr_in6).cast::(), + size_of::() as libc::socklen_t, + )); + } + + let (_, peer_addr) = + sockname(|storage, len| unsafe { libc::getpeername(client_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V6(peer_addr) = peer_addr else { + // We connected to an IPv6 address so we also expect + // an IPv6 address to be returned. + panic!() + }; + + assert_eq!(addr.sin6_family, peer_addr.sin6_family); + assert_eq!(addr.sin6_port, peer_addr.sin6_port); + assert_eq!(addr.sin6_flowinfo, peer_addr.sin6_flowinfo); + assert_eq!(addr.sin6_scope_id, peer_addr.sin6_scope_id); + assert_eq!(addr.sin6_addr.s6_addr, peer_addr.sin6_addr.s6_addr); + + server_thread.join().unwrap(); +} + /// Set a socket option. It's the caller's responsibility to ensure that `T` is /// associated with the given socket option. /// diff --git a/src/tools/miri/tests/pass/shims/socket.rs b/src/tools/miri/tests/pass/shims/socket.rs index 2e63e00c67d90..852397a356916 100644 --- a/src/tools/miri/tests/pass/shims/socket.rs +++ b/src/tools/miri/tests/pass/shims/socket.rs @@ -8,6 +8,7 @@ fn main() { test_create_ipv4_listener(); test_create_ipv6_listener(); test_accept_and_connect(); + test_peer_addr(); } fn test_create_ipv4_listener() { @@ -34,3 +35,22 @@ fn test_accept_and_connect() { handle.join().unwrap(); } + +/// Test whether the [`TcpStream::peer_addr`] of a connected socket +/// is the same address as the one the stream was connected to. +fn test_peer_addr() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + // Get local address with randomized port to know where + // we need to connect to. + let address = listener.local_addr().unwrap(); + + let handle = thread::spawn(move || { + let (_stream, _addr) = listener.accept().unwrap(); + }); + + let stream = TcpStream::connect(address).unwrap(); + let peer_addr = stream.peer_addr().unwrap(); + assert_eq!(address, peer_addr); + + handle.join().unwrap(); +} From c9f2a6ef226d622d2ba4cb8a100fb2c1c53289ae Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 26 Mar 2026 05:27:36 +0000 Subject: [PATCH 17/55] Prepare for merging from rust-lang/rust This updates the rust-version file to 1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index effc9080877a2..68f38716dbb0b 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -8a703520e80d87d4423c01f9d4fbc9e5f6533a02 +1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55 From e56d8665eada851af8c11854b16c8ca11c16b186 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 26 Mar 2026 05:36:48 +0000 Subject: [PATCH 18/55] fmt --- .../tests/fail/function_pointers/abi_mismatch_return_type.rs | 3 ++- .../miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs index 8bf46af71e821..3f9c42a782233 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs @@ -1,5 +1,6 @@ fn main() { - fn f() -> u32 { //~ ERROR: type u32 passing return place of type () + fn f() -> u32 { + //~^ERROR: type u32 passing return place of type () 42 } diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs index 7bc26237576a3..0635fdd149204 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -5,7 +5,8 @@ use std::intrinsics::mir::*; use std::num::NonZero; use std::ptr; -fn f(c: u32) { //~ERROR: expected something greater or equal to 1 +fn f(c: u32) { + //~^ERROR: expected something greater or equal to 1 println!("{c}"); } From e12a6db6482487c3ae81a40818745e09e0460411 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Wed, 21 Jan 2026 20:21:15 -0800 Subject: [PATCH 19/55] Implement MoveFileExW shim --- .../miri/src/shims/windows/foreign_items.rs | 10 +++++++ src/tools/miri/src/shims/windows/fs.rs | 30 +++++++++++++++++++ .../miri/tests/pass-dep/shims/windows-fs.rs | 20 ++++++++++++- src/tools/miri/tests/pass/shims/fs.rs | 2 +- 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 0bdf6bb785056..e628e50290e4b 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -451,6 +451,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?; this.write_scalar(res, dest)?; } + "MoveFileExW" => { + let [existing_name, new_name, flags] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _, *const _, u32) -> winapi::BOOL), + link_name, + abi, + args, + )?; + let res = this.MoveFileExW(existing_name, new_name, flags)?; + this.write_scalar(res, dest)?; + } // Allocation "HeapAlloc" => { diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index e5a98e86d6453..1ee93cf911c5a 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -490,6 +490,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } + fn MoveFileExW( + &mut self, + existing_name: &OpTy<'tcx>, + new_name: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let existing_name = this.read_path_from_wide_str(this.read_pointer(existing_name)?)?; + let new_name = this.read_path_from_wide_str(this.read_pointer(new_name)?)?; + + let flags = this.read_scalar(flags)?.to_u32()?; + + // Flag to indicate whether we should replace an existing file. + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexw + let movefile_replace_existing = this.eval_windows_u32("c", "MOVEFILE_REPLACE_EXISTING"); + + if flags != movefile_replace_existing { + throw_unsup_format!("MoveFileExW: Unsupported `dwFlags` value {}", flags); + } + + match std::fs::rename(existing_name, new_name) { + Ok(_) => interp_ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } + fn DeleteFileW( &mut self, file_name: &OpTy<'tcx>, // LPCWSTR diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index 91639c5023252..79cb551386a18 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -22,7 +22,7 @@ use windows_sys::Win32::Storage::FileSystem::{ FILE_ALLOCATION_INFO, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT, FILE_END_OF_FILE_INFO, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, FileAllocationInfo, FileEndOfFileInfo, - FlushFileBuffers, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, + FlushFileBuffers, GetFileInformationByHandle, MoveFileExW, OPEN_ALWAYS, OPEN_EXISTING, SetFileInformationByHandle, SetFilePointerEx, }; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; @@ -42,6 +42,7 @@ fn main() { test_set_file_info(); test_dup_handle(); test_flush_buffers(); + test_move_file(); } } @@ -376,6 +377,23 @@ unsafe fn test_flush_buffers() { } } +unsafe fn test_move_file() { + let tmp_dir = utils::tmp(); + + let temp = tmp_dir.join("test_move_file.txt"); + let temp_new = tmp_dir.join("test_move_file_new.txt"); + let mut file = fs::File::options().create(true).write(true).open(&temp).unwrap(); + file.write_all(b"Hello, World!\n").unwrap(); + + let from = to_wide_cstr(&temp); + let to = to_wide_cstr(&temp_new); + if MoveFileExW(from.as_ptr(), to.as_ptr(), 1) == 0 { + panic!("Failed to rename file from {} to {}", temp.display(), temp_new.display()); + } + + assert_eq!(fs::read_to_string(temp_new).unwrap(), "Hello, World!\n"); +} + fn to_wide_cstr(path: &Path) -> Vec { let mut raw_path = path.as_os_str().encode_wide().collect::>(); raw_path.extend([0, 0]); diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 50b5dbfba1cdd..e6c15c81d9fd4 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -30,9 +30,9 @@ fn main() { test_file_clone(); test_file_set_len(); test_file_sync(); + test_rename(); // Windows file handling is very incomplete. if cfg!(not(windows)) { - test_rename(); test_directory(); test_canonicalize(); #[cfg(unix)] From 576a7277cbea967c5784750f2851099b3c7a9732 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Thu, 12 Mar 2026 13:25:40 +0300 Subject: [PATCH 20/55] Take first task group for further execution --- compiler/rustc_data_structures/src/sync/parallel.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index b112ecc2fbad1..966c34f7e1525 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -145,7 +145,9 @@ fn par_slice( const MAX_GROUP_COUNT: usize = 128; let group_size = items.len().div_ceil(MAX_GROUP_COUNT); - let groups = items.chunks_mut(group_size); + let mut groups = items.chunks_mut(group_size); + + let Some(first_group) = groups.next() else { return }; // Reverse the order of the later functions since Rayon executes them in reverse // order when using a single thread. This ensures the execution order matches @@ -159,6 +161,11 @@ fn par_slice( } }); } + + // Run the first function without spawning to avoid overwhelming stealing. + for i in first_group.iter_mut() { + guard.run(|| for_each(i)); + } }); } From db49482afe01c3fc207e6efa1bc6cf67911ce585 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2026 22:07:43 +0100 Subject: [PATCH 21/55] ci: bump checkout action --- src/tools/miri/.github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 4eeba30228924..9129562efe1d7 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: env: HOST_TARGET: ${{ matrix.host_target }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: install multiarch if: ${{ matrix.multiarch != '' }} run: | @@ -105,7 +105,7 @@ jobs: name: style checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: ./.github/workflows/setup - name: rustfmt @@ -121,7 +121,7 @@ jobs: name: bootstrap build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 # Deliberately skipping `./.github/workflows/setup` as we do our own setup - name: Add cache for cargo id: cache @@ -156,7 +156,7 @@ jobs: name: coverage report runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: ./.github/workflows/setup - name: coverage run: ./miri test --coverage @@ -191,7 +191,7 @@ jobs: pull-requests: write if: ${{ github.event_name == 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 256 # get a bit more of the history - name: install josh-sync From 5983fd3bed08c67f8b39cc44d2bbe76579b35827 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2026 22:08:45 +0100 Subject: [PATCH 22/55] bump sysroot builder (support for new build-dir layout) --- src/tools/miri/cargo-miri/Cargo.lock | 50 ++++++++++++---------------- src/tools/miri/cargo-miri/Cargo.toml | 2 +- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index 45be05fcc7f78..977728f63499a 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -230,9 +230,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7" +checksum = "eec3905e8201688412f6f4b1f6c86d38b3ee6578f59ba85f41330a3af61e8365" dependencies = [ "anyhow", "rustc_version", @@ -339,11 +339,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -392,45 +392,42 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" dependencies = [ "indexmap", - "serde", + "serde_core", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "toml_edit" -version = "0.22.27" +name = "toml_parser" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_writer" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "unicode-ident" @@ -489,12 +486,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" [[package]] name = "wit-bindgen" diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index e8da7f2ca8a74..568bb29f49f88 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -18,7 +18,7 @@ directories = "6" rustc_version = "0.4" serde_json = "1.0.40" cargo_metadata = "0.23" -rustc-build-sysroot = "0.5.10" +rustc-build-sysroot = "0.5.12" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. From d9a72196631ef948aba67da2ed109d581dd27dbf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2026 22:09:35 +0100 Subject: [PATCH 23/55] test with new build dir layout --- src/tools/miri/ci/ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 6c0bceac7731f..9bacbbcf4597c 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -28,6 +28,7 @@ begingroup "Building Miri" export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--locked" +export CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT=true # Determine configuration for installed build (used by test-cargo-miri and `./miri bench`). # We use the default set of features for this. From 6183ecdda52ba9b9b93f656f9a37492168c82726 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2026 22:39:52 +0100 Subject: [PATCH 24/55] native-lib: fix passing repr(C) enums --- src/tools/miri/src/shims/native_lib/mod.rs | 5 +++-- .../miri/tests/native-lib/pass/scalar_arguments.rs | 11 +++++++++++ src/tools/miri/tests/native-lib/scalar_arguments.c | 9 +++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 6a281ddbb7b2f..b302a07cf0c53 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -396,8 +396,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches what codegen does. This does mean that we support some types whose ABI is not // stable, but that's fine -- we are anyway quite conservative in native-lib mode. if let BackendRepr::Scalar(s) = layout.backend_repr { - // Simple sanity-check: this cannot be `repr(C)`. - assert!(!layout.ty.ty_adt_def().is_some_and(|adt| adt.repr().c())); + // Simple sanity-check: this cannot be a `repr(C)` struct or union. (It could be a + // repr(C) enum. Those indeed behave like integers in the ABI.) + assert!(!layout.ty.ty_adt_def().is_some_and(|adt| !adt.is_enum() && adt.repr().c())); return Ok(match s.primitive() { Primitive::Int(Integer::I8, /* signed */ true) => FfiType::i8(), Primitive::Int(Integer::I16, /* signed */ true) => FfiType::i16(), diff --git a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs index 231df67bb5b8c..07584ba236b98 100644 --- a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs +++ b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs @@ -1,3 +1,10 @@ +#[allow(unused)] +#[repr(C)] +enum CEnum { + A, + B, +} + extern "C" { fn add_one_int(x: i32) -> i32; fn add_int16(x: i16) -> i16; @@ -19,6 +26,7 @@ extern "C" { fn get_unsigned_int() -> u32; fn add_float(x: f32) -> f32; fn printer(); + fn scalar_enum(e: CEnum) -> u8; } fn main() { @@ -43,5 +51,8 @@ fn main() { // test void function that prints from C printer(); + + // test passing enums with scalar layout + assert_eq!(scalar_enum(CEnum::B), 1); } } diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c index 720f1982178c8..19ca940204a08 100644 --- a/src/tools/miri/tests/native-lib/scalar_arguments.c +++ b/src/tools/miri/tests/native-lib/scalar_arguments.c @@ -4,6 +4,11 @@ // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) +enum cenum { + cenum_a, + cenum_b, +}; + EXPORT int32_t add_one_int(int32_t x) { return 2 + x; } @@ -38,6 +43,10 @@ EXPORT uint8_t u8_id(uint8_t x) { return x; } +EXPORT uint8_t scalar_enum(enum cenum e) { + return (uint8_t)e; +} + // To test that functions not marked with EXPORT cannot be called by Miri. int32_t not_exported(void) { return 0; From 1c3e8d133d07d7492afa355c544b8bb15251141b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2026 22:55:21 +0100 Subject: [PATCH 25/55] fix UB in test_swap_ptr_triple_dangling --- src/tools/miri/tests/native-lib/pass/ptr_write_access.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs index 57def78b0ab17..03f14dcc3cc9b 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs @@ -176,7 +176,7 @@ fn test_swap_ptr_triple_dangling() { } extern "C" { - fn swap_ptr_triple_dangling(t_ptr: *const Triple); + fn swap_ptr_triple_dangling(t_ptr: *mut Triple); } let x = 101; @@ -184,9 +184,9 @@ fn test_swap_ptr_triple_dangling() { let ptr = Box::as_ptr(&b); drop(b); let z = 121; - let triple = Triple { ptr0: &raw const x, ptr1: ptr, ptr2: &raw const z }; + let mut triple = Triple { ptr0: &raw const x, ptr1: ptr, ptr2: &raw const z }; - unsafe { swap_ptr_triple_dangling(&triple) } + unsafe { swap_ptr_triple_dangling(&mut triple) } assert_eq!(unsafe { *triple.ptr2 }, x); } From 7500768c6877b2f75d4b6263df70f9a45b9ee1eb Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 28 Mar 2026 21:58:50 +0000 Subject: [PATCH 26/55] Use flag subtraction pattern for _umtx_time flags check. Instead of listing supported flags twice (once for the unsupported check and once for extraction), subtract known flags and check for != 0 at the end, matching the convention used elsewhere in Miri. --- src/tools/miri/src/shims/unix/freebsd/sync.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs index 8c585c7ec2641..7c46dd549bc0a 100644 --- a/src/tools/miri/src/shims/unix/freebsd/sync.rs +++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs @@ -215,14 +215,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(duration) = this.read_timespec(×pec_place)? else { return interp_ok(None) }; let flags_place = this.project_field(ut, FieldIdx::from_u32(1))?; - let flags = this.read_scalar(&flags_place)?.to_u32()?; + let mut flags = this.read_scalar(&flags_place)?.to_u32()?; - if flags & !abs_time != 0 { + let abs_time_flag = if flags & abs_time != 0 { + flags &= !abs_time; + true + } else { + false + }; + if flags != 0 { throw_unsup_format!("unsupported `_umtx_time` flags: {:#x}", flags); } - let abs_time_flag = flags & abs_time != 0; - let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?; let clock_id = this.read_scalar(&clock_id_place)?; let Some(timeout_clock) = this.parse_clockid(clock_id) else { From 424dfe5544b77e239b995d2594d4bb445654e27e Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 29 Mar 2026 05:28:27 +0000 Subject: [PATCH 27/55] Prepare for merging from rust-lang/rust This updates the rust-version file to 148adf223edb0444eb1f99753919dd2080c2a534. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 68f38716dbb0b..c98397c1c67fa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55 +148adf223edb0444eb1f99753919dd2080c2a534 From 5bc280c0a97b235412ad43d5866284faca324c21 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 29 Mar 2026 05:37:03 +0000 Subject: [PATCH 28/55] fmt --- .../tests/pass/intrinsics/portable-simd.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index 1e86c458ac21c..f81f62e176021 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -134,13 +134,19 @@ fn simd_ops_f16() { assert_eq!(simd_reduce_min(b), -4.0f16); assert_eq!( - simd_maximum_number_nsz(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])), + simd_maximum_number_nsz( + f16x2::from_array([0.0, f16::NAN]), + f16x2::from_array([f16::NAN, 0.0]) + ), f16x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_max(f16x2::from_array([0.0, f16::NAN])), 0.0f16); assert_eq!(simd_reduce_max(f16x2::from_array([f16::NAN, 0.0])), 0.0f16); assert_eq!( - simd_minimum_number_nsz(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])), + simd_minimum_number_nsz( + f16x2::from_array([0.0, f16::NAN]), + f16x2::from_array([f16::NAN, 0.0]) + ), f16x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_min(f16x2::from_array([0.0, f16::NAN])), 0.0f16); @@ -348,13 +354,19 @@ fn simd_ops_f128() { assert_eq!(simd_reduce_min(b), -4.0f128); assert_eq!( - simd_maximum_number_nsz(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])), + simd_maximum_number_nsz( + f128x2::from_array([0.0, f128::NAN]), + f128x2::from_array([f128::NAN, 0.0]) + ), f128x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_max(f128x2::from_array([0.0, f128::NAN])), 0.0f128); assert_eq!(simd_reduce_max(f128x2::from_array([f128::NAN, 0.0])), 0.0f128); assert_eq!( - simd_minimum_number_nsz(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])), + simd_minimum_number_nsz( + f128x2::from_array([0.0, f128::NAN]), + f128x2::from_array([f128::NAN, 0.0]) + ), f128x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_min(f128x2::from_array([0.0, f128::NAN])), 0.0f128); From 5bbdfb078d206282b75386530fe650749a76785d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Mar 2026 12:56:05 +0200 Subject: [PATCH 29/55] use 'flag subtraction' pattern for 'open' --- src/tools/miri/src/shims/unix/fs.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 9873af85b989b..5adc5932883ef 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -364,6 +364,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.emit_diagnostic(NonHaltingDiagnostic::FileInProcOpened); } + // We will "subtract" supported flags from this and at the end check that no bits are left. + let mut flag = flag; + let mut options = OpenOptions::new(); let o_rdonly = this.eval_libc_i32("O_RDONLY"); @@ -379,6 +382,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Now we check the access mode let access_mode = flag & 0b11; + flag &= !access_mode; if access_mode == o_rdonly { writable = false; @@ -390,23 +394,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { throw_unsup_format!("unsupported access mode {:#x}", access_mode); } - // We need to check that there aren't unsupported options in `flag`. For this we try to - // reproduce the content of `flag` in the `mirror` variable using only the supported - // options. - let mut mirror = access_mode; let o_append = this.eval_libc_i32("O_APPEND"); if flag & o_append == o_append { + flag &= !o_append; options.append(true); - mirror |= o_append; } let o_trunc = this.eval_libc_i32("O_TRUNC"); if flag & o_trunc == o_trunc { + flag &= !o_trunc; options.truncate(true); - mirror |= o_trunc; } let o_creat = this.eval_libc_i32("O_CREAT"); if flag & o_creat == o_creat { + flag &= !o_creat; // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but // C integer promotion rules mean that on the ABI level, it gets passed as `u32` // (see https://github.com/rust-lang/rust/issues/71915). @@ -430,11 +431,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - mirror |= o_creat; - let o_excl = this.eval_libc_i32("O_EXCL"); if flag & o_excl == o_excl { - mirror |= o_excl; + flag &= !o_excl; options.create_new(true); } else { options.create(true); @@ -442,9 +441,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let o_cloexec = this.eval_libc_i32("O_CLOEXEC"); if flag & o_cloexec == o_cloexec { + flag &= !o_cloexec; // We do not need to do anything for this flag because `std` already sets it. // (Technically we do not support *not* setting this flag, but we ignore that.) - mirror |= o_cloexec; } if this.tcx.sess.target.os == Os::Linux { let o_tmpfile = this.eval_libc_i32("O_TMPFILE"); @@ -456,6 +455,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let o_nofollow = this.eval_libc_i32("O_NOFOLLOW"); if flag & o_nofollow == o_nofollow { + flag &= !o_nofollow; #[cfg(unix)] { use std::os::unix::fs::OpenOptionsExt; @@ -472,13 +472,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return_i32(LibcError("ELOOP")); } } - mirror |= o_nofollow; } - // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`, - // then we throw an error. - if flag != mirror { - throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); + // If `flag` has any bits left set, those are not supported. + if flag != 0 { + throw_unsup_format!("unsupported flags {:#x}", flag); } // Reject if isolation is enabled. From 684bff70b5ed1e4921773251b072812fb9a002cb Mon Sep 17 00:00:00 2001 From: aditya <189266166+Bougerous@users.noreply.github.com> Date: Fri, 13 Mar 2026 08:59:56 +0530 Subject: [PATCH 30/55] Add aarch64 CRC32 intrinsic shims Implement shims for the 8 aarch64 CRC32 LLVM intrinsics: - crc32b/h/w/x (standard CRC-32, polynomial 0x104C11DB7) - crc32cb/ch/cw/cx (CRC-32C/Castagnoli, polynomial 0x11EDC6F41) Co-Authored-By: Claude Opus 4.6 --- src/tools/miri/src/shims/aarch64.rs | 43 +++++++++++++ src/tools/miri/src/shims/mod.rs | 1 + src/tools/miri/src/shims/simd/math.rs | 41 +++++++++++++ src/tools/miri/src/shims/simd/mod.rs | 1 + src/tools/miri/src/shims/x86/sse42.rs | 46 ++++---------- .../shims/aarch64/intrinsics-aarch64-crc32.rs | 61 +++++++++++++++++++ 6 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 src/tools/miri/src/shims/simd/math.rs create mode 100644 src/tools/miri/src/shims/simd/mod.rs create mode 100644 src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs index d06b02a41334f..7138ec3d122ba 100644 --- a/src/tools/miri/src/shims/aarch64.rs +++ b/src/tools/miri/src/shims/aarch64.rs @@ -85,6 +85,49 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(val, &this.project_index(&dest, i)?)?; } } + // Used to implement the __crc32{b,h,w,x} and __crc32c{b,h,w,x} functions. + // Polynomial 0x04C11DB7 (standard CRC-32): + // https://developer.arm.com/documentation/ddi0602/latest/Base-Instructions/CRC32B--CRC32H--CRC32W--CRC32X--CRC32-checksum- + // Polynomial 0x1EDC6F41 (CRC-32C / Castagnoli): + // https://developer.arm.com/documentation/ddi0602/latest/Base-Instructions/CRC32CB--CRC32CH--CRC32CW--CRC32CX--CRC32C-checksum- + "crc32b" | "crc32h" | "crc32w" | "crc32x" | "crc32cb" | "crc32ch" | "crc32cw" + | "crc32cx" => { + this.expect_target_feature_for_intrinsic(link_name, "crc")?; + // The polynomial constants below include the leading 1 bit + // (e.g. 0x104C11DB7 instead of 0x04C11DB7) which the ARM docs + // omit but the polynomial division algorithm requires. + let (bit_size, polynomial): (u32, u128) = match unprefixed_name { + "crc32b" => (8, 0x104C11DB7), + "crc32h" => (16, 0x104C11DB7), + "crc32w" => (32, 0x104C11DB7), + "crc32x" => (64, 0x104C11DB7), + "crc32cb" => (8, 0x11EDC6F41), + "crc32ch" => (16, 0x11EDC6F41), + "crc32cw" => (32, 0x11EDC6F41), + "crc32cx" => (64, 0x11EDC6F41), + _ => unreachable!(), + }; + + let [left, right] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let left = this.read_scalar(left)?; + let right = this.read_scalar(right)?; + + // The CRC accumulator is always u32. The data argument is u32 for + // b/h/w variants and u64 for the x variant, per the LLVM intrinsic + // definitions (all b/h/w take i32, only x takes i64). + // https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/IntrinsicsAArch64.td + // For b/h, the Rust std::arch wrappers accept u8/u16 and zero-extend + // to i32 before calling the LLVM intrinsic, so the upper bits of the + // i32 are always zero. compute_crc32 only uses the low `bit_size` bits. + let crc = left.to_u32()?; + let data = + if bit_size == 64 { right.to_u64()? } else { u64::from(right.to_u32()?) }; + + let result = + crate::shims::simd::math::compute_crc32(crc, data, bit_size, polynomial); + this.write_scalar(Scalar::from_u32(result), dest)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 281dfc758f4e7..09a00363cfdaf 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -7,6 +7,7 @@ mod files; mod math; #[cfg(all(feature = "native-lib", unix))] pub mod native_lib; +mod simd; mod unix; mod windows; mod x86; diff --git a/src/tools/miri/src/shims/simd/math.rs b/src/tools/miri/src/shims/simd/math.rs new file mode 100644 index 0000000000000..5ba32eedc3bef --- /dev/null +++ b/src/tools/miri/src/shims/simd/math.rs @@ -0,0 +1,41 @@ +/// Compute a CRC32 checksum using the given polynomial. +/// +/// `bit_size` is the number of relevant data bits (8, 16, 32, or 64). +/// Only the low `bit_size` bits of `data` are used; higher bits are ignored. +/// `polynomial` includes the leading 1 bit (e.g. `0x11EDC6F41` for CRC32C). +#[expect(clippy::arithmetic_side_effects)] +pub(crate) fn compute_crc32(crc: u32, data: u64, bit_size: u32, polynomial: u128) -> u32 { + // Bit-reverse inputs to match hardware CRC conventions. + let crc = u128::from(crc.reverse_bits()); + // Reverse all 64 bits of `data`, then shift right by `64 - bit_size`. This + // discards the (now-reversed) higher bits, leaving only the reversed low + // `bit_size` bits in the lowest positions (with zeros above). + let v = u128::from(data.reverse_bits() >> (64 - bit_size)); + + // Perform polynomial division modulo 2. + // The algorithm for the division is an adapted version of the + // schoolbook division algorithm used for normal integer or polynomial + // division. In this context, the quotient is not calculated, since + // only the remainder is needed. + // + // The algorithm works as follows: + // 1. Pull down digits until division can be performed. In the context of division + // modulo 2 it means locating the most significant digit of the dividend and shifting + // the divisor such that the position of the divisors most significand digit and the + // dividends most significand digit match. + // 2. Perform a division and determine the remainder. Since it is arithmetic modulo 2, + // this operation is a simple bitwise exclusive or. + // 3. Repeat steps 1. and 2. until the full remainder is calculated. This is the case + // once the degree of the remainder polynomial is smaller than the degree of the + // divisor polynomial. In other words, the number of leading zeros of the remainder + // is larger than the number of leading zeros of the divisor. It is important to + // note that standard arithmetic comparison is not applicable here: + // 0b10011 / 0b11111 = 0b01100 is a valid division, even though the dividend is + // smaller than the divisor. + let mut dividend = (crc << bit_size) ^ (v << 32); + while dividend.leading_zeros() <= polynomial.leading_zeros() { + dividend ^= (polynomial << polynomial.leading_zeros()) >> dividend.leading_zeros(); + } + + u32::try_from(dividend).unwrap().reverse_bits() +} diff --git a/src/tools/miri/src/shims/simd/mod.rs b/src/tools/miri/src/shims/simd/mod.rs new file mode 100644 index 0000000000000..0c937aa8d9352 --- /dev/null +++ b/src/tools/miri/src/shims/simd/mod.rs @@ -0,0 +1 @@ +pub(crate) mod math; diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 7c0f9c570e2ef..c7a43427ca888 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -5,6 +5,7 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; use rustc_target::spec::Arch; +use crate::shims::simd::math::compute_crc32; use crate::*; /// A bitmask constant for scrutinizing the immediate byte provided @@ -445,46 +446,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The 64-bit version will only consider the lower 32 bits, // while the upper 32 bits get discarded. #[expect(clippy::as_conversions)] - u128::from((left.to_u64()? as u32).reverse_bits()) + { + left.to_u64()? as u32 + } } else { - u128::from(left.to_u32()?.reverse_bits()) + left.to_u32()? }; - let v = match bit_size { - 8 => u128::from(right.to_u8()?.reverse_bits()), - 16 => u128::from(right.to_u16()?.reverse_bits()), - 32 => u128::from(right.to_u32()?.reverse_bits()), - 64 => u128::from(right.to_u64()?.reverse_bits()), + let data = match bit_size { + 8 => u64::from(right.to_u8()?), + 16 => u64::from(right.to_u16()?), + 32 => u64::from(right.to_u32()?), + 64 => right.to_u64()?, _ => unreachable!(), }; - // Perform polynomial division modulo 2. - // The algorithm for the division is an adapted version of the - // schoolbook division algorithm used for normal integer or polynomial - // division. In this context, the quotient is not calculated, since - // only the remainder is needed. - // - // The algorithm works as follows: - // 1. Pull down digits until division can be performed. In the context of division - // modulo 2 it means locating the most significant digit of the dividend and shifting - // the divisor such that the position of the divisors most significand digit and the - // dividends most significand digit match. - // 2. Perform a division and determine the remainder. Since it is arithmetic modulo 2, - // this operation is a simple bitwise exclusive or. - // 3. Repeat steps 1. and 2. until the full remainder is calculated. This is the case - // once the degree of the remainder polynomial is smaller than the degree of the - // divisor polynomial. In other words, the number of leading zeros of the remainder - // is larger than the number of leading zeros of the divisor. It is important to - // note that standard arithmetic comparison is not applicable here: - // 0b10011 / 0b11111 = 0b01100 is a valid division, even though the dividend is - // smaller than the divisor. - let mut dividend = (crc << bit_size) ^ (v << 32); - const POLYNOMIAL: u128 = 0x11EDC6F41; - while dividend.leading_zeros() <= POLYNOMIAL.leading_zeros() { - dividend ^= - (POLYNOMIAL << POLYNOMIAL.leading_zeros()) >> dividend.leading_zeros(); - } - - let result = u32::try_from(dividend).unwrap().reverse_bits(); + let result = compute_crc32(crc, data, bit_size, 0x11EDC6F41); let result = if bit_size == 64 { Scalar::from_u64(u64::from(result)) } else { diff --git a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs new file mode 100644 index 0000000000000..849f99ee36cce --- /dev/null +++ b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs @@ -0,0 +1,61 @@ +// We're testing aarch64 CRC32 target specific features +//@only-target: aarch64 +//@compile-flags: -C target-feature=+crc + +use std::arch::aarch64::*; +use std::arch::is_aarch64_feature_detected; + +fn main() { + assert!(is_aarch64_feature_detected!("crc")); + + unsafe { + test_crc32_standard(); + test_crc32c_castagnoli(); + } +} + +#[target_feature(enable = "crc")] +unsafe fn test_crc32_standard() { + // __crc32b: 8-bit input + assert_eq!(__crc32b(0x00000000, 0x01), 0x77073096); + assert_eq!(__crc32b(0xffffffff, 0x61), 0x174841bc); + assert_eq!(__crc32b(0x2aa1e72b, 0x2a), 0x772d9171); + + // __crc32h: 16-bit input + assert_eq!(__crc32h(0x00000000, 0x0001), 0x191b3141); + assert_eq!(__crc32h(0xffffffff, 0x1234), 0xf6b56fbf); + assert_eq!(__crc32h(0x8ecec3b5, 0x022b), 0x03a1db7c); + + // __crc32w: 32-bit input + assert_eq!(__crc32w(0x00000000, 0x00000001), 0xb8bc6765); + assert_eq!(__crc32w(0xffffffff, 0x12345678), 0x5092782d); + assert_eq!(__crc32w(0xae2912c8, 0x00845fed), 0xc5690dd4); + + // __crc32d: 64-bit input + assert_eq!(__crc32d(0x00000000, 0x0000000000000001), 0xccaa009e); + assert_eq!(__crc32d(0xffffffff, 0x123456789abcdef0), 0xe6ddf8b5); + assert_eq!(__crc32d(0x0badeafe, 0xc0febeefdadafefe), 0x61a45fba); +} + +#[target_feature(enable = "crc")] +unsafe fn test_crc32c_castagnoli() { + // __crc32cb: 8-bit input + assert_eq!(__crc32cb(0x00000000, 0x01), 0xf26b8303); + assert_eq!(__crc32cb(0xffffffff, 0x61), 0x3e2fbccf); + assert_eq!(__crc32cb(0x2aa1e72b, 0x2a), 0xf24122e4); + + // __crc32ch: 16-bit input + assert_eq!(__crc32ch(0x00000000, 0x0001), 0x13a29877); + assert_eq!(__crc32ch(0xffffffff, 0x1234), 0xf13f4cea); + assert_eq!(__crc32ch(0x8ecec3b5, 0x022b), 0x013bb2fb); + + // __crc32cw: 32-bit input + assert_eq!(__crc32cw(0x00000000, 0x00000001), 0xdd45aab8); + assert_eq!(__crc32cw(0xffffffff, 0x12345678), 0x4dece20c); + assert_eq!(__crc32cw(0xae2912c8, 0x00845fed), 0xffae2ed1); + + // __crc32cd: 64-bit input + assert_eq!(__crc32cd(0x00000000, 0x0000000000000001), 0x493c7d27); + assert_eq!(__crc32cd(0xffffffff, 0x123456789abcdef0), 0xd95b664b); + assert_eq!(__crc32cd(0x0badeafe, 0xc0febeefdadafefe), 0x5b44f54f); +} From 59f15fbbb8caa60cf8ba32d065fc294be33fbc73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2026 21:02:23 +0100 Subject: [PATCH 31/55] minor tweaks --- src/tools/miri/src/shims/aarch64.rs | 9 +++-- src/tools/miri/src/shims/math.rs | 48 +++++++++++++++++++++++++++ src/tools/miri/src/shims/mod.rs | 1 - src/tools/miri/src/shims/simd/math.rs | 41 ----------------------- src/tools/miri/src/shims/simd/mod.rs | 1 - src/tools/miri/src/shims/x86/sse42.rs | 6 ++-- 6 files changed, 54 insertions(+), 52 deletions(-) delete mode 100644 src/tools/miri/src/shims/simd/math.rs delete mode 100644 src/tools/miri/src/shims/simd/mod.rs diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs index 7138ec3d122ba..b96d1b1a38dd8 100644 --- a/src/tools/miri/src/shims/aarch64.rs +++ b/src/tools/miri/src/shims/aarch64.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use crate::shims::math::compute_crc32; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -117,15 +118,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // b/h/w variants and u64 for the x variant, per the LLVM intrinsic // definitions (all b/h/w take i32, only x takes i64). // https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/IntrinsicsAArch64.td - // For b/h, the Rust std::arch wrappers accept u8/u16 and zero-extend - // to i32 before calling the LLVM intrinsic, so the upper bits of the - // i32 are always zero. compute_crc32 only uses the low `bit_size` bits. + // If the higher bits are non-zero, `compute_crc32` will panic. We should probably + // raise a proper error instead, but outside stdarch nobody can trigger this anyway. let crc = left.to_u32()?; let data = if bit_size == 64 { right.to_u64()? } else { u64::from(right.to_u32()?) }; - let result = - crate::shims::simd::math::compute_crc32(crc, data, bit_size, polynomial); + let result = compute_crc32(crc, data, bit_size, polynomial); this.write_scalar(Scalar::from_u32(result), dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), diff --git a/src/tools/miri/src/shims/math.rs b/src/tools/miri/src/shims/math.rs index ef185aa2a3e9f..1da7fbbdac0ce 100644 --- a/src/tools/miri/src/shims/math.rs +++ b/src/tools/miri/src/shims/math.rs @@ -245,3 +245,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } } + +/// Compute a CRC32 checksum using the given polynomial. +/// +/// `bit_size` is the number of relevant data bits (8, 16, 32, or 64). +/// Only the low `bit_size` bits of `data` are used; higher bits must be zero. +/// `polynomial` includes the leading 1 bit (e.g. `0x11EDC6F41` for CRC32C). +/// +/// Following hardware CRC conventions, `crc` and `data` bits are assumed to be reversed, +/// and output bits will be equally reversed. +pub(crate) fn compute_crc32(crc: u32, data: u64, bit_size: u32, polynomial: u128) -> u32 { + assert!( + bit_size == 64 || data < 1u64.strict_shl(bit_size), + "crc32: `data` is larger than {bit_size} bits" + ); + // Bit-reverse inputs to match hardware CRC conventions. + let crc = u128::from(crc.reverse_bits()); + // Reverse all 64 bits of `data`, then shift right by `64 - bit_size`. This + // discards the (now-reversed) higher bits, leaving only the reversed low + // `bit_size` bits in the lowest positions (with zeros above). + let v = u128::from(data.reverse_bits() >> (64u32.strict_sub(bit_size))); + + // Perform polynomial division modulo 2. + // The algorithm for the division is an adapted version of the + // schoolbook division algorithm used for normal integer or polynomial + // division. In this context, the quotient is not calculated, since + // only the remainder is needed. + // + // The algorithm works as follows: + // 1. Pull down digits until division can be performed. In the context of division + // modulo 2 it means locating the most significant digit of the dividend and shifting + // the divisor such that the position of the divisors most significand digit and the + // dividends most significand digit match. + // 2. Perform a division and determine the remainder. Since it is arithmetic modulo 2, + // this operation is a simple bitwise exclusive or. + // 3. Repeat steps 1. and 2. until the full remainder is calculated. This is the case + // once the degree of the remainder polynomial is smaller than the degree of the + // divisor polynomial. In other words, the number of leading zeros of the remainder + // is larger than the number of leading zeros of the divisor. It is important to + // note that standard arithmetic comparison is not applicable here: + // 0b10011 / 0b11111 = 0b01100 is a valid division, even though the dividend is + // smaller than the divisor. + let mut dividend = (crc << bit_size) ^ (v << 32); + while dividend.leading_zeros() <= polynomial.leading_zeros() { + dividend ^= (polynomial << polynomial.leading_zeros()) >> dividend.leading_zeros(); + } + + u32::try_from(dividend).unwrap().reverse_bits() +} diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 09a00363cfdaf..281dfc758f4e7 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -7,7 +7,6 @@ mod files; mod math; #[cfg(all(feature = "native-lib", unix))] pub mod native_lib; -mod simd; mod unix; mod windows; mod x86; diff --git a/src/tools/miri/src/shims/simd/math.rs b/src/tools/miri/src/shims/simd/math.rs deleted file mode 100644 index 5ba32eedc3bef..0000000000000 --- a/src/tools/miri/src/shims/simd/math.rs +++ /dev/null @@ -1,41 +0,0 @@ -/// Compute a CRC32 checksum using the given polynomial. -/// -/// `bit_size` is the number of relevant data bits (8, 16, 32, or 64). -/// Only the low `bit_size` bits of `data` are used; higher bits are ignored. -/// `polynomial` includes the leading 1 bit (e.g. `0x11EDC6F41` for CRC32C). -#[expect(clippy::arithmetic_side_effects)] -pub(crate) fn compute_crc32(crc: u32, data: u64, bit_size: u32, polynomial: u128) -> u32 { - // Bit-reverse inputs to match hardware CRC conventions. - let crc = u128::from(crc.reverse_bits()); - // Reverse all 64 bits of `data`, then shift right by `64 - bit_size`. This - // discards the (now-reversed) higher bits, leaving only the reversed low - // `bit_size` bits in the lowest positions (with zeros above). - let v = u128::from(data.reverse_bits() >> (64 - bit_size)); - - // Perform polynomial division modulo 2. - // The algorithm for the division is an adapted version of the - // schoolbook division algorithm used for normal integer or polynomial - // division. In this context, the quotient is not calculated, since - // only the remainder is needed. - // - // The algorithm works as follows: - // 1. Pull down digits until division can be performed. In the context of division - // modulo 2 it means locating the most significant digit of the dividend and shifting - // the divisor such that the position of the divisors most significand digit and the - // dividends most significand digit match. - // 2. Perform a division and determine the remainder. Since it is arithmetic modulo 2, - // this operation is a simple bitwise exclusive or. - // 3. Repeat steps 1. and 2. until the full remainder is calculated. This is the case - // once the degree of the remainder polynomial is smaller than the degree of the - // divisor polynomial. In other words, the number of leading zeros of the remainder - // is larger than the number of leading zeros of the divisor. It is important to - // note that standard arithmetic comparison is not applicable here: - // 0b10011 / 0b11111 = 0b01100 is a valid division, even though the dividend is - // smaller than the divisor. - let mut dividend = (crc << bit_size) ^ (v << 32); - while dividend.leading_zeros() <= polynomial.leading_zeros() { - dividend ^= (polynomial << polynomial.leading_zeros()) >> dividend.leading_zeros(); - } - - u32::try_from(dividend).unwrap().reverse_bits() -} diff --git a/src/tools/miri/src/shims/simd/mod.rs b/src/tools/miri/src/shims/simd/mod.rs deleted file mode 100644 index 0c937aa8d9352..0000000000000 --- a/src/tools/miri/src/shims/simd/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod math; diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index c7a43427ca888..6b0e6726e8f79 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -5,7 +5,7 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; use rustc_target::spec::Arch; -use crate::shims::simd::math::compute_crc32; +use crate::shims::math::compute_crc32; use crate::*; /// A bitmask constant for scrutinizing the immediate byte provided @@ -446,9 +446,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The 64-bit version will only consider the lower 32 bits, // while the upper 32 bits get discarded. #[expect(clippy::as_conversions)] - { - left.to_u64()? as u32 - } + (left.to_u64()? as u32) } else { left.to_u32()? }; From 785b5113608a886309962ed836ee7a4bcf13bfaa Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 30 Mar 2026 10:08:12 +0800 Subject: [PATCH 32/55] fix where clause rustfix suggestion spacing --- .../rustc_ast_passes/src/ast_validation.rs | 20 ++++++++++++------- ...lias-type-where-suggest-issue-153567.fixed | 17 ++++++++++++++++ .../alias-type-where-suggest-issue-153567.rs | 17 ++++++++++++++++ ...ias-type-where-suggest-issue-153567.stderr | 16 +++++++++++++++ ...-clause-placement-assoc-type-in-impl.fixed | 8 ++++---- ...clause-placement-assoc-type-in-impl.stderr | 8 ++++---- ...clause-placement-assoc-type-in-trait.fixed | 4 ++-- ...lause-placement-assoc-type-in-trait.stderr | 4 ++-- 8 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 tests/ui/where-clauses/alias-type-where-suggest-issue-153567.fixed create mode 100644 tests/ui/where-clauses/alias-type-where-suggest-issue-153567.rs create mode 100644 tests/ui/where-clauses/alias-type-where-suggest-issue-153567.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd14e91435690..d59b148154c93 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -173,17 +173,19 @@ impl<'a> AstValidator<'a> { { let mut state = State::new(); + let mut needs_comma = !ty_alias.after_where_clause.predicates.is_empty(); if !ty_alias.after_where_clause.has_where_token { state.space(); state.word_space("where"); + } else if !needs_comma { + state.space(); } - let mut first = ty_alias.after_where_clause.predicates.is_empty(); for p in &ty_alias.generics.where_clause.predicates { - if !first { + if needs_comma { state.word_space(","); } - first = false; + needs_comma = true; state.print_where_predicate(p); } @@ -1832,7 +1834,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { Some((right, snippet)) } }; - let left_sp = err.span; + let left_sp = self + .sess + .source_map() + .span_extend_prev_while(err.span, char::is_whitespace) + .unwrap_or(err.span); self.lint_buffer.dyn_buffer_lint( DEPRECATED_WHERE_CLAUSE_LOCATION, item.id, @@ -1846,9 +1852,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { sugg, } } - None => { - errors::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp } - } + None => errors::DeprecatedWhereClauseLocationSugg::RemoveWhere { + span: err.span, + }, }; errors::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level) }, diff --git a/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.fixed b/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.fixed new file mode 100644 index 0000000000000..01da73716e884 --- /dev/null +++ b/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.fixed @@ -0,0 +1,17 @@ +//@ check-pass +//@ run-rustfix +//@ compile-flags: --force-warn deprecated_where_clause_location + + +#![allow(dead_code)] + +trait Trait { + type Assoc; +} + +impl Trait for i32 { + type Assoc = () where i32: Copy; + //~^ WARNING where clause not allowed here +} + +fn main() {} diff --git a/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.rs b/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.rs new file mode 100644 index 0000000000000..cdee4c753b87d --- /dev/null +++ b/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ run-rustfix +//@ compile-flags: --force-warn deprecated_where_clause_location + + +#![allow(dead_code)] + +trait Trait { + type Assoc; +} + +impl Trait for i32 { + type Assoc where i32: Copy = () where; + //~^ WARNING where clause not allowed here +} + +fn main() {} diff --git a/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.stderr b/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.stderr new file mode 100644 index 0000000000000..d3421505bf5ca --- /dev/null +++ b/tests/ui/where-clauses/alias-type-where-suggest-issue-153567.stderr @@ -0,0 +1,16 @@ +warning: where clause not allowed here + --> $DIR/alias-type-where-suggest-issue-153567.rs:13:16 + | +LL | type Assoc where i32: Copy = () where; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #89122 for more information + = note: requested on the command line with `--force-warn deprecated-where-clause-location` +help: move it to the end of the type declaration + | +LL - type Assoc where i32: Copy = () where; +LL + type Assoc = () where i32: Copy; + | + +warning: 1 warning emitted + diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed index 9b935b1667878..5f3882ccb412e 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed @@ -14,12 +14,12 @@ trait Trait { impl Trait for u32 { // Not fine, suggests moving. - type Assoc = () where u32: Copy; + type Assoc = () where u32: Copy; //~^ WARNING where clause not allowed here // Not fine, suggests moving `u32: Copy` - type Assoc2 = () where i32: Copy, u32: Copy; + type Assoc2 = () where i32: Copy, u32: Copy; //~^ WARNING where clause not allowed here - type Assoc3 = () where; + type Assoc3 = () where; //~^ WARNING where clause not allowed here } @@ -27,7 +27,7 @@ impl Trait for i32 { // Fine. type Assoc = () where u32: Copy; // Not fine, suggests moving both. - type Assoc2 = () where u32: Copy, i32: Copy; + type Assoc2 = () where u32: Copy, i32: Copy; //~^ WARNING where clause not allowed here type Assoc3 = () where; //~^ WARNING where clause not allowed here diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr index 5809ff8f80347..f31c8b2dd8219 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr @@ -9,7 +9,7 @@ LL | type Assoc where u32: Copy = (); help: move it to the end of the type declaration | LL - type Assoc where u32: Copy = (); -LL + type Assoc = () where u32: Copy; +LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here @@ -22,7 +22,7 @@ LL | type Assoc2 where u32: Copy = () where i32: Copy; help: move it to the end of the type declaration | LL - type Assoc2 where u32: Copy = () where i32: Copy; -LL + type Assoc2 = () where i32: Copy, u32: Copy; +LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: where clause not allowed here @@ -35,7 +35,7 @@ LL | type Assoc3 where = (); help: move it to the end of the type declaration | LL - type Assoc3 where = (); -LL + type Assoc3 = () where; +LL + type Assoc3 = () where; | warning: where clause not allowed here @@ -48,7 +48,7 @@ LL | type Assoc2 where u32: Copy, i32: Copy = (); help: move it to the end of the type declaration | LL - type Assoc2 where u32: Copy, i32: Copy = (); -LL + type Assoc2 = () where u32: Copy, i32: Copy; +LL + type Assoc2 = () where u32: Copy, i32: Copy; | warning: where clause not allowed here diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed index 719f1d2a4c603..02dba8f946d6c 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed @@ -6,10 +6,10 @@ trait Trait { // Not fine, suggests moving. - type Assoc = () where u32: Copy; + type Assoc = () where u32: Copy; //~^ WARNING where clause not allowed here // Not fine, suggests moving `u32: Copy` - type Assoc2 = () where i32: Copy, u32: Copy; + type Assoc2 = () where i32: Copy, u32: Copy; //~^ WARNING where clause not allowed here } diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr index 9e9967ef7391a..1b7c09897b7b8 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr @@ -9,7 +9,7 @@ LL | type Assoc where u32: Copy = (); help: move it to the end of the type declaration | LL - type Assoc where u32: Copy = (); -LL + type Assoc = () where u32: Copy; +LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here @@ -22,7 +22,7 @@ LL | type Assoc2 where u32: Copy = () where i32: Copy; help: move it to the end of the type declaration | LL - type Assoc2 where u32: Copy = () where i32: Copy; -LL + type Assoc2 = () where i32: Copy, u32: Copy; +LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: 2 warnings emitted From 77199806b7ca6ccbe57e5692e861d6bab131b10e Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 30 Mar 2026 05:38:07 +0000 Subject: [PATCH 33/55] Prepare for merging from rust-lang/rust This updates the rust-version file to 116458d0a5ae01cd517cabd2d1aee7f5457018ab. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index c98397c1c67fa..85571d95f742d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -148adf223edb0444eb1f99753919dd2080c2a534 +116458d0a5ae01cd517cabd2d1aee7f5457018ab From 29710ca2705f5b87d217f6a36b4a9afbd0bc87f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 27 Jan 2026 16:09:52 +0100 Subject: [PATCH 34/55] remove debug requirement from hooks --- compiler/rustc_middle/src/hooks/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 0ddcdac817b80..1a7a8f5cae60d 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -35,8 +35,10 @@ macro_rules! declare_hooks { impl Default for Providers { fn default() -> Self { + #[allow(unused)] Providers { - $($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),* + $($name: + |_, $($arg,)*| default_hook(stringify!($name))),* } } } @@ -118,8 +120,6 @@ declare_hooks! { } #[cold] -fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! { - bug!( - "`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function" - ) +fn default_hook(name: &str) -> ! { + bug!("`tcx.{name}` cannot be called as `{name}` was never assigned to a provider function") } From bf42a53bf7de0171ad8191abf7fc7f86ab8d4d6b Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 30 Mar 2026 09:15:22 +0000 Subject: [PATCH 35/55] delete several `ui/consts` tests --- tests/ui/consts/const-bound.rs | 19 ------------------- tests/ui/consts/const-enum-tuple.rs | 11 ----------- tests/ui/consts/const-enum-tuple2.rs | 11 ----------- tests/ui/consts/const-enum-tuplestruct2.rs | 12 ------------ tests/ui/consts/const.rs | 6 ------ 5 files changed, 59 deletions(-) delete mode 100644 tests/ui/consts/const-bound.rs delete mode 100644 tests/ui/consts/const-enum-tuple.rs delete mode 100644 tests/ui/consts/const-enum-tuple2.rs delete mode 100644 tests/ui/consts/const-enum-tuplestruct2.rs delete mode 100644 tests/ui/consts/const.rs diff --git a/tests/ui/consts/const-bound.rs b/tests/ui/consts/const-bound.rs deleted file mode 100644 index 00a833ba3f79e..0000000000000 --- a/tests/ui/consts/const-bound.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -// Make sure const bounds work on things, and test that a few types -// are const. - - -fn foo(x: T) -> T { x } - -struct F { field: isize } - -pub fn main() { - /*foo(1); - foo("hi".to_string()); - foo(vec![1, 2, 3]); - foo(F{field: 42}); - foo((1, 2)); - foo(@1);*/ - foo(Box::new(1)); -} diff --git a/tests/ui/consts/const-enum-tuple.rs b/tests/ui/consts/const-enum-tuple.rs deleted file mode 100644 index fe6b54aa79351..0000000000000 --- a/tests/ui/consts/const-enum-tuple.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum E { V16(u16), V32(u32) } -static C: (E, u16, u16) = (E::V16(0xDEAD), 0x600D, 0xBAD); - -pub fn main() { - let (_, n, _) = C; - assert!(n != 0xBAD); - assert_eq!(n, 0x600D); -} diff --git a/tests/ui/consts/const-enum-tuple2.rs b/tests/ui/consts/const-enum-tuple2.rs deleted file mode 100644 index 713209943d3ed..0000000000000 --- a/tests/ui/consts/const-enum-tuple2.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum E { V0, V16(u16) } -static C: (E, u16, u16) = (E::V0, 0x600D, 0xBAD); - -pub fn main() { - let (_, n, _) = C; - assert!(n != 0xBAD); - assert_eq!(n, 0x600D); -} diff --git a/tests/ui/consts/const-enum-tuplestruct2.rs b/tests/ui/consts/const-enum-tuplestruct2.rs deleted file mode 100644 index dc44532369524..0000000000000 --- a/tests/ui/consts/const-enum-tuplestruct2.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum E { V0, V16(u16) } -struct S(E, u16, u16); -static C: S = S(E::V0, 0x600D, 0xBAD); - -pub fn main() { - let S(_, n, _) = C; - assert!(n != 0xBAD); - assert_eq!(n, 0x600D); -} diff --git a/tests/ui/consts/const.rs b/tests/ui/consts/const.rs deleted file mode 100644 index 1f1c6e30b4a08..0000000000000 --- a/tests/ui/consts/const.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass -#![allow(non_upper_case_globals)] - -static i: isize = 10; - -pub fn main() { println!("{}", i); } From e61842d378622d3bbb9271b6edc9b01872c43665 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Mon, 30 Mar 2026 10:54:46 +0000 Subject: [PATCH 36/55] Update `mir-opt` 64-bit panic-abort tests for `Alignment` rename These seem to have been missed when the PR originally merged. --- ...without_updating_operand.test.GVN.64bit.panic-abort.diff | 2 +- ...8_print_invalid_constant.main.GVN.64bit.panic-abort.diff | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 88fb27386218e..0219db325c8f6 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -51,7 +51,7 @@ StorageLive(_12); StorageLive(_13); - _13 = boxed::box_new_uninit(const <() as std::mem::SizedTypeProperties>::LAYOUT) -> [return: bb2, unwind unreachable]; -+ _13 = boxed::box_new_uninit(const Layout {{ size: 0_usize, align: std::mem::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}) -> [return: bb2, unwind unreachable]; ++ _13 = boxed::box_new_uninit(const Layout {{ size: 0_usize, align: std::mem::Alignment {{ _inner_repr_trick: mem::alignment::AlignmentEnum::_Align1Shl0 }} }}) -> [return: bb2, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index 139cf2116fc49..11d64d05c7d18 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -63,7 +63,7 @@ bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); -+ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::mem::Alignment {{ _inner_repr_trick: Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum }} }}; ++ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::mem::Alignment {{ _inner_repr_trick: Scalar(0x0000000000000000): mem::alignment::AlignmentEnum }} }}; StorageDead(_8); StorageDead(_2); StorageLive(_3); @@ -73,8 +73,8 @@ StorageLive(_7); - _7 = copy _1; - _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb4, unwind unreachable]; -+ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::mem::Alignment {{ _inner_repr_trick: Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum }} }}; -+ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::mem::Alignment {{ _inner_repr_trick: Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum }} }}, const false) -> [return: bb4, unwind unreachable]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::mem::Alignment {{ _inner_repr_trick: Scalar(0x0000000000000000): mem::alignment::AlignmentEnum }} }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::mem::Alignment {{ _inner_repr_trick: Scalar(0x0000000000000000): mem::alignment::AlignmentEnum }} }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { From 17e0cc3ebd6562dde473e49207d1a79901b3fa2c Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Mon, 23 Mar 2026 18:09:15 +0000 Subject: [PATCH 37/55] Create `Ty` type alias in `rustc_type_ir` --- .../src/canonical/canonicalizer.rs | 6 +- .../src/canonical/mod.rs | 6 +- .../rustc_next_trait_solver/src/coherence.rs | 29 ++++--- .../rustc_next_trait_solver/src/delegate.rs | 8 +- .../src/placeholder.rs | 2 +- .../rustc_next_trait_solver/src/resolve.rs | 6 +- .../src/solve/assembly/mod.rs | 12 +-- .../src/solve/assembly/structural_traits.rs | 38 ++++---- .../src/solve/effect_goals.rs | 6 +- .../src/solve/eval_ctxt/mod.rs | 28 +++--- .../rustc_next_trait_solver/src/solve/mod.rs | 10 +-- .../src/solve/normalizes_to/mod.rs | 4 +- .../src/solve/trait_goals.rs | 27 +++--- compiler/rustc_type_ir/src/binder.rs | 16 ++-- compiler/rustc_type_ir/src/error.rs | 8 +- compiler/rustc_type_ir/src/fast_reject.rs | 15 ++-- compiler/rustc_type_ir/src/flags.rs | 4 +- compiler/rustc_type_ir/src/fold.rs | 8 +- compiler/rustc_type_ir/src/generic_arg.rs | 6 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 34 +++----- compiler/rustc_type_ir/src/inherent.rs | 36 ++++---- compiler/rustc_type_ir/src/lib.rs | 6 +- compiler/rustc_type_ir/src/outlives.rs | 8 +- compiler/rustc_type_ir/src/predicate.rs | 48 +++++------ compiler/rustc_type_ir/src/predicate_kind.rs | 6 +- compiler/rustc_type_ir/src/relate.rs | 18 ++-- compiler/rustc_type_ir/src/relate/combine.rs | 16 ++-- .../src/relate/solver_relating.rs | 16 ++-- compiler/rustc_type_ir/src/solve/mod.rs | 4 +- compiler/rustc_type_ir/src/sty/mod.rs | 3 + compiler/rustc_type_ir/src/ty_kind.rs | 46 +++++----- compiler/rustc_type_ir/src/ty_kind/closure.rs | 86 +++++++++---------- compiler/rustc_type_ir/src/visit.rs | 8 +- 33 files changed, 292 insertions(+), 282 deletions(-) create mode 100644 compiler/rustc_type_ir/src/sty/mod.rs diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index ce2be24adc586..5a0f149fd0550 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -78,7 +78,7 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner /// We can simply cache based on the ty itself, because we use /// `ty::BoundVarIndexKind::Canonical`. - cache: HashMap, + cache: HashMap, ty::Ty>, } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { @@ -316,7 +316,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { (max_universe, self.variables, var_kinds) } - fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn inner_fold_ty(&mut self, t: ty::Ty) -> ty::Ty { let kind = match t.kind() { ty::Infer(i) => match i { ty::TyVar(vid) => { @@ -475,7 +475,7 @@ impl, I: Interner> TypeFolder for Canonicaliz Region::new_canonical_bound(self.cx(), var) } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: ty::Ty) -> ty::Ty { if !t.flags().intersects(NEEDS_CANONICAL) { t } else if let Some(&ty) = self.cache.get(&t) { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 1f64f09fe787f..cd42bf8b57b60 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -16,7 +16,7 @@ use rustc_index::IndexVec; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ - self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, + self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, Ty, TypeFoldable, }; use tracing::instrument; @@ -53,7 +53,7 @@ impl ResponseT for inspect::State { pub(super) fn canonicalize_goal( delegate: &D, goal: Goal, - opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], + opaque_types: &[(ty::OpaqueTypeKey, Ty)], ) -> (Vec, CanonicalInput) where D: SolverDelegate, @@ -264,7 +264,7 @@ fn register_region_constraints( fn register_new_opaque_types( delegate: &D, - opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], + opaque_types: &[(ty::OpaqueTypeKey, Ty)], span: I::Span, ) where D: SolverDelegate, diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index c370fd24a1bb3..69cebb0a3dc64 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -47,7 +47,7 @@ pub enum Conflict { pub fn trait_ref_is_knowable( infcx: &Infcx, trait_ref: ty::TraitRef, - mut lazily_normalize_ty: impl FnMut(I::Ty) -> Result, + mut lazily_normalize_ty: impl FnMut(ty::Ty) -> Result, E>, ) -> Result, E> where Infcx: InferCtxtLike, @@ -115,14 +115,14 @@ impl From for IsFirstInputType { #[derive_where(Debug; I: Interner, T: Debug)] pub enum OrphanCheckErr { - NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>), + NonLocalInputType(Vec<(ty::Ty, IsFirstInputType)>), UncoveredTyParams(UncoveredTyParams), } #[derive_where(Debug; I: Interner, T: Debug)] pub struct UncoveredTyParams { pub uncovered: T, - pub local_ty: Option, + pub local_ty: Option>, } /// Checks whether a trait-ref is potentially implementable by a crate. @@ -222,8 +222,8 @@ pub fn orphan_check_trait_ref( infcx: &Infcx, trait_ref: ty::TraitRef, in_crate: InCrate, - lazily_normalize_ty: impl FnMut(I::Ty) -> Result, -) -> Result>, E> + lazily_normalize_ty: impl FnMut(ty::Ty) -> Result, E>, +) -> Result>>, E> where Infcx: InferCtxtLike, I: Interner, @@ -262,14 +262,14 @@ struct OrphanChecker<'a, Infcx, I: Interner, F> { lazily_normalize_ty: F, /// Ignore orphan check failures and exclusively search for the first local type. search_first_local_ty: bool, - non_local_tys: Vec<(I::Ty, IsFirstInputType)>, + non_local_tys: Vec<(ty::Ty, IsFirstInputType)>, } impl<'a, Infcx, I, F, E> OrphanChecker<'a, Infcx, I, F> where Infcx: InferCtxtLike, I: Interner, - F: FnOnce(I::Ty) -> Result, + F: FnOnce(ty::Ty) -> Result, E>, { fn new(infcx: &'a Infcx, in_crate: InCrate, lazily_normalize_ty: F) -> Self { OrphanChecker { @@ -282,12 +282,15 @@ where } } - fn found_non_local_ty(&mut self, t: I::Ty) -> ControlFlow> { + fn found_non_local_ty(&mut self, t: ty::Ty) -> ControlFlow> { self.non_local_tys.push((t, self.in_self_ty.into())); ControlFlow::Continue(()) } - fn found_uncovered_ty_param(&mut self, ty: I::Ty) -> ControlFlow> { + fn found_uncovered_ty_param( + &mut self, + ty: ty::Ty, + ) -> ControlFlow> { if self.search_first_local_ty { return ControlFlow::Continue(()); } @@ -305,15 +308,15 @@ where enum OrphanCheckEarlyExit { NormalizationFailure(E), - UncoveredTyParam(I::Ty), - LocalTy(I::Ty), + UncoveredTyParam(ty::Ty), + LocalTy(ty::Ty), } impl<'a, Infcx, I, F, E> TypeVisitor for OrphanChecker<'a, Infcx, I, F> where Infcx: InferCtxtLike, I: Interner, - F: FnMut(I::Ty) -> Result, + F: FnMut(ty::Ty) -> Result, E>, { type Result = ControlFlow>; @@ -321,7 +324,7 @@ where ControlFlow::Continue(()) } - fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { + fn visit_ty(&mut self, ty: ty::Ty) -> Self::Result { let ty = self.infcx.shallow_resolve(ty); let ty = match (self.lazily_normalize_ty)(ty) { Ok(norm_ty) if norm_ty.is_ty_var() => ty, diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 9d5aa8bc124b6..1714ae3dd6b2e 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable}; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Ty, TypeFoldable}; pub trait SolverDelegate: Deref + Sized { type Infcx: InferCtxtLike; @@ -70,7 +70,7 @@ pub trait SolverDelegate: Deref + Sized { def_id: ::DefId, args: ::GenericArgs, param_env: ::ParamEnv, - hidden_ty: ::Ty, + hidden_ty: Ty, goals: &mut Vec::Predicate>>, ); @@ -86,8 +86,8 @@ pub trait SolverDelegate: Deref + Sized { fn is_transmutable( &self, - src: ::Ty, - dst: ::Ty, + src: Ty, + dst: Ty, assume: ::Const, ) -> Result; } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index 83f3bdf01dc83..fe7521c86e9be 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -113,7 +113,7 @@ where } } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: ty::Ty) -> ty::Ty { match t.kind() { ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() + 1 diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index c3c57eccd6eff..86bf05bdb57cc 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,7 +1,7 @@ use rustc_type_ir::data_structures::DelayedMap; use rustc_type_ir::inherent::*; use rustc_type_ir::{ - self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, + self as ty, InferCtxtLike, Interner, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -19,7 +19,7 @@ where delegate: &'a D, /// We're able to use a cache here as the folder does not have any /// mutable state. - cache: DelayedMap, + cache: DelayedMap, Ty>, } pub fn eager_resolve_vars>( @@ -45,7 +45,7 @@ impl, I: Interner> TypeFolder for EagerResolv self.delegate.cx() } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: Ty) -> Ty { match t.kind() { ty::Infer(ty::TyVar(vid)) => { let resolved = self.delegate.opportunistic_resolve_ty_var(vid); 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 32b1e93bf98be..f58318b83625d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -46,11 +46,11 @@ where D: SolverDelegate, I: Interner, { - fn self_ty(self) -> I::Ty; + fn self_ty(self) -> ty::Ty; fn trait_ref(self, cx: I) -> ty::TraitRef; - fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self; + fn with_replaced_self_ty(self, cx: I, self_ty: ty::Ty) -> Self; fn trait_def_id(self, cx: I) -> I::TraitId; @@ -683,7 +683,7 @@ where // hitting another overflow error something. Add a depth parameter needed later. fn assemble_alias_bound_candidates_recur>( &mut self, - self_ty: I::Ty, + self_ty: ty::Ty, goal: Goal, candidates: &mut Vec>, consider_self_bounds: AliasBoundKind, @@ -1017,13 +1017,13 @@ where struct ReplaceOpaque { cx: I, alias_ty: ty::AliasTy, - self_ty: I::Ty, + self_ty: ty::Ty, } impl TypeFolder for ReplaceOpaque { fn cx(&self) -> I { self.cx } - fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + fn fold_ty(&mut self, ty: ty::Ty) -> ty::Ty { if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() { if alias_ty == self.alias_ty { return self.self_ty; @@ -1280,7 +1280,7 @@ where ControlFlow::Continue(()) } - fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { + fn visit_ty(&mut self, ty: ty::Ty) -> Self::Result { let ty = self.ecx.replace_bound_vars(ty, &mut self.universes); let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else { return ControlFlow::Break(Err(NoSolution)); 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 cd74e87b670f1..af25b3ed26e6a 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 @@ -21,8 +21,8 @@ use crate::solve::{AdtDestructorKind, EvalCtxt, Goal, NoSolution}; #[instrument(level = "trace", skip(ecx), ret)] pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( ecx: &EvalCtxt<'_, D>, - ty: I::Ty, -) -> Result>, NoSolution> + ty: ty::Ty, +) -> Result>>, NoSolution> where D: SolverDelegate, I: Interner, @@ -108,8 +108,8 @@ where pub(in crate::solve) fn instantiate_constituent_tys_for_sizedness_trait( ecx: &EvalCtxt<'_, D>, sizedness: SizedTraitKind, - ty: I::Ty, -) -> Result>, NoSolution> + ty: ty::Ty, +) -> Result>>, NoSolution> where D: SolverDelegate, I: Interner, @@ -186,8 +186,8 @@ where #[instrument(level = "trace", skip(ecx), ret)] pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( ecx: &EvalCtxt<'_, D>, - ty: I::Ty, -) -> Result>, NoSolution> + ty: ty::Ty, +) -> Result>>, NoSolution> where D: SolverDelegate, I: Interner, @@ -268,9 +268,9 @@ where // Returns a binder of the tupled inputs types and output type from a builtin callable type. pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable( cx: I, - self_ty: I::Ty, + self_ty: ty::Ty, goal_kind: ty::ClosureKind, -) -> Result>, NoSolution> { +) -> Result, ty::Ty)>>, NoSolution> { match self_ty.kind() { // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnDef(def_id, args) => { @@ -408,13 +408,13 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable { - pub tupled_inputs_ty: I::Ty, + pub tupled_inputs_ty: ty::Ty, /// Type returned by calling the closure /// i.e. `f()`. - pub output_coroutine_ty: I::Ty, + pub output_coroutine_ty: ty::Ty, /// Type returned by `await`ing the output /// i.e. `f().await`. - pub coroutine_return_ty: I::Ty, + pub coroutine_return_ty: ty::Ty, } // Returns a binder of the tupled inputs types, output type, and coroutine type @@ -424,7 +424,7 @@ pub(in crate::solve) struct AsyncCallableRelevantTypes { // know the kind already, we can short-circuit this check. pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( cx: I, - self_ty: I::Ty, + self_ty: ty::Ty, goal_kind: ty::ClosureKind, env_region: I::Region, ) -> Result<(ty::Binder>, Vec), NoSolution> { @@ -608,7 +608,7 @@ fn coroutine_closure_to_certain_coroutine( def_id: I::CoroutineClosureId, args: ty::CoroutineClosureArgs, sig: ty::CoroutineClosureSignature, -) -> I::Ty { +) -> ty::Ty { sig.to_coroutine_given_kind_and_upvars( cx, args.parent_args(), @@ -632,7 +632,7 @@ fn coroutine_closure_to_ambiguous_coroutine( def_id: I::CoroutineClosureId, args: ty::CoroutineClosureArgs, sig: ty::CoroutineClosureSignature, -) -> I::Ty { +) -> ty::Ty { let upvars_projection_def_id = cx.require_lang_item(SolverLangItem::AsyncFnKindUpvars); let tupled_upvars_ty = Ty::new_projection( cx, @@ -664,8 +664,8 @@ fn coroutine_closure_to_ambiguous_coroutine( #[instrument(level = "trace", skip(cx), ret)] pub(in crate::solve) fn extract_fn_def_from_const_callable( cx: I, - self_ty: I::Ty, -) -> Result<(ty::Binder, I::DefId, I::GenericArgs), NoSolution> { + self_ty: ty::Ty, +) -> Result<(ty::Binder, ty::Ty)>, I::DefId, I::GenericArgs), NoSolution> { match self_ty.kind() { ty::FnDef(def_id, args) => { let sig = cx.fn_sig(def_id); @@ -742,7 +742,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( // the old solver, for as long as that exists. pub(in crate::solve) fn const_conditions_for_destruct( cx: I, - self_ty: I::Ty, + self_ty: ty::Ty, ) -> Result>, NoSolution> { let destruct_def_id = cx.require_trait_lang_item(SolverTraitLangItem::Destruct); @@ -923,7 +923,7 @@ where struct ReplaceProjectionWith<'a, 'b, I: Interner, D: SolverDelegate> { ecx: &'a mut EvalCtxt<'b, D>, param_env: I::ParamEnv, - self_ty: I::Ty, + self_ty: ty::Ty, mapping: &'a HashMap>>>, nested: Vec>, } @@ -1009,7 +1009,7 @@ where self.ecx.cx() } - fn try_fold_ty(&mut self, ty: I::Ty) -> Result { + fn try_fold_ty(&mut self, ty: ty::Ty) -> Result, Ambiguous> { if let ty::Alias(ty::Projection, alias_ty) = ty.kind() && let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? { diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 4b1e4b2de571d..9a0a82acbc931 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -13,7 +13,7 @@ use super::assembly::{Candidate, structural_traits}; use crate::delegate::SolverDelegate; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, - QueryResult, assembly, + QueryResult, Ty, assembly, }; impl assembly::GoalKind for ty::HostEffectPredicate @@ -21,7 +21,7 @@ where D: SolverDelegate, I: Interner, { - fn self_ty(self) -> I::Ty { + fn self_ty(self) -> Ty { self.self_ty() } @@ -29,7 +29,7 @@ where self.trait_ref } - fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + fn with_replaced_self_ty(self, cx: I, self_ty: Ty) -> Self { self.with_replaced_self_ty(cx, self_ty) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6841fe1c5124e..d6ed220909732 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -10,7 +10,7 @@ use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::search_graph::{CandidateHeadUsages, PathKind}; use rustc_type_ir::solve::OpaqueTypesJank; use rustc_type_ir::{ - self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder, + self as ty, CanonicalVarValues, InferCtxtLike, Interner, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; @@ -781,7 +781,7 @@ where region } - pub(super) fn next_ty_infer(&mut self) -> I::Ty { + pub(super) fn next_ty_infer(&mut self) -> Ty { let ty = self.delegate.next_ty_infer(); self.inspect.add_var_value(ty); ty @@ -829,7 +829,7 @@ where term: I::Term, universe_of_term: ty::UniverseIndex, delegate: &'a D, - cache: HashSet, + cache: HashSet>, } impl, I: Interner> ContainsTermOrNotNameable<'_, D, I> { @@ -846,7 +846,7 @@ where for ContainsTermOrNotNameable<'_, D, I> { type Result = ControlFlow<()>; - fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + fn visit_ty(&mut self, t: Ty) -> Self::Result { if self.cache.contains(&t) { return ControlFlow::Continue(()); } @@ -1072,7 +1072,7 @@ where self.delegate.resolve_vars_if_possible(value) } - pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty { + pub(super) fn shallow_resolve(&self, ty: Ty) -> Ty { self.delegate.shallow_resolve(ty) } @@ -1092,7 +1092,7 @@ where args } - pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { + pub(super) fn register_ty_outlives(&self, ty: Ty, lt: I::Region) { self.delegate.register_ty_outlives(ty, lt, self.origin_span); } @@ -1134,8 +1134,8 @@ where pub(super) fn register_hidden_type_in_storage( &mut self, opaque_type_key: ty::OpaqueTypeKey, - hidden_ty: I::Ty, - ) -> Option { + hidden_ty: Ty, + ) -> Option> { self.delegate.register_hidden_type_in_storage(opaque_type_key, hidden_ty, self.origin_span) } @@ -1144,7 +1144,7 @@ where opaque_def_id: I::DefId, opaque_args: I::GenericArgs, param_env: I::ParamEnv, - hidden_ty: I::Ty, + hidden_ty: Ty, ) { let mut goals = Vec::new(); self.delegate.add_item_bounds_for_hidden_type( @@ -1170,8 +1170,8 @@ where pub(super) fn is_transmutable( &mut self, - src: I::Ty, - dst: I::Ty, + src: Ty, + dst: Ty, assume: I::Const, ) -> Result { self.delegate.is_transmutable(dst, src, assume) @@ -1195,7 +1195,7 @@ where pub(crate) fn opaques_with_sub_unified_hidden_type( &self, - self_ty: I::Ty, + self_ty: Ty, ) -> Vec> { if let ty::Infer(ty::TyVar(vid)) = self_ty.kind() { self.delegate.opaques_with_sub_unified_hidden_type(vid) @@ -1389,7 +1389,7 @@ where ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv, normalization_goal_source: GoalSource, - cache: HashMap, + cache: HashMap, Ty>, } impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I> @@ -1421,7 +1421,7 @@ where self.ecx.cx() } - fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + fn fold_ty(&mut self, ty: Ty) -> Ty { match ty.kind() { ty::Alias(..) if !ty.has_escaping_bound_vars() => { let infer_ty = self.ecx.next_ty_infer(); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 58bd7cf663d98..71b28cf1ad277 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -24,7 +24,7 @@ mod trait_goals; use derive_where::derive_where; use rustc_type_ir::inherent::*; pub use rustc_type_ir::solve::*; -use rustc_type_ir::{self as ty, Interner, TyVid, TypingMode}; +use rustc_type_ir::{self as ty, Interner, Ty, TyVid, TypingMode}; use tracing::instrument; pub use self::eval_ctxt::{ @@ -88,7 +88,7 @@ where #[instrument(level = "trace", skip(self))] fn compute_type_outlives_goal( &mut self, - goal: Goal>, + goal: Goal>>, ) -> QueryResult { let ty::OutlivesPredicate(ty, lt) = goal.predicate; self.register_ty_outlives(ty, lt); @@ -205,7 +205,7 @@ where #[instrument(level = "trace", skip(self), ret)] fn compute_const_arg_has_type_goal( &mut self, - goal: Goal, + goal: Goal)>, ) -> QueryResult { let (ct, ty) = goal.predicate; let ct = self.structurally_normalize_const(goal.param_env, ct)?; @@ -315,8 +315,8 @@ where fn structurally_normalize_ty( &mut self, param_env: I::ParamEnv, - ty: I::Ty, - ) -> Result { + ty: Ty, + ) -> Result, NoSolution> { self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty()) } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 13f2ad8f82eba..13ed945857db2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -125,7 +125,7 @@ where D: SolverDelegate, I: Interner, { - fn self_ty(self) -> I::Ty { + fn self_ty(self) -> ty::Ty { self.self_ty() } @@ -133,7 +133,7 @@ where self.alias.trait_ref(cx) } - fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + fn with_replaced_self_ty(self, cx: I, self_ty: ty::Ty) -> Self { self.with_replaced_self_ty(cx, self_ty) } 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 6589a12c4cc2d..82051b2fea4ef 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -29,7 +29,7 @@ where D: SolverDelegate, I: Interner, { - fn self_ty(self) -> I::Ty { + fn self_ty(self) -> ty::Ty { self.self_ty() } @@ -37,7 +37,7 @@ where self.trait_ref } - fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + fn with_replaced_self_ty(self, cx: I, self_ty: ty::Ty) -> Self { self.with_replaced_self_ty(cx, self_ty) } @@ -929,7 +929,7 @@ where /// ``` fn consider_builtin_dyn_upcast_candidates( &mut self, - goal: Goal, + goal: Goal, ty::Ty)>, a_data: I::BoundExistentialPredicates, a_region: I::Region, b_data: I::BoundExistentialPredicates, @@ -977,7 +977,7 @@ where fn consider_builtin_unsize_to_dyn_candidate( &mut self, - goal: Goal, + goal: Goal, ty::Ty)>, b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Result, NoSolution> { @@ -1018,7 +1018,7 @@ where fn consider_builtin_upcast_to_principal( &mut self, - goal: Goal, + goal: Goal, ty::Ty)>, source: CandidateSource, a_data: I::BoundExistentialPredicates, a_region: I::Region, @@ -1132,9 +1132,9 @@ where /// `#[rustc_deny_explicit_impl]` in this case. fn consider_builtin_array_unsize( &mut self, - goal: Goal, - a_elem_ty: I::Ty, - b_elem_ty: I::Ty, + goal: Goal, ty::Ty)>, + a_elem_ty: ty::Ty, + b_elem_ty: ty::Ty, ) -> Result, NoSolution> { self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) @@ -1156,7 +1156,7 @@ where /// ``` fn consider_builtin_struct_unsize( &mut self, - goal: Goal, + goal: Goal, ty::Ty)>, def: I::AdtDef, a_args: I::GenericArgs, b_args: I::GenericArgs, @@ -1319,8 +1319,8 @@ where goal: Goal>, constituent_tys: impl Fn( &EvalCtxt<'_, D>, - I::Ty, - ) -> Result>, NoSolution>, + ty::Ty, + ) -> Result>>, NoSolution>, ) -> Result, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { let goals = @@ -1542,7 +1542,10 @@ where self.merge_trait_candidates(candidate_preference_mode, candidates, failed_candidate_info) } - fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option, NoSolution>> { + fn try_stall_coroutine( + &mut self, + self_ty: ty::Ty, + ) -> Option, NoSolution>> { if let ty::Coroutine(def_id, _) = self_ty.kind() { match self.typing_mode() { TypingMode::Analysis { diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 0b0f0fd2f4249..6528aa7526b21 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -16,7 +16,7 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldabl use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, DebruijnIndex, Interner, UniverseIndex}; +use crate::{self as ty, DebruijnIndex, Interner, Ty, UniverseIndex}; /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -274,7 +274,7 @@ pub struct ValidateBoundVars { // We only cache types because any complex const will have to step through // a type at some point anyways. We may encounter the same variable at // different levels of binding, so this can't just be `Ty`. - visited: SsoHashSet<(ty::DebruijnIndex, I::Ty)>, + visited: SsoHashSet<(ty::DebruijnIndex, Ty)>, } impl ValidateBoundVars { @@ -297,7 +297,7 @@ impl TypeVisitor for ValidateBoundVars { result } - fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + fn visit_ty(&mut self, t: Ty) -> Self::Result { if t.outer_exclusive_binder() < self.binder_index || !self.visited.insert((self.binder_index, t)) { @@ -724,7 +724,7 @@ impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { } } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: Ty) -> Ty { if !t.has_param() { return t; } @@ -753,7 +753,7 @@ impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { } impl<'a, I: Interner> ArgFolder<'a, I> { - fn ty_for_param(&self, p: I::ParamTy, source_ty: I::Ty) -> I::Ty { + fn ty_for_param(&self, p: I::ParamTy, source_ty: Ty) -> Ty { // Look up the type in the args. It really should be in there. let opt_ty = self.args.get(p.index() as usize).map(|arg| arg.kind()); let ty = match opt_ty { @@ -767,7 +767,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> { #[cold] #[inline(never)] - fn type_param_expected(&self, p: I::ParamTy, ty: I::Ty, kind: ty::GenericArgKind) -> ! { + fn type_param_expected(&self, p: I::ParamTy, ty: Ty, kind: ty::GenericArgKind) -> ! { panic!( "expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}", p, @@ -780,7 +780,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> { #[cold] #[inline(never)] - fn type_param_out_of_range(&self, p: I::ParamTy, ty: I::Ty) -> ! { + fn type_param_out_of_range(&self, p: I::ParamTy, ty: Ty) -> ! { panic!( "type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}", p, @@ -1277,7 +1277,7 @@ impl PlaceholderConst { Self { universe: ui, bound, _tcx: PhantomData } } - pub fn find_const_ty_from_env(self, env: I::ParamEnv) -> I::Ty { + pub fn find_const_ty_from_env(self, env: I::ParamEnv) -> Ty { let mut candidates = env.caller_bounds().iter().filter_map(|clause| { // `ConstArgHasType` are never desugared to be higher ranked. match clause.kind().skip_binder() { diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index eba4c7c6644ac..ef542af7f1f9a 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -2,7 +2,7 @@ use derive_where::derive_where; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::solve::NoSolution; -use crate::{self as ty, Interner}; +use crate::{self as ty, Interner, Ty}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(TypeFoldable_Generic, TypeVisitable_Generic, GenericTypeVisitable)] @@ -36,15 +36,15 @@ pub enum TypeError { RegionsInsufficientlyPolymorphic(ty::BoundRegion, I::Region), RegionsPlaceholderMismatch, - Sorts(ExpectedFound), - ArgumentSorts(ExpectedFound, usize), + Sorts(ExpectedFound>), + ArgumentSorts(ExpectedFound>, usize), Traits(ExpectedFound), VariadicMismatch(ExpectedFound), /// Instantiating a type variable with the given type would have /// created a cycle (because it appears somewhere within that /// type). - CyclicTy(I::Ty), + CyclicTy(Ty), CyclicConst(I::Const), ProjectionMismatched(ExpectedFound), ExistentialMismatch(ExpectedFound), diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index ed6416a7f55f2..72b58776565b5 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -113,7 +113,7 @@ pub enum TreatParams { /// ¹ meaning that if the outermost layers are different, then the whole types are also different. pub fn simplify_type( cx: I, - ty: I::Ty, + ty: ty::Ty, treat_params: TreatParams, ) -> Option> { match ty.kind() { @@ -236,11 +236,16 @@ impl bool { + pub fn types_may_unify(self, lhs: ty::Ty, rhs: ty::Ty) -> bool { self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH) } - pub fn types_may_unify_with_depth(self, lhs: I::Ty, rhs: I::Ty, depth_limit: usize) -> bool { + pub fn types_may_unify_with_depth( + self, + lhs: ty::Ty, + rhs: ty::Ty, + depth_limit: usize, + ) -> bool { self.types_may_unify_inner(lhs, rhs, depth_limit) } @@ -268,7 +273,7 @@ impl bool { + fn types_may_unify_inner(self, lhs: ty::Ty, rhs: ty::Ty, depth: usize) -> bool { if lhs == rhs { return true; } @@ -527,7 +532,7 @@ impl bool { + fn var_and_ty_may_unify(self, var: ty::InferTy, ty: ty::Ty) -> bool { if !ty.is_known_rigid() { return true; } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 7e905da0785f8..6962a7ab1d727 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -1,6 +1,6 @@ use crate::inherent::*; use crate::visit::Flags; -use crate::{self as ty, Interner}; +use crate::{self as ty, Interner, Ty}; bitflags::bitflags! { /// Flags that we track on types. These flags are propagated upwards @@ -430,7 +430,7 @@ impl FlagComputation { } } - fn add_ty(&mut self, ty: I::Ty) { + fn add_ty(&mut self, ty: Ty) { self.add_flags(ty.flags()); self.add_exclusive_binder(ty.outer_exclusive_binder()); } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index d1a50599e8b9c..ef162b21b660e 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -135,7 +135,7 @@ pub trait TypeFolder: Sized { t.super_fold_with(self) } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: ty::Ty) -> ty::Ty { t.super_fold_with(self) } @@ -177,7 +177,7 @@ pub trait FallibleTypeFolder: Sized { t.try_super_fold_with(self) } - fn try_fold_ty(&mut self, t: I::Ty) -> Result { + fn try_fold_ty(&mut self, t: ty::Ty) -> Result, Self::Error> { t.try_super_fold_with(self) } @@ -408,7 +408,7 @@ impl TypeFolder for Shifter { } } - fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + fn fold_ty(&mut self, ty: ty::Ty) -> ty::Ty { match ty.kind() { ty::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty) if debruijn >= self.current_index => @@ -538,7 +538,7 @@ where } } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: ty::Ty) -> ty::Ty { if t.has_type_flags( TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED, ) { diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs index 5d612740fdd84..22a4ebd03b69c 100644 --- a/compiler/rustc_type_ir/src/generic_arg.rs +++ b/compiler/rustc_type_ir/src/generic_arg.rs @@ -3,7 +3,7 @@ use derive_where::derive_where; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::GenericTypeVisitable; -use crate::Interner; +use crate::{Interner, Ty}; #[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)] #[derive(GenericTypeVisitable)] @@ -13,7 +13,7 @@ use crate::Interner; )] pub enum GenericArgKind { Lifetime(I::Region), - Type(I::Ty), + Type(Ty), Const(I::Const), } @@ -26,7 +26,7 @@ impl Eq for GenericArgKind {} derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) )] pub enum TermKind { - Ty(I::Ty), + Ty(Ty), Const(I::Const), } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index feafcee7bad9e..843d1eb37b7d9 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -6,7 +6,7 @@ use crate::fold::TypeFoldable; use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::{self as ty, Interner, TyVid}; +use crate::{self as ty, Interner, Ty, TyVid}; /// The current typing mode of an inference context. We unfortunately have some /// slightly different typing rules depending on the current context. See the @@ -161,12 +161,9 @@ pub trait InferCtxtLike: Sized { fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid; fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; - fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; - fn opportunistic_resolve_float_var( - &self, - vid: ty::FloatVid, - ) -> ::Ty; + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty; + fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty; fn opportunistic_resolve_ct_var( &self, vid: ty::ConstVid, @@ -179,7 +176,7 @@ pub trait InferCtxtLike: Sized { fn is_changed_arg(&self, arg: ::GenericArg) -> bool; fn next_region_infer(&self) -> ::Region; - fn next_ty_infer(&self) -> ::Ty; + fn next_ty_infer(&self) -> Ty; fn next_const_infer(&self) -> ::Const; fn fresh_args_for_item( &self, @@ -209,7 +206,7 @@ pub trait InferCtxtLike: Sized { target_is_expected: bool, target_vid: ty::TyVid, instantiation_variance: ty::Variance, - source_ty: ::Ty, + source_ty: Ty, ) -> RelateResult; fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue); fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue); @@ -223,10 +220,7 @@ pub trait InferCtxtLike: Sized { fn set_tainted_by_errors(&self, e: ::ErrorGuaranteed); - fn shallow_resolve( - &self, - ty: ::Ty, - ) -> ::Ty; + fn shallow_resolve(&self, ty: Ty) -> Ty; fn shallow_resolve_const( &self, ty: ::Const, @@ -254,7 +248,7 @@ pub trait InferCtxtLike: Sized { fn register_ty_outlives( &self, - ty: ::Ty, + ty: Ty, r: ::Region, span: ::Span, ); @@ -263,26 +257,26 @@ pub trait InferCtxtLike: Sized { fn opaque_types_storage_num_entries(&self) -> Self::OpaqueTypeStorageEntries; fn clone_opaque_types_lookup_table( &self, - ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + ) -> Vec<(ty::OpaqueTypeKey, Ty)>; fn clone_duplicate_opaque_types( &self, - ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + ) -> Vec<(ty::OpaqueTypeKey, Ty)>; fn clone_opaque_types_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, - ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + ) -> Vec<(ty::OpaqueTypeKey, Ty)>; fn opaques_with_sub_unified_hidden_type(&self, ty: TyVid) -> Vec>; fn register_hidden_type_in_storage( &self, opaque_type_key: ty::OpaqueTypeKey, - hidden_ty: ::Ty, + hidden_ty: Ty, span: ::Span, - ) -> Option<::Ty>; + ) -> Option>; fn add_duplicate_opaque_type( &self, opaque_type_key: ty::OpaqueTypeKey, - hidden_ty: ::Ty, + hidden_ty: Ty, span: ::Span, ); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 116fd100bf0a9..45590561d9d08 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -55,7 +55,7 @@ pub trait Ty>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; fn new_projection_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self { - Ty::new_alias( + Self::new_alias( interner, ty::AliasTyKind::Projection, ty::AliasTy::new_from_args(interner, def_id, args), @@ -67,7 +67,7 @@ pub trait Ty>: def_id: I::DefId, args: impl IntoIterator>, ) -> Self { - Ty::new_alias( + Self::new_alias( interner, ty::AliasTyKind::Projection, ty::AliasTy::new(interner, def_id, args), @@ -108,7 +108,7 @@ pub trait Ty>: fn new_slice(interner: I, ty: Self) -> Self; - fn new_tup(interner: I, tys: &[I::Ty]) -> Self; + fn new_tup(interner: I, tys: &[ty::Ty]) -> Self; fn new_tup_from_iter(interner: I, iter: It) -> T::Output where @@ -121,7 +121,7 @@ pub trait Ty>: fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; - fn new_unsafe_binder(interner: I, ty: ty::Binder) -> Self; + fn new_unsafe_binder(interner: I, ty: ty::Binder>) -> Self; fn tuple_fields(self) -> I::Tys; @@ -158,7 +158,7 @@ pub trait Ty>: self.kind().fn_sig(interner) } - fn discriminant_ty(self, interner: I) -> I::Ty; + fn discriminant_ty(self, interner: I) -> ty::Ty; fn is_known_rigid(self) -> bool { self.kind().is_known_rigid() @@ -198,11 +198,11 @@ pub trait Ty>: } pub trait Tys>: - Copy + Debug + Hash + Eq + SliceLike + TypeFoldable + Default + Copy + Debug + Hash + Eq + SliceLike> + TypeFoldable + Default { fn inputs(self) -> I::FnInputTys; - fn output(self) -> I::Ty; + fn output(self) -> ty::Ty; } pub trait Abi>: Copy + Debug + Hash + Eq { @@ -290,7 +290,7 @@ pub trait Const>: } pub trait ValueConst>: Copy + Debug + Hash + Eq { - fn ty(self) -> I::Ty; + fn ty(self) -> ty::Ty; fn valtree(self) -> I::ValTree; } @@ -310,7 +310,7 @@ pub trait GenericArg>: + IntoKind> + TypeVisitable + Relate - + From + + From> + From + From + From @@ -323,11 +323,11 @@ pub trait GenericArg>: } } - fn as_type(&self) -> Option { + fn as_type(&self) -> Option> { if let ty::GenericArgKind::Type(ty) = self.kind() { Some(ty) } else { None } } - fn expect_ty(&self) -> I::Ty { + fn expect_ty(&self) -> ty::Ty { self.as_type().expect("expected a type") } @@ -359,11 +359,11 @@ pub trait GenericArg>: pub trait Term>: Copy + Debug + Hash + Eq + IntoKind> + TypeFoldable + Relate { - fn as_type(&self) -> Option { + fn as_type(&self) -> Option> { if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None } } - fn expect_ty(&self) -> I::Ty { + fn expect_ty(&self) -> ty::Ty { self.as_type().expect("expected a type, but found a const") } @@ -413,7 +413,7 @@ pub trait GenericArgs>: target: I::GenericArgs, ) -> I::GenericArgs; - fn type_at(self, i: usize) -> I::Ty; + fn type_at(self, i: usize) -> ty::Ty; fn region_at(self, i: usize) -> I::Region; @@ -459,7 +459,7 @@ pub trait Predicate>: + UpcastFrom> + UpcastFrom>> + UpcastFrom> - + UpcastFrom> + + UpcastFrom>> + UpcastFrom> + IntoKind>> + Elaboratable @@ -578,7 +578,7 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { /// Returns the type of the struct tail. /// /// Expects the `AdtDef` to be a struct. If it is not, then this will panic. - fn struct_tail_ty(self, interner: I) -> Option>; + fn struct_tail_ty(self, interner: I) -> Option>>; fn is_phantom_data(self) -> bool; @@ -591,13 +591,13 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { ) -> Option>; // FIXME: perhaps use `all_fields` and expose `FieldDef`. - fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; + fn all_field_tys(self, interner: I) -> ty::EarlyBinder>>; fn sizedness_constraint( self, interner: I, sizedness: SizedTraitKind, - ) -> Option>; + ) -> Option>>; fn is_fundamental(self) -> bool; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a0b444024ca79..6c838cf8a48ac 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -31,6 +31,7 @@ pub mod outlives; pub mod relate; pub mod search_graph; pub mod solve; +pub mod sty; pub mod walk; // These modules are not `pub` since they are glob-imported. @@ -78,6 +79,7 @@ pub use predicate_kind::*; pub use region_kind::*; pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy}; use rustc_type_ir_macros::GenericTypeVisitable; +pub use sty::*; pub use ty_info::*; pub use ty_kind::*; pub use upcast::*; @@ -443,8 +445,8 @@ impl fmt::Display for ClosureKind { } pub struct FieldInfo { - pub base: I::Ty, - pub ty: I::Ty, + pub base: Ty, + pub ty: Ty, pub variant: Option, pub variant_idx: VariantIdx, pub name: I::Symbol, diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 300e5c0b46956..cc79d6589e6fb 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -8,7 +8,7 @@ use smallvec::{SmallVec, smallvec}; use crate::data_structures::SsoHashSet; use crate::inherent::*; use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor}; -use crate::{self as ty, Interner}; +use crate::{self as ty, Interner, Ty}; #[derive_where(Debug; I: Interner)] pub enum Component { @@ -55,7 +55,7 @@ pub enum Component { /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn push_outlives_components( cx: I, - ty: I::Ty, + ty: Ty, out: &mut SmallVec<[Component; 4]>, ) { ty.visit_with(&mut OutlivesCollector { cx, out, visited: Default::default() }); @@ -64,14 +64,14 @@ pub fn push_outlives_components( struct OutlivesCollector<'a, I: Interner> { cx: I, out: &'a mut SmallVec<[Component; 4]>, - visited: SsoHashSet, + visited: SsoHashSet>, } impl TypeVisitor for OutlivesCollector<'_, I> { #[cfg(not(feature = "nightly"))] type Result = (); - fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { + fn visit_ty(&mut self, ty: Ty) -> Self::Result { if !self.visited.insert(ty) { return; } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 113192cc02eb8..f4975f3ad4486 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -101,7 +101,7 @@ impl TraitRef { ) } - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> Self { TraitRef::new( interner, self.def_id, @@ -110,13 +110,13 @@ impl TraitRef { } #[inline] - pub fn self_ty(&self) -> I::Ty { + pub fn self_ty(&self) -> ty::Ty { self.args.type_at(0) } } impl ty::Binder> { - pub fn self_ty(&self) -> ty::Binder { + pub fn self_ty(&self) -> ty::Binder> { self.map_bound_ref(|tr| tr.self_ty()) } @@ -152,7 +152,7 @@ pub struct TraitPredicate { impl Eq for TraitPredicate {} impl TraitPredicate { - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> Self { Self { trait_ref: self.trait_ref.with_replaced_self_ty(interner, self_ty), polarity: self.polarity, @@ -163,7 +163,7 @@ impl TraitPredicate { self.trait_ref.def_id } - pub fn self_ty(self) -> I::Ty { + pub fn self_ty(self) -> ty::Ty { self.trait_ref.self_ty() } } @@ -174,7 +174,7 @@ impl ty::Binder> { self.skip_binder().def_id() } - pub fn self_ty(self) -> ty::Binder { + pub fn self_ty(self) -> ty::Binder> { self.map_bound(|trait_ref| trait_ref.self_ty()) } @@ -307,7 +307,7 @@ impl ty::Binder> { /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). - pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause { + pub fn with_self_ty(&self, cx: I, self_ty: ty::Ty) -> I::Clause { match self.skip_binder() { ExistentialPredicate::Trait(tr) => self.rebind(tr).with_self_ty(cx, self_ty).upcast(cx), ExistentialPredicate::Projection(p) => { @@ -384,7 +384,7 @@ impl ExistentialTraitRef { /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self type. A common choice is `mk_err()` /// or some placeholder type. - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> TraitRef { + pub fn with_self_ty(self, interner: I, self_ty: ty::Ty) -> TraitRef { // otherwise the escaping vars would be captured by the binder // debug_assert!(!self_ty.has_escaping_bound_vars()); @@ -401,7 +401,7 @@ impl ty::Binder> { /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self type. A common choice is `mk_err()` /// or some placeholder type. - pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder> { + pub fn with_self_ty(&self, cx: I, self_ty: ty::Ty) -> ty::Binder> { self.map_bound(|trait_ref| trait_ref.with_self_ty(cx, self_ty)) } } @@ -459,7 +459,7 @@ impl ExistentialProjection { ExistentialTraitRef::new_from_args(interner, def_id.try_into().unwrap(), args) } - pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { + pub fn with_self_ty(&self, interner: I, self_ty: ty::Ty) -> ProjectionPredicate { // otherwise the escaping regions would be captured by the binders debug_assert!(!self_ty.has_escaping_bound_vars()); @@ -487,7 +487,7 @@ impl ExistentialProjection { } impl ty::Binder> { - pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder> { + pub fn with_self_ty(&self, cx: I, self_ty: ty::Ty) -> ty::Binder> { self.map_bound(|p| p.with_self_ty(cx, self_ty)) } @@ -683,11 +683,11 @@ impl AliasTerm { /// The following methods work only with (trait) associated term projections. impl AliasTerm { - pub fn self_ty(self) -> I::Ty { + pub fn self_ty(self) -> ty::Ty { self.args.type_at(0) } - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> Self { AliasTerm::new( interner, self.def_id, @@ -796,11 +796,11 @@ pub struct ProjectionPredicate { impl Eq for ProjectionPredicate {} impl ProjectionPredicate { - pub fn self_ty(self) -> I::Ty { + pub fn self_ty(self) -> ty::Ty { self.projection_term.self_ty() } - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> ProjectionPredicate { Self { projection_term: self.projection_term.with_replaced_self_ty(interner, self_ty), ..self @@ -859,11 +859,11 @@ pub struct NormalizesTo { impl Eq for NormalizesTo {} impl NormalizesTo { - pub fn self_ty(self) -> I::Ty { + pub fn self_ty(self) -> ty::Ty { self.alias.self_ty() } - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> NormalizesTo { Self { alias: self.alias.with_replaced_self_ty(interner, self_ty), ..self } } @@ -896,11 +896,11 @@ pub struct HostEffectPredicate { impl Eq for HostEffectPredicate {} impl HostEffectPredicate { - pub fn self_ty(self) -> I::Ty { + pub fn self_ty(self) -> ty::Ty { self.trait_ref.self_ty() } - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> Self { Self { trait_ref: self.trait_ref.with_replaced_self_ty(interner, self_ty), ..self } } @@ -915,7 +915,7 @@ impl ty::Binder> { self.skip_binder().def_id() } - pub fn self_ty(self) -> ty::Binder { + pub fn self_ty(self) -> ty::Binder> { self.map_bound(|trait_ref| trait_ref.self_ty()) } @@ -936,8 +936,8 @@ impl ty::Binder> { )] pub struct SubtypePredicate { pub a_is_expected: bool, - pub a: I::Ty, - pub b: I::Ty, + pub a: ty::Ty, + pub b: ty::Ty, } impl Eq for SubtypePredicate {} @@ -950,8 +950,8 @@ impl Eq for SubtypePredicate {} derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) )] pub struct CoercePredicate { - pub a: I::Ty, - pub b: I::Ty, + pub a: ty::Ty, + pub b: ty::Ty, } impl Eq for CoercePredicate {} diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 445e85a888fca..b6ff27fb238e6 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -5,7 +5,7 @@ use derive_where::derive_where; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{self as ty, Interner}; +use crate::{self as ty, Interner, Ty}; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. @@ -25,7 +25,7 @@ pub enum ClauseKind { RegionOutlives(ty::OutlivesPredicate), /// `where T: 'r` - TypeOutlives(ty::OutlivesPredicate), + TypeOutlives(ty::OutlivesPredicate>), /// `where ::Name == X`, approximately. /// See the `ProjectionPredicate` struct for details. @@ -33,7 +33,7 @@ pub enum ClauseKind { /// Ensures that a const generic argument to a parameter `const N: u8` /// is of type `u8`. - ConstArgHasType(I::Const, I::Ty), + ConstArgHasType(I::Const, Ty), /// No syntax: `T` well-formed. WellFormed(I::Term), diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index d33c6036dadd8..31248bea4cf85 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -44,7 +44,7 @@ pub enum VarianceDiagInfo { Invariant { /// The generic type containing the generic parameter /// that changes the variance (e.g. `*mut T`, `MyStruct`) - ty: I::Ty, + ty: ty::Ty, /// The index of the generic parameter being used /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) param_index: u32, @@ -75,13 +75,13 @@ pub trait TypeRelation: Sized { fn relate_ty_args( &mut self, - a_ty: I::Ty, - b_ty: I::Ty, + a_ty: ty::Ty, + b_ty: ty::Ty, ty_def_id: I::DefId, a_arg: I::GenericArgs, b_arg: I::GenericArgs, - mk: impl FnOnce(I::GenericArgs) -> I::Ty, - ) -> RelateResult; + mk: impl FnOnce(I::GenericArgs) -> ty::Ty, + ) -> RelateResult>; /// Switch variance for the purpose of relating `a` and `b`. fn relate_with_variance>( @@ -98,7 +98,7 @@ pub trait TypeRelation: Sized { // additional hooks for other types in the future if needed // without making older code, which called `relate`, obsolete. - fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult; + fn tys(&mut self, a: ty::Ty, b: ty::Ty) -> RelateResult>; fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult; @@ -332,9 +332,9 @@ impl Relate for ty::ExistentialTraitRef { #[instrument(level = "trace", skip(relation), ret)] pub fn structurally_relate_tys>( relation: &mut R, - a: I::Ty, - b: I::Ty, -) -> RelateResult { + a: ty::Ty, + b: ty::Ty, +) -> RelateResult> { let cx = relation.cx(); match (a.kind(), b.kind()) { (ty::Infer(_), _) | (_, ty::Infer(_)) => { diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 64b87fac77f94..11fbbf89b9c7b 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -39,15 +39,15 @@ where ); /// Register `AliasRelate` obligation(s) that both types must be related to each other. - fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); + fn register_alias_relate_predicate(&mut self, a: ty::Ty, b: ty::Ty); } pub fn super_combine_tys( infcx: &Infcx, relation: &mut R, - a: I::Ty, - b: I::Ty, -) -> RelateResult + a: ty::Ty, + b: ty::Ty, +) -> RelateResult> where Infcx: InferCtxtLike, I: Interner, @@ -226,13 +226,13 @@ where pub fn combine_ty_args( infcx: &Infcx, relation: &mut R, - a_ty: I::Ty, - b_ty: I::Ty, + a_ty: ty::Ty, + b_ty: ty::Ty, variances: I::VariancesOf, a_args: I::GenericArgs, b_args: I::GenericArgs, - mk: impl FnOnce(I::GenericArgs) -> I::Ty, -) -> RelateResult + mk: impl FnOnce(I::GenericArgs) -> ty::Ty, +) -> RelateResult> where Infcx: InferCtxtLike, I: Interner, diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 82ee4f75fcb0a..1494d67d3c603 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -5,7 +5,7 @@ use crate::data_structures::DelayedSet; use crate::relate::combine::combine_ty_args; pub use crate::relate::*; use crate::solve::Goal; -use crate::{self as ty, InferCtxtLike, Interner}; +use crate::{self as ty, InferCtxtLike, Interner, Ty}; pub trait RelateExt: InferCtxtLike { fn relate>( @@ -104,7 +104,7 @@ pub struct SolverRelating<'infcx, Infcx, I: Interner> { /// constrain `?1` to `u32`. When using the cache entry from the /// first time we've related these types, this only happens when /// later proving the `Subtype(?0, ?1)` goal from the first relation. - cache: DelayedSet<(ty::Variance, I::Ty, I::Ty)>, + cache: DelayedSet<(ty::Variance, Ty, Ty)>, } impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I> @@ -142,13 +142,13 @@ where fn relate_ty_args( &mut self, - a_ty: I::Ty, - b_ty: I::Ty, + a_ty: Ty, + b_ty: Ty, def_id: I::DefId, a_args: I::GenericArgs, b_args: I::GenericArgs, - _: impl FnOnce(I::GenericArgs) -> I::Ty, - ) -> RelateResult { + _: impl FnOnce(I::GenericArgs) -> Ty, + ) -> RelateResult> { if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles @@ -178,7 +178,7 @@ where } #[instrument(skip(self), level = "trace")] - fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult { + fn tys(&mut self, a: Ty, b: Ty) -> RelateResult> { if a == b { return Ok(a); } @@ -383,7 +383,7 @@ where self.goals.extend(obligations); } - fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) { + fn register_alias_relate_predicate(&mut self, a: Ty, b: Ty) { self.register_predicates([ty::Binder::dummy(match self.ambient_variance { ty::Covariant => ty::PredicateKind::AliasRelate( a.into(), diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 72b7df22b30d5..23e6075452b18 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -11,7 +11,7 @@ use rustc_type_ir_macros::{ use crate::lang_items::SolverTraitLangItem; use crate::search_graph::PathKind; -use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast}; +use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Ty, Upcast}; pub type CanonicalInput::Predicate> = ty::CanonicalQueryInput>; @@ -254,7 +254,7 @@ impl Eq for Response {} #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { pub region_constraints: Vec>, - pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + pub opaque_types: Vec<(ty::OpaqueTypeKey, Ty)>, pub normalization_nested_goals: NestedNormalizationGoals, } diff --git a/compiler/rustc_type_ir/src/sty/mod.rs b/compiler/rustc_type_ir/src/sty/mod.rs new file mode 100644 index 0000000000000..5b73d372384b8 --- /dev/null +++ b/compiler/rustc_type_ir/src/sty/mod.rs @@ -0,0 +1,3 @@ +/// This type is temporary and exists to cut down the bloat of further PR's +/// moving `struct Ty` from `rustc_middle` to `rustc_type_ir`. +pub type Ty = ::Ty; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 983d8f0820b6b..24d28acc05e98 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -100,7 +100,7 @@ pub enum TyKind { Str, /// An array with the given length. Written as `[T; N]`. - Array(I::Ty, I::Const), + Array(ty::Ty, I::Const), /// A pattern newtype. /// @@ -109,17 +109,17 @@ pub enum TyKind { /// Only `Copy` and `Clone` will automatically get implemented for pattern types. /// Auto-traits treat this as if it were an aggregate with a single nested type. /// Only supports integer range patterns for now. - Pat(I::Ty, I::Pat), + Pat(ty::Ty, I::Pat), /// The pointee of an array slice. Written as `[T]`. - Slice(I::Ty), + Slice(ty::Ty), /// A raw pointer. Written as `*mut T` or `*const T` - RawPtr(I::Ty, Mutability), + RawPtr(ty::Ty, Mutability), /// A reference; a pointer with an associated lifetime. Written as /// `&'a mut T` or `&'a T`. - Ref(I::Region, I::Ty, Mutability), + Ref(I::Region, ty::Ty, Mutability), /// The anonymous type of a function declaration/definition. /// @@ -469,18 +469,18 @@ impl AliasTy { matches!(self.kind(interner), AliasTyKind::Opaque) } - pub fn to_ty(self, interner: I) -> I::Ty { + pub fn to_ty(self, interner: I) -> ty::Ty { Ty::new_alias(interner, self.kind(interner), self) } } /// The following methods work only with (trait) associated type projections. impl AliasTy { - pub fn self_ty(self) -> I::Ty { + pub fn self_ty(self) -> ty::Ty { self.args.type_at(0) } - pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: ty::Ty) -> Self { AliasTy::new( interner, self.def_id, @@ -735,7 +735,7 @@ impl fmt::Debug for InferTy { )] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] pub struct TypeAndMut { - pub ty: I::Ty, + pub ty: ty::Ty, pub mutbl: Mutability, } @@ -765,7 +765,7 @@ impl FnSig { self.inputs_and_output.inputs() } - pub fn output(self) -> I::Ty { + pub fn output(self) -> ty::Ty { self.inputs_and_output.output() } @@ -783,7 +783,7 @@ impl ty::Binder> { #[inline] #[track_caller] - pub fn input(self, index: usize) -> ty::Binder { + pub fn input(self, index: usize) -> ty::Binder> { self.map_bound(|fn_sig| fn_sig.inputs().get(index).unwrap()) } @@ -792,7 +792,7 @@ impl ty::Binder> { } #[inline] - pub fn output(self) -> ty::Binder { + pub fn output(self) -> ty::Binder> { self.map_bound(|fn_sig| fn_sig.output()) } @@ -856,21 +856,21 @@ impl fmt::Debug for FnSig { } // FIXME: this is a distinct type because we need to define `Encode`/`Decode` -// impls in this crate for `Binder`. +// impls in this crate for `Binder>`. #[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] -pub struct UnsafeBinderInner(ty::Binder); +pub struct UnsafeBinderInner(ty::Binder>); impl Eq for UnsafeBinderInner {} -impl From> for UnsafeBinderInner { - fn from(value: ty::Binder) -> Self { +impl From>> for UnsafeBinderInner { + fn from(value: ty::Binder>) -> Self { UnsafeBinderInner(value) } } -impl From> for ty::Binder { +impl From> for ty::Binder> { fn from(value: UnsafeBinderInner) -> Self { value.0 } @@ -883,7 +883,7 @@ impl fmt::Debug for UnsafeBinderInner { } impl Deref for UnsafeBinderInner { - type Target = ty::Binder; + type Target = ty::Binder>; fn deref(&self) -> &Self::Target { &self.0 @@ -894,7 +894,7 @@ impl Deref for UnsafeBinderInner { impl rustc_serialize::Encodable for UnsafeBinderInner where - I::Ty: rustc_serialize::Encodable, + ty::Ty: rustc_serialize::Encodable, I::BoundVarKinds: rustc_serialize::Encodable, { fn encode(&self, e: &mut E) { @@ -907,7 +907,7 @@ where impl rustc_serialize::Decodable for UnsafeBinderInner where - I::Ty: TypeVisitable + rustc_serialize::Decodable, + ty::Ty: TypeVisitable + rustc_serialize::Decodable, I::BoundVarKinds: rustc_serialize::Decodable, { fn decode(decoder: &mut D) -> Self { @@ -937,7 +937,7 @@ impl FnSigTys { self.inputs_and_output.inputs() } - pub fn output(self) -> I::Ty { + pub fn output(self) -> ty::Ty { self.inputs_and_output.output() } } @@ -960,7 +960,7 @@ impl ty::Binder> { #[inline] #[track_caller] - pub fn input(self, index: usize) -> ty::Binder { + pub fn input(self, index: usize) -> ty::Binder> { self.map_bound(|sig_tys| sig_tys.inputs().get(index).unwrap()) } @@ -969,7 +969,7 @@ impl ty::Binder> { } #[inline] - pub fn output(self) -> ty::Binder { + pub fn output(self) -> ty::Binder> { self.map_bound(|sig_tys| sig_tys.output()) } } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index e8f94c8e7cc92..08c303b8de9c8 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -121,13 +121,13 @@ pub struct ClosureArgsParts { /// This is the args of the typeck root. pub parent_args: I::GenericArgsSlice, /// Represents the maximum calling capability of the closure. - pub closure_kind_ty: I::Ty, + pub closure_kind_ty: ty::Ty, /// Captures the closure's signature. This closure signature is "tupled", and /// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`. - pub closure_sig_as_fn_ptr_ty: I::Ty, + pub closure_sig_as_fn_ptr_ty: ty::Ty, /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: I::Ty, + pub tupled_upvars_ty: ty::Ty, } impl ClosureArgs { @@ -169,14 +169,14 @@ impl ClosureArgs { /// Returns the tuple type representing the upvars for this closure. #[inline] - pub fn tupled_upvars_ty(self) -> I::Ty { + pub fn tupled_upvars_ty(self) -> ty::Ty { self.split().tupled_upvars_ty } /// Returns the closure kind for this closure; may return a type /// variable during inference. To get the closure kind during /// inference, use `infcx.closure_kind(args)`. - pub fn kind_ty(self) -> I::Ty { + pub fn kind_ty(self) -> ty::Ty { self.split().closure_kind_ty } @@ -185,7 +185,7 @@ impl ClosureArgs { // FIXME(eddyb) this should be unnecessary, as the shallowly resolved // type is known at the time of the creation of `ClosureArgs`, // see `rustc_hir_analysis::check::closure`. - pub fn sig_as_fn_ptr_ty(self) -> I::Ty { + pub fn sig_as_fn_ptr_ty(self) -> ty::Ty { self.split().closure_sig_as_fn_ptr_ty } @@ -223,7 +223,7 @@ pub struct CoroutineClosureArgsParts { /// This is the args of the typeck root. pub parent_args: I::GenericArgsSlice, /// Represents the maximum calling capability of the closure. - pub closure_kind_ty: I::Ty, + pub closure_kind_ty: ty::Ty, /// Represents all of the relevant parts of the coroutine returned by this /// coroutine-closure. This signature parts type will have the general /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where @@ -232,10 +232,10 @@ pub struct CoroutineClosureArgsParts { /// /// Use `coroutine_closure_sig` to break up this type rather than using it /// yourself. - pub signature_parts_ty: I::Ty, + pub signature_parts_ty: ty::Ty, /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: I::Ty, + pub tupled_upvars_ty: ty::Ty, /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`. /// This allows us to represent the binder of the self-captures of the closure. /// @@ -243,7 +243,7 @@ pub struct CoroutineClosureArgsParts { /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`, /// while the `tupled_upvars_ty`, representing the by-move version of the same /// captures, will be `(String,)`. - pub coroutine_captures_by_ref_ty: I::Ty, + pub coroutine_captures_by_ref_ty: ty::Ty, } impl CoroutineClosureArgs { @@ -277,11 +277,11 @@ impl CoroutineClosureArgs { } #[inline] - pub fn tupled_upvars_ty(self) -> I::Ty { + pub fn tupled_upvars_ty(self) -> ty::Ty { self.split().tupled_upvars_ty } - pub fn kind_ty(self) -> I::Ty { + pub fn kind_ty(self) -> ty::Ty { self.split().closure_kind_ty } @@ -289,7 +289,7 @@ impl CoroutineClosureArgs { self.kind_ty().to_opt_closure_kind().unwrap() } - pub fn signature_parts_ty(self) -> I::Ty { + pub fn signature_parts_ty(self) -> ty::Ty { self.split().signature_parts_ty } @@ -314,7 +314,7 @@ impl CoroutineClosureArgs { }) } - pub fn coroutine_captures_by_ref_ty(self) -> I::Ty { + pub fn coroutine_captures_by_ref_ty(self) -> ty::Ty { self.split().coroutine_captures_by_ref_ty } @@ -358,10 +358,10 @@ impl TypeVisitor for HasRegionsBoundAt { #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] pub struct CoroutineClosureSignature { - pub tupled_inputs_ty: I::Ty, - pub resume_ty: I::Ty, - pub yield_ty: I::Ty, - pub return_ty: I::Ty, + pub tupled_inputs_ty: ty::Ty, + pub resume_ty: ty::Ty, + pub yield_ty: ty::Ty, + pub return_ty: ty::Ty, // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types // never actually differ. But we save them rather than recreating them @@ -393,10 +393,10 @@ impl CoroutineClosureSignature { self, cx: I, parent_args: I::GenericArgsSlice, - coroutine_kind_ty: I::Ty, + coroutine_kind_ty: ty::Ty, coroutine_def_id: I::CoroutineId, - tupled_upvars_ty: I::Ty, - ) -> I::Ty { + tupled_upvars_ty: ty::Ty, + ) -> ty::Ty { let coroutine_args = ty::CoroutineArgs::new( cx, ty::CoroutineArgsParts { @@ -424,9 +424,9 @@ impl CoroutineClosureSignature { coroutine_def_id: I::CoroutineId, goal_kind: ty::ClosureKind, env_region: I::Region, - closure_tupled_upvars_ty: I::Ty, - coroutine_captures_by_ref_ty: I::Ty, - ) -> I::Ty { + closure_tupled_upvars_ty: ty::Ty, + coroutine_captures_by_ref_ty: ty::Ty, + ) -> ty::Ty { let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( cx, goal_kind, @@ -457,11 +457,11 @@ impl CoroutineClosureSignature { pub fn tupled_upvars_by_closure_kind( cx: I, kind: ty::ClosureKind, - tupled_inputs_ty: I::Ty, - closure_tupled_upvars_ty: I::Ty, - coroutine_captures_by_ref_ty: I::Ty, + tupled_inputs_ty: ty::Ty, + closure_tupled_upvars_ty: ty::Ty, + coroutine_captures_by_ref_ty: ty::Ty, env_region: I::Region, - ) -> I::Ty { + ) -> ty::Ty { match kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { let ty::FnPtr(sig_tys, _) = coroutine_captures_by_ref_ty.kind() else { @@ -503,7 +503,7 @@ struct FoldEscapingRegions { // Depends on `debruijn` because we may have types with regions of different // debruijn depths depending on the binders we've entered. - cache: DelayedMap<(ty::DebruijnIndex, I::Ty), I::Ty>, + cache: DelayedMap<(ty::DebruijnIndex, ty::Ty), ty::Ty>, } impl TypeFolder for FoldEscapingRegions { @@ -511,7 +511,7 @@ impl TypeFolder for FoldEscapingRegions { self.interner } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn fold_ty(&mut self, t: ty::Ty) -> ty::Ty { if !t.has_vars_bound_at_or_above(self.debruijn) { t } else if let Some(&t) = self.cache.get(&(self.debruijn, t)) { @@ -553,9 +553,9 @@ impl TypeFolder for FoldEscapingRegions { #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] pub struct GenSig { - pub resume_ty: I::Ty, - pub yield_ty: I::Ty, - pub return_ty: I::Ty, + pub resume_ty: ty::Ty, + pub yield_ty: ty::Ty, + pub return_ty: ty::Ty, } impl Eq for GenSig {} @@ -581,15 +581,15 @@ pub struct CoroutineArgsParts { /// kind: `i8`/`i16`/`i32`. /// /// For regular coroutines, this field will always just be `()`. - pub kind_ty: I::Ty, + pub kind_ty: ty::Ty, - pub resume_ty: I::Ty, - pub yield_ty: I::Ty, - pub return_ty: I::Ty, + pub resume_ty: ty::Ty, + pub yield_ty: ty::Ty, + pub return_ty: ty::Ty, /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: I::Ty, + pub tupled_upvars_ty: ty::Ty, } impl CoroutineArgs { @@ -619,7 +619,7 @@ impl CoroutineArgs { } // Returns the kind of the coroutine. See docs on the `kind_ty` field. - pub fn kind_ty(self) -> I::Ty { + pub fn kind_ty(self) -> ty::Ty { self.split().kind_ty } @@ -638,22 +638,22 @@ impl CoroutineArgs { /// Returns the tuple type representing the upvars for this coroutine. #[inline] - pub fn tupled_upvars_ty(self) -> I::Ty { + pub fn tupled_upvars_ty(self) -> ty::Ty { self.split().tupled_upvars_ty } /// Returns the type representing the resume type of the coroutine. - pub fn resume_ty(self) -> I::Ty { + pub fn resume_ty(self) -> ty::Ty { self.split().resume_ty } /// Returns the type representing the yield type of the coroutine. - pub fn yield_ty(self) -> I::Ty { + pub fn yield_ty(self) -> ty::Ty { self.split().yield_ty } /// Returns the type representing the return type of the coroutine. - pub fn return_ty(self) -> I::Ty { + pub fn return_ty(self) -> ty::Ty { self.split().return_ty } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 6e62e1031a969..1ee4bff6b7a11 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -52,7 +52,7 @@ use smallvec::SmallVec; use thin_vec::ThinVec; use crate::inherent::*; -use crate::{self as ty, Interner, TypeFlags}; +use crate::{self as ty, Interner, Ty, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -98,7 +98,7 @@ pub trait TypeVisitor: Sized { t.super_visit_with(self) } - fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + fn visit_ty(&mut self, t: Ty) -> Self::Result { t.super_visit_with(self) } @@ -417,7 +417,7 @@ impl TypeVisitor for HasTypeFlagsVisitor { } #[inline] - fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + fn visit_ty(&mut self, t: Ty) -> Self::Result { // Note: no `super_visit_with` call. let flags = t.flags(); if flags.intersects(self.flags) { @@ -522,7 +522,7 @@ impl TypeVisitor for HasEscapingVarsVisitor { } #[inline] - fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + fn visit_ty(&mut self, t: Ty) -> Self::Result { // If the outer-exclusive-binder is *strictly greater* than // `outer_index`, that means that `t` contains some content // bound at `outer_index` or above (because From 02611d8d3fc12f5be01773ba793b0bcb275b1f08 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 21 Mar 2026 15:38:11 +0100 Subject: [PATCH 38/55] aarch64: add shims for pairwise widening/wrapping addition --- src/tools/miri/src/shims/aarch64.rs | 87 ++++++++++++++++++ .../shims/aarch64/intrinsics-aarch64-neon.rs | 92 +++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs index b96d1b1a38dd8..6a914d5cfa68a 100644 --- a/src/tools/miri/src/shims/aarch64.rs +++ b/src/tools/miri/src/shims/aarch64.rs @@ -59,6 +59,93 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_immediate(*res_lane, &dest)?; } } + + // Wrapping pairwise addition. + // + // Concatenates the two input vectors and adds adjacent elements. For input vectors `v` + // and `w` this computes `[v0 + v1, v2 + v3, ..., w0 + w1, w2 + w3, ...]`, using + // wrapping addition for `+`. + // + // Used by `vpadd_{s8, u8, s16, u16, s32, u32}`. + name if name.starts_with("neon.addp.") => { + let [left, right] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(left_len, dest_len); + + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout, dest.layout); + + assert!(dest_len.is_multiple_of(2)); + let half_len = dest_len.strict_div(2); + + for lane_idx in 0..dest_len { + // The left and right vectors are concatenated. + let (src, src_pair_idx) = if lane_idx < half_len { + (&left, lane_idx) + } else { + (&right, lane_idx.strict_sub(half_len)) + }; + // Convert "pair index" into "index of first element of the pair". + let i = src_pair_idx.strict_mul(2); + + let lhs = this.read_immediate(&this.project_index(src, i)?)?; + let rhs = this.read_immediate(&this.project_index(src, i.strict_add(1))?)?; + + // Wrapping addition on the element type. + let sum = this.binary_op(BinOp::Add, &lhs, &rhs)?; + + let dst_lane = this.project_index(&dest, lane_idx)?; + this.write_immediate(*sum, &dst_lane)?; + } + } + + // Widening pairwise addition. + // + // Takes a single input vector, and an output vector with half as many lanes and double + // the element width. Takes adjacent pairs of elements, widens both, and then adds them + // together. + // + // Used by `vpaddl_{u8, u16, u32}` and `vpaddlq_{u8, u16, u32}`. + name if name.starts_with("neon.uaddlp.") => { + let [src] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + let (src, src_len) = this.project_to_simd(src)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + // Operates pairwise, so src has twice as many lanes. + assert_eq!(src_len, dest_len.strict_mul(2)); + + let src_elem_size = src.layout.field(this, 0).size; + let dest_elem_size = dest.layout.field(this, 0).size; + + // Widens, so dest elements must be exactly twice as wide. + assert_eq!(dest_elem_size.bytes(), src_elem_size.bytes().strict_mul(2)); + + for dest_idx in 0..dest_len { + let src_idx = dest_idx.strict_mul(2); + + let a_scalar = this.read_scalar(&this.project_index(&src, src_idx)?)?; + let b_scalar = + this.read_scalar(&this.project_index(&src, src_idx.strict_add(1))?)?; + + let a_val = a_scalar.to_uint(src_elem_size)?; + let b_val = b_scalar.to_uint(src_elem_size)?; + + // Use addition on u128 to simulate widening addition for the destination type. + // This cannot wrap since the element type is at most u64. + let sum = a_val.strict_add(b_val); + + let dst_lane = this.project_index(&dest, dest_idx)?; + this.write_scalar(Scalar::from_uint(sum, dest_elem_size), &dst_lane)?; + } + } + // Vector table lookup: each index selects a byte from the 16-byte table, out-of-range -> 0. // Used to implement vtbl1_u8 function. // LLVM does not have a portable shuffle that takes non-const indices diff --git a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs index 6d3f153e194f3..884f8eff41bdb 100644 --- a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs +++ b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs @@ -12,6 +12,8 @@ fn main() { unsafe { test_vpmaxq_u8(); test_tbl1_v16i8_basic(); + test_vpadd(); + test_vpaddl(); } } @@ -65,3 +67,93 @@ fn test_tbl1_v16i8_basic() { assert_eq!(&got2_arr[3..16], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12][..]); } } +#[target_feature(enable = "neon")] +unsafe fn test_vpadd() { + let a = vld1_s8([1, 2, 3, 4, 5, 6, 7, 8].as_ptr()); + let b = vld1_s8([9, 10, -1, 2, i8::MIN, i8::MIN, i8::MAX, i8::MAX].as_ptr()); + let e = + [3i8, 7, 11, 15, 19, -1 + 2, i8::MIN.wrapping_add(i8::MIN), i8::MAX.wrapping_add(i8::MAX)]; + let mut r = [0i8; 8]; + vst1_s8(r.as_mut_ptr(), vpadd_s8(a, b)); + assert_eq!(r, e); + + let a = vld1_s16([1, 2, 3, 4].as_ptr()); + let b = vld1_s16([-1, 2, i16::MAX, i16::MAX].as_ptr()); + let e = [3i16, 7, -1 + 2, i16::MAX.wrapping_add(i16::MAX)]; + let mut r = [0i16; 4]; + vst1_s16(r.as_mut_ptr(), vpadd_s16(a, b)); + assert_eq!(r, e); + + let a = vld1_s32([1, 2].as_ptr()); + let b = vld1_s32([i32::MAX, i32::MAX].as_ptr()); + let e = [3i32, i32::MAX.wrapping_add(i32::MAX)]; + let mut r = [0i32; 2]; + vst1_s32(r.as_mut_ptr(), vpadd_s32(a, b)); + assert_eq!(r, e); + + let a = vld1_u8([1, 2, 3, 4, 5, 6, 7, 8].as_ptr()); + let b = vld1_u8([9, 10, 11, 12, 13, 14, u8::MAX, u8::MAX].as_ptr()); + let e = [3u8, 7, 11, 15, 19, 23, 27, 254]; + let mut r = [0u8; 8]; + vst1_u8(r.as_mut_ptr(), vpadd_u8(a, b)); + assert_eq!(r, e); + + let a = vld1_u16([1, 2, 3, 4].as_ptr()); + let b = vld1_u16([5, 6, u16::MAX, u16::MAX].as_ptr()); + let e = [3u16, 7, 11, 65534]; + let mut r = [0u16; 4]; + vst1_u16(r.as_mut_ptr(), vpadd_u16(a, b)); + assert_eq!(r, e); + + let a = vld1_u32([1, 2].as_ptr()); + let b = vld1_u32([u32::MAX, u32::MAX].as_ptr()); + let e = [3u32, u32::MAX.wrapping_add(u32::MAX)]; + let mut r = [0u32; 2]; + vst1_u32(r.as_mut_ptr(), vpadd_u32(a, b)); + assert_eq!(r, e); +} + +#[target_feature(enable = "neon")] +unsafe fn test_vpaddl() { + let a = vld1_u8([1, 2, 3, 4, 5, 6, u8::MAX, u8::MAX].as_ptr()); + let e = [3u16, 7, 11, 510]; + let mut r = [0u16; 4]; + vst1_u16(r.as_mut_ptr(), vpaddl_u8(a)); + assert_eq!(r, e); + + let a = vld1q_u8([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, u8::MAX, u8::MAX].as_ptr()); + let e = [3u16, 7, 11, 15, 19, 23, 27, 510]; + let mut r = [0u16; 8]; + vst1q_u16(r.as_mut_ptr(), vpaddlq_u8(a)); + assert_eq!(r, e); + + let a = vld1_u16([1, 2, u16::MAX, u16::MAX].as_ptr()); + let e = [3u32, 131070]; + let mut r = [0u32; 2]; + vst1_u32(r.as_mut_ptr(), vpaddl_u16(a)); + assert_eq!(r, e); + + let a = vld1q_u16([1, 2, 3, 4, 5, 6, u16::MAX, u16::MAX].as_ptr()); + let e = [3u32, 7, 11, 131070]; + let mut r = [0u32; 4]; + vst1q_u32(r.as_mut_ptr(), vpaddlq_u16(a)); + assert_eq!(r, e); + + let a = vld1_u32([1, 2].as_ptr()); + let e = [3u64]; + let mut r = [0u64; 1]; + vst1_u64(r.as_mut_ptr(), vpaddl_u32(a)); + assert_eq!(r, e); + + let a = vld1_u32([u32::MAX, u32::MAX].as_ptr()); + let e = [8589934590]; + let mut r = [0u64; 1]; + vst1_u64(r.as_mut_ptr(), vpaddl_u32(a)); + assert_eq!(r, e); + + let a = vld1q_u32([1, 2, u32::MAX, u32::MAX].as_ptr()); + let e = [3u64, 8589934590]; + let mut r = [0u64; 2]; + vst1q_u64(r.as_mut_ptr(), vpaddlq_u32(a)); + assert_eq!(r, e); +} From fe4e53ebf240e2a0d06a02813bb9ba379080a90c Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 29 Mar 2026 10:03:53 +0000 Subject: [PATCH 39/55] extract AttributeParseError rendering code into smaller subfunctions --- .../src/session_diagnostics.rs | 139 +++++++++++------- 1 file changed, 84 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index bab830098f1a8..c95245707ece6 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -594,19 +594,96 @@ pub(crate) struct AttributeParseError<'a> { pub(crate) suggestions: Vec, } +impl<'a> AttributeParseError<'a> { + fn render_expected_specific_argument( + &self, + diag: &mut Diag<'_, G>, + possibilities: &[Symbol], + strings: bool, + ) where + G: EmissionGuarantee, + { + let quote = if strings { '"' } else { '`' }; + match possibilities { + &[] => {} + &[x] => { + diag.span_label( + self.span, + format!("the only valid argument here is {quote}{x}{quote}"), + ); + } + [first, second] => { + diag.span_label( + self.span, + format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"), + ); + } + [first @ .., second_to_last, last] => { + let mut res = String::new(); + for i in first { + res.push_str(&format!("{quote}{i}{quote}, ")); + } + res.push_str(&format!("{quote}{second_to_last}{quote} or {quote}{last}{quote}")); + + diag.span_label(self.span, format!("valid arguments are {res}")); + } + } + } + + fn render_expected_specific_argument_list( + &self, + diag: &mut Diag<'_, G>, + possibilities: &[Symbol], + strings: bool, + ) where + G: EmissionGuarantee, + { + let description = self.description(); + + let quote = if strings { '"' } else { '`' }; + match possibilities { + &[] => {} + &[x] => { + diag.span_label( + self.span, + format!( + "this {description} is only valid with {quote}{x}{quote} as an argument" + ), + ); + } + [first, second] => { + diag.span_label(self.span, format!("this {description} is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument")); + } + [first @ .., second_to_last, last] => { + let mut res = String::new(); + for i in first { + res.push_str(&format!("{quote}{i}{quote}, ")); + } + res.push_str(&format!("{quote}{second_to_last}{quote} or {quote}{last}{quote}")); + + diag.span_label(self.span, format!("this {description} is only valid with one of the following arguments: {res}")); + } + } + } + + fn description(&self) -> &'static str { + match self.description { + ParsedDescription::Attribute => "attribute", + ParsedDescription::Macro => "macro", + } + } +} + impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let name = self.path.to_string(); - let description = match self.description { - ParsedDescription::Attribute => "attribute", - ParsedDescription::Macro => "macro", - }; + let description = self.description(); let mut diag = Diag::new(dcx, level, format!("malformed `{name}` {description} input")); diag.span(self.attr_span); diag.code(E0539); - match self.reason { + match &self.reason { AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => { if let Some(start_point_span) = byte_string { diag.span_suggestion( @@ -693,62 +770,14 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { strings, list: false, } => { - let quote = if strings { '"' } else { '`' }; - match possibilities { - &[] => {} - &[x] => { - diag.span_label( - self.span, - format!("the only valid argument here is {quote}{x}{quote}"), - ); - } - [first, second] => { - diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}")); - } - [first @ .., second_to_last, last] => { - let mut res = String::new(); - for i in first { - res.push_str(&format!("{quote}{i}{quote}, ")); - } - res.push_str(&format!( - "{quote}{second_to_last}{quote} or {quote}{last}{quote}" - )); - - diag.span_label(self.span, format!("valid arguments are {res}")); - } - } + self.render_expected_specific_argument(&mut diag, *possibilities, *strings); } AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings, list: true, } => { - let quote = if strings { '"' } else { '`' }; - match possibilities { - &[] => {} - &[x] => { - diag.span_label( - self.span, - format!( - "this {description} is only valid with {quote}{x}{quote} as an argument" - ), - ); - } - [first, second] => { - diag.span_label(self.span, format!("this {description} is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument")); - } - [first @ .., second_to_last, last] => { - let mut res = String::new(); - for i in first { - res.push_str(&format!("{quote}{i}{quote}, ")); - } - res.push_str(&format!( - "{quote}{second_to_last}{quote} or {quote}{last}{quote}" - )); - - diag.span_label(self.span, format!("this {description} is only valid with one of the following arguments: {res}")); - } - } + self.render_expected_specific_argument_list(&mut diag, *possibilities, *strings); } AttributeParseErrorReason::ExpectedIdentifier => { diag.span_label(self.span, "expected a valid identifier here"); From 79d00dbf251cc14886b9b71b902659d5cf65f80d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2026 14:48:37 +0200 Subject: [PATCH 40/55] update lockfile --- Cargo.lock | 53 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4c1a02c018af..8b3792cef61bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3421,14 +3421,14 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7" +checksum = "eec3905e8201688412f6f4b1f6c86d38b3ee6578f59ba85f41330a3af61e8365" dependencies = [ "anyhow", "rustc_version", "tempfile", - "toml 0.8.23", + "toml 1.1.0+spec-1.1.0", "walkdir", ] @@ -5195,9 +5195,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" dependencies = [ "serde_core", ] @@ -5693,7 +5693,6 @@ version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ - "indexmap", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -5708,13 +5707,28 @@ checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap", "serde_core", - "serde_spanned 1.0.3", + "serde_spanned 1.1.0", "toml_datetime 0.7.3", "toml_parser", "toml_writer", "winnow 0.7.13", ] +[[package]] +name = "toml" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.0", + "toml_datetime 1.1.0+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.0", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -5733,6 +5747,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -5762,11 +5785,11 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "winnow 0.7.13", + "winnow 1.0.0", ] [[package]] @@ -5777,9 +5800,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.4" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "tracing" @@ -6765,6 +6788,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" + [[package]] name = "winsplit" version = "0.1.0" From d29c4895994dae92c6e8e47aec08fd4c81fb5d54 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 9 Mar 2026 01:41:56 +0900 Subject: [PATCH 41/55] add self-referential param-env normalization regression avoid ICE on invalid param-env normalization remove 120033 crash test fix comments use rustc_no_implicit_bounds set #![allow(incomplete_features)] --- .../rustc_trait_selection/src/traits/mod.rs | 19 +++----- tests/crashes/120033.rs | 16 ------- ...zed-param-env-unconstrained-type-120033.rs | 22 ++++++++++ ...param-env-unconstrained-type-120033.stderr | 43 +++++++++++++++++++ ...elf-referential-param-env-normalization.rs | 18 ++++++++ ...referential-param-env-normalization.stderr | 42 ++++++++++++++++++ 6 files changed, 132 insertions(+), 28 deletions(-) delete mode 100644 tests/crashes/120033.rs create mode 100644 tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs create mode 100644 tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr create mode 100644 tests/ui/traits/self-referential-param-env-normalization.rs create mode 100644 tests/ui/traits/self-referential-param-env-normalization.stderr diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 1fde7e5d43b76..bdad1b259b733 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -300,19 +300,14 @@ fn do_normalize_predicates<'tcx>( Ok(predicates) => Ok(predicates), Err(fixup_err) => { // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable. - // - // @lcnr: Let's still ICE here for now. I want a test case - // for that. - span_bug!( + // variable wound up unconstrained. That can happen for + // ill-formed impls, so we delay a bug here instead of + // immediately ICEing and let type checking report the + // actual user-facing errors. + Err(tcx.dcx().span_delayed_bug( span, - "inference variables in normalized parameter environment: {}", - fixup_err - ); + format!("inference variables in normalized parameter environment: {fixup_err}"), + )) } } } diff --git a/tests/crashes/120033.rs b/tests/crashes/120033.rs deleted file mode 100644 index 7584f98ec9060..0000000000000 --- a/tests/crashes/120033.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #120033 -#![feature(non_lifetime_binders)] -#![allow(sized_hierarchy_migration)] -#![feature(sized_hierarchy)] // added to keep parameters unconstrained - -pub trait Foo { - type Bar; -} - -pub struct Bar {} - -pub fn f() -where - T1: for Foo>, - T2: for Foo = T1::Bar>, -{} diff --git a/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs new file mode 100644 index 0000000000000..52f83966c6bd1 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs @@ -0,0 +1,22 @@ +//@ compile-flags: --crate-type=lib + +// Regression test for + +#![feature(rustc_attrs)] +#![feature(non_lifetime_binders)] +#![allow(incomplete_features)] +#![rustc_no_implicit_bounds] + +pub trait Foo { + type Bar; +} + +pub struct Bar {} //~ ERROR cannot find trait `AutoTrait` + +pub fn f() +where + T1: for Foo>, //~ ERROR missing generics for associated type `Foo::Bar` + //~| ERROR missing generics for associated type `Foo::Bar` + T2: for Foo = T1::Bar>, +{ +} diff --git a/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr new file mode 100644 index 0000000000000..c95e6c68fc6a1 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr @@ -0,0 +1,43 @@ +error[E0405]: cannot find trait `AutoTrait` in this scope + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:14:20 + | +LL | pub struct Bar {} + | ^^^^^^^^^ not found in this scope + +error[E0107]: missing generics for associated type `Foo::Bar` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:18:27 + | +LL | T1: for Foo>, + | ^^^ expected 1 generic argument + | +note: associated type defined here, with 1 generic parameter: `K` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:11:10 + | +LL | type Bar; + | ^^^ - +help: add missing generic argument + | +LL | T1: for Foo = Bar>, + | +++ + +error[E0107]: missing generics for associated type `Foo::Bar` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:18:27 + | +LL | T1: for Foo>, + | ^^^ expected 1 generic argument + | +note: associated type defined here, with 1 generic parameter: `K` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:11:10 + | +LL | type Bar; + | ^^^ - + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing generic argument + | +LL | T1: for Foo = Bar>, + | +++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0405. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/self-referential-param-env-normalization.rs b/tests/ui/traits/self-referential-param-env-normalization.rs new file mode 100644 index 0000000000000..a40c8cc26bd94 --- /dev/null +++ b/tests/ui/traits/self-referential-param-env-normalization.rs @@ -0,0 +1,18 @@ +//~ ERROR overflow evaluating the requirement `Self: StreamingIterator<'_>` [E0275] +// Regression test for . + +trait StreamingIterator<'a> { + type Item: 'a; +} + +impl<'b, I, T> StreamingIterator<'b> for I +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates [E0207] +where + I: IntoIterator, + T: FnMut(Self::Item, I::Item), +{ + type Item = T; + //~^ ERROR overflow evaluating the requirement `I: IntoIterator` [E0275] +} + +fn main() {} diff --git a/tests/ui/traits/self-referential-param-env-normalization.stderr b/tests/ui/traits/self-referential-param-env-normalization.stderr new file mode 100644 index 0000000000000..5e9c2c92eaac6 --- /dev/null +++ b/tests/ui/traits/self-referential-param-env-normalization.stderr @@ -0,0 +1,42 @@ +error[E0275]: overflow evaluating the requirement `Self: StreamingIterator<'_>` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`self_referential_param_env_normalization`) +note: required for `Self` to implement `StreamingIterator<'_>` + --> $DIR/self-referential-param-env-normalization.rs:8:16 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T: FnMut(Self::Item, I::Item), + | -------------------------- unsatisfied trait bound introduced here + = note: 127 redundant requirements hidden + = note: required for `Self` to implement `StreamingIterator<'a>` + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/self-referential-param-env-normalization.rs:8:13 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^ unconstrained type parameter + +error[E0275]: overflow evaluating the requirement `I: IntoIterator` + --> $DIR/self-referential-param-env-normalization.rs:14:17 + | +LL | type Item = T; + | ^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`self_referential_param_env_normalization`) +note: required for `I` to implement `StreamingIterator<'_>` + --> $DIR/self-referential-param-env-normalization.rs:8:16 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T: FnMut(Self::Item, I::Item), + | -------------------------- unsatisfied trait bound introduced here + = note: 127 redundant requirements hidden + = note: required for `I` to implement `StreamingIterator<'b>` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0275. +For more information about an error, try `rustc --explain E0207`. From 6518de37d450f35e18fc49502ea6183fda065714 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 30 Mar 2026 21:55:05 +0800 Subject: [PATCH 42/55] Skip suggestions pointing to extern macro def for assert_eq --- .../src/error_reporting/traits/suggestions.rs | 34 +++++++++--- .../assert-ne-no-invalid-help-issue-146204.rs | 23 ++++++++ ...ert-ne-no-invalid-help-issue-146204.stderr | 55 +++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs create mode 100644 tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr 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 a16bbf20238c0..151008790daf0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -545,8 +545,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .all(|obligation| self.predicate_may_hold(obligation)) }) && steps > 0 { + if span.in_external_macro(self.tcx.sess.source_map()) { + return false; + } let derefs = "*".repeat(steps); let msg = "consider dereferencing here"; + let call_node = self.tcx.hir_node(*call_hir_id); let is_receiver = matches!( call_node, @@ -593,7 +597,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) { // Suggest dereferencing the LHS, RHS, or both terms of a binop if possible - let trait_pred = predicate.unwrap_or(trait_pred); let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); let lhs_autoderef = (self.autoderef_steps)(lhs_ty); @@ -644,6 +647,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) { let make_sugg = |mut expr: &Expr<'_>, mut steps| { + if expr.span.in_external_macro(self.tcx.sess.source_map()) { + return None; + } let mut prefix_span = expr.span.shrink_to_lo(); let mut msg = "consider dereferencing here"; if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind { @@ -661,10 +667,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Empty suggestions with empty spans ICE with debug assertions if steps == 0 { - return ( + return Some(( msg.trim_end_matches(" and dereferencing instead"), vec![(prefix_span, String::new())], - ); + )); } let derefs = "*".repeat(steps); let needs_parens = steps > 0 && expr_needs_parens(expr); @@ -686,7 +692,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if !prefix_span.is_empty() { suggestion.push((prefix_span, String::new())); } - (msg, suggestion) + Some((msg, suggestion)) }; if let Some(lsteps) = lsteps @@ -694,8 +700,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && lsteps > 0 && rsteps > 0 { - let mut suggestion = make_sugg(lhs, lsteps).1; - suggestion.append(&mut make_sugg(rhs, rsteps).1); + let Some((_, mut suggestion)) = make_sugg(lhs, lsteps) else { + return false; + }; + let Some((_, mut rhs_suggestion)) = make_sugg(rhs, rsteps) else { + return false; + }; + suggestion.append(&mut rhs_suggestion); err.multipart_suggestion( "consider dereferencing both sides of the expression", suggestion, @@ -705,13 +716,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else if let Some(lsteps) = lsteps && lsteps > 0 { - let (msg, suggestion) = make_sugg(lhs, lsteps); + let Some((msg, suggestion)) = make_sugg(lhs, lsteps) else { + return false; + }; err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); return true; } else if let Some(rsteps) = rsteps && rsteps > 0 { - let (msg, suggestion) = make_sugg(rhs, rsteps); + let Some((msg, suggestion)) = make_sugg(rhs, rsteps) else { + return false; + }; err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); return true; } @@ -4815,6 +4830,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { + if span.in_external_macro(self.tcx.sess.source_map()) { + return; + } // We can only suggest the slice coercion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs new file mode 100644 index 0000000000000..5a6ef0421e2fa --- /dev/null +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs @@ -0,0 +1,23 @@ +macro_rules! local_assert_ne { + ($left:expr, $right:expr $(,)?) => { + match (&$left, &$right) { + (left_val, right_val) => { + if *left_val == *right_val { + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + panic!(); + } + } + } + }; +} + +fn main() { + let buf = [0_u8; 4]; + assert_ne!(buf, b"----"); + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + + assert_eq!(buf, b"----"); + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + + local_assert_ne!(buf, b"----"); +} diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr new file mode 100644 index 0000000000000..359deee7bee4b --- /dev/null +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr @@ -0,0 +1,55 @@ +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:16:5 + | +LL | assert_ne!(buf, b"----"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `[u8; 4] == &[u8; 4]` + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq` + `&[u8; N]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + and 11 others + +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:19:5 + | +LL | assert_eq!(buf, b"----"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `[u8; 4] == &[u8; 4]` + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq` + `&[u8; N]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + and 11 others + +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:5:30 + | +LL | if *left_val == *right_val { + | ^^ no implementation for `[u8; 4] == &[u8; 4]` +... +LL | local_assert_ne!(buf, b"----"); + | ------------------------------ in this macro invocation + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = note: this error originates in the macro `local_assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider dereferencing here + | +LL | if *left_val == **right_val { + | + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. From bb40df6e560bb892aa7768faadf53946438017dd Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 29 Mar 2026 10:03:53 +0000 Subject: [PATCH 43/55] document why it is important to early return on ExpectedStringLiteral --- compiler/rustc_attr_parsing/src/session_diagnostics.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index c95245707ece6..7321260972157 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -687,13 +687,15 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => { if let Some(start_point_span) = byte_string { diag.span_suggestion( - start_point_span, + *start_point_span, "consider removing the prefix", "", Applicability::MaybeIncorrect, ); diag.note("expected a normal string literal, not a byte string literal"); + // Avoid emitting an "attribute must be of the form" suggestion, as the + // attribute is likely to be well-formed already. return diag; } else { diag.span_label(self.span, "expected a string literal here"); From 61ea83db4197587424b7a2c5c3c0a792b9e36188 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 30 Mar 2026 20:39:42 +0000 Subject: [PATCH 44/55] delete some duplicated tests --- tests/ui/associated-types/issue-47814.rs | 13 ------------- tests/ui/associated-types/issue-47814.stderr | 14 -------------- tests/ui/fn/issue-1900.rs | 2 -- tests/ui/fn/issue-1900.stderr | 9 --------- .../specialization-feature-gate-default.rs | 11 ----------- .../specialization-feature-gate-default.stderr | 15 --------------- 6 files changed, 64 deletions(-) delete mode 100644 tests/ui/associated-types/issue-47814.rs delete mode 100644 tests/ui/associated-types/issue-47814.stderr delete mode 100644 tests/ui/fn/issue-1900.rs delete mode 100644 tests/ui/fn/issue-1900.stderr delete mode 100644 tests/ui/specialization/defaultimpl/specialization-feature-gate-default.rs delete mode 100644 tests/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr diff --git a/tests/ui/associated-types/issue-47814.rs b/tests/ui/associated-types/issue-47814.rs deleted file mode 100644 index 90e8a3bc2f2f4..0000000000000 --- a/tests/ui/associated-types/issue-47814.rs +++ /dev/null @@ -1,13 +0,0 @@ -struct ArpIPv4<'a> { - s: &'a u8 -} - -impl<'a> ArpIPv4<'a> { - const LENGTH: usize = 20; - - pub fn to_buffer() -> [u8; Self::LENGTH] { //~ ERROR generic `Self` types are currently not permitted in anonymous constants - unimplemented!() - } -} - -pub fn main() {} diff --git a/tests/ui/associated-types/issue-47814.stderr b/tests/ui/associated-types/issue-47814.stderr deleted file mode 100644 index 7382426b0ffaa..0000000000000 --- a/tests/ui/associated-types/issue-47814.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: generic `Self` types are currently not permitted in anonymous constants - --> $DIR/issue-47814.rs:8:32 - | -LL | pub fn to_buffer() -> [u8; Self::LENGTH] { - | ^^^^ - | -note: not a concrete type - --> $DIR/issue-47814.rs:5:10 - | -LL | impl<'a> ArpIPv4<'a> { - | ^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/fn/issue-1900.rs b/tests/ui/fn/issue-1900.rs deleted file mode 100644 index 761bd3170270c..0000000000000 --- a/tests/ui/fn/issue-1900.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { } -//~^ ERROR `main` function is not allowed to have generic parameters diff --git a/tests/ui/fn/issue-1900.stderr b/tests/ui/fn/issue-1900.stderr deleted file mode 100644 index 31fd46c8e2a53..0000000000000 --- a/tests/ui/fn/issue-1900.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0131]: `main` function is not allowed to have generic parameters - --> $DIR/issue-1900.rs:1:8 - | -LL | fn main() { } - | ^^^ `main` cannot have generic parameters - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0131`. diff --git a/tests/ui/specialization/defaultimpl/specialization-feature-gate-default.rs b/tests/ui/specialization/defaultimpl/specialization-feature-gate-default.rs deleted file mode 100644 index 89158b65a6e29..0000000000000 --- a/tests/ui/specialization/defaultimpl/specialization-feature-gate-default.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Check that specialization must be ungated to use the `default` keyword - -trait Foo { - fn foo(&self); -} - -default impl Foo for T { //~ ERROR specialization is unstable - fn foo(&self) {} -} - -fn main() {} diff --git a/tests/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr b/tests/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr deleted file mode 100644 index e28d9c9fa836f..0000000000000 --- a/tests/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: specialization is unstable - --> $DIR/specialization-feature-gate-default.rs:7:1 - | -LL | / default impl Foo for T { -LL | | fn foo(&self) {} -LL | | } - | |_^ - | - = note: see issue #31844 for more information - = help: add `#![feature(specialization)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. From d24ebcb47c36519b259a706e0cf3d80bcd293aea Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 30 Mar 2026 20:40:15 +0000 Subject: [PATCH 45/55] rename some `issues-*` tests --- src/tools/tidy/src/issues.txt | 3 --- .../{issue-78720.rs => nested-copy-drops-83176.rs} | 1 + .../{issue-78720.stderr => nested-copy-drops-83176.stderr} | 2 +- tests/ui/impl-trait/rpit/unit-impl-default-36379.rs | 6 ++++++ tests/ui/issues/issue-36379.rs | 5 ----- 5 files changed, 8 insertions(+), 9 deletions(-) rename tests/ui/closures/2229_closure_analysis/migrations/{issue-78720.rs => nested-copy-drops-83176.rs} (77%) rename tests/ui/closures/2229_closure_analysis/migrations/{issue-78720.stderr => nested-copy-drops-83176.stderr} (88%) create mode 100644 tests/ui/impl-trait/rpit/unit-impl-default-36379.rs delete mode 100644 tests/ui/issues/issue-36379.rs diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index f382502c7068b..3b23fe5d80826 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -117,7 +117,6 @@ ui/associated-types/issue-44153.rs ui/associated-types/issue-47139-1.rs ui/associated-types/issue-47139-2.rs ui/associated-types/issue-47385.rs -ui/associated-types/issue-47814.rs ui/associated-types/issue-48010.rs ui/associated-types/issue-48551.rs ui/associated-types/issue-50301.rs @@ -406,7 +405,6 @@ ui/closures/2229_closure_analysis/match/issue-87097.rs ui/closures/2229_closure_analysis/match/issue-87426.rs ui/closures/2229_closure_analysis/match/issue-87988.rs ui/closures/2229_closure_analysis/match/issue-88331.rs -ui/closures/2229_closure_analysis/migrations/issue-78720.rs ui/closures/2229_closure_analysis/migrations/issue-86753.rs ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs ui/closures/2229_closure_analysis/run_pass/issue-87378.rs @@ -1001,7 +999,6 @@ ui/fmt/issue-86085.rs ui/fmt/issue-89173.rs ui/fmt/issue-91556.rs ui/fn/issue-1451.rs -ui/fn/issue-1900.rs ui/fn/issue-3044.rs ui/fn/issue-3099.rs ui/fn/issue-3904.rs diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs b/tests/ui/closures/2229_closure_analysis/migrations/nested-copy-drops-83176.rs similarity index 77% rename from tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs rename to tests/ui/closures/2229_closure_analysis/migrations/nested-copy-drops-83176.rs index 3e72eec4ea8c6..2df8931f7ef7a 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs +++ b/tests/ui/closures/2229_closure_analysis/migrations/nested-copy-drops-83176.rs @@ -1,3 +1,4 @@ +// Regression test for https://github.com/rust-lang/rust/issues/83176. //@ run-pass #![warn(rust_2021_incompatible_closure_captures)] diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr b/tests/ui/closures/2229_closure_analysis/migrations/nested-copy-drops-83176.stderr similarity index 88% rename from tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr rename to tests/ui/closures/2229_closure_analysis/migrations/nested-copy-drops-83176.stderr index 2609e2951ec54..595173b49da68 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr +++ b/tests/ui/closures/2229_closure_analysis/migrations/nested-copy-drops-83176.stderr @@ -1,5 +1,5 @@ warning: irrefutable `if let` pattern - --> $DIR/issue-78720.rs:7:8 + --> $DIR/nested-copy-drops-83176.rs:8:8 | LL | if let a = "" { | ^^^^^^^^^^ diff --git a/tests/ui/impl-trait/rpit/unit-impl-default-36379.rs b/tests/ui/impl-trait/rpit/unit-impl-default-36379.rs new file mode 100644 index 0000000000000..43c93065739d3 --- /dev/null +++ b/tests/ui/impl-trait/rpit/unit-impl-default-36379.rs @@ -0,0 +1,6 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/36379 +//@ check-pass + +fn _test() -> impl Default { } + +fn main() {} diff --git a/tests/ui/issues/issue-36379.rs b/tests/ui/issues/issue-36379.rs deleted file mode 100644 index 6e275b03a7029..0000000000000 --- a/tests/ui/issues/issue-36379.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ check-pass - -fn _test() -> impl Default { } - -fn main() {} From 6cd26567db61c85479cdf6192a18f6d6bce43ca8 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 30 Mar 2026 20:40:27 +0000 Subject: [PATCH 46/55] add more FIXMEs and details to `ui/README.md` --- tests/ui/README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/ui/README.md b/tests/ui/README.md index eb14039d8151a..a9e7f022c2b60 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -36,6 +36,8 @@ These tests exercise the [`annotate-snippets`]-based emitter implementation. [`annotate-snippets`]: https://github.com/rust-lang/annotate-snippets-rs +**FIXME**: merge this with `error-emitter` + ## `tests/ui/anon-params` These tests deal with anonymous parameters (no name, only type), a deprecated feature that becomes a hard error in Edition 2018. @@ -141,6 +143,8 @@ However, only a single test was ever added to this category: . @@ -730,6 +734,8 @@ Tests on type inference. Tests for diagnostics on infinitely recursive types without indirection. +**FIXME**: check for overlap with `structs-enums/enum-rec` and `structs-enums/struct-rec` + ## `tests/ui/inline-const/` These tests revolve around the inline `const` block that forces the compiler to const-eval its content. @@ -853,7 +859,9 @@ Tests exercising analysis for unused variables, unreachable statements, function ## `tests/ui/loop-match` -Tests for `loop` with `match` expressions. +Tests for the `loop_match` feature to optimize `loop`s consisting of one big `match` expressions. + +See [Tracking issue for way to express intraprocedural finite state machines #132306](https://github.com/rust-lang/rust/issues/132306). ## `tests/ui/loops/` @@ -891,6 +899,8 @@ See [Tracking issue for allowing overlapping implementations for marker trait #2 Broad category of tests on `match` constructs. +**FIXME**: many tests overlap with `tests/ui/bindings`, try to reduce duplication. + ## `tests/ui/methods/` A broad category for anything related to methods and method resolution. @@ -899,6 +909,8 @@ A broad category for anything related to methods and method resolution. Certain mir-opt regression tests. +**FIXME**: many tests in this directory are not about MIR or optimizations, relocate these. + ## `tests/ui/mir-dataflow` Tests for MIR dataflow analysis. @@ -977,6 +989,8 @@ Tests that exercises edge cases, such as specific floats, large or very small nu Tests that checks numeric types and their interactions, such as casting among them with `as` or providing the wrong numeric suffix. +**FIXME**: these tests could get moved to other directories, in particular `cast/` or `parser/`. + ## `tests/ui/object-lifetime/` Tests on lifetimes on objects, such as a lifetime bound not being able to be deduced from context, or checking that lifetimes are inherited properly. @@ -1308,7 +1322,7 @@ Some standard library tests which are too inconvenient or annoying to implement ## `tests/ui/str/` -Exercise `str` keyword and string slices. +Exercise `str` primitive and string slices. ## `tests/ui/structs/` @@ -1464,6 +1478,8 @@ See [RFC 0132 Unified Function Call Syntax](https://github.com/rust-lang/rfcs/bl `#![feature(unboxed_closures)]`, `Fn`, `FnMut` and `FnOnce` traits +**FIXME**: many tests have `unboxed-closure` in their name but only test normal closures, rename these. + See [Tracking issue for Fn traits (`unboxed_closures` & `fn_traits` feature)](https://github.com/rust-lang/rust/issues/29625). ## `tests/ui/underscore-lifetime/`: `'_` elided lifetime From 59fe28d0ff4e6fa757d2ad31149252ddaff0d1df Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 18 Jun 2025 06:25:32 +0000 Subject: [PATCH 47/55] compiler-builtins: Clean up features Remove the `compiler-builtins` feature from default because it prevents testing via the default `cargo test` command. It made more sense as a default when `compiler-builtins` was a dependency that some crates added via crates.io, but is no longer needed. The `rustc-dep-of-std` feature is also removed since it doesn't do anything beyond what the `compiler-builtins` feature already does. --- library/alloc/Cargo.toml | 2 +- library/compiler-builtins/builtins-shim/Cargo.toml | 8 +++----- library/compiler-builtins/compiler-builtins/Cargo.toml | 10 ++++------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 541257b6cda6e..b32e5e991cc74 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["rustc-dep-of-std"] } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml index 37d3407e9f668..32b0308a7b3c9 100644 --- a/library/compiler-builtins/builtins-shim/Cargo.toml +++ b/library/compiler-builtins/builtins-shim/Cargo.toml @@ -39,7 +39,7 @@ test = false cc = { version = "1.2", optional = true } [features] -default = ["compiler-builtins"] +default = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics @@ -50,7 +50,8 @@ c = ["dep:cc"] # the generic versions on all platforms. no-asm = [] -# Flag this library as the unstable compiler-builtins lib +# Flag this library as the unstable compiler-builtins lib. This must be enabled +# when using as `std`'s dependency.' compiler-builtins = [] # Generate memory-related intrinsics like memcpy @@ -60,9 +61,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Only used in the compiler's build system -rustc-dep-of-std = ["compiler-builtins"] - # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index a8b8920421b3e..d9acb8341d483 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ core = { path = "../../core", optional = true } cc = { version = "1.2", optional = true } [features] -default = ["compiler-builtins"] +default = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics @@ -45,8 +45,9 @@ c = ["dep:cc"] # the generic versions on all platforms. no-asm = [] -# Flag this library as the unstable compiler-builtins lib -compiler-builtins = [] +# Flag this library as the unstable compiler-builtins lib. This must be enabled +# when using as `std`'s dependency.' +compiler-builtins = ["dep:core"] # Generate memory-related intrinsics like memcpy mem = [] @@ -55,9 +56,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Only used in the compiler's build system -rustc-dep-of-std = ["compiler-builtins", "dep:core"] - # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] From 2d87df126960770259499fffc0afcbc262c06944 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Tue, 31 Mar 2026 00:08:31 +0100 Subject: [PATCH 48/55] Add a test for a now fixed ICE with `offset_of!()` --- ...f-unsized-trait-object-missing-lifetime.rs | 20 ++++++++++++++ ...sized-trait-object-missing-lifetime.stderr | 27 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.rs create mode 100644 tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.stderr diff --git a/tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.rs b/tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.rs new file mode 100644 index 0000000000000..b28e093662350 --- /dev/null +++ b/tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.rs @@ -0,0 +1,20 @@ +//@ edition:2021 +// Regression test for #125805. +// ICE when using `offset_of!` on a field whose type is a bare trait object +// with a missing lifetime parameter. + +trait X<'a> {} + +use std::mem::offset_of; + +struct T { + y: X, + //~^ ERROR missing lifetime specifier [E0106] + //~| ERROR expected a type, found a trait [E0782] +} + +fn other() { + offset_of!(T, y); +} + +fn main() {} diff --git a/tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.stderr b/tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.stderr new file mode 100644 index 0000000000000..7f4a370d86d80 --- /dev/null +++ b/tests/ui/offset-of/offset-of-unsized-trait-object-missing-lifetime.stderr @@ -0,0 +1,27 @@ +error[E0106]: missing lifetime specifier + --> $DIR/offset-of-unsized-trait-object-missing-lifetime.rs:11:8 + | +LL | y: X, + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL ~ struct T<'a> { +LL ~ y: X<'a>, + | + +error[E0782]: expected a type, found a trait + --> $DIR/offset-of-unsized-trait-object-missing-lifetime.rs:11:8 + | +LL | y: X, + | ^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | y: dyn X, + | +++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0106, E0782. +For more information about an error, try `rustc --explain E0106`. From 4ca5c07a1b117fbd183b439a658f26b00bec760b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 30 Mar 2026 18:14:29 -0700 Subject: [PATCH 49/55] build-manifest: Use zlib-rs --- src/tools/build-manifest/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 2b0afae76da42..0b766a3e557c5 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -8,7 +8,7 @@ toml = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" anyhow = "1.0.32" -flate2 = "1.0.26" +flate2 = { version = "1.1.9", default-features = false, features = ["zlib-rs"] } xz2 = "0.1.7" tar = "0.4.45" sha2 = "0.10.1" From 3d1fb4c1b337f0edf7199974a0f91182c422d19d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 30 Mar 2026 18:14:57 -0700 Subject: [PATCH 50/55] rust-installer: Use zlib-rs --- src/tools/rust-installer/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml index e0c93e3c4477b..0cb9fa76b2f9e 100644 --- a/src/tools/rust-installer/Cargo.toml +++ b/src/tools/rust-installer/Cargo.toml @@ -11,7 +11,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0.19" -flate2 = "1.0.1" +flate2 = { version = "1.1.9", default-features = false, features = ["zlib-rs"] } rayon = "1.0" tar = "0.4.45" walkdir = "2" From 1a67e2be36e50967ea962d90364b6b150055a966 Mon Sep 17 00:00:00 2001 From: Crystal Durham Date: Mon, 30 Mar 2026 21:33:53 -0400 Subject: [PATCH 51/55] Fix AtomicPtr::update's cfg gate --- library/core/src/sync/atomic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0077b5b9d31b7..004772267da74 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2136,7 +2136,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "atomic_try_update", since = "1.95.0")] - #[cfg(target_has_atomic = "8")] + #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_should_not_be_called_on_const_items] pub fn update( From 722b2d36269b9dea4893a6ecd55cde31b2df9991 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 30 Mar 2026 18:43:16 -0700 Subject: [PATCH 52/55] Cargo.lock: Update for zlib-rs --- Cargo.lock | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4c1a02c018af..c1c592da7767f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1422,12 +1422,13 @@ checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -6944,3 +6945,9 @@ dependencies = [ "quote", "syn 2.0.110", ] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" From 3fd1107165b62823e210ec6f1060d9e463b28c22 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 30 Mar 2026 18:57:49 -0700 Subject: [PATCH 53/55] tidy: Allow zlib-rs as a Rust dependency --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index c6624b1b3697d..b0730de771395 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -504,6 +504,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "zerotrie", "zerovec", "zerovec-derive", + "zlib-rs", // tidy-alphabetical-end ]; From dd1d5b7f505f0de3585b8d8cab5959fadaa1fcb1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 30 Mar 2026 19:44:35 -0700 Subject: [PATCH 54/55] citool: use zlib-rs --- src/ci/citool/Cargo.lock | 19 +++++++++++++++++-- src/ci/citool/Cargo.toml | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index fe1c92f049e0b..a208de47256ca 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -170,6 +170,7 @@ dependencies = [ "clap", "csv", "diff", + "flate2", "glob-match", "insta", "serde", @@ -344,12 +345,13 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -630,6 +632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -812,6 +815,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "similar" version = "2.7.0" @@ -1187,3 +1196,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index 0b1f2fe79bf75..f97d5e807fcc8 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -9,6 +9,7 @@ askama = "0.15.4" clap = { version = "4.5", features = ["derive"] } csv = "1" diff = "0.1" +flate2 = { version = "1.1.9", default-features = false, features = ["zlib-rs"] } # For feature flag only glob-match = "0.2" serde = { version = "1", features = ["derive"] } serde_yaml = "0.9" From 620e92f0166738113eac8ec774253501324a6e75 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Tue, 3 Mar 2026 18:49:37 -0700 Subject: [PATCH 55/55] stabilize new Range type and iterator stabilizes `core::range::Range` stabilizes `core::range::RangeIter` stabilizes `std::range` which was missed in prior PRs Updates docs to reflect stabilization (removed "experimental") `RangeIter::remainder` is excluded from stabilization --- compiler/rustc_index/src/lib.rs | 6 +- library/core/src/range.rs | 56 ++++++++----------- library/core/src/range/iter.rs | 13 ++--- library/core/src/slice/index.rs | 4 +- library/core/src/str/traits.rs | 2 +- library/coretests/tests/lib.rs | 1 - library/std/src/lib.rs | 2 +- .../feature-gates/feature-gate-new_range.rs | 2 - .../feature-gate-new_range.stderr | 6 +- tests/ui/new-range/disabled.rs | 2 +- tests/ui/new-range/enabled.rs | 1 - tests/ui/range/new_range_stability.rs | 22 ++++++-- tests/ui/range/new_range_stability.stderr | 34 ++++------- 13 files changed, 72 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index dc7fe03dcf3c6..1b8c8e3bd2c86 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,9 +2,13 @@ #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![cfg_attr(feature = "nightly", feature(extend_one, step_trait))] -#![cfg_attr(feature = "nightly", feature(new_range_api))] // tidy-alphabetical-end +// FIXME(#125687): new_range_api recently stabilized +// Remove this when it hits stable. cfg(bootstrap) +#![allow(stable_features)] +#![cfg_attr(feature = "nightly", feature(new_range_api))] + pub mod bit_set; #[cfg(feature = "nightly")] pub mod interval; diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2007533e68e54..d4be1b67d3862 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -1,19 +1,18 @@ -//! # Experimental replacement range types +//! # Replacement range types //! -//! The types within this module are meant to replace the existing -//! `Range`, `RangeInclusive`, and `RangeFrom` types in a future edition. +//! The types within this module are meant to replace the legacy `Range`, +//! `RangeInclusive`, `RangeToInclusive` and `RangeFrom` types in a future edition. //! //! ``` -//! #![feature(new_range_api)] -//! use core::range::{Range, RangeFrom, RangeInclusive}; +//! use core::range::{Range, RangeFrom, RangeInclusive, RangeToInclusive}; //! //! let arr = [0, 1, 2, 3, 4]; -//! assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); -//! assert_eq!(arr[ .. 3 ], [0, 1, 2 ]); -//! assert_eq!(arr[ ..=3 ], [0, 1, 2, 3 ]); -//! assert_eq!(arr[ RangeFrom::from(1.. )], [ 1, 2, 3, 4]); -//! assert_eq!(arr[ Range::from(1..3 )], [ 1, 2 ]); -//! assert_eq!(arr[RangeInclusive::from(1..=3)], [ 1, 2, 3 ]); +//! assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +//! assert_eq!(arr[ .. 3 ], [0, 1, 2 ]); +//! assert_eq!(arr[RangeToInclusive::from( ..=3)], [0, 1, 2, 3 ]); +//! assert_eq!(arr[ RangeFrom::from(1.. )], [ 1, 2, 3, 4]); +//! assert_eq!(arr[ Range::from(1..3 )], [ 1, 2 ]); +//! assert_eq!(arr[ RangeInclusive::from(1..=3)], [ 1, 2, 3 ]); //! ``` use crate::fmt; @@ -21,7 +20,7 @@ use crate::hash::Hash; mod iter; -#[unstable(feature = "new_range_api", issue = "125687")] +#[unstable(feature = "new_range_api_legacy", issue = "125687")] pub mod legacy; #[doc(inline)] @@ -31,7 +30,7 @@ pub use iter::RangeFromIter; #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] pub use iter::RangeInclusiveIter; #[doc(inline)] -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] pub use iter::RangeIter; // FIXME(#125687): re-exports temporarily removed @@ -57,7 +56,6 @@ use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds}; /// # Examples /// /// ``` -/// #![feature(new_range_api)] /// use core::range::Range; /// /// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 }); @@ -66,17 +64,17 @@ use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds}; #[lang = "RangeCopy"] #[derive(Copy, Hash)] #[derive_const(Clone, Default, PartialEq, Eq)] -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] pub struct Range { /// The lower bound of the range (inclusive). - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] pub start: Idx, /// The upper bound of the range (exclusive). - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] pub end: Idx, } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for Range { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; @@ -94,7 +92,6 @@ impl Range { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::Range; /// /// let mut i = Range::from(3..9).iter().map(|n| n*n); @@ -102,7 +99,7 @@ impl Range { /// assert_eq!(i.next(), Some(16)); /// assert_eq!(i.next(), Some(25)); /// ``` - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn iter(&self) -> RangeIter { self.clone().into_iter() @@ -115,7 +112,6 @@ impl> Range { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::Range; /// /// assert!(!Range::from(3..5).contains(&2)); @@ -132,7 +128,7 @@ impl> Range { /// assert!(!Range::from(f32::NAN..1.0).contains(&0.5)); /// ``` #[inline] - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where @@ -147,7 +143,6 @@ impl> Range { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::Range; /// /// assert!(!Range::from(3..5).is_empty()); @@ -158,7 +153,6 @@ impl> Range { /// The range is empty if either side is incomparable: /// /// ``` - /// #![feature(new_range_api)] /// use core::range::Range; /// /// assert!(!Range::from(3.0..5.0).is_empty()); @@ -166,7 +160,7 @@ impl> Range { /// assert!( Range::from(f32::NAN..5.0).is_empty()); /// ``` #[inline] - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn is_empty(&self) -> bool where @@ -176,7 +170,7 @@ impl> Range { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for Range { fn start_bound(&self) -> Bound<&T> { @@ -193,7 +187,7 @@ impl const RangeBounds for Range { /// If you need to use this implementation where `T` is unsized, /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`. -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for Range<&T> { fn start_bound(&self) -> Bound<&T> { @@ -204,8 +198,7 @@ impl const RangeBounds for Range<&T> { } } -// #[unstable(feature = "range_into_bounds", issue = "136903")] -#[unstable(feature = "new_range_api", issue = "125687")] +#[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const IntoBounds for Range { fn into_bounds(self) -> (Bound, Bound) { @@ -213,7 +206,7 @@ impl const IntoBounds for Range { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From> for legacy::Range { #[inline] @@ -221,8 +214,7 @@ impl const From> for legacy::Range { Self { start: value.start, end: value.end } } } - -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From> for Range { #[inline] diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index c29b498bd25f8..a5db3699bc402 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -6,7 +6,7 @@ use crate::range::{Range, RangeFrom, RangeInclusive, legacy}; use crate::{intrinsics, mem}; /// By-value [`Range`] iterator. -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[derive(Debug, Clone)] pub struct RangeIter(legacy::Range); @@ -17,7 +17,6 @@ impl RangeIter { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// #![feature(new_range_remainder)] /// /// let range = core::range::Range::from(3..11); @@ -65,7 +64,7 @@ unsafe_range_trusted_random_access_impl! { u64 i64 } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl Iterator for RangeIter { type Item = A; @@ -133,7 +132,7 @@ impl Iterator for RangeIter { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl DoubleEndedIterator for RangeIter { #[inline] fn next_back(&mut self) -> Option { @@ -154,10 +153,10 @@ impl DoubleEndedIterator for RangeIter { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for RangeIter {} -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for RangeIter {} -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl IntoIterator for Range { type Item = A; type IntoIter = RangeIter; @@ -300,7 +299,7 @@ impl IntoIterator for RangeInclusive { // since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`. macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl ExactSizeIterator for RangeIter<$t> { } )*) } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index b30f82a5783ad..f1727a1f629cb 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -125,7 +125,7 @@ mod private_slice_index { #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")] impl Sealed for (ops::Bound, ops::Bound) {} - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::Range {} #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] impl Sealed for range::RangeInclusive {} @@ -458,7 +458,7 @@ unsafe impl const SliceIndex<[T]> for ops::Range { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex<[T]> for range::Range { type Output = [T]; diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 336f074883d25..da0039f055fde 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -258,7 +258,7 @@ unsafe impl const SliceIndex for ops::Range { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex for range::Range { type Output = str; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index fba144c0e9839..90a33aeead150 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -85,7 +85,6 @@ #![feature(maybe_uninit_uninit_array_transpose)] #![feature(min_specialization)] #![feature(never_type)] -#![feature(new_range_api)] #![feature(next_index)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(nonzero_from_str_radix)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7497fa100eb9e..1730742dffe93 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -537,7 +537,7 @@ pub use core::option; pub use core::pin; #[stable(feature = "rust1", since = "1.0.0")] pub use core::ptr; -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")] pub use core::range; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; diff --git a/tests/ui/feature-gates/feature-gate-new_range.rs b/tests/ui/feature-gates/feature-gate-new_range.rs index 32eeb0424b645..6fd4f19fa8dc6 100644 --- a/tests/ui/feature-gates/feature-gate-new_range.rs +++ b/tests/ui/feature-gates/feature-gate-new_range.rs @@ -1,5 +1,3 @@ -#![feature(new_range_api)] - fn main() { let a: core::range::RangeFrom = 1..; //~^ ERROR mismatched types diff --git a/tests/ui/feature-gates/feature-gate-new_range.stderr b/tests/ui/feature-gates/feature-gate-new_range.stderr index b7f70d30bfa0b..c7f2d2171b106 100644 --- a/tests/ui/feature-gates/feature-gate-new_range.stderr +++ b/tests/ui/feature-gates/feature-gate-new_range.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/feature-gate-new_range.rs:4:41 + --> $DIR/feature-gate-new_range.rs:2:41 | LL | let a: core::range::RangeFrom = 1..; | -------------------------- ^^^ expected `RangeFrom`, found `RangeFrom<{integer}>` @@ -14,7 +14,7 @@ LL | let a: core::range::RangeFrom = (1..).into(); | + ++++++++ error[E0308]: mismatched types - --> $DIR/feature-gate-new_range.rs:6:37 + --> $DIR/feature-gate-new_range.rs:4:37 | LL | let b: core::range::Range = 2..3; | ---------------------- ^^^^ expected `Range`, found `Range<{integer}>` @@ -29,7 +29,7 @@ LL | let b: core::range::Range = (2..3).into(); | + ++++++++ error[E0308]: mismatched types - --> $DIR/feature-gate-new_range.rs:8:46 + --> $DIR/feature-gate-new_range.rs:6:46 | LL | let c: core::range::RangeInclusive = 4..=5; | ------------------------------- ^^^^^ expected `RangeInclusive`, found `RangeInclusive<{integer}>` diff --git a/tests/ui/new-range/disabled.rs b/tests/ui/new-range/disabled.rs index ab6fbd3276b3f..528c464117a13 100644 --- a/tests/ui/new-range/disabled.rs +++ b/tests/ui/new-range/disabled.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(new_range_api)] +#![feature(new_range_api_legacy)] fn main() { // Unchanged diff --git a/tests/ui/new-range/enabled.rs b/tests/ui/new-range/enabled.rs index b49681eaacde3..6d9a1259b7756 100644 --- a/tests/ui/new-range/enabled.rs +++ b/tests/ui/new-range/enabled.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(new_range_api)] #![feature(new_range)] fn main() { diff --git a/tests/ui/range/new_range_stability.rs b/tests/ui/range/new_range_stability.rs index 71a0f02e58968..965be17efa747 100644 --- a/tests/ui/range/new_range_stability.rs +++ b/tests/ui/range/new_range_stability.rs @@ -6,6 +6,7 @@ use std::range::{ RangeToInclusive, RangeFrom, RangeFromIter, + Range, }; fn range_inclusive(mut r: RangeInclusive) { @@ -43,13 +44,24 @@ fn range_from(mut r: RangeFrom) { i.remainder(); //~ ERROR unstable } -// Unstable module +fn range(mut r: Range) { + &[1, 2, 3][r]; -use std::range::legacy; //~ ERROR unstable + r.start; + r.end; + r.contains(&5); + r.is_empty(); + r.iter(); -// Unstable types + let mut i = r.into_iter(); + i.next(); -use std::range::Range; //~ ERROR unstable -use std::range::RangeIter; //~ ERROR unstable + // Left unstable + i.remainder(); //~ ERROR unstable +} + +// Unstable module + +use std::range::legacy; //~ ERROR unstable fn main() {} diff --git a/tests/ui/range/new_range_stability.stderr b/tests/ui/range/new_range_stability.stderr index 64ef6a4166873..ac269a2b2227e 100644 --- a/tests/ui/range/new_range_stability.stderr +++ b/tests/ui/range/new_range_stability.stderr @@ -1,35 +1,25 @@ -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:48:5 +error[E0658]: use of unstable library feature `new_range_api_legacy` + --> $DIR/new_range_stability.rs:65:5 | LL | use std::range::legacy; | ^^^^^^^^^^^^^^^^^^ | = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable + = help: add `#![feature(new_range_api_legacy)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:52:5 - | -LL | use std::range::Range; - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:53:5 +error[E0658]: use of unstable library feature `new_range_remainder` + --> $DIR/new_range_stability.rs:23:7 | -LL | use std::range::RangeIter; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | i.remainder(); + | ^^^^^^^^^ | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable + = note: see issue #154458 for more information + = help: add `#![feature(new_range_remainder)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_remainder` - --> $DIR/new_range_stability.rs:22:7 + --> $DIR/new_range_stability.rs:44:7 | LL | i.remainder(); | ^^^^^^^^^ @@ -39,7 +29,7 @@ LL | i.remainder(); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_remainder` - --> $DIR/new_range_stability.rs:43:7 + --> $DIR/new_range_stability.rs:60:7 | LL | i.remainder(); | ^^^^^^^^^ @@ -48,6 +38,6 @@ LL | i.remainder(); = help: add `#![feature(new_range_remainder)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`.