From 3c3027d59a4302240595bfa506f3133219c27bb1 Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Thu, 7 May 2026 18:57:42 +0900 Subject: [PATCH 1/9] Add `mut_restriction` feature --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b43dbad611a0..1b3ce2427c3c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -505,6 +505,7 @@ macro_rules! gate_all { gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); gate_all!(move_expr, "`move(expr)` syntax is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); + gate_all!(mut_restriction, "`mut` restrictions are experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8202f4c31c91..da45596d0b74 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -648,6 +648,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows `mut ref` and `mut ref mut` identifier patterns. (incomplete, mut_ref, "1.79.0", Some(123076)), + /// Allows `mut(crate) field: Type` restrictions. + (incomplete, mut_restriction, "CURRENT_RUSTC_VERSION", Some(105077)), /// Allows using `#[naked]` on `extern "Rust"` functions. (unstable, naked_functions_rustic_abi, "1.88.0", Some(138997)), /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72339efd0a13..7869731ef82f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1338,6 +1338,7 @@ must_use, mut_preserve_binding_mode_2024, mut_ref, + mut_restriction, mutable, naked, naked_asm, From 41c61112a7e5853c7181a00b5d68ad7c2d79c1f7 Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Thu, 7 May 2026 19:11:53 +0900 Subject: [PATCH 2/9] Introduce `mut` restrictions to AST --- compiler/rustc_ast/src/ast.rs | 8 ++++++++ compiler/rustc_ast/src/ast_traits.rs | 19 +++++++++++++++---- compiler/rustc_ast/src/visit.rs | 6 ++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fa29fb76c51a..af8ad425507c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3582,6 +3582,13 @@ pub struct ImplRestriction { pub tokens: Option, } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct MutRestriction { + pub kind: RestrictionKind, + pub span: Span, + pub tokens: Option, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum RestrictionKind { Unrestricted, @@ -3597,6 +3604,7 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, + pub mut_restriction: MutRestriction, pub safety: Safety, pub ident: Option, diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 73bfa0ba7ab6..74d8ae469b3d 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -8,8 +8,8 @@ use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, - FieldDef, ForeignItem, GenericParam, ImplRestriction, Item, NodeId, Param, Pat, PatField, Path, - Stmt, StmtKind, Ty, Variant, Visibility, WherePredicate, + FieldDef, ForeignItem, GenericParam, ImplRestriction, Item, MutRestriction, NodeId, Param, Pat, + PatField, Path, Stmt, StmtKind, Ty, Variant, Visibility, WherePredicate, }; /// A trait for AST nodes having an ID. @@ -108,7 +108,8 @@ fn tokens_mut(&mut self) -> Option<&mut Option> { Path, Ty, Visibility, - ImplRestriction + ImplRestriction, + MutRestriction, ); impl_has_tokens_none!( Arm, @@ -254,7 +255,17 @@ fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {} Variant, WherePredicate, ); -impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility, ImplRestriction); +impl_has_attrs_none!( + Attribute, + AttrItem, + Block, + Pat, + Path, + Ty, + Visibility, + ImplRestriction, + MutRestriction +); impl HasAttrs for Box { const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ed8c3787bfec..1e96d1d52f7e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -582,12 +582,14 @@ fn visit_ident(&mut self, Ident { name: _, span }: &$($lt)? $($mut)? Ident) -> S fn visit_generics(Generics); fn visit_inline_asm(InlineAsm); fn visit_inline_asm_sym(InlineAsmSym); + fn visit_impl_restriction(ImplRestriction); //fn visit_item(Item); fn visit_label(Label); fn visit_lifetime(Lifetime, _ctxt: LifetimeCtxt); fn visit_local(Local); fn visit_mac_call(MacCall); fn visit_macro_def(MacroDef); + fn visit_mut_restriction(MutRestriction); fn visit_param_bound(GenericBound, _ctxt: BoundKind); fn visit_param(Param); fn visit_pat_field(PatField); @@ -597,7 +599,6 @@ fn visit_ident(&mut self, Ident { name: _, span }: &$($lt)? $($mut)? Ident) -> S fn visit_poly_trait_ref(PolyTraitRef); fn visit_precise_capturing_arg(PreciseCapturingArg); fn visit_qself(QSelf); - fn visit_impl_restriction(ImplRestriction); fn visit_trait_ref(TraitRef); fn visit_ty_pat(TyPat); fn visit_ty(Ty); @@ -1106,12 +1107,14 @@ pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? pub fn walk_generics(Generics); pub fn walk_inline_asm(InlineAsm); pub fn walk_inline_asm_sym(InlineAsmSym); + pub fn walk_impl_restriction(ImplRestriction); //pub fn walk_item(Item); pub fn walk_label(Label); pub fn walk_lifetime(Lifetime); pub fn walk_local(Local); pub fn walk_mac(MacCall); pub fn walk_macro_def(MacroDef); + pub fn walk_mut_restriction(MutRestriction); pub fn walk_param_bound(GenericBound); pub fn walk_param(Param); pub fn walk_pat_field(PatField); @@ -1121,7 +1124,6 @@ pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? pub fn walk_poly_trait_ref(PolyTraitRef); pub fn walk_precise_capturing_arg(PreciseCapturingArg); pub fn walk_qself(QSelf); - pub fn walk_impl_restriction(ImplRestriction); pub fn walk_trait_ref(TraitRef); pub fn walk_ty_pat(TyPat); pub fn walk_ty(Ty); From c43fa7a8bb96298f9fe370a6a11303b13a86a576 Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Thu, 7 May 2026 20:17:43 +0900 Subject: [PATCH 3/9] Parse `mut` restrictions --- compiler/rustc_expand/src/placeholders.rs | 5 + compiler/rustc_parse/src/errors.rs | 20 ++++ compiler/rustc_parse/src/parser/item.rs | 20 +++- compiler/rustc_parse/src/parser/mod.rs | 125 ++++++++++++++-------- compiler/rustc_resolve/src/late.rs | 1 + 5 files changed, 124 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 2db18429a521..4044a414c5fe 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -186,6 +186,11 @@ fn mac_placeholder() -> Box { ty: ty(), vis, is_placeholder: true, + mut_restriction: ast::MutRestriction { + kind: ast::RestrictionKind::Unrestricted, + span: DUMMY_SP, + tokens: None, + }, safety: Safety::Default, default: None, }]), diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 12dc35d29ad9..a0b6321a6c43 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1287,6 +1287,26 @@ pub(crate) struct IncorrectImplRestriction { pub inner_str: String, } +#[derive(Diagnostic)] +#[diag("incorrect `mut` restriction")] +#[help( + "some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path" +)] +pub(crate) struct IncorrectMutRestriction { + #[primary_span] + #[suggestion( + "help: use `in` to restrict mutations to the path `{$inner_str}`", + code = "in {inner_str}", + applicability = "machine-applicable" + )] + pub span: Span, + pub inner_str: String, +} + #[derive(Diagnostic)] #[diag(" ... else {\"{\"} ... {\"}\"} is not allowed")] pub(crate) struct AssignmentElseNotAllowed { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 68fda3b86ddc..bed03800d3f4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2108,6 +2108,7 @@ pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec PResult<'a, ThinVec PResult<'a, Fie self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; + let mut_restriction = this.parse_mut_restriction()?; let safety = this.parse_unsafe_field(); - this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs, ident_span) - .map(|field| (field, Trailing::No, UsePreAttrPos::No)) + this.parse_single_struct_field( + adt_ty, + lo, + vis, + mut_restriction, + safety, + attrs, + ident_span, + ) + .map(|field| (field, Trailing::No, UsePreAttrPos::No)) }) } @@ -2176,11 +2187,12 @@ fn parse_single_struct_field( adt_ty: &str, lo: Span, vis: Visibility, + mut_restriction: MutRestriction, safety: Safety, attrs: AttrVec, ident_span: Span, ) -> PResult<'a, FieldDef> { - let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; + let a_var = self.parse_name_and_ty(adt_ty, lo, vis, mut_restriction, safety, attrs)?; match self.token.kind { token::Comma => { self.bump(); @@ -2299,6 +2311,7 @@ fn parse_name_and_ty( adt_ty: &str, lo: Span, vis: Visibility, + mut_restriction: MutRestriction, safety: Safety, attrs: AttrVec, ) -> PResult<'a, FieldDef> { @@ -2337,6 +2350,7 @@ fn parse_name_and_ty( ident: Some(name), vis, safety, + mut_restriction, id: DUMMY_NODE_ID, ty, default, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 850d64c8ecf4..a16ddb34b3c2 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -36,8 +36,8 @@ use rustc_ast::{ self as ast, AnonConst, AttrArgs, AttrId, BinOpKind, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, ImplRestriction, - MgcaDisambiguation, Mutability, Recovered, RestrictionKind, Safety, StrLit, Visibility, - VisibilityKind, + MgcaDisambiguation, MutRestriction, Mutability, Recovered, RestrictionKind, Safety, StrLit, + Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -51,8 +51,8 @@ use tracing::debug; use crate::errors::{ - self, IncorrectImplRestriction, IncorrectVisibilityRestriction, NonStringAbiLiteral, - TokenDescription, + self, IncorrectImplRestriction, IncorrectMutRestriction, IncorrectVisibilityRestriction, + NonStringAbiLiteral, TokenDescription, }; use crate::exp; @@ -297,6 +297,13 @@ fn none() -> SeqSep { } } +/// Whether parsing `impl` or `mut` restrictions. +#[derive(Clone, Copy, Debug)] +enum ParsingRestrictionKind { + Impl, + Mut, +} + #[derive(Debug)] pub enum FollowedByType { Yes, @@ -1550,37 +1557,9 @@ fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { /// Enforces the `impl_restriction` feature gate whenever an explicit restriction is encountered. fn parse_impl_restriction(&mut self) -> PResult<'a, ImplRestriction> { if self.eat_keyword(exp!(Impl)) { - let lo = self.prev_token.span; - // No units or tuples are allowed to follow `impl` here, so we can safely bump `(`. - self.expect(exp!(OpenParen))?; - if self.eat_keyword(exp!(In)) { - let path = self.parse_path(PathStyle::Mod)?; // `in path` - self.expect(exp!(CloseParen))?; // `)` - let restriction = RestrictionKind::Restricted { - path: Box::new(path), - id: ast::DUMMY_NODE_ID, - shorthand: false, - }; - let span = lo.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::impl_restriction, span); - return Ok(ImplRestriction { kind: restriction, span, tokens: None }); - } else if self.look_ahead(1, |t| t == &token::CloseParen) - && self.is_keyword_ahead(0, &[kw::Crate, kw::Super, kw::SelfLower]) - { - let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` - self.expect(exp!(CloseParen))?; // `)` - let restriction = RestrictionKind::Restricted { - path: Box::new(path), - id: ast::DUMMY_NODE_ID, - shorthand: true, - }; - let span = lo.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::impl_restriction, span); - return Ok(ImplRestriction { kind: restriction, span, tokens: None }); - } else { - self.recover_incorrect_impl_restriction(lo)?; - // Emit diagnostic, but continue with no impl restriction. - } + let (kind, span, gated_span) = self.parse_restriction(ParsingRestrictionKind::Impl)?; + self.psess.gated_spans.gate(sym::impl_restriction, gated_span); + return Ok(ImplRestriction { kind, span, tokens: None }); } Ok(ImplRestriction { kind: RestrictionKind::Unrestricted, @@ -1589,15 +1568,73 @@ fn parse_impl_restriction(&mut self) -> PResult<'a, ImplRestriction> { }) } - /// Recovery for e.g. `impl(something) trait` - fn recover_incorrect_impl_restriction(&mut self, lo: Span) -> PResult<'a, ()> { - let path = self.parse_path(PathStyle::Mod)?; - self.expect(exp!(CloseParen))?; // `)` - let path_str = pprust::path_to_string(&path); - self.dcx().emit_err(IncorrectImplRestriction { span: path.span, inner_str: path_str }); - let end = self.prev_token.span; - self.psess.gated_spans.gate(sym::impl_restriction, lo.to(end)); - Ok(()) + /// Parses an optional `mut` restriction. + /// Enforces the `mut_restriction` feature gate whenever an explicit restriction is encountered. + fn parse_mut_restriction(&mut self) -> PResult<'a, MutRestriction> { + if self.eat_keyword(exp!(Mut)) { + let (kind, span, gated_span) = self.parse_restriction(ParsingRestrictionKind::Mut)?; + self.psess.gated_spans.gate(sym::mut_restriction, gated_span); + return Ok(MutRestriction { kind, span, tokens: None }); + } + Ok(MutRestriction { + kind: RestrictionKind::Unrestricted, + span: self.token.span.shrink_to_lo(), + tokens: None, + }) + } + + /// Parses `impl` or `mut` restrictions. + /// Returns the parsed restriction and its span, as well as the gated span. + fn parse_restriction( + &mut self, + restriction_kind: ParsingRestrictionKind, + ) -> PResult<'a, (RestrictionKind, Span, Span)> { + let lo = self.prev_token.span; + // No units or tuples are allowed to follow `impl` or `mut` here, so we can safely bump `(`. + self.expect(exp!(OpenParen))?; + if self.eat_keyword(exp!(In)) { + let path = self.parse_path(PathStyle::Mod)?; // `in path` + self.expect(exp!(CloseParen))?; // `)` + let restriction = RestrictionKind::Restricted { + path: Box::new(path), + id: ast::DUMMY_NODE_ID, + shorthand: false, + }; + let span = lo.to(self.prev_token.span); + Ok((restriction, span, span)) + } else if self.look_ahead(1, |t| t == &token::CloseParen) + && self.is_keyword_ahead(0, &[kw::Crate, kw::Super, kw::SelfLower]) + { + let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` + self.expect(exp!(CloseParen))?; // `)` + let restriction = RestrictionKind::Restricted { + path: Box::new(path), + id: ast::DUMMY_NODE_ID, + shorthand: true, + }; + let span = lo.to(self.prev_token.span); + Ok((restriction, span, span)) + } else { + // Emit diagnostic, but continue with no restrictions. + // Recovery for `impl(something) trait` or `mut (something) field`. + let path = self.parse_path(PathStyle::Mod)?; + self.expect(exp!(CloseParen))?; // `)` + let path_str = pprust::path_to_string(&path); + let end = self.prev_token.span; + match restriction_kind { + ParsingRestrictionKind::Impl => { + self.dcx().emit_err(IncorrectImplRestriction { + span: path.span, + inner_str: path_str, + }); + } + ParsingRestrictionKind::Mut => { + self.dcx() + .emit_err(IncorrectMutRestriction { span: path.span, inner_str: path_str }); + } + } + Ok((RestrictionKind::Unrestricted, self.token.span.shrink_to_lo(), lo.to(end))) + } } /// Parses `extern string_literal?`. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 21b36f1934c3..fc8578e30292 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1479,6 +1479,7 @@ fn visit_field_def(&mut self, f: &'ast FieldDef) { ty, is_placeholder: _, default, + mut_restriction: _, safety: _, } = f; walk_list!(self, visit_attribute, attrs); From a8a6aa8f59bb94c56aff50a3fd5a33f78424acc2 Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Wed, 20 May 2026 19:54:56 +0900 Subject: [PATCH 4/9] Pretty print `mut` restrictions --- compiler/rustc_ast_pretty/src/pprust/mod.rs | 4 ++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 4 ++++ .../rustc_ast_pretty/src/pprust/state/item.rs | 16 ++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 25b398b84924..19bd8fd11bf2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -84,6 +84,10 @@ pub fn impl_restriction_to_string(r: &ast::ImplRestriction) -> String { State::new().impl_restriction_to_string(r) } +pub fn mut_restriction_to_string(r: &ast::MutRestriction) -> String { + State::new().mut_restriction_to_string(r) +} + pub fn meta_list_item_to_string(li: &ast::MetaItemInner) -> String { State::new().meta_list_item_to_string(li) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f46ce8fd7686..8b2da2acaa52 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1153,6 +1153,10 @@ fn impl_restriction_to_string(&self, r: &ast::ImplRestriction) -> String { Self::to_string(|s| s.print_impl_restriction(r)) } + fn mut_restriction_to_string(&self, r: &ast::MutRestriction) -> String { + Self::to_string(|s| s.print_mut_restriction(r)) + } + fn block_to_string(&self, blk: &ast::Block) -> String { Self::to_string(|s| { let (cb, ib) = s.head(""); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index b3a8f5d8cac3..820c49cd0612 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -511,6 +511,20 @@ pub(crate) fn print_impl_restriction(&mut self, impl_restriction: &ast::ImplRest } } + pub(crate) fn print_mut_restriction(&mut self, mut_restriction: &ast::MutRestriction) { + match &mut_restriction.kind { + ast::RestrictionKind::Restricted { path, shorthand, .. } => { + let path = Self::to_string(|s| s.print_path(path, false, 0)); + if *shorthand { + self.word_nbsp(format!("mut({path})")) + } else { + self.word_nbsp(format!("mut(in {path})")) + } + } + ast::RestrictionKind::Unrestricted => {} + } + } + fn print_defaultness(&mut self, defaultness: ast::Defaultness) { if let ast::Defaultness::Default(_) = defaultness { self.word_nbsp("default"); @@ -537,6 +551,7 @@ fn print_struct( s.maybe_print_comment(field.span.lo()); s.print_outer_attributes(&field.attrs); s.print_visibility(&field.vis); + s.print_mut_restriction(&field.mut_restriction); s.print_type(&field.ty) }); self.pclose(); @@ -562,6 +577,7 @@ fn print_struct( self.maybe_print_comment(field.span.lo()); self.print_outer_attributes(&field.attrs); self.print_visibility(&field.vis); + self.print_mut_restriction(&field.mut_restriction); self.print_ident(field.ident.unwrap()); self.word_nbsp(":"); self.print_type(&field.ty); From 9aa5a17cee9384083b02db8b322848958fed93ae Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Wed, 20 May 2026 20:02:16 +0900 Subject: [PATCH 5/9] Add `eq_mut_restriction` to clippy_utils --- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 7b408471574f..c41ffad8431b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -726,6 +726,7 @@ pub fn eq_struct_field(l: &FieldDef, r: &FieldDef) -> bool { l.is_placeholder == r.is_placeholder && over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) + && eq_mut_restriction(&l.mut_restriction, &r.mut_restriction) && both(l.ident.as_ref(), r.ident.as_ref(), |l, r| eq_id(*l, *r)) && eq_ty(&l.ty, &r.ty) } @@ -846,6 +847,10 @@ pub fn eq_impl_restriction(l: &ImplRestriction, r: &ImplRestriction) -> bool { eq_restriction_kind(&l.kind, &r.kind) } +pub fn eq_mut_restriction(l: &MutRestriction, r: &MutRestriction) -> bool { + eq_restriction_kind(&l.kind, &r.kind) +} + fn eq_restriction_kind(l: &RestrictionKind, r: &RestrictionKind) -> bool { match (l, r) { (RestrictionKind::Unrestricted, RestrictionKind::Unrestricted) => true, From dbb7b811ee1d2e89f815869e1f8189eb9874832f Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Wed, 20 May 2026 22:38:39 +0900 Subject: [PATCH 6/9] rustfmt `mut` restriction --- src/tools/rustfmt/src/items.rs | 5 +- src/tools/rustfmt/src/utils.rs | 11 +- .../rustfmt/tests/source/mut-restriction.rs | 108 ++++++++++++++++++ .../rustfmt/tests/target/mut-restriction.rs | 35 ++++++ 4 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 src/tools/rustfmt/tests/source/mut-restriction.rs create mode 100644 src/tools/rustfmt/tests/target/mut-restriction.rs diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 32f71703e019..6757381f8356 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1889,15 +1889,16 @@ pub(crate) fn rewrite_struct_field_prefix( field: &ast::FieldDef, ) -> RewriteResult { let vis = format_visibility(context, &field.vis); + let mut_restriction = format_mut_restriction(context, &field.mut_restriction); let safety = format_safety(field.safety); let type_annotation_spacing = type_annotation_spacing(context.config); Ok(match field.ident { Some(name) => format!( - "{vis}{safety}{}{}:", + "{vis}{mut_restriction}{safety}{}{}:", rewrite_ident(context, name), type_annotation_spacing.0 ), - None => format!("{vis}{safety}"), + None => format!("{vis}{mut_restriction}{safety}"), }) } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index de72c9ce14bc..3ec8a36eb5a8 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -2,8 +2,8 @@ use rustc_ast::YieldKind; use rustc_ast::ast::{ - self, Attribute, ImplRestriction, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, - RestrictionKind, Visibility, VisibilityKind, + self, Attribute, ImplRestriction, MetaItem, MetaItemInner, MetaItemKind, MutRestriction, + NodeId, Path, RestrictionKind, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol}; @@ -81,6 +81,13 @@ pub(crate) fn format_impl_restriction( format_restriction("impl", context, &impl_restriction.kind) } +pub(crate) fn format_mut_restriction( + context: &RewriteContext<'_>, + mut_restriction: &MutRestriction, +) -> String { + format_restriction("mut", context, &mut_restriction.kind) +} + fn format_restriction( kw: &'static str, context: &RewriteContext<'_>, diff --git a/src/tools/rustfmt/tests/source/mut-restriction.rs b/src/tools/rustfmt/tests/source/mut-restriction.rs new file mode 100644 index 000000000000..990cbd476bfa --- /dev/null +++ b/src/tools/rustfmt/tests/source/mut-restriction.rs @@ -0,0 +1,108 @@ +#![feature(mut_restrictions, unsafe_fields)] + +struct FooS { + pub + mut(crate) + field1: (), + pub + mut(crate + ) + unsafe + field2: (), +} + +struct BazS { + pub + mut ( in foo + :: + bar ) + field1: (), + pub + mut( + in foo + :: + bar + ) unsafe + field2: (), +} + +struct FooS2( + pub + mut(crate) + (), +); + +struct BazS2( + pub + mut ( in foo + :: + bar ) + (), +); + +enum Enum { + Foo { + pub(crate) mut(self) + field1: (), + pub + mut(self + ) + unsafe + field2: (), + }, + Baz { + pub + mut ( in foo + :: + bar ) + field1: (), + pub( + crate + ) + mut( + in foo + :: + bar + ) unsafe field2: (), + }, + FooT( + pub(crate) + mut(self) + (), + ), + BazT( + pub(crate + ) + mut ( in foo + :: + bar ) + (), + ), + +} + +union Union { + pub + mut(crate) + field1: (), + pub(crate + ) + mut ( in foo + :: + bar ) + field2: (), + pub + mut(crate + ) + unsafe + field3: (), + pub( + crate + ) + mut( + in foo + :: + bar + ) unsafe + field4: (), +} diff --git a/src/tools/rustfmt/tests/target/mut-restriction.rs b/src/tools/rustfmt/tests/target/mut-restriction.rs new file mode 100644 index 000000000000..3ac5d6ae912d --- /dev/null +++ b/src/tools/rustfmt/tests/target/mut-restriction.rs @@ -0,0 +1,35 @@ +#![feature(mut_restrictions, unsafe_fields)] + +struct FooS { + pub mut(crate) field1: (), + pub mut(crate) unsafe field2: (), +} + +struct BazS { + pub mut(in foo::bar) field1: (), + pub mut(in foo::bar) unsafe field2: (), +} + +struct FooS2(pub mut(crate) ()); + +struct BazS2(pub mut(in foo::bar) ()); + +enum Enum { + Foo { + pub(crate) mut(self) field1: (), + pub mut(self) unsafe field2: (), + }, + Baz { + pub mut(in foo::bar) field1: (), + pub(crate) mut(in foo::bar) unsafe field2: (), + }, + FooT(pub(crate) mut(self) ()), + BazT(pub(crate) mut(in foo::bar) ()), +} + +union Union { + pub mut(crate) field1: (), + pub(crate) mut(in foo::bar) field2: (), + pub mut(crate) unsafe field3: (), + pub(crate) mut(in foo::bar) unsafe field4: (), +} From cb3173473c0a92c09498b94f6067fb653e11bf29 Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Thu, 7 May 2026 21:22:54 +0900 Subject: [PATCH 7/9] Add UI tests --- tests/ui/README.md | 3 + .../feature-gate-mut-restriction.rs | 104 +++++ ...e-gate-mut-restriction.without_gate.stderr | 403 ++++++++++++++++++ .../recover-incorrect-mut-restriction.rs | 25 ++ .../recover-incorrect-mut-restriction.stderr | 130 ++++++ 5 files changed, 665 insertions(+) create mode 100644 tests/ui/mut-restriction/feature-gate-mut-restriction.rs create mode 100644 tests/ui/mut-restriction/feature-gate-mut-restriction.without_gate.stderr create mode 100644 tests/ui/mut-restriction/recover-incorrect-mut-restriction.rs create mode 100644 tests/ui/mut-restriction/recover-incorrect-mut-restriction.stderr diff --git a/tests/ui/README.md b/tests/ui/README.md index 39402f78bb5e..dbffa54468d5 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -943,6 +943,9 @@ Tests on moves (destructive moves). Broad category of tests on mutability, such as the `mut` keyword, borrowing a value as both immutable and mutable (and the associated error), or adding mutable references to `const` declarations. +## `tests/ui/mut-restriction/` +Tests for `#![feature(mut_restriction)]`. See [Tracking issue for restrictions #105077](https://github.com/rust-lang/rust/issues/105077). + ## `tests/ui/namespace/` Contains a single test. It imports a massive amount of very similar types from a crate, then attempts various permutations of their namespace paths, checking for errors or the lackthereof. diff --git a/tests/ui/mut-restriction/feature-gate-mut-restriction.rs b/tests/ui/mut-restriction/feature-gate-mut-restriction.rs new file mode 100644 index 000000000000..3ec3345cf72a --- /dev/null +++ b/tests/ui/mut-restriction/feature-gate-mut-restriction.rs @@ -0,0 +1,104 @@ +//@ revisions: with_gate without_gate +//@[with_gate] check-pass + +#![cfg_attr(with_gate, feature(mut_restriction))] +#![feature(unsafe_fields)] + +pub struct Foo { + pub mut(crate) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(self) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental +} + +pub struct TupFoo(pub mut(crate) i32, pub mut(self) i32); //[without_gate]~ ERROR `mut` restrictions are experimental +//[without_gate]~^ ERROR `mut` restrictions are experimental + +pub enum EnumFoo { + Var { + mut(self) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + mut(crate) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + }, + Tup(mut(self) i32, mut(crate) i32), //[without_gate]~ ERROR `mut` restrictions are experimental + //[without_gate]~^ ERROR `mut` restrictions are experimental +} + +pub union UnionFoo { + pub mut(self) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(crate) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental +} + +pub mod foo { + pub struct Bar { + pub mut(super) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(in crate::foo) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + } + + pub struct TupBar(pub mut(super) i32, pub mut(in crate::foo) i32); //[without_gate]~ ERROR `mut` restrictions are experimental + //[without_gate]~^ ERROR `mut` restrictions are experimental + + pub enum EnumBar { + Var { + mut(in crate::foo) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + mut(super) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + }, + Tup(mut(in crate::foo) i32, mut(super) i32), //[without_gate]~ ERROR `mut` restrictions are experimental + //[without_gate]~^ ERROR `mut` restrictions are experimental + } + + pub union UnionBar { + pub mut(in crate::foo) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(super) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + } +} + +#[cfg(false)] +pub struct Baz { + pub mut(crate) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(self) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental +} + +#[cfg(false)] +pub struct TupBaz(pub mut(crate) i32, pub mut(self) i32); //[without_gate]~ ERROR `mut` restrictions are experimental +//[without_gate]~^ ERROR `mut` restrictions are experimental + +#[cfg(false)] +pub enum EnumBaz { + Var { + mut(self) x: i32, //[without_gate]~ ERROR `mut` restrictions + mut(crate) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + }, + Tup(mut(self) i32, mut(crate) i32), //[without_gate]~ ERROR `mut` restrictions are experimental + //[without_gate]~^ ERROR `mut` restrictions are experimental +} + +#[cfg(false)] +pub union UnionBaz { + pub mut(self) x: i32, //[without_gate]~ ERROR `mut` + pub mut(crate) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental +} + +#[cfg(false)] +pub mod bar { + pub struct Bar { + pub mut(super) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(in crate::foo) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + } + + pub struct TupBar(pub mut(super) i32, pub mut(in crate::foo) i32); //[without_gate]~ ERROR `mut` restrictions are experimental + //[without_gate]~^ ERROR `mut` restrictions are experimental + + pub enum EnumBar { + Var { + mut(in crate::foo) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + mut(super) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + }, + Tup(mut(in crate::foo) i32, mut(super) i32), //[without_gate]~ ERROR `mut` restrictions are experimental + //[without_gate]~^ ERROR `mut` restrictions are experimental + } + + pub union UnionBar { + pub mut(in crate::foo) x: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + pub mut(super) unsafe y: i32, //[without_gate]~ ERROR `mut` restrictions are experimental + } +} + +fn main() {} diff --git a/tests/ui/mut-restriction/feature-gate-mut-restriction.without_gate.stderr b/tests/ui/mut-restriction/feature-gate-mut-restriction.without_gate.stderr new file mode 100644 index 000000000000..8f6193c03055 --- /dev/null +++ b/tests/ui/mut-restriction/feature-gate-mut-restriction.without_gate.stderr @@ -0,0 +1,403 @@ +error[E0658]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:8:9 + | +LL | pub mut(crate) x: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:9:9 + | +LL | pub mut(self) unsafe y: i32, + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:12:23 + | +LL | pub struct TupFoo(pub mut(crate) i32, pub mut(self) i32); + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:12:43 + | +LL | pub struct TupFoo(pub mut(crate) i32, pub mut(self) i32); + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:17:9 + | +LL | mut(self) x: i32, + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:18:9 + | +LL | mut(crate) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:20:9 + | +LL | Tup(mut(self) i32, mut(crate) i32), + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:20:24 + | +LL | Tup(mut(self) i32, mut(crate) i32), + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:25:9 + | +LL | pub mut(self) x: i32, + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:26:9 + | +LL | pub mut(crate) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:31:13 + | +LL | pub mut(super) x: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:32:13 + | +LL | pub mut(in crate::foo) unsafe y: i32, + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:35:27 + | +LL | pub struct TupBar(pub mut(super) i32, pub mut(in crate::foo) i32); + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:35:47 + | +LL | pub struct TupBar(pub mut(super) i32, pub mut(in crate::foo) i32); + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:40:13 + | +LL | mut(in crate::foo) x: i32, + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:41:13 + | +LL | mut(super) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:43:13 + | +LL | Tup(mut(in crate::foo) i32, mut(super) i32), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:43:37 + | +LL | Tup(mut(in crate::foo) i32, mut(super) i32), + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:48:13 + | +LL | pub mut(in crate::foo) x: i32, + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:49:13 + | +LL | pub mut(super) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:55:9 + | +LL | pub mut(crate) x: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:56:9 + | +LL | pub mut(self) unsafe y: i32, + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:60:23 + | +LL | pub struct TupBaz(pub mut(crate) i32, pub mut(self) i32); + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:60:43 + | +LL | pub struct TupBaz(pub mut(crate) i32, pub mut(self) i32); + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:66:9 + | +LL | mut(self) x: i32, + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:67:9 + | +LL | mut(crate) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:69:9 + | +LL | Tup(mut(self) i32, mut(crate) i32), + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:69:24 + | +LL | Tup(mut(self) i32, mut(crate) i32), + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:75:9 + | +LL | pub mut(self) x: i32, + | ^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:76:9 + | +LL | pub mut(crate) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:82:13 + | +LL | pub mut(super) x: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:83:13 + | +LL | pub mut(in crate::foo) unsafe y: i32, + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:86:27 + | +LL | pub struct TupBar(pub mut(super) i32, pub mut(in crate::foo) i32); + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:86:47 + | +LL | pub struct TupBar(pub mut(super) i32, pub mut(in crate::foo) i32); + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:91:13 + | +LL | mut(in crate::foo) x: i32, + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:92:13 + | +LL | mut(super) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:94:13 + | +LL | Tup(mut(in crate::foo) i32, mut(super) i32), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:94:37 + | +LL | Tup(mut(in crate::foo) i32, mut(super) i32), + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:99:13 + | +LL | pub mut(in crate::foo) x: i32, + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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]: `mut` restrictions are experimental + --> $DIR/feature-gate-mut-restriction.rs:100:13 + | +LL | pub mut(super) unsafe y: i32, + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(mut_restriction)]` 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 40 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/mut-restriction/recover-incorrect-mut-restriction.rs b/tests/ui/mut-restriction/recover-incorrect-mut-restriction.rs new file mode 100644 index 000000000000..5a996b0c1d46 --- /dev/null +++ b/tests/ui/mut-restriction/recover-incorrect-mut-restriction.rs @@ -0,0 +1,25 @@ +#![feature(mut_restriction, unsafe_fields)] + +pub mod foo { + pub struct Foo { + pub mut(crate::foo) x: i32, //~ ERROR incorrect `mut` restriction + pub mut(crate::foo) unsafe y: i32, //~ ERROR incorrect `mut` restriction + } + + pub struct TupFoo(pub mut(crate::foo) i32); //~ ERROR incorrect `mut` restriction + + pub enum EnumFoo { + Var { + mut(crate::foo) x: i32, //~ ERROR incorrect `mut` restriction + mut(crate::foo) unsafe y: i32 //~ ERROR incorrect `mut` restriction + }, + Tup(mut(crate::foo) i32), //~ ERROR incorrect `mut` restriction + } + + pub union UnionFoo { + pub mut(crate::foo) x: i32, //~ ERROR incorrect `mut` restriction + pub mut(crate::foo) unsafe y: i32, //~ ERROR incorrect `mut` restriction + } +} + +fn main() {} diff --git a/tests/ui/mut-restriction/recover-incorrect-mut-restriction.stderr b/tests/ui/mut-restriction/recover-incorrect-mut-restriction.stderr new file mode 100644 index 000000000000..50e5216a1628 --- /dev/null +++ b/tests/ui/mut-restriction/recover-incorrect-mut-restriction.stderr @@ -0,0 +1,130 @@ +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:5:17 + | +LL | pub mut(crate::foo) x: i32, + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | pub mut(in crate::foo) x: i32, + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:6:17 + | +LL | pub mut(crate::foo) unsafe y: i32, + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | pub mut(in crate::foo) unsafe y: i32, + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:9:31 + | +LL | pub struct TupFoo(pub mut(crate::foo) i32); + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | pub struct TupFoo(pub mut(in crate::foo) i32); + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:13:17 + | +LL | mut(crate::foo) x: i32, + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | mut(in crate::foo) x: i32, + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:14:17 + | +LL | mut(crate::foo) unsafe y: i32 + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | mut(in crate::foo) unsafe y: i32 + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:16:17 + | +LL | Tup(mut(crate::foo) i32), + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | Tup(mut(in crate::foo) i32), + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:20:17 + | +LL | pub mut(crate::foo) x: i32, + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | pub mut(in crate::foo) x: i32, + | ++ + +error: incorrect `mut` restriction + --> $DIR/recover-incorrect-mut-restriction.rs:21:17 + | +LL | pub mut(crate::foo) unsafe y: i32, + | ^^^^^^^^^^ + | + = help: some possible `mut` restrictions are: + `mut(crate)`: can only be mutated in the current crate + `mut(super)`: can only be mutated in the parent module + `mut(self)`: can only be mutated in current module + `mut(in path::to::module)`: can only be mutated in the specified path +help: help: use `in` to restrict mutations to the path `crate::foo` + | +LL | pub mut(in crate::foo) unsafe y: i32, + | ++ + +error: aborting due to 8 previous errors + From d3bb7198e7d207f6adf6f57c9d13e1f20d4b5d1e Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Wed, 20 May 2026 19:46:08 +0900 Subject: [PATCH 8/9] Add `stringify!` tests --- tests/ui/macros/stringify.rs | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index fec991ec95b7..fde68f8f760d 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -10,14 +10,17 @@ #![feature(const_trait_impl)] #![feature(coroutines)] #![feature(decl_macro)] +#![feature(impl_restriction)] #![feature(macro_guard_matcher)] #![feature(more_qualified_paths)] #![feature(move_expr)] +#![feature(mut_restriction)] #![feature(never_patterns)] #![feature(specialization)] #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(unsafe_fields)] #![deny(unused_macros)] // These macros force the use of AST pretty-printing by converting the input to @@ -924,6 +927,65 @@ fn test_impl_restriction() { ); } +#[test] +fn test_mut_restriction() { + assert_eq!( + stringify!(pub struct Foo { pub mut(crate) x: u8, pub mut(self) unsafe y: u8 }), + "pub struct Foo { pub mut(crate) x: u8, pub mut(self) unsafe y: u8 }" + ); + assert_eq!( + stringify!(pub struct Foo { pub mut(super) x: u8, pub mut(in path::to) unsafe y: u8 }), + "pub struct Foo { pub mut(super) x: u8, pub mut(in path::to) unsafe y: u8 }" + ); + assert_eq!( + stringify!(pub struct Foo { pub mut(in crate::path::to) x: u8 }), + "pub struct Foo { pub mut(in crate::path::to) x: u8 }" + ); + + assert_eq!( + stringify!(pub struct Foo(pub mut(crate) u8, pub mut(self) u8, pub mut(super) u8)), + "pub struct Foo(pub mut(crate) u8, pub mut(self) u8, pub mut(super) u8)" + ); + assert_eq!( + stringify!(pub struct Foo(pub mut(in path::to) u8, pub mut(in crate::path::to) u8)), + "pub struct Foo(pub mut(in path::to) u8, pub mut(in crate::path::to) u8)" + ); + + assert_eq!( + stringify!(pub enum Foo { Var{ pub mut(crate) x: u8, pub mut(self) unsafe y: u8 } }), + "pub enum Foo { Var{ pub mut(crate) x: u8, pub mut(self) unsafe y: u8 } }" + ); + assert_eq!( + stringify!(pub enum Foo { Var{ pub mut(super) x: u8, pub mut(in path::to) y: u8 } }), + "pub enum Foo { Var{ pub mut(super) x: u8, pub mut(in path::to) y: u8 } }" + ); + assert_eq!( + stringify!(pub enum Foo { Var{ pub mut(in crate::path::to) x: u8 } }), + "pub enum Foo { Var{ pub mut(in crate::path::to) x: u8 } }" + ); + assert_eq!( + stringify!(pub enum Foo { Tup(pub mut(crate) u8, pub mut(self) u8, pub mut(super) u8) }), + "pub enum Foo { Tup(pub mut(crate) u8, pub mut(self) u8, pub mut(super) u8) }" + ); + assert_eq!( + stringify!(pub enum Foo { Tup(pub mut(in path::to) u8, pub mut(in crate::path::to) u8) }), + "pub enum Foo { Tup(pub mut(in path::to) u8, pub mut(in crate::path::to) u8) }" + ); + + assert_eq!( + stringify!(pub union Foo { x: pub mut(crate) u8, y: pub mut(self) unsafe u8 }), + "pub union Foo { x: pub mut(crate) u8, y: pub mut(self) unsafe u8 }" + ); + assert_eq!( + stringify!(pub union Foo { x: pub mut(super) u8, y: pub mut(in path::to) unsafe u8 }), + "pub union Foo { x: pub mut(super) u8, y: pub mut(in path::to) unsafe u8 }" + ); + assert_eq!( + stringify!(pub union Foo { x: pub mut(in crate::path::to) u8 }), + "pub union Foo { x: pub mut(in crate::path::to) u8 }" + ); +} + #[test] fn test_punct() { // For all these cases, we should preserve spaces between the tokens. From 572a2e4177edf3e83d725f15887835da39d43fd2 Mon Sep 17 00:00:00 2001 From: CoCo-Japan-pan <115922543+CoCo-Japan-pan@users.noreply.github.com> Date: Wed, 20 May 2026 19:48:07 +0900 Subject: [PATCH 9/9] Bless UI test for input-stats.rs --- tests/ui/stats/input-stats.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index a91a15bc63df..b4d8277a46c0 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -33,8 +33,8 @@ ast-stats - Trait 352 (NN.N%) 4 ast-stats AssocItem 320 (NN.N%) 4 80 ast-stats - Fn 160 (NN.N%) 2 ast-stats - Type 160 (NN.N%) 2 +ast-stats FieldDef 272 (NN.N%) 2 136 ast-stats Variant 208 (NN.N%) 2 104 -ast-stats FieldDef 208 (NN.N%) 2 104 ast-stats Block 192 (NN.N%) 6 32 ast-stats Stmt 160 (NN.N%) 5 32 ast-stats - Let 32 (NN.N%) 1 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_560 127 +ast-stats Total 7_624 127 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats