From f3ed0a55c1a1069cd184b33109e2e8ca7ece452b Mon Sep 17 00:00:00 2001 From: Shina <53410646+s7tya@users.noreply.github.com> Date: Sat, 13 Jun 2026 00:18:39 +0000 Subject: [PATCH 01/17] Ensure inferred let pattern types are well-formed Co-authored-by: Kivooeo --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 10 +++ tests/ui/wf/let-pat-inferred-non-wf.rs | 58 +++++++++++++++++ tests/ui/wf/let-pat-inferred-non-wf.stderr | 62 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 tests/ui/wf/let-pat-inferred-non-wf.rs create mode 100644 tests/ui/wf/let-pat-inferred-non-wf.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index f3bf57ab4cd34..a76f350879f48 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -904,6 +904,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check the pattern. Override if necessary to avoid knock-on errors. self.check_pat_top(decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin)); let pat_ty = self.node_ty(decl.pat.hir_id); + if decl.ty.is_none() + && decl.init.is_none() + && !matches!(decl.pat.kind, hir::PatKind::Binding(.., None) | hir::PatKind::Wild) + { + self.register_wf_obligation( + decl_ty.into(), + decl.pat.span, + ObligationCauseCode::WellFormed(None), + ); + } self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); if let Some(blk) = decl.origin.try_get_else() { diff --git a/tests/ui/wf/let-pat-inferred-non-wf.rs b/tests/ui/wf/let-pat-inferred-non-wf.rs new file mode 100644 index 0000000000000..ab032161ebb51 --- /dev/null +++ b/tests/ui/wf/let-pat-inferred-non-wf.rs @@ -0,0 +1,58 @@ +// Regression test for https://github.com/rust-lang/rust/issues/150040 +// When a `let PAT;` has no explicit type, later assignments can infer a non-well-formed +// pattern type such as `[str; 2]` or `(str, i32)`. We must reject those array and tuple +// patterns instead of accepting the invalid type or causing ICE. + +#![allow(unused)] + +struct S(T); + +fn should_fail_1() { + let ref y @ [ref x, _]; //~ ERROR E0277 + x = ""; +} + +fn should_fail_2() { + let [ref x]; //~ ERROR E0277 + x = ""; +} + +fn should_fail_3() { + let [[ref x], [_, y @ ..]]; //~ ERROR E0277 + x = ""; + y = []; +} + +fn should_fail_4() { + let [(ref a, b), x]; //~ ERROR E0277 + a = ""; + b = 5; +} + +fn should_fail_5() { + let (ref a, b); //~ ERROR E0277 + a = ""; + b = 5; +} + +fn should_fail_6() { + let [S(ref x)]; //~ ERROR E0277 + x = ""; +} + +fn should_pass_1() { + let ref x; + x = ""; +} + +fn should_pass_2() { + let ref y @ (ref x,); + x = ""; +} + +fn should_pass_3() { + let S(ref x); + x = ""; +} + +fn main() {} diff --git a/tests/ui/wf/let-pat-inferred-non-wf.stderr b/tests/ui/wf/let-pat-inferred-non-wf.stderr new file mode 100644 index 0000000000000..1c524a22b432b --- /dev/null +++ b/tests/ui/wf/let-pat-inferred-non-wf.stderr @@ -0,0 +1,62 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/let-pat-inferred-non-wf.rs:11:9 + | +LL | let ref y @ [ref x, _]; + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: slice and array elements must have `Sized` type + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/let-pat-inferred-non-wf.rs:16:9 + | +LL | let [ref x]; + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: slice and array elements must have `Sized` type + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/let-pat-inferred-non-wf.rs:21:9 + | +LL | let [[ref x], [_, y @ ..]]; + | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: slice and array elements must have `Sized` type + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/let-pat-inferred-non-wf.rs:27:9 + | +LL | let [(ref a, b), x]; + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/let-pat-inferred-non-wf.rs:33:9 + | +LL | let (ref a, b); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/let-pat-inferred-non-wf.rs:39:9 + | +LL | let [S(ref x)]; + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `S`, the trait `Sized` is not implemented for `str` +note: required because it appears within the type `S` + --> $DIR/let-pat-inferred-non-wf.rs:8:8 + | +LL | struct S(T); + | ^ + = note: slice and array elements must have `Sized` type + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. From c1ee079aa5726d5a051fbe889cf8f0ba790efce0 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Thu, 25 Jun 2026 12:15:20 -0300 Subject: [PATCH 02/17] Normalize next-gen region constraints Canonicalize and evaluate next-gen region constraints before query response canonicalization so equivalent constraints merge structurally. --- compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 49b5b7e9b1c87..3d0f087950b67 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 @@ -5,7 +5,7 @@ use std::ops::ControlFlow; use rustc_macros::StableHash; use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; -use rustc_type_ir::region_constraint::RegionConstraint; +use rustc_type_ir::region_constraint::{RegionConstraint, evaluate_solver_constraint}; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, PathKind}; @@ -1540,7 +1540,9 @@ where // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. let region_constraints = if self.cx().assumptions_on_binders() { ExternalRegionConstraints::NextGen(if let Certainty::Yes = certainty { - self.delegate.get_solver_region_constraint() + evaluate_solver_constraint( + &self.delegate.get_solver_region_constraint().canonical_form(), + ) } else { RegionConstraint::new_true() }) From cece6fd8aa7fb36285925e7a79b45f68cd795977 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Thu, 25 Jun 2026 12:15:38 -0300 Subject: [PATCH 03/17] Add regression test for object candidates Cover the dyn object supertrait case that used to leave equivalent next-gen region constraints in different shapes. --- .../object-candidate-regions-issue-157729.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/ui/assumptions_on_binders/object-candidate-regions-issue-157729.rs diff --git a/tests/ui/assumptions_on_binders/object-candidate-regions-issue-157729.rs b/tests/ui/assumptions_on_binders/object-candidate-regions-issue-157729.rs new file mode 100644 index 0000000000000..91642aec2f6e6 --- /dev/null +++ b/tests/ui/assumptions_on_binders/object-candidate-regions-issue-157729.rs @@ -0,0 +1,40 @@ +//@ build-pass +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +// Regression test for #157729. +// The object candidates for `dyn Derived<()>` can differ only in the structural +// representation of semantically equivalent next-gen region constraints. These +// constraints must be normalized before response canonicalization so the +// candidates merge instead of remaining ambiguous and causing an ICE during +// instance resolution. + +trait Proj { + type S; +} + +impl Proj for () { + type S = (); +} + +impl Proj for i32 { + type S = i32; +} + +trait Base { + fn is_base(&self); +} + +trait Derived: Base + Base<()> { + fn is_derived(&self); +} + +fn f(obj: &dyn Derived

) { + obj.is_derived(); + Base::::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let _x: fn(_) = f::<()>; + let _x: fn(_) = f::; +} From 3ad430de9791d6e8217e9f7122a37de96759e2bb Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Mon, 20 Jul 2026 21:28:53 -0300 Subject: [PATCH 04/17] Preserve normalized solver region constraints --- compiler/rustc_infer/src/infer/context.rs | 3 +- compiler/rustc_infer/src/infer/mod.rs | 32 +++++++++++-------- .../src/infer/snapshot/undo_log.rs | 6 ++-- .../rustc_type_ir/src/region_constraint.rs | 9 +++--- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index d1d864246b9ff..aa0f1afcda6b0 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -364,7 +364,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { use rustc_data_structures::undo_log::UndoLogs; use crate::infer::UndoLog; - inner.undo_log.push(UndoLog::PushSolverRegionConstraint); + let previous_was_and = inner.solver_region_constraint_storage.is_and(); + inner.undo_log.push(UndoLog::PushSolverRegionConstraint { previous_was_and }); inner.solver_region_constraint_storage.push(c); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 72820a31a95b9..ef235274daac3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1841,12 +1841,21 @@ impl<'tcx> SolverRegionConstraintStorage<'tcx> { self.0.clone() } - fn pop(&mut self) -> Option> { + fn is_and(&self) -> bool { + self.0.is_and() + } + + fn pop(&mut self, previous_was_and: bool) -> Option> { match &mut self.0 { SolverRegionConstraint::And(and) => { let mut and = core::mem::take(and).into_iter().collect::>(); let popped = and.pop()?; - self.0 = SolverRegionConstraint::And(and.into_boxed_slice()); + if previous_was_and { + self.0 = SolverRegionConstraint::And(and.into_boxed_slice()); + } else { + assert_eq!(and.len(), 1); + self.0 = and.pop().unwrap(); + } Some(popped) } _ => unreachable!(), @@ -1855,25 +1864,20 @@ impl<'tcx> SolverRegionConstraintStorage<'tcx> { #[instrument(level = "debug")] fn push(&mut self, constraint: SolverRegionConstraint<'tcx>) { - match &mut self.0 { + match core::mem::replace(&mut self.0, SolverRegionConstraint::new_true()) { SolverRegionConstraint::And(and) => { - let and = core::mem::take(and) - .into_iter() - .chain([constraint]) - .collect::>() - .into_boxed_slice(); + let and = + and.into_iter().chain([constraint]).collect::>().into_boxed_slice(); self.0 = SolverRegionConstraint::And(and); } - _ => unreachable!(), + previous => { + self.0 = SolverRegionConstraint::And(Box::new([previous, constraint])); + } } } #[instrument(level = "debug", skip(self))] fn overwrite_solver_region_constraint(&mut self, constraint: SolverRegionConstraint<'tcx>) { - if !constraint.is_and() { - self.0 = SolverRegionConstraint::And(vec![constraint].into_boxed_slice()) - } else { - self.0 = constraint; - } + self.0 = constraint; } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 09d8eb3bf9232..eb5b3fe7bfd41 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -28,7 +28,7 @@ pub(crate) enum UndoLog<'tcx> { RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), PushTypeOutlivesConstraint, - PushSolverRegionConstraint, + PushSolverRegionConstraint { previous_was_and: bool }, OverwriteSolverRegionConstraint { old_constraint: SolverRegionConstraint<'tcx> }, PushRegionAssumption, PushHirTypeckPotentiallyRegionDependentGoal, @@ -79,8 +79,8 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), - UndoLog::PushSolverRegionConstraint => { - let popped = self.solver_region_constraint_storage.pop(); + UndoLog::PushSolverRegionConstraint { previous_was_and } => { + let popped = self.solver_region_constraint_storage.pop(previous_was_and); assert_matches!( popped, Some(_), diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index e42e96901b74d..e33f1b3dfa5f1 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -356,10 +356,11 @@ impl RegionConstraint { [or1, rest_ors @ ..] => { let mut choices = vec![]; for choice in or1 { - choices.extend(permutations(rest_ors).into_iter().map(|mut and| { - and.push(choice.clone()); - and - })); + choices.extend( + permutations(rest_ors) + .into_iter() + .map(|and| std::iter::once(choice.clone()).chain(and).collect()), + ); } choices } From 6d216c7a19e419be2fb9d8931c6076f78e676129 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Mon, 20 Jul 2026 21:29:21 -0300 Subject: [PATCH 05/17] Normalize eagerly handled region constraints --- .../rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs | 9 ++++++--- .../src/solve/eval_ctxt/solver_region_constraints.rs | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) 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 3d0f087950b67..673b8b62e5853 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 @@ -1540,9 +1540,12 @@ where // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. let region_constraints = if self.cx().assumptions_on_binders() { ExternalRegionConstraints::NextGen(if let Certainty::Yes = certainty { - evaluate_solver_constraint( - &self.delegate.get_solver_region_constraint().canonical_form(), - ) + let constraint = self.delegate.get_solver_region_constraint(); + debug_assert_eq!( + constraint, + evaluate_solver_constraint(&constraint.clone().canonical_form()) + ); + constraint } else { RegionConstraint::new_true() }) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs index 129a7b0f0de78..9d2da722b2553 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs @@ -9,6 +9,7 @@ use rustc_type_ir::outlives::{Component, push_outlives_components}; use rustc_type_ir::region_constraint::TransitiveRelationBuilder; use rustc_type_ir::region_constraint::{ Assumptions, RegionConstraint, eagerly_handle_placeholders_in_universe, + evaluate_solver_constraint, }; use rustc_type_ir::{ AliasTy, Binder, ClauseKind, InferCtxtLike, Interner, OutlivesPredicate, Region, TypeVisitable, @@ -136,6 +137,7 @@ where .fold(constraint, |constraint, u| { eagerly_handle_placeholders_in_universe(&**self.delegate, constraint, u) }); + let constraint = evaluate_solver_constraint(&constraint.canonical_form()); self.delegate.overwrite_solver_region_constraint(constraint.clone()); From 9b4184ba9af999d47425bbe512ef753af818dad4 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Sun, 26 Jul 2026 14:04:45 -0300 Subject: [PATCH 06/17] Ignore query cycle test under parallel frontend --- .../min_specialization/next-solver-region-resolution.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs index a49fe6184890f..b316e02b0fc91 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs @@ -22,3 +22,5 @@ where } fn main() {} + +//@ ignore-parallel-frontend query cycle From 26fba41cdb63d8d5df001f99f34d3e2e5629daa5 Mon Sep 17 00:00:00 2001 From: b1yd <2156864690@qq.com> Date: Tue, 4 Aug 2026 18:53:45 +0800 Subject: [PATCH 07/17] Fix inaccurate description for crate and pathroot --- compiler/rustc_resolve/src/diagnostics/impls.rs | 5 ++++- tests/rustdoc-ui/issues/issue-61732.rs | 2 +- tests/rustdoc-ui/issues/issue-61732.stderr | 2 +- .../imports/suggest-import-issue-120074.edition2015.stderr | 2 +- tests/ui/imports/suggest-import-issue-120074.post2015.stderr | 2 +- tests/ui/imports/suggest-import-issue-120074.rs | 2 +- tests/ui/resolve/editions-crate-root-2015.stderr | 2 +- tests/ui/resolve/editions-crate-root-2018.stderr | 4 ++-- tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs | 2 +- .../resolve/path-suggestion-duplicated-crate-keyword.stderr | 2 +- tests/ui/resolve/visibility-indeterminate.stderr | 2 +- .../rfc-2126-extern-absolute-paths/non-existent-2.stderr | 2 +- 12 files changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 212629395c98b..16c26cfa23be1 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -2944,7 +2944,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let scope = match &path[..failed_segment_idx] { [.., prev] => { - if prev.ident.name == kw::PathRoot { + if prev.ident.name == kw::PathRoot && self.tcx.sess.edition() > Edition::Edition2015 + { + format!("the list of imported crates") + } else if prev.ident.name == kw::PathRoot || prev.ident.name == kw::Crate { format!("the crate root") } else { format!("`{}`", prev.ident) diff --git a/tests/rustdoc-ui/issues/issue-61732.rs b/tests/rustdoc-ui/issues/issue-61732.rs index b375298ea40e9..31d7052b3227a 100644 --- a/tests/rustdoc-ui/issues/issue-61732.rs +++ b/tests/rustdoc-ui/issues/issue-61732.rs @@ -1,4 +1,4 @@ // This previously triggered an ICE. pub(in crate::r#mod) fn main() {} -//~^ ERROR cannot find module or crate `r#mod` in `crate` +//~^ ERROR cannot find module or crate `r#mod` in the crate root diff --git a/tests/rustdoc-ui/issues/issue-61732.stderr b/tests/rustdoc-ui/issues/issue-61732.stderr index 49d5bfc9a2f05..718bb5b7d1c3a 100644 --- a/tests/rustdoc-ui/issues/issue-61732.stderr +++ b/tests/rustdoc-ui/issues/issue-61732.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find module or crate `r#mod` in `crate` +error[E0433]: cannot find module or crate `r#mod` in the crate root --> $DIR/issue-61732.rs:3:15 | LL | pub(in crate::r#mod) fn main() {} diff --git a/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr index b079471e809c9..1a9941b6da705 100644 --- a/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr +++ b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find `bar` in `crate` +error[E0433]: cannot find `bar` in the crate root --> $DIR/suggest-import-issue-120074.rs:14:35 | LL | println!("Hello, {}!", crate::bar::do_the_thing); diff --git a/tests/ui/imports/suggest-import-issue-120074.post2015.stderr b/tests/ui/imports/suggest-import-issue-120074.post2015.stderr index 045a7df3feeaf..8479abfb59905 100644 --- a/tests/ui/imports/suggest-import-issue-120074.post2015.stderr +++ b/tests/ui/imports/suggest-import-issue-120074.post2015.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find `bar` in `crate` +error[E0433]: cannot find `bar` in the crate root --> $DIR/suggest-import-issue-120074.rs:14:35 | LL | println!("Hello, {}!", crate::bar::do_the_thing); diff --git a/tests/ui/imports/suggest-import-issue-120074.rs b/tests/ui/imports/suggest-import-issue-120074.rs index 27027405f4dee..bdf8090b0cd0c 100644 --- a/tests/ui/imports/suggest-import-issue-120074.rs +++ b/tests/ui/imports/suggest-import-issue-120074.rs @@ -11,5 +11,5 @@ pub mod foo { } fn main() { - println!("Hello, {}!", crate::bar::do_the_thing); //~ ERROR cannot find `bar` in `crate` + println!("Hello, {}!", crate::bar::do_the_thing); //~ ERROR cannot find `bar` in the crate root } diff --git a/tests/ui/resolve/editions-crate-root-2015.stderr b/tests/ui/resolve/editions-crate-root-2015.stderr index a4002349387a9..9c129fd2f9209 100644 --- a/tests/ui/resolve/editions-crate-root-2015.stderr +++ b/tests/ui/resolve/editions-crate-root-2015.stderr @@ -9,7 +9,7 @@ help: you might be missing a crate named `nonexistant`, add it to your project a LL + extern crate nonexistant; | -error[E0433]: cannot find module or crate `nonexistant` in `crate` +error[E0433]: cannot find module or crate `nonexistant` in the crate root --> $DIR/editions-crate-root-2015.rs:7:30 | LL | fn crate_inner(_: crate::nonexistant::Foo) { diff --git a/tests/ui/resolve/editions-crate-root-2018.stderr b/tests/ui/resolve/editions-crate-root-2018.stderr index c7ce936700511..8919172bdea43 100644 --- a/tests/ui/resolve/editions-crate-root-2018.stderr +++ b/tests/ui/resolve/editions-crate-root-2018.stderr @@ -1,10 +1,10 @@ -error[E0433]: cannot find `nonexistant` in the crate root +error[E0433]: cannot find `nonexistant` in the list of imported crates --> $DIR/editions-crate-root-2018.rs:4:26 | LL | fn global_inner(_: ::nonexistant::Foo) { | ^^^^^^^^^^^ could not find `nonexistant` in the list of imported crates -error[E0433]: cannot find `nonexistant` in `crate` +error[E0433]: cannot find `nonexistant` in the crate root --> $DIR/editions-crate-root-2018.rs:7:30 | LL | fn crate_inner(_: crate::nonexistant::Foo) { diff --git a/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs index 294885b997da3..18a0397b11c5f 100644 --- a/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs +++ b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs @@ -8,7 +8,7 @@ pub mod unix { pub mod utils { pub fn f() { let _x = crate::linux::system::Y; - //~^ ERROR cannot find `linux` in `crate` + //~^ ERROR cannot find `linux` in the crate root } } pub mod system { diff --git a/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr index 49c2db34d2b4d..f3b28425c072b 100644 --- a/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr +++ b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find `linux` in `crate` +error[E0433]: cannot find `linux` in the crate root --> $DIR/path-suggestion-duplicated-crate-keyword.rs:10:33 | LL | let _x = crate::linux::system::Y; diff --git a/tests/ui/resolve/visibility-indeterminate.stderr b/tests/ui/resolve/visibility-indeterminate.stderr index d58d45ab792b4..b86e22cfc8e00 100644 --- a/tests/ui/resolve/visibility-indeterminate.stderr +++ b/tests/ui/resolve/visibility-indeterminate.stderr @@ -4,7 +4,7 @@ error: cannot find macro `foo` in this scope LL | foo!(); | ^^^ -error[E0433]: cannot find `bar` in the crate root +error[E0433]: cannot find `bar` in the list of imported crates --> $DIR/visibility-indeterminate.rs:5:10 | LL | pub(in ::bar) struct Baz {} diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr index 553365c932239..b7411c2fb9893 100644 --- a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find `xcrate` in the crate root +error[E0433]: cannot find `xcrate` in the list of imported crates --> $DIR/non-existent-2.rs:4:15 | LL | let s = ::xcrate::S; From 47fb4b92beec3ef280e8e3d9bf26f9ca31e9a3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 13:05:45 +0200 Subject: [PATCH 08/17] Do not eagerly download rustfmt when parsing the config --- src/bootstrap/src/core/build_steps/format.rs | 27 +++++++++++++++++--- src/bootstrap/src/core/build_steps/test.rs | 9 +++++-- src/bootstrap/src/core/config/config.rs | 14 +++++----- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 53cb03a41fc4d..1060f7928c1b2 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -9,7 +9,8 @@ use std::sync::mpsc::SyncSender; use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; -use crate::core::builder::{Builder, Kind}; +use crate::core::builder::{Builder, Kind, Step}; +use crate::core::download::{DownloadContext, maybe_download_rustfmt}; use crate::utils::build_stamp::BuildStamp; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; @@ -58,7 +59,8 @@ fn rustfmt( fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, BuildStamp)> { let stamp_file = BuildStamp::new(&build.out).with_prefix("rustfmt"); - let mut cmd = command(build.config.initial_rustfmt.as_ref()?); + let rustfmt = build.ensure(InternalRustfmt); + let mut cmd = command(rustfmt.as_ref()?); cmd.arg("--version"); let output = cmd.allow_failure().run_capture(build); @@ -101,6 +103,25 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]).map(Some) } +/// Rustfmt set via the config, or downloaded from CI, used to format local Rust code. +/// +/// This is separate from the in-tree rustfmt. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct InternalRustfmt; + +impl Step for InternalRustfmt { + type Output = Option; + + fn run(self, builder: &Builder<'_>) -> Self::Output { + // Rustfmt configured through the config + if let Some(initial_rustfmt) = &builder.config.external_rustfmt { + return Some(initial_rustfmt.clone()); + } + // No rustfmt was configured, try to download it + maybe_download_rustfmt(DownloadContext::from(&builder.config), &builder.config.out) + } +} + #[derive(serde_derive::Deserialize)] struct RustfmtConfig { ignore: Vec, @@ -243,7 +264,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { let override_ = override_builder.build().unwrap(); // `override` is a reserved keyword - let rustfmt_path = build.config.initial_rustfmt.clone().unwrap_or_else(|| { + let rustfmt_path = build.ensure(InternalRustfmt).unwrap_or_else(|| { eprintln!("fmt error: `x fmt` is not supported on this channel"); crate::exit!(1); }); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9257a238a3498..5f437febec0f7 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -17,6 +17,7 @@ use build_helper::git::get_closest_upstream_commit; use crate::core::build_steps::compile::{ArtifactKeepMode, Std, run_cargo}; use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler}; +use crate::core::build_steps::format::InternalRustfmt; use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; @@ -1095,7 +1096,7 @@ impl CommandLineStep for IntrinsicTest { cmd.env("CFLAGS", cflags); // intrinsic-test shells out to `cargo` and `rustfmt` make bootstrap's // managed binaries findable by prepending their dirs to PATH. - let Some(rustfmt_path) = builder.config.initial_rustfmt.clone() else { + let Some(rustfmt_path) = builder.ensure(InternalRustfmt) else { eprintln!( "WARNING: intrinsic-test skipped because rustfmt is required but not available on this channel" ); @@ -1629,7 +1630,11 @@ impl CommandLineStep for Tidy { if builder.config.channel == "dev" || builder.config.channel == "nightly" { if !builder.config.json_output { builder.info("fmt check"); - if builder.config.initial_rustfmt.is_none() { + + // Note: this actually sets up or downloads rustfmt, so running this step here is + // load-bearing + let rustfmt = builder.ensure(InternalRustfmt); + if rustfmt.is_none() { let inferred_rustfmt_dir = builder.initial_sysroot.join("bin"); eprintln!( "\ diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 81a425fba1cab..9cd91a2382f62 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -53,9 +53,7 @@ use crate::core::config::{ GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, }; -use crate::core::download::{ - DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, -}; +use crate::core::download::{DownloadContext, download_beta_toolchain, is_download_ci_available}; use crate::utils::channel; use crate::utils::exec::{ExecutionContext, command}; use crate::utils::helpers::{exe, fail, get_host_target}; @@ -310,7 +308,11 @@ pub struct Config { pub initial_rustdoc: PathBuf, pub initial_cargo_clippy: Option, pub initial_sysroot: PathBuf, - pub initial_rustfmt: Option, + + /// Externally configured `rustfmt` binary for formatting in-tree source code. + /// If you want to use rustfmt for formatting, use the `InternalRustfmt` step, instead of + /// accessing this directly. + pub external_rustfmt: Option, /// The paths to work with. For example: with `./x check foo bar` we get /// `paths=["foo", "bar"]`. @@ -1168,8 +1170,6 @@ impl Config { } } - let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out)); - if matches!(bootstrap_override_lld, BootstrapOverrideLld::SelfContained) && !lld_enabled && flags_stage.unwrap_or(0) > 0 @@ -1447,6 +1447,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to explicit_stage_from_cli: flags_stage.is_some(), explicit_stage_from_config, extended: build_extended.unwrap_or(false), + external_rustfmt: build_rustfmt, free_args: flags_free_args, full_bootstrap: build_full_bootstrap.unwrap_or(false), gcc_ci_mode, @@ -1461,7 +1462,6 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to initial_cargo_clippy: build_cargo_clippy, initial_rustc, initial_rustdoc, - initial_rustfmt, initial_sysroot, jobs: Some(threads_from_config(flags_jobs.or(build_jobs).unwrap_or(0))), json_output: flags_json_output, From 83c82b5f3287b2d1dc89d47bf62b51a6baae6db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 13:21:51 +0200 Subject: [PATCH 09/17] Explictily pass rustfmt path to the `format` function --- src/bootstrap/src/core/build_steps/format.rs | 12 +++++++----- src/bootstrap/src/core/build_steps/test.rs | 6 +++--- src/bootstrap/src/lib.rs | 9 ++++++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 1060f7928c1b2..2061a4230c575 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -142,7 +142,13 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { } } -pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { +pub fn format( + build: &Builder<'_>, + rustfmt_path: PathBuf, + check: bool, + all: bool, + paths: &[PathBuf], +) { if build.kind == Kind::Format && build.top_stage != 0 { eprintln!("ERROR: `x fmt` only supports stage 0."); eprintln!("HELP: Use `x run rustfmt` to run in-tree rustfmt."); @@ -264,10 +270,6 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { let override_ = override_builder.build().unwrap(); // `override` is a reserved keyword - let rustfmt_path = build.ensure(InternalRustfmt).unwrap_or_else(|| { - eprintln!("fmt error: `x fmt` is not supported on this channel"); - crate::exit!(1); - }); assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); let src = build.src.clone(); let (tx, rx): (SyncSender, _) = std::sync::mpsc::sync_channel(128); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5f437febec0f7..cf61f713d372f 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1633,8 +1633,7 @@ impl CommandLineStep for Tidy { // Note: this actually sets up or downloads rustfmt, so running this step here is // load-bearing - let rustfmt = builder.ensure(InternalRustfmt); - if rustfmt.is_none() { + let Some(rustfmt) = builder.ensure(InternalRustfmt) else { let inferred_rustfmt_dir = builder.initial_sysroot.join("bin"); eprintln!( "\ @@ -1646,10 +1645,11 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to CHAN = builder.config.channel, ); crate::exit!(1); - } + }; let all = false; crate::core::build_steps::format::format( builder, + rustfmt, !builder.config.cmd.bless(), all, &[], diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7d119247b3bac..8ae655e2bfe5d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -32,6 +32,7 @@ use utils::build_stamp::BuildStamp; use utils::channel::GitInfo; use utils::exec::ExecutionContext; +use crate::core::build_steps::format::InternalRustfmt; use crate::core::builder; use crate::core::builder::Kind; use crate::core::config::{BootstrapOverrideLld, DryRun, LlvmLibunwind, TargetSelection, flags}; @@ -759,8 +760,14 @@ impl Build { match &self.config.cmd { Subcommand::Format { check, all } => { + let builder = builder::Builder::new(self); + let rustfmt_path = builder.ensure(InternalRustfmt).unwrap_or_else(|| { + eprintln!("fmt error: `x fmt` is not supported on this channel"); + crate::exit!(1); + }); return core::build_steps::format::format( - &builder::Builder::new(self), + &builder, + rustfmt_path, *check, *all, &self.config.paths, From 5e428305aa576342571fdce675446b4c0f0760e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 13:26:39 +0200 Subject: [PATCH 10/17] Simplify `maybe_download_rustfmt` --- src/bootstrap/src/core/build_steps/format.rs | 4 ++-- src/bootstrap/src/core/download.rs | 25 ++++++++------------ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 2061a4230c575..4f3a6e9908384 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -10,7 +10,7 @@ use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; use crate::core::builder::{Builder, Kind, Step}; -use crate::core::download::{DownloadContext, maybe_download_rustfmt}; +use crate::core::download::maybe_download_rustfmt; use crate::utils::build_stamp::BuildStamp; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; @@ -118,7 +118,7 @@ impl Step for InternalRustfmt { return Some(initial_rustfmt.clone()); } // No rustfmt was configured, try to download it - maybe_download_rustfmt(DownloadContext::from(&builder.config), &builder.config.out) + maybe_download_rustfmt(&builder.config, &builder.config.out) } } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d3bc5718b171e..596bd5bc2fa99 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -530,25 +530,20 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't /// reuse target directories or artifacts -pub(crate) fn maybe_download_rustfmt<'a>( - dwn_ctx: impl AsRef>, - out: &Path, -) -> Option { +pub(crate) fn maybe_download_rustfmt(config: &Config, out: &Path) -> Option { // Don't actually download rustfmt during unit tests. if cfg!(test) { return Some(PathBuf::new()); } - let dwn_ctx = dwn_ctx.as_ref(); - - if dwn_ctx.exec_ctx.dry_run() { + if config.dry_run() { return Some(PathBuf::new()); } - let VersionMetadata { date, version, .. } = dwn_ctx.stage0_metadata.rustfmt.as_ref()?; + let VersionMetadata { date, version, .. } = config.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); - let host = dwn_ctx.host_target; + let host = config.host_target; let bin_root = out.join(host).join("rustfmt"); let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host)); let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel); @@ -557,7 +552,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( } download_component( - dwn_ctx, + DownloadContext::from(config), out, DownloadSource::Dist, format!("rustfmt-{version}-{build}.tar.xz", build = host.triple), @@ -567,7 +562,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( ); download_component( - dwn_ctx, + DownloadContext::from(config), out, DownloadSource::Dist, format!("rustc-{version}-{build}.tar.xz", build = host.triple), @@ -576,14 +571,14 @@ pub(crate) fn maybe_download_rustfmt<'a>( "rustfmt", ); - if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); + if should_fix_bins_and_dylibs(config.patch_binaries_for_nix, &config.exec_ctx) { + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustfmt"), &config.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("cargo-fmt"), &config.exec_ctx); let lib_dir = bin_root.join("lib"); for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &lib.path(), &config.exec_ctx); } } } From 022681964901a8fee3488ffc2a0e4bf8b473e514 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 13:45:20 +0200 Subject: [PATCH 11/17] MaybeDangling: ensure references fit inside the address space --- .../src/interpret/validity.rs | 48 +++++++++++++------ .../validity/maybe_dangling_ref_too_big.rs | 7 +++ .../maybe_dangling_ref_too_big.stderr | 13 +++++ 3 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.rs create mode 100644 src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 328b8b83a947f..d0bcc52fc9734 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -647,6 +647,25 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { None } } else { + // We are not checking dereferenceability, but we still want to ensure that the pointer + // *could* be dereferenceable in *some* memory: we have to be able to compute the + // address at the end of this range without overflowing.. + let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx); + // Skip this if we don't know the absolute address (during CTFE). + if let Ok(addr) = scalar.try_to_scalar_int() { + // Try to compute the end address. + let addr = Size::from_bytes(addr.to_target_usize(*self.ecx.tcx)); + if addr.checked_add(size, self.ecx).is_none() { + throw_validation_failure!( + self.path, + format!( + "encountered a {ptr_kind} that is too close to the end of the address space for a pointee of {} bytes", + size.bytes(), + ) + ) + } + } + // Pointer remains unchanged. None }; @@ -658,20 +677,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.reset_pointer_provenance(value, &ptr)?; } - // Check alignment after dereferenceable (if both are violated, trigger the error above). - try_validation!( - self.ecx.check_ptr_align( - place.ptr(), - align, - ), - self.path, - Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => format!( - "encountered an unaligned {ptr_kind} (required {required_bytes} byte alignment but found {found_bytes})", - required_bytes = required.bytes(), - found_bytes = has.bytes() - ), - ); - // Make sure this is non-null. This is obviously needed when `may_dangle` is set, // but even if we did check dereferenceability above that would still allow null // pointers if `size` is zero. @@ -686,6 +691,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ) ) } + // Do not allow references to uninhabited types. if !place.layout.ty.is_opsem_inhabited(*self.ecx.tcx, self.ecx.typing_env) { let ty = place.layout.ty; @@ -695,6 +701,20 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ) } + // Check alignment after dereferenceable (if both are violated, trigger the error above). + try_validation!( + self.ecx.check_ptr_align( + place.ptr(), + align, + ), + self.path, + Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => format!( + "encountered an unaligned {ptr_kind} (required {required_bytes} byte alignment but found {found_bytes})", + required_bytes = required.bytes(), + found_bytes = has.bytes() + ), + ); + // Recursive checking (but not inside `MaybeDangling` of course). if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() && !self.may_dangle diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.rs b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.rs new file mode 100644 index 0000000000000..350e46a31df64 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.rs @@ -0,0 +1,7 @@ +#![feature(maybe_dangling)] +use std::mem::{transmute, MaybeDangling}; + +fn main() { + let _x: MaybeDangling<&i8> = unsafe { transmute(usize::MAX) }; + //~^ERROR: too close to the end of the address space +} diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr new file mode 100644 index 0000000000000..f0966586d4dc7 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: encountered a reference that is too close to the end of the address space for a pointee of 1 bytes + --> tests/fail/validity/maybe_dangling_ref_too_big.rs:LL:CC + | +LL | let _x: MaybeDangling<&i8> = unsafe { transmute(usize::MAX) }; + | ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 5395227813e4be09fc56b08feb50fa12f99cb125 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Sun, 9 Aug 2026 01:33:21 -0500 Subject: [PATCH 12/17] use recognizer functions for enums and tuple structs --- src/etc/lldb_batchmode/runner.py | 1 + src/etc/lldb_lookup.py | 49 +++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/etc/lldb_batchmode/runner.py b/src/etc/lldb_batchmode/runner.py index cd0879f63cee6..e7615b4d9e19e 100644 --- a/src/etc/lldb_batchmode/runner.py +++ b/src/etc/lldb_batchmode/runner.py @@ -117,6 +117,7 @@ def execute_command(command_interpreter: lldb.SBCommandInterpreter, command: str + str(res.GetError()) ) else: + print(res.GetOutput()) print(res.GetError()) diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index ce6aeb6576e02..5b58628ad29c0 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -126,27 +126,44 @@ def register_providers_compatibility(): global RUST_CATEGORY if LLDBFeature.TypeRecognizers in FEATURE_FLAGS: - # FIXME: this can be removed once full support for type recognizers is added. - # This prevents a semi-unfixable regression for CodeLLDB - register_synth( - synthetic_lookup, + # enforce uniform aggregate formatting + register_summary( + StructSummaryProvider, lldb.SBTypeNameSpecifier( MOD_PREFIX + is_udt.__name__, lldb.eFormatterMatchCallback, ), + lldb.eTypeOptionCascade + | lldb.eTypeOptionHideEmptyAggregates + | lldb.eTypeOptionHideChildren, + ) + + # Tuple-structs + register_synth( + TupleSyntheticProvider, + lldb.SBTypeNameSpecifier( + MOD_PREFIX + is_tuple_type.__name__, lldb.eFormatterMatchCallback + ), + lldb.eTypeOptionCascade, + ) + + # Gnu Sum-type Enums + register_synth( + ClangEncodedEnumProvider, + lldb.SBTypeNameSpecifier( + MOD_PREFIX + is_gnu_enum.__name__, + lldb.eFormatterMatchCallback, + ), lldb.eTypeOptionCascade, ) - # enforce uniform aggregate formatting register_summary( - StructSummaryProvider, + ClangEncodedEnumSummaryProvider, lldb.SBTypeNameSpecifier( - MOD_PREFIX + is_udt.__name__, + MOD_PREFIX + is_gnu_enum.__name__, lldb.eFormatterMatchCallback, ), - lldb.eTypeOptionCascade - | lldb.eTypeOptionHideEmptyAggregates - | lldb.eTypeOptionHideChildren, + lldb.eTypeOptionCascade, ) else: # Need to toss any remaining types through this so that GNU enums are caught @@ -395,6 +412,18 @@ def is_udt(type: lldb.SBType, _dict: LLDBOpaque) -> bool: ) +def is_gnu_enum(type: lldb.SBType, _dict: LLDBOpaque) -> bool: + return ( + type.GetNumberOfFields() == 1 + and type.GetFieldAtIndex(0).GetName() == "$variants$" + ) + + +def is_tuple_type(type: lldb.SBType, _dict: LLDBOpaque) -> bool: + fields = type.fields + return len(fields) != 0 and is_tuple_fields(fields) + + def classify_rust_type(type: lldb.SBType, is_msvc: bool) -> RustType: if type.IsPointerType(): return RustType.Indirection From 57e48b019698769b4f41346d438cf23187248785 Mon Sep 17 00:00:00 2001 From: Aphek Date: Sun, 9 Aug 2026 21:03:43 -0300 Subject: [PATCH 13/17] Fix references to unsupported on sys::paths::unix These were broken by PR https://github.com/rust-lang/rust/pull/150885, commit f2dd93228abcf29ab85960457df7a6f828eb3cb9 --- library/std/src/sys/paths/unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index 7d916b843f24e..e023451b13c8c 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -47,7 +47,7 @@ pub fn getcwd() -> io::Result { #[cfg(target_os = "espidf")] pub fn chdir(_p: &path::Path) -> io::Result<()> { - crate::sys::pal::unsupported::unsupported() + crate::sys::pal::unsupported() } #[cfg(not(target_os = "espidf"))] @@ -385,7 +385,7 @@ pub fn current_exe() -> io::Result { #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] pub fn current_exe() -> io::Result { - crate::sys::pal::unsupported::unsupported() + crate::sys::pal::unsupported() } #[cfg(target_os = "fuchsia")] From 86a16af97cd19f6dbea59b3a58d6d5cee38d7e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Aug 2026 12:57:37 +0200 Subject: [PATCH 14/17] Clarify `InternalRustfmt` comment --- src/bootstrap/src/core/build_steps/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 4f3a6e9908384..ee74820da0999 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -105,7 +105,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str /// Rustfmt set via the config, or downloaded from CI, used to format local Rust code. /// -/// This is separate from the in-tree rustfmt. +/// We never ship this rustfmt, it is designed only for internal usage. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct InternalRustfmt; From 1bf4fbaf4555e7479ec0916537873f91715c95d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Aug 2026 13:05:20 +0200 Subject: [PATCH 15/17] Download stage 0 rustfmt after running `x setup` --- src/bootstrap/src/core/build_steps/setup.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 7b0bd1e3067fb..9527e9e9879b4 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -18,6 +18,7 @@ use std::{fmt, fs, io}; use serde_derive::{Deserialize, Serialize}; use sha2::Digest; +use crate::core::build_steps::format; use crate::core::builder::{Builder, CommandLineStep, RunConfig, ShouldRun}; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; use crate::utils::exec::command; @@ -676,6 +677,10 @@ impl CommandLineStep for Editor { Ok(editor_kind) => { if let Some(editor_kind) = editor_kind { while !t!(create_editor_settings_maybe(config, &editor_kind)) {} + + // Also pre-download stage 0 rustfmt, so that the IDE configs which point to + // `build/host/rustfmt` have an available binary to work with. + builder.ensure(format::InternalRustfmt); } else { println!("Ok, skipping editor setup!"); } From a9235505d663758ec737ac95b75f2f7b483efe32 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 6 Aug 2026 13:48:05 +0000 Subject: [PATCH 16/17] mir: prohibit projection into scalable vec --- compiler/rustc_mir_transform/src/sroa.rs | 4 ++- compiler/rustc_mir_transform/src/validate.rs | 2 +- .../crates/core_arch/src/aarch64/sve/mod.rs | 8 ++--- ...roa.bar.ScalarReplacementOfAggregates.diff | 32 +++++++++++++++++++ ...roa.foo.ScalarReplacementOfAggregates.diff | 32 +++++++++++++++++++ tests/mir-opt/sroa/scalable_sroa.rs | 30 +++++++++++++++++ tests/ui/scalable-vectors/auxiliary/simple.rs | 9 ++++++ .../project-into-field-extern.rs | 16 ++++++++++ .../project-into-field-extern.stderr | 9 ++++++ .../ui/scalable-vectors/project-into-field.rs | 24 ++++++++++++++ .../project-into-field.stderr | 8 +++++ 11 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 tests/mir-opt/sroa/scalable_sroa.bar.ScalarReplacementOfAggregates.diff create mode 100644 tests/mir-opt/sroa/scalable_sroa.foo.ScalarReplacementOfAggregates.diff create mode 100644 tests/mir-opt/sroa/scalable_sroa.rs create mode 100644 tests/ui/scalable-vectors/auxiliary/simple.rs create mode 100644 tests/ui/scalable-vectors/project-into-field-extern.rs create mode 100644 tests/ui/scalable-vectors/project-into-field-extern.stderr create mode 100644 tests/ui/scalable-vectors/project-into-field.rs create mode 100644 tests/ui/scalable-vectors/project-into-field.stderr diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index b16336fb9150c..f4f90372b4a8d 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -69,7 +69,9 @@ fn escaping_locals<'tcx>( return true; } if let ty::Adt(def, _args) = ty.kind() - && (def.repr().simd() || tcx.is_lang_item(def.did(), LangItem::DynMetadata)) + && (def.repr().simd() + || def.repr().scalable() + || tcx.is_lang_item(def.did(), LangItem::DynMetadata)) { // Exclude #[repr(simd)] types so that they are not de-optimized into an array // (MCP#838 banned projections into SIMD types, but if the value is unused diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 4413d5064bd14..af058fb4abb3b 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -707,7 +707,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - if adt_def.repr().simd() { + if adt_def.repr().simd() || adt_def.repr().scalable() { self.fail( location, format!( diff --git a/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs index f11ca660b15e2..41fd12d3517b4 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs @@ -39,7 +39,7 @@ impl SveInto for T { macro_rules! impl_sve_type { ($(($v:vis, $elem_type:ty, $name:ident, $elt:literal))*) => ($( #[doc = concat!("Scalable vector of type ", stringify!($elem_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector($elt)] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($elem_type); @@ -52,21 +52,21 @@ macro_rules! impl_sve_tuple_type { )*); (@ ($v:vis, $vec_type:ty, 2, $name:ident)) => ( #[doc = concat!("Two-element tuple of scalable vectors of type ", stringify!($vec_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($vec_type, $vec_type); ); (@ ($v:vis, $vec_type:ty, 3, $name:ident)) => ( #[doc = concat!("Three-element tuple of scalable vectors of type ", stringify!($vec_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($vec_type, $vec_type, $vec_type); ); (@ ($v:vis, $vec_type:ty, 4, $name:ident)) => ( #[doc = concat!("Four-element tuple of scalable vectors of type ", stringify!($vec_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($vec_type, $vec_type, $vec_type, $vec_type); diff --git a/tests/mir-opt/sroa/scalable_sroa.bar.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/scalable_sroa.bar.ScalarReplacementOfAggregates.diff new file mode 100644 index 0000000000000..fa4b14620b10e --- /dev/null +++ b/tests/mir-opt/sroa/scalable_sroa.bar.ScalarReplacementOfAggregates.diff @@ -0,0 +1,32 @@ +- // MIR for `bar` before ScalarReplacementOfAggregates ++ // MIR for `bar` after ScalarReplacementOfAggregates + + fn bar(_1: &[svuint32x2_t], _2: svuint32x2_t) -> () { + debug simds => _1; + debug _unused => _2; + let mut _0: (); + let _3: std::arch::aarch64::svuint32x2_t; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug a => _3; + } + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = const 0_usize; + _5 = PtrMetadata(copy _1); + _6 = Lt(copy _4, copy _5); + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; + } + + bb1: { + _3 = copy (*_1)[_4]; + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/sroa/scalable_sroa.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/scalable_sroa.foo.ScalarReplacementOfAggregates.diff new file mode 100644 index 0000000000000..0aceea57e17a6 --- /dev/null +++ b/tests/mir-opt/sroa/scalable_sroa.foo.ScalarReplacementOfAggregates.diff @@ -0,0 +1,32 @@ +- // MIR for `foo` before ScalarReplacementOfAggregates ++ // MIR for `foo` after ScalarReplacementOfAggregates + + fn foo(_1: &[svuint32_t], _2: svuint32_t) -> () { + debug simds => _1; + debug _unused => _2; + let mut _0: (); + let _3: std::arch::aarch64::svuint32_t; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug a => _3; + } + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = const 0_usize; + _5 = PtrMetadata(copy _1); + _6 = Lt(copy _4, copy _5); + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; + } + + bb1: { + _3 = copy (*_1)[_4]; + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/sroa/scalable_sroa.rs b/tests/mir-opt/sroa/scalable_sroa.rs new file mode 100644 index 0000000000000..a282bdae83265 --- /dev/null +++ b/tests/mir-opt/sroa/scalable_sroa.rs @@ -0,0 +1,30 @@ +//@ only-aarch64 +//@ needs-unwind +#![feature(stdarch_aarch64_sve)] + +// SRoA expands things even if they're unused +// + +use std::arch::aarch64::{svuint32_t, svuint32x2_t}; + +// EMIT_MIR scalable_sroa.foo.ScalarReplacementOfAggregates.diff +pub(crate) fn foo(simds: &[svuint32_t], _unused: svuint32_t) { + // CHECK-LABEL: fn foo + // CHECK-NOT: u32 + // CHECK: let [[SIMD:_.+]]: std::arch::aarch64::svuint32_t; + // CHECK-NOT: u32 + // CHECK: [[SIMD]] = copy (*_1)[0 of 1]; + // CHECK-NOT: u32 + let a = simds[0]; +} + +// EMIT_MIR scalable_sroa.bar.ScalarReplacementOfAggregates.diff +pub(crate) fn bar(simds: &[svuint32x2_t], _unused: svuint32x2_t) { + // CHECK-LABEL: fn bar + // CHECK-NOT: { , } + // CHECK: let [[SIMD:_.+]]: std::arch::aarch64::svuint32x2_t; + // CHECK-NOT: { , } + // CHECK: [[SIMD]] = copy (*_1)[0 of 1]; + // CHECK-NOT: { , } + let a = simds[0]; +} diff --git a/tests/ui/scalable-vectors/auxiliary/simple.rs b/tests/ui/scalable-vectors/auxiliary/simple.rs new file mode 100644 index 0000000000000..36fe12da3b5c0 --- /dev/null +++ b/tests/ui/scalable-vectors/auxiliary/simple.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Copt-level=0 +//@ only-aarch64 +#![allow(internal_features)] +#![feature(rustc_attrs)] +#![crate_type = "rlib"] + +#[allow(unused)] // Only used on aarch64-unknown-linux-gnu. +#[rustc_scalable_vector(4)] +pub struct Sv(f32); diff --git a/tests/ui/scalable-vectors/project-into-field-extern.rs b/tests/ui/scalable-vectors/project-into-field-extern.rs new file mode 100644 index 0000000000000..38db4537cce0c --- /dev/null +++ b/tests/ui/scalable-vectors/project-into-field-extern.rs @@ -0,0 +1,16 @@ +//@ aux-build: simple.rs +//@ compile-flags: -Copt-level=0 +//@ check-fail +//@ only-aarch64 +#![allow(internal_features)] +#![crate_type = "lib"] + +extern crate simple; + +pub use simple::Sv; + +#[target_feature(enable = "sve")] +pub fn field(x: Sv) -> f32 { + x.0 + //~^ ERROR: field `0` of struct `Sv` is private +} diff --git a/tests/ui/scalable-vectors/project-into-field-extern.stderr b/tests/ui/scalable-vectors/project-into-field-extern.stderr new file mode 100644 index 0000000000000..c521d1bf06148 --- /dev/null +++ b/tests/ui/scalable-vectors/project-into-field-extern.stderr @@ -0,0 +1,9 @@ +error[E0616]: field `0` of struct `Sv` is private + --> $DIR/project-into-field-extern.rs:14:7 + | +LL | x.0 + | ^ private field + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0616`. diff --git a/tests/ui/scalable-vectors/project-into-field.rs b/tests/ui/scalable-vectors/project-into-field.rs new file mode 100644 index 0000000000000..4b829de8f2280 --- /dev/null +++ b/tests/ui/scalable-vectors/project-into-field.rs @@ -0,0 +1,24 @@ +//@ add-minicore +//@ build-fail +//@ compile-flags: -Copt-level=0 --target=aarch64-unknown-linux-gnu +//@ dont-check-compiler-stderr +//@ failure-status: 101 +//@ ignore-backends: gcc +//@ needs-llvm-components: aarch64 +#![feature(no_core, rustc_attrs)] +#![no_std] +#![no_core] +#![crate_type = "lib"] +#![allow(internal_features)] + +extern crate minicore; + +#[rustc_scalable_vector(4)] +pub struct Sv(f32); + +#[target_feature(enable = "sve")] +pub fn field(x: Sv) -> f32 { + x.0 + //~^ ERROR broken MIR in Item + //~| ERROR Projecting into SIMD type Sv is banned by MCP#838 +} diff --git a/tests/ui/scalable-vectors/project-into-field.stderr b/tests/ui/scalable-vectors/project-into-field.stderr new file mode 100644 index 0000000000000..7a13c17646a96 --- /dev/null +++ b/tests/ui/scalable-vectors/project-into-field.stderr @@ -0,0 +1,8 @@ +error: cannot project into scalable vector type `Sv` + --> $DIR/project-into-field.rs:18:5 + | +LL | x.0 + | ^^^ + +error: aborting due to 1 previous error + From f6d18c60d14c1a69126e8c86f752012ab73822e1 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 10 Aug 2026 12:08:09 +0000 Subject: [PATCH 17/17] Use `remove_dir_all` for `./x clean` --- src/bootstrap/src/core/build_steps/clean.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 292885e99a34b..8219ffd5ec586 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -177,6 +177,16 @@ fn clean_default(build: &Build) { } fn rm_rf(path: &Path) { + match fs::remove_dir_all(path) { + Ok(()) => return, + // Already deleted, nothing for us to do. + Err(e) if e.kind() == ErrorKind::NotFound => return, + _ => {} + } + + // If remove_dir_all fails then retry. + // We do so manually so we can provide better diagnostics, + // e.g. pointing to the exact file that failed. match path.symlink_metadata() { Err(e) => { if e.kind() == ErrorKind::NotFound { @@ -235,7 +245,7 @@ where t!(fs::set_permissions(path, p)); f(path).unwrap_or_else(|e| { // Delete symlinked directories on Windows - if m.file_type().is_symlink() && path.is_dir() && fs::remove_dir(path).is_ok() { + if fs::remove_dir(path).is_ok() { return; } panic!("failed to {} {}: {}", desc, path.display(), e);