Skip to content

Commit 4cbe0ee

Browse files
veluca93jhpratt
andcommitted
Draft implementation of the unsafe-fields RFC.
Co-Authored-By: Jacob Pratt <[email protected]>
1 parent 9b18a12 commit 4cbe0ee

File tree

27 files changed

+396
-32
lines changed

27 files changed

+396
-32
lines changed

compiler/rustc_ast/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3028,6 +3028,7 @@ pub struct FieldDef {
30283028
pub id: NodeId,
30293029
pub span: Span,
30303030
pub vis: Visibility,
3031+
pub safety: Safety,
30313032
pub ident: Option<Ident>,
30323033

30333034
pub ty: P<Ty>,

compiler/rustc_ast/src/mut_visit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1044,10 +1044,11 @@ pub fn walk_flat_map_field_def<T: MutVisitor>(
10441044
visitor: &mut T,
10451045
mut fd: FieldDef,
10461046
) -> SmallVec<[FieldDef; 1]> {
1047-
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd;
1047+
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = &mut fd;
10481048
visitor.visit_id(id);
10491049
visit_attrs(visitor, attrs);
10501050
visitor.visit_vis(vis);
1051+
visit_safety(visitor, safety);
10511052
visit_opt(ident, |ident| visitor.visit_ident(ident));
10521053
visitor.visit_ty(ty);
10531054
visitor.visit_span(span);

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>(
929929
}
930930

931931
pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result {
932-
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field;
932+
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _ } = field;
933933
walk_list!(visitor, visit_attribute, attrs);
934934
try_visit!(visitor.visit_vis(vis));
935935
visit_opt!(visitor, visit_ident, ident);

compiler/rustc_ast_lowering/src/item.rs

+1
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
724724
},
725725
vis_span: self.lower_span(f.vis.span),
726726
ty,
727+
safety: self.lower_safety(f.safety, hir::Safety::Safe),
727728
}
728729
}
729730

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
547547
gate_all!(global_registration, "global registration is experimental");
548548
gate_all!(return_type_notation, "return type notation is experimental");
549549
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
550+
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
550551

551552
if !visitor.features.never_patterns() {
552553
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_expand/src/placeholders.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_ast::mut_visit::*;
22
use rustc_ast::ptr::P;
33
use rustc_ast::token::Delimiter;
44
use rustc_ast::visit::AssocCtxt;
5-
use rustc_ast::{self as ast};
5+
use rustc_ast::{self as ast, Safety};
66
use rustc_data_structures::fx::FxHashMap;
77
use rustc_span::DUMMY_SP;
88
use rustc_span::symbol::Ident;
@@ -173,6 +173,7 @@ pub(crate) fn placeholder(
173173
ty: ty(),
174174
vis,
175175
is_placeholder: true,
176+
safety: Safety::Default,
176177
}]),
177178
AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
178179
attrs: Default::default(),

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,8 @@ declare_features! (
628628
/// Allows creation of instances of a struct by moving fields that have
629629
/// not changed from prior instances of the same struct (RFC #2528)
630630
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
631+
/// Allows declaring fields `unsafe`.
632+
(unstable, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(1234567)), // FIXME: proper tracking issue.
631633
/// Allows const generic parameters to be defined with types that
632634
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
633635
(incomplete, unsized_const_params, "1.82.0", Some(95174)),

compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3192,6 +3192,7 @@ pub struct FieldDef<'hir> {
31923192
pub hir_id: HirId,
31933193
pub def_id: LocalDefId,
31943194
pub ty: &'hir Ty<'hir>,
3195+
pub safety: Safety,
31953196
}
31963197

31973198
impl FieldDef<'_> {

compiler/rustc_hir_analysis/src/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ fn lower_variant(
10311031
did: f.def_id.to_def_id(),
10321032
name: f.ident.name,
10331033
vis: tcx.visibility(f.def_id),
1034+
safety: f.safety,
10341035
})
10351036
.collect();
10361037
let recovered = match def {

compiler/rustc_metadata/src/rmeta/decoder.rs

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_data_structures::sync::{Lock, Lrc, OnceLock};
1515
use rustc_data_structures::unhash::UnhashMap;
1616
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
1717
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
18+
use rustc_hir::Safety;
1819
use rustc_hir::def::Res;
1920
use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
2021
use rustc_hir::definitions::{DefPath, DefPathData};
@@ -1101,6 +1102,7 @@ impl<'a> CrateMetadataRef<'a> {
11011102
did,
11021103
name: self.item_name(did.index),
11031104
vis: self.get_visibility(did.index),
1105+
safety: self.get_safety(did.index),
11041106
})
11051107
.collect(),
11061108
adt_kind,
@@ -1162,6 +1164,10 @@ impl<'a> CrateMetadataRef<'a> {
11621164
.map_id(|index| self.local_def_id(index))
11631165
}
11641166

1167+
fn get_safety(self, id: DefIndex) -> Safety {
1168+
self.root.tables.safety.get(self, id).unwrap_or_else(|| self.missing("safety", id))
1169+
}
1170+
11651171
fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
11661172
self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
11671173
}

compiler/rustc_metadata/src/rmeta/encoder.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
15971597
f.did.index
15981598
}));
15991599

1600+
for field in &variant.fields {
1601+
// FIXME: this probably blows up rmeta size.
1602+
self.tables.safety.set_some(field.did.index, field.safety);
1603+
}
1604+
16001605
if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
16011606
let fn_sig = tcx.fn_sig(ctor_def_id);
16021607
// FIXME only encode signature for ctor_def_id

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ define_tables! {
413413
associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>,
414414
def_kind: Table<DefIndex, DefKind>,
415415
visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
416+
safety: Table<DefIndex, hir::Safety>,
416417
def_span: Table<DefIndex, LazyValue<Span>>,
417418
def_ident_span: Table<DefIndex, LazyValue<Span>>,
418419
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,

compiler/rustc_metadata/src/rmeta/table.rs

+7
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,13 @@ fixed_size_enum! {
198198
}
199199
}
200200

201+
fixed_size_enum! {
202+
hir::Safety {
203+
( Unsafe )
204+
( Safe )
205+
}
206+
}
207+
201208
fixed_size_enum! {
202209
ty::Asyncness {
203210
( Yes )

compiler/rustc_middle/src/ty/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ pub struct FieldDef {
13651365
pub did: DefId,
13661366
pub name: Symbol,
13671367
pub vis: Visibility<DefId>,
1368+
pub safety: hir::Safety,
13681369
}
13691370

13701371
impl PartialEq for FieldDef {
@@ -1377,15 +1378,16 @@ impl PartialEq for FieldDef {
13771378
// of `FieldDef` changes, a compile-error will be produced, reminding
13781379
// us to revisit this assumption.
13791380

1380-
let Self { did: lhs_did, name: _, vis: _ } = &self;
1381+
let Self { did: lhs_did, name: _, vis: _, safety: _ } = &self;
13811382

1382-
let Self { did: rhs_did, name: _, vis: _ } = other;
1383+
let Self { did: rhs_did, name: _, vis: _, safety: _ } = other;
13831384

13841385
let res = lhs_did == rhs_did;
13851386

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

@@ -1405,7 +1407,7 @@ impl Hash for FieldDef {
14051407
// of `FieldDef` changes, a compile-error will be produced, reminding
14061408
// us to revisit this assumption.
14071409

1408-
let Self { did, name: _, vis: _ } = &self;
1410+
let Self { did, name: _, vis: _, safety: _ } = &self;
14091411

14101412
did.hash(s)
14111413
}

compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ trivially_parameterized_over_tcx! {
8686
rustc_attr::Stability,
8787
rustc_hir::Constness,
8888
rustc_hir::Defaultness,
89+
rustc_hir::Safety,
8990
rustc_hir::CoroutineKind,
9091
rustc_hir::IsAsync,
9192
rustc_hir::LangItem,

compiler/rustc_mir_build/messages.ftl

+30
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed
125125
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
126126
.label = initializing type with `rustc_layout_scalar_valid_range` attr
127127
128+
mir_build_initializing_type_with_unsafe_field_requires_unsafe =
129+
initializing type with an unsafe field is unsafe and requires unsafe block
130+
.note = unsafe fields may carry library invariants
131+
.label = initialization of struct with unsafe field
132+
133+
mir_build_initializing_type_with_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
134+
initializing type with an unsafe field is unsafe and requires unsafe block
135+
.note = unsafe fields may carry library invariants
136+
.label = initialization of struct with unsafe field
137+
128138
mir_build_inline_assembly_requires_unsafe =
129139
use of inline assembly is unsafe and requires unsafe block
130140
.note = inline assembly is entirely unchecked and can cause undefined behavior
@@ -340,6 +350,16 @@ mir_build_unreachable_pattern = unreachable pattern
340350
.unreachable_covered_by_many = multiple earlier patterns match some of the same values
341351
.suggestion = remove the match arm
342352
353+
mir_build_unsafe_field_requires_unsafe =
354+
use of unsafe field is unsafe and requires unsafe block
355+
.note = unsafe fields may carry library invariants
356+
.label = use of unsafe field
357+
358+
mir_build_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
359+
use of unsafe field is unsafe and requires unsafe block
360+
.note = unsafe fields may carry library invariants
361+
.label = use of unsafe field
362+
343363
mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
344364
mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items
345365
@@ -388,6 +408,11 @@ mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
388408
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
389409
.label = initializing type with `rustc_layout_scalar_valid_range` attr
390410
411+
mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_unsafe_field_requires_unsafe =
412+
initializing type with an unsafe field is unsafe and requires unsafe block
413+
.note = unsafe fields may carry library invariants
414+
.label = initialization of struct with unsafe field
415+
391416
mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
392417
use of inline assembly is unsafe and requires unsafe block
393418
.note = inline assembly is entirely unchecked and can cause undefined behavior
@@ -408,6 +433,11 @@ mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
408433
.note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
409434
.label = access to union field
410435
436+
mir_build_unsafe_op_in_unsafe_fn_unsafe_field_requires_unsafe =
437+
use of unsafe field is unsafe and requires unsafe block
438+
.note = unsafe fields may carry library invariants
439+
.label = use of unsafe field
440+
411441
mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
412442
413443
mir_build_unused_unsafe = unnecessary `unsafe` block

0 commit comments

Comments
 (0)