Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
af52084
Lower `mut` restriction to `ty::FieldDef`
CoCo-Japan-pan Jul 24, 2026
feac214
bless thir-print
CoCo-Japan-pan Jul 25, 2026
0cfc42a
Emit error in mutation of restricted field
CoCo-Japan-pan Jul 24, 2026
0e42a37
Add UI tests for mutation of restricted fields
CoCo-Japan-pan Jul 24, 2026
f416665
Emit error in struct expressions with restricted fields
CoCo-Japan-pan Jul 25, 2026
c2b967d
Add UI tests for struct expressions with restricted fields
CoCo-Japan-pan Jul 25, 2026
c31baa9
use match to be exhaustive
CoCo-Japan-pan Jul 26, 2026
e53106b
rename to mutating_span
CoCo-Japan-pan Jul 26, 2026
56e2afd
remove 2015 edition from UI tests of field mutations
CoCo-Japan-pan Jul 26, 2026
9cd7eef
remove 2015 edition from UI tests of struct expressions
CoCo-Japan-pan Jul 26, 2026
d638a6a
Add an inline comment and UI tests for array/slice fields
CoCo-Japan-pan Jul 26, 2026
bf48600
Add an inline comment explaining why we only check for `ty::Adt` and …
CoCo-Japan-pan Jul 26, 2026
237aac0
Add an immutatble reference test for struct
CoCo-Japan-pan Jul 28, 2026
43c4f30
Add an immutable reference test for enum
CoCo-Japan-pan Jul 28, 2026
2347351
Add tests for inline assembly
CoCo-Japan-pan Jul 28, 2026
97bfaa7
Use `_` in `mut` restriction tests
CoCo-Japan-pan Jul 28, 2026
e6f4b35
Add tests using ref
CoCo-Japan-pan Jul 28, 2026
c5cf7e1
Run CheckMutRestriction only when there are no errors
CoCo-Japan-pan Jul 29, 2026
6b937d0
Seperate the inline asm test
CoCo-Japan-pan Jul 29, 2026
673a9db
Add field name to restricted field mutation error diagnostic
CoCo-Japan-pan Jul 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,12 @@ fn lower_variant<'tcx>(
did: f.def_id.to_def_id(),
name: f.ident.name,
vis: tcx.visibility(f.def_id),
mut_restriction: match f.mut_restriction.kind {
hir::RestrictionKind::Unrestricted => ty::RestrictionKind::Unrestricted,
hir::RestrictionKind::Restricted(path) => {
ty::RestrictionKind::Restricted(path.res, f.mut_restriction.span)
}
},
safety: f.safety,
value: f.default.map(|v| v.def_id.to_def_id()),
})
Expand Down Expand Up @@ -926,19 +932,16 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
false,
is_auto == hir::IsAuto::Yes,
safety,
if let hir::RestrictionKind::Restricted(path) = impl_restriction.kind {
ty::trait_def::ImplRestrictionKind::Restricted(path.res, impl_restriction.span)
} else {
ty::trait_def::ImplRestrictionKind::Unrestricted
match impl_restriction.kind {
hir::RestrictionKind::Restricted(path) => {
ty::RestrictionKind::Restricted(path.res, impl_restriction.span)
}
hir::RestrictionKind::Unrestricted => ty::RestrictionKind::Unrestricted,
},
),
hir::ItemKind::TraitAlias(constness, ..) => (
constness,
true,
false,
hir::Safety::Safe,
ty::trait_def::ImplRestrictionKind::Unrestricted,
),
hir::ItemKind::TraitAlias(constness, ..) => {
(constness, true, false, hir::Safety::Safe, ty::RestrictionKind::Unrestricted)
}
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
};

Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use rustc_hir::{CanonicalSymbols, Safety};
use rustc_index::Idx;
use rustc_middle::middle::lib_features::LibFeatures;
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::ty::Visibility;
use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::{RestrictionKind, Visibility};
use rustc_middle::{bug, implement_ty_decoder};
use rustc_proc_macro::bridge::client::Client as ProcMacroClient;
use rustc_serialize::opaque::MemDecoder;
Expand Down Expand Up @@ -1144,6 +1144,7 @@ impl CrateMetadata {
did,
name: self.item_name(did.index),
vis: self.get_visibility(tcx, did.index),
mut_restriction: self.get_mut_restriction(tcx, did.index),
safety: self.get_safety(did.index),
value: self.get_default_field(tcx, did.index),
})
Expand Down Expand Up @@ -1206,6 +1207,15 @@ impl CrateMetadata {
.map_id(|index| ModId::new_unchecked(self.local_def_id(index)))
}

fn get_mut_restriction(&self, tcx: TyCtxt<'_>, id: DefIndex) -> RestrictionKind {
self.root
.tables
.mut_restriction
.get(self, id)
.unwrap_or_else(|| self.missing("mut_restriction", id))
.decode((self, tcx))
}

fn get_safety(&self, id: DefIndex) -> Safety {
self.root.tables.safety.get(self, id)
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {

for field in &variant.fields {
self.tables.safety.set(field.did.index, field.safety);
record!(
self.tables.mut_restriction[field.did] <- field.mut_restriction
);
}

if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ define_tables! {
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<DefIdMap<Vec<DefId>>>>,
live_args_for_alias_from_outlives_bounds: Table<DefIndex, LazyValue<Option<ty::EarlyBinder<'static, Vec<ty::GenericArg<'static>>>>>>,
args_known_to_outlive_alias_params: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Vec<(ty::Region<'static>, Vec<ty::GenericArg<'static>>)>>>>,
mut_restriction: Table<DefIndex, LazyValue<ty::RestrictionKind>>,
}

#[derive(TyEncodable, TyDecodable)]
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/parameterized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ trivially_parameterized_over_tcx! {
rustc_middle::ty::Generics,
rustc_middle::ty::ImplTraitInTraitData,
rustc_middle::ty::IntrinsicDef,
rustc_middle::ty::RestrictionKind,
rustc_middle::ty::TraitDef,
rustc_middle::ty::Variance,
rustc_middle::ty::Visibility<DefIndex>,
Expand Down
74 changes: 69 additions & 5 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
pub use crate::ty::diagnostics::*;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::{FnAbiError, LayoutError};
use crate::ty::print::{with_crate_prefix, with_no_trimmed_paths};
use crate::ty::util::Discr;
use crate::ty::walk::TypeWalker;

Expand Down Expand Up @@ -410,6 +411,66 @@ impl Visibility {
}
}

#[derive(Debug, StableHash, PartialEq, Clone, Copy, Encodable, Decodable)]
pub enum RestrictionKind {
Unrestricted,
Restricted(DefId, Span),
}

impl RestrictionKind {
/// Returns `true` if the behavior is allowed/unrestricted in the given module.
/// A value of `false` indicates that the behavior is prohibited.
pub fn is_allowed_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool {
match self {
RestrictionKind::Unrestricted => true,
RestrictionKind::Restricted(restricted_to, _) => {
tcx.is_descendant_of(module, restricted_to)
}
}
}

/// Obtain the [`Span`] of the restriction. Panics if the restriction is unrestricted.
pub fn expect_span(self) -> Span {
match self {
RestrictionKind::Unrestricted => {
bug!("called `expect_span` on an unrestricted item")
}
RestrictionKind::Restricted(_, span) => span,
}
}

/// Obtain the path of the restriction. If unrestricted, an empty string is returned.
pub fn restriction_path(self, tcx: TyCtxt<'_>) -> String {
match self {
RestrictionKind::Unrestricted => String::new(),
RestrictionKind::Restricted(restricted_to, _) => {
if restricted_to.krate == rustc_hir::def_id::LOCAL_CRATE {
with_crate_prefix!(with_no_trimmed_paths!(tcx.def_path_str(restricted_to)))
} else {
tcx.def_path_str(restricted_to.krate.as_mod_id())
}
}
}
}

/// Obtain the stricter restriction between `self` and `rhs`.
/// Panics if the restrictions do not reference the same crate.
pub fn stricter_of(self, rhs: Self, tcx: TyCtxt<'_>) -> Self {
match (self, rhs) {
(RestrictionKind::Unrestricted, r) | (r, RestrictionKind::Unrestricted) => r,
(
RestrictionKind::Restricted(left_did, _),
RestrictionKind::Restricted(right_did, _),
) => {
if left_did.krate != right_did.krate {
bug!("stricter_of: left and right restriction do not reference the same crate");
}
if tcx.is_descendant_of(left_did, right_did) { self } else { rhs }
}
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, StableHash)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ClosureSizeProfileData<'tcx> {
Expand Down Expand Up @@ -1545,6 +1606,7 @@ pub struct FieldDef {
pub did: DefId,
pub name: Symbol,
pub vis: Visibility<ModId>,
pub mut_restriction: RestrictionKind,
pub safety: hir::Safety,
pub value: Option<DefId>,
}
Expand All @@ -1559,16 +1621,18 @@ impl PartialEq for FieldDef {
// of `FieldDef` changes, a compile-error will be produced, reminding
// us to revisit this assumption.

let Self { did: lhs_did, name: _, vis: _, safety: _, value: _ } = &self;
let Self { did: lhs_did, name: _, vis: _, mut_restriction: _, safety: _, value: _ } = &self;

let Self { did: rhs_did, name: _, vis: _, safety: _, value: _ } = other;
let Self { did: rhs_did, name: _, vis: _, mut_restriction: _, safety: _, value: _ } = other;

let res = lhs_did == rhs_did;

// Double check that implicit assumption detailed above.
if cfg!(debug_assertions) && res {
let deep =
self.name == other.name && self.vis == other.vis && self.safety == other.safety;
let deep = self.name == other.name
&& self.vis == other.vis
&& self.mut_restriction == other.mut_restriction
&& self.safety == other.safety;
assert!(deep, "FieldDef for the same def-id has differing data");
}

Expand All @@ -1588,7 +1652,7 @@ impl Hash for FieldDef {
// of `FieldDef` changes, a compile-error will be produced, reminding
// us to revisit this assumption.

let Self { did, name: _, vis: _, safety: _, value: _ } = &self;
let Self { did, name: _, vis: _, mut_restriction: _, safety: _, value: _ } = &self;

did.hash(s)
}
Expand Down
51 changes: 2 additions & 49 deletions compiler/rustc_middle/src/ty/trait_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ use tracing::debug;
use crate::query::LocalCrate;
use crate::traits::specialization_graph;
use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
use crate::ty::print::{with_crate_prefix, with_no_trimmed_paths};
use crate::ty::{Ident, Ty, TyCtxt};
use crate::ty::{Ident, RestrictionKind, Ty, TyCtxt};

/// A trait's definition with type information.
#[derive(StableHash, Encodable, Decodable)]
pub struct TraitDef {
pub def_id: DefId,

/// Restrictions on trait implementations.
pub impl_restriction: ImplRestrictionKind,
pub impl_restriction: RestrictionKind,

pub safety: hir::Safety,

Expand Down Expand Up @@ -101,52 +100,6 @@ pub enum TraitSpecializationKind {
AlwaysApplicable,
}

/// Whether the trait implementation is unrestricted or restricted within a specific module.
#[derive(StableHash, PartialEq, Clone, Copy, Encodable, Decodable)]
pub enum ImplRestrictionKind {
/// The restriction does not affect this trait, and it can be implemented anywhere.
Unrestricted,
/// This trait can only be implemented within the specified module.
Restricted(DefId, Span),
}

impl ImplRestrictionKind {
/// Returns `true` if the behavior is allowed/unrestricted in the given module.
/// A value of `false` indicates that the behavior is prohibited.
pub fn is_allowed_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool {
match self {
ImplRestrictionKind::Unrestricted => true,
ImplRestrictionKind::Restricted(restricted_to, _) => {
tcx.is_descendant_of(module, restricted_to)
}
}
}

/// Obtain the [`Span`] of the restriction. Panics if the restriction is unrestricted.
pub fn expect_span(self) -> Span {
match self {
ImplRestrictionKind::Unrestricted => {
bug!("called `expect_span` on an unrestricted item")
}
ImplRestrictionKind::Restricted(_, span) => span,
}
}

/// Obtain the path of the restriction. If unrestricted, an empty string is returned.
pub fn restriction_path(self, tcx: TyCtxt<'_>) -> String {
match self {
ImplRestrictionKind::Unrestricted => String::new(),
ImplRestrictionKind::Restricted(restricted_to, _) => {
if restricted_to.krate == rustc_hir::def_id::LOCAL_CRATE {
with_crate_prefix!(with_no_trimmed_paths!(tcx.def_path_str(restricted_to)))
} else {
tcx.def_path_str(restricted_to.krate.as_mod_id())
}
}
}
}
}

#[derive(Default, Debug, StableHash)]
pub struct TraitImpls {
blanket_impls: Vec<DefId>,
Expand Down
Loading
Loading