diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 997c44cffff03..609d62fefa1a5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3036,6 +3036,7 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, + pub safety: Safety, pub ident: Option, pub ty: P, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 44bb44cb7288e..4bb98778f482a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1044,10 +1044,11 @@ pub fn walk_flat_map_field_def( visitor: &mut T, mut fd: FieldDef, ) -> SmallVec<[FieldDef; 1]> { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; + let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = &mut fd; visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); + visit_safety(visitor, safety); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_ty(ty); visitor.visit_span(span); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 2f8115441de9e..50c64189f1381 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -929,7 +929,7 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>( } pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result { - let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field; + let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _ } = field; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); visit_opt!(visitor, visit_ident, ident); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d724560750114..48b42fa2e9762 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -724,6 +724,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }, vis_span: self.lower_span(f.vis.span), ty, + safety: self.lower_safety(f.safety, hir::Safety::Safe), } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 396aac3451560..26b36cd718fa8 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -548,6 +548,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); + gate_all!(unsafe_fields, "`unsafe` fields are experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 610c69e9d21b4..aa8a4adc84d48 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -2,7 +2,7 @@ use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::visit::AssocCtxt; -use rustc_ast::{self as ast}; +use rustc_ast::{self as ast, Safety}; use rustc_data_structures::fx::FxHashMap; use rustc_span::DUMMY_SP; use rustc_span::symbol::Ident; @@ -173,6 +173,7 @@ pub(crate) fn placeholder( ty: ty(), vis, is_placeholder: true, + safety: Safety::Default, }]), AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant { attrs: Default::default(), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8326d0031ea60..56f2a9ae783e2 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -623,6 +623,8 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), + /// Allows declaring fields `unsafe`. + (unstable, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(1234567)), // FIXME: proper tracking issue. /// Allows const generic parameters to be defined with types that /// are not `Sized`, e.g. `fn foo() {`. (incomplete, unsized_const_params, "1.82.0", Some(95174)), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 554097bf11515..16e53a27128b8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3177,6 +3177,7 @@ pub struct FieldDef<'hir> { pub hir_id: HirId, pub def_id: LocalDefId, pub ty: &'hir Ty<'hir>, + pub safety: Safety, } impl FieldDef<'_> { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 63a0e7d31c3b0..81e27217ae8b6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1031,6 +1031,7 @@ fn lower_variant( did: f.def_id.to_def_id(), name: f.ident.name, vis: tcx.visibility(f.def_id), + safety: f.safety, }) .collect(); let recovered = match def { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 87357b74c411e..56beff5aa6425 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -15,6 +15,7 @@ use rustc_data_structures::sync::{Lock, Lrc, OnceLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; +use rustc_hir::Safety; use rustc_hir::def::Res; use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefPath, DefPathData}; @@ -1101,6 +1102,7 @@ impl<'a> CrateMetadataRef<'a> { did, name: self.item_name(did.index), vis: self.get_visibility(did.index), + safety: self.get_safety(did.index), }) .collect(), adt_kind, @@ -1162,6 +1164,10 @@ impl<'a> CrateMetadataRef<'a> { .map_id(|index| self.local_def_id(index)) } + fn get_safety(self, id: DefIndex) -> Safety { + self.root.tables.safety.get(self, id).unwrap_or_else(|| self.missing("safety", id)) + } + fn get_trait_item_def_id(self, id: DefIndex) -> Option { self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self)) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b5391247cea54..442c6a40a9421 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1595,6 +1595,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { f.did.index })); + for field in &variant.fields { + // FIXME: this probably blows up rmeta size. + self.tables.safety.set_some(field.did.index, field.safety); + } + if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { let fn_sig = tcx.fn_sig(ctor_def_id); // FIXME only encode signature for ctor_def_id diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 58f58efb116fe..1f4f84f9706fd 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -411,6 +411,7 @@ define_tables! { associated_item_or_field_def_ids: Table>, def_kind: Table, visibility: Table>>, + safety: Table, def_span: Table>, def_ident_span: Table>, lookup_stability: Table>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 63abd2be9a57a..9438350ca0972 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -198,6 +198,13 @@ fixed_size_enum! { } } +fixed_size_enum! { + hir::Safety { + ( Unsafe ) + ( Safe ) + } +} + fixed_size_enum! { ty::Asyncness { ( Yes ) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1a3128ed936ab..f2681602a13cf 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1357,6 +1357,7 @@ pub struct FieldDef { pub did: DefId, pub name: Symbol, pub vis: Visibility, + pub safety: hir::Safety, } impl PartialEq for FieldDef { @@ -1369,15 +1370,16 @@ 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: _ } = &self; + let Self { did: lhs_did, name: _, vis: _, safety: _ } = &self; - let Self { did: rhs_did, name: _, vis: _ } = other; + let Self { did: rhs_did, name: _, vis: _, safety: _ } = 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; + let deep = + self.name == other.name && self.vis == other.vis && self.safety == other.safety; assert!(deep, "FieldDef for the same def-id has differing data"); } @@ -1397,7 +1399,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: _ } = &self; + let Self { did, name: _, vis: _, safety: _ } = &self; did.hash(s) } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 7c280bc8b49e9..f7322217aa33f 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -86,6 +86,7 @@ trivially_parameterized_over_tcx! { rustc_attr::Stability, rustc_hir::Constness, rustc_hir::Defaultness, + rustc_hir::Safety, rustc_hir::CoroutineKind, rustc_hir::IsAsync, rustc_hir::LangItem, diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 55149570dbc4d..02ed3b09053b9 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -125,6 +125,16 @@ mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior .label = initializing type with `rustc_layout_scalar_valid_range` attr +mir_build_initializing_type_with_unsafe_field_requires_unsafe = + initializing type with an unsafe field is unsafe and requires unsafe block + .note = unsafe fields may carry library invariants + .label = initialization of struct with unsafe field + +mir_build_initializing_type_with_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + initializing type with an unsafe field is unsafe and requires unsafe block + .note = unsafe fields may carry library invariants + .label = initialization of struct with unsafe field + mir_build_inline_assembly_requires_unsafe = use of inline assembly is unsafe and requires unsafe block .note = inline assembly is entirely unchecked and can cause undefined behavior @@ -340,6 +350,16 @@ mir_build_unreachable_pattern = unreachable pattern .unreachable_covered_by_many = multiple earlier patterns match some of the same values .suggestion = remove the match arm +mir_build_unsafe_field_requires_unsafe = + use of unsafe field is unsafe and requires unsafe block + .note = unsafe fields may carry library invariants + .label = use of unsafe field + +mir_build_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of unsafe field is unsafe and requires unsafe block + .note = unsafe fields may carry library invariants + .label = use of unsafe field + mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items @@ -388,6 +408,11 @@ mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe = .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior .label = initializing type with `rustc_layout_scalar_valid_range` attr +mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_unsafe_field_requires_unsafe = + initializing type with an unsafe field is unsafe and requires unsafe block + .note = unsafe fields may carry library invariants + .label = initialization of struct with unsafe field + mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe = use of inline assembly is unsafe and requires unsafe block .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 = .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior .label = access to union field +mir_build_unsafe_op_in_unsafe_fn_unsafe_field_requires_unsafe = + use of unsafe field is unsafe and requires unsafe block + .note = unsafe fields may carry library invariants + .label = use of unsafe field + mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns mir_build_unused_unsafe = unnecessary `unsafe` block diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f3e6301d9d165..0542a48680cd6 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -4,7 +4,7 @@ use std::ops::Bound; use rustc_errors::DiagArgValue; use rustc_hir::def::DefKind; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Safety}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::mir::BorrowKind; use rustc_middle::span_bug; @@ -538,15 +538,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } ExprKind::Adt(box AdtExpr { adt_def, - variant_index: _, + variant_index, args: _, user_ty: _, fields: _, base: _, - }) => match self.tcx.layout_scalar_valid_range(adt_def.did()) { - (Bound::Unbounded, Bound::Unbounded) => {} - _ => self.requires_unsafe(expr.span, InitializingTypeWith), - }, + }) => { + if adt_def.variant(variant_index).fields.iter().any(|x| x.safety == Safety::Unsafe) + { + self.requires_unsafe(expr.span, InitializingTypeWithUnsafeField) + } + match self.tcx.layout_scalar_valid_range(adt_def.did()) { + (Bound::Unbounded, Bound::Unbounded) => {} + _ => self.requires_unsafe(expr.span, InitializingTypeWith), + } + } ExprKind::Closure(box ClosureExpr { closure_id, args: _, @@ -560,23 +566,25 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { let def_id = did.expect_local(); self.visit_inner_body(def_id); } - ExprKind::Field { lhs, .. } => { + ExprKind::Field { lhs, variant_index, name } => { let lhs = &self.thir[lhs]; - if let ty::Adt(adt_def, _) = lhs.ty.kind() - && adt_def.is_union() - { - if let Some(assigned_ty) = self.assignment_info { - if assigned_ty.needs_drop(self.tcx, self.param_env) { - // This would be unsafe, but should be outright impossible since we - // reject such unions. - assert!( - self.tcx.dcx().has_errors().is_some(), - "union fields that need dropping should be impossible: \ + if let ty::Adt(adt_def, _) = lhs.ty.kind() { + if adt_def.variant(variant_index).fields[name].safety == Safety::Unsafe { + self.requires_unsafe(expr.span, UseOfUnsafeField); + } else if adt_def.is_union() { + if let Some(assigned_ty) = self.assignment_info { + if assigned_ty.needs_drop(self.tcx, self.param_env) { + // This would be unsafe, but should be outright impossible since we + // reject such unions. + assert!( + self.tcx.dcx().has_errors().is_some(), + "union fields that need dropping should be impossible: \ {assigned_ty}" - ); + ); + } + } else { + self.requires_unsafe(expr.span, AccessToUnionField); } - } else { - self.requires_unsafe(expr.span, AccessToUnionField); } } } @@ -648,8 +656,10 @@ enum UnsafeOpKind { CallToUnsafeFunction(Option), UseOfInlineAssembly, InitializingTypeWith, + InitializingTypeWithUnsafeField, UseOfMutableStatic, UseOfExternStatic, + UseOfUnsafeField, DerefOfRawPointer, AccessToUnionField, MutationOfLayoutConstrainedField, @@ -729,6 +739,15 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), + InitializingTypeWithUnsafeField => tcx.emit_node_span_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe { + span, + unsafe_not_inherited_note, + }, + ), UseOfMutableStatic => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, @@ -747,6 +766,15 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), + UseOfUnsafeField => tcx.emit_node_span_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe { + span, + unsafe_not_inherited_note, + }, + ), DerefOfRawPointer => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, @@ -886,6 +914,20 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }); } + InitializingTypeWithUnsafeField if unsafe_op_in_unsafe_fn_allowed => { + dcx.emit_err( + InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + span, + unsafe_not_inherited_note, + }, + ); + } + InitializingTypeWithUnsafeField => { + dcx.emit_err(InitializingTypeWithUnsafeFieldRequiresUnsafe { + span, + unsafe_not_inherited_note, + }); + } UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => { dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span, @@ -904,6 +946,15 @@ impl UnsafeOpKind { UseOfExternStatic => { dcx.emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note }); } + UseOfUnsafeField if unsafe_op_in_unsafe_fn_allowed => { + dcx.emit_err(UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + span, + unsafe_not_inherited_note, + }); + } + UseOfUnsafeField => { + dcx.emit_err(UseOfUnsafeFieldRequiresUnsafe { span, unsafe_not_inherited_note }); + } DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => { dcx.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 00f65e0c7d093..7dba4c0e1e8db 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -86,6 +86,16 @@ pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(LintDiagnostic)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_unsafe_field_requires_unsafe, code = E0133)] +#[note] +pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe { + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe, code = E0133)] #[note] @@ -106,6 +116,16 @@ pub(crate) struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(LintDiagnostic)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_unsafe_field_requires_unsafe, code = E0133)] +#[note] +pub(crate) struct UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe { + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe, code = E0133)] #[note] @@ -250,6 +270,17 @@ pub(crate) struct InitializingTypeWithRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(Diagnostic)] +#[diag(mir_build_initializing_type_with_unsafe_field_requires_unsafe, code = E0133)] +#[note] +pub(crate) struct InitializingTypeWithUnsafeFieldRequiresUnsafe { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + #[derive(Diagnostic)] #[diag( mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, @@ -264,6 +295,20 @@ pub(crate) struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(Diagnostic)] +#[diag( + mir_build_initializing_type_with_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + code = E0133 +)] +#[note] +pub(crate) struct InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + #[derive(Diagnostic)] #[diag(mir_build_mutable_static_requires_unsafe, code = E0133)] #[note] @@ -308,6 +353,28 @@ pub(crate) struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(Diagnostic)] +#[diag(mir_build_unsafe_field_requires_unsafe, code = E0133)] +#[note] +pub(crate) struct UseOfUnsafeFieldRequiresUnsafe { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + +#[derive(Diagnostic)] +#[diag(mir_build_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] +#[note] +pub(crate) struct UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + #[derive(Diagnostic)] #[diag(mir_build_deref_raw_pointer_requires_unsafe, code = E0133)] #[note] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6b4e2d0f4e2f5..a42c911c50d6c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1774,6 +1774,17 @@ impl<'a> Parser<'a> { Ok((fields, recovered)) } + fn parse_unsafe_field(&mut self) -> Safety { + // not using parse_safety as that also accepts `safe`. + if self.eat_keyword(kw::Unsafe) { + let span = self.prev_token.uninterpolated_span(); + self.psess.gated_spans.gate(sym::unsafe_fields, span); + Safety::Unsafe(span) + } else { + Safety::Default + } + } + pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec> { // This is the case where we find `struct Foo(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function @@ -1797,6 +1808,7 @@ impl<'a> Parser<'a> { return Err(err); } }; + let safety = p.parse_unsafe_field(); let ty = match p.parse_ty() { Ok(ty) => ty, Err(err) => { @@ -1811,6 +1823,7 @@ impl<'a> Parser<'a> { FieldDef { span: lo.to(ty.span), vis, + safety, ident: None, id: DUMMY_NODE_ID, ty, @@ -1833,7 +1846,8 @@ impl<'a> Parser<'a> { self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - this.parse_single_struct_field(adt_ty, lo, vis, attrs) + let safety = this.parse_unsafe_field(); + this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs) .map(|field| (field, Trailing::No, UsePreAttrPos::No)) }) } @@ -1844,10 +1858,11 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, + safety: Safety, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let mut seen_comma: bool = false; - let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?; + let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; if self.token == token::Comma { seen_comma = true; } @@ -1975,6 +1990,7 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, + safety: Safety, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; @@ -2000,6 +2016,7 @@ impl<'a> Parser<'a> { span: lo.to(self.prev_token.span), ident: Some(name), vis, + safety, id: DUMMY_NODE_ID, ty, attrs, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f89fd0f7f2ae5..e48375915ff85 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2081,6 +2081,7 @@ symbols! { unsafe_cell, unsafe_cell_raw_get, unsafe_extern_blocks, + unsafe_fields, unsafe_no_drop_flag, unsafe_pin_internals, unsize, diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 327a547b2959c..8a7b5aa1919d4 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1916,15 +1916,15 @@ pub(crate) fn rewrite_struct_field_prefix( field: &ast::FieldDef, ) -> RewriteResult { let vis = format_visibility(context, &field.vis); + let safety = format_safety(field.safety); let type_annotation_spacing = type_annotation_spacing(context.config); Ok(match field.ident { Some(name) => format!( - "{}{}{}:", - vis, + "{vis}{safety}{}{}:", rewrite_ident(context, name), type_annotation_spacing.0 ), - None => vis.to_string(), + None => format!("{vis}{safety}"), }) } diff --git a/src/tools/rustfmt/tests/source/unsafe-field.rs b/src/tools/rustfmt/tests/source/unsafe-field.rs new file mode 100644 index 0000000000000..1feba9f709a23 --- /dev/null +++ b/src/tools/rustfmt/tests/source/unsafe-field.rs @@ -0,0 +1,25 @@ +struct Foo { + unsafe + field: (), +} + +struct FooTuple( + unsafe + (), +); + +enum Bar { + Variant { + unsafe + field: (), + }, + VariantTuple( + unsafe + (), + ), +} + +union Baz { + unsafe + field: (), +} diff --git a/src/tools/rustfmt/tests/target/unsafe-field.rs b/src/tools/rustfmt/tests/target/unsafe-field.rs new file mode 100644 index 0000000000000..13edab2a1c915 --- /dev/null +++ b/src/tools/rustfmt/tests/target/unsafe-field.rs @@ -0,0 +1,14 @@ +struct Foo { + unsafe field: (), +} + +struct FooTuple(unsafe ()); + +enum Bar { + Variant { unsafe field: () }, + VariantTuple(unsafe ()), +} + +union Baz { + unsafe field: (), +} diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs new file mode 100644 index 0000000000000..de22486f41e83 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --crate-type=lib +//@ revisions: with_gate without_gate +//@ [with_gate] check-pass + +#![cfg_attr(with_gate, feature(unsafe_fields))] + +struct Foo { + unsafe field: (), //[without_gate]~ ERROR +} + +struct FooTuple(unsafe ()); //[without_gate]~ ERROR + +enum Bar { + Variant { unsafe field: () }, //[without_gate]~ ERROR + VariantTuple(unsafe ()), //[without_gate]~ ERROR +} + +union Baz { + unsafe field: (), //[without_gate]~ ERROR +} diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.without_gate.stderr b/tests/ui/feature-gates/feature-gate-unsafe_fields.without_gate.stderr new file mode 100644 index 0000000000000..4533a15c0a6fd --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.without_gate.stderr @@ -0,0 +1,53 @@ +error[E0658]: `unsafe` fields are experimental + --> $DIR/feature-gate-unsafe_fields.rs:8:5 + | +LL | unsafe field: (), + | ^^^^^^ + | + = note: see issue #1234567 for more information + = help: add `#![feature(unsafe_fields)]` 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]: `unsafe` fields are experimental + --> $DIR/feature-gate-unsafe_fields.rs:11:17 + | +LL | struct FooTuple(unsafe ()); + | ^^^^^^ + | + = note: see issue #1234567 for more information + = help: add `#![feature(unsafe_fields)]` 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]: `unsafe` fields are experimental + --> $DIR/feature-gate-unsafe_fields.rs:14:15 + | +LL | Variant { unsafe field: () }, + | ^^^^^^ + | + = note: see issue #1234567 for more information + = help: add `#![feature(unsafe_fields)]` 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]: `unsafe` fields are experimental + --> $DIR/feature-gate-unsafe_fields.rs:15:18 + | +LL | VariantTuple(unsafe ()), + | ^^^^^^ + | + = note: see issue #1234567 for more information + = help: add `#![feature(unsafe_fields)]` 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]: `unsafe` fields are experimental + --> $DIR/feature-gate-unsafe_fields.rs:19:5 + | +LL | unsafe field: (), + | ^^^^^^ + | + = note: see issue #1234567 for more information + = help: add `#![feature(unsafe_fields)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index bd0c8cbc3b12b..1f255f99e0b6e 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -15,17 +15,17 @@ ast-stats-1 ForeignItem 88 ( 1.3%) 1 88 ast-stats-1 - Fn 88 ( 1.3%) 1 ast-stats-1 Arm 96 ( 1.4%) 2 48 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 -ast-stats-1 FieldDef 160 ( 2.4%) 2 80 ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Let 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.4%) 3 +ast-stats-1 FieldDef 176 ( 2.6%) 2 88 ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 Variant 208 ( 3.1%) 2 104 ast-stats-1 AssocItem 352 ( 5.3%) 4 88 -ast-stats-1 - Type 176 ( 2.7%) 2 -ast-stats-1 - Fn 176 ( 2.7%) 2 +ast-stats-1 - Type 176 ( 2.6%) 2 +ast-stats-1 - Fn 176 ( 2.6%) 2 ast-stats-1 GenericBound 352 ( 5.3%) 4 88 ast-stats-1 - Trait 352 ( 5.3%) 4 ast-stats-1 GenericParam 480 ( 7.2%) 5 96 @@ -38,7 +38,7 @@ ast-stats-1 - Path 72 ( 1.1%) 1 ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Lit 144 ( 2.2%) 2 -ast-stats-1 - Block 216 ( 3.3%) 3 +ast-stats-1 - Block 216 ( 3.2%) 3 ast-stats-1 PathSegment 744 (11.2%) 31 24 ast-stats-1 Ty 896 (13.5%) 14 64 ast-stats-1 - Ref 64 ( 1.0%) 1 @@ -53,7 +53,7 @@ ast-stats-1 - Enum 136 ( 2.0%) 1 ast-stats-1 - Fn 272 ( 4.1%) 2 ast-stats-1 - Use 408 ( 6.1%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_640 +ast-stats-1 Total 6_656 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -73,14 +73,14 @@ ast-stats-2 InlineAsm 120 ( 1.6%) 1 120 ast-stats-2 Attribute 128 ( 1.8%) 4 32 ast-stats-2 - DocComment 32 ( 0.4%) 1 ast-stats-2 - Normal 96 ( 1.3%) 3 -ast-stats-2 FieldDef 160 ( 2.2%) 2 80 ast-stats-2 Param 160 ( 2.2%) 4 40 ast-stats-2 Stmt 160 ( 2.2%) 5 32 ast-stats-2 - Let 32 ( 0.4%) 1 ast-stats-2 - Semi 32 ( 0.4%) 1 ast-stats-2 - Expr 96 ( 1.3%) 3 +ast-stats-2 FieldDef 176 ( 2.4%) 2 88 ast-stats-2 Block 192 ( 2.6%) 6 32 -ast-stats-2 Variant 208 ( 2.9%) 2 104 +ast-stats-2 Variant 208 ( 2.8%) 2 104 ast-stats-2 AssocItem 352 ( 4.8%) 4 88 ast-stats-2 - Type 176 ( 2.4%) 2 ast-stats-2 - Fn 176 ( 2.4%) 2 @@ -98,7 +98,7 @@ ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Lit 144 ( 2.0%) 2 ast-stats-2 - Block 216 ( 3.0%) 3 -ast-stats-2 PathSegment 864 (11.9%) 36 24 +ast-stats-2 PathSegment 864 (11.8%) 36 24 ast-stats-2 Ty 896 (12.3%) 14 64 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - Ptr 64 ( 0.9%) 1 @@ -111,9 +111,9 @@ ast-stats-2 - Impl 136 ( 1.9%) 1 ast-stats-2 - ExternCrate 136 ( 1.9%) 1 ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.7%) 2 -ast-stats-2 - Use 544 ( 7.5%) 4 +ast-stats-2 - Use 544 ( 7.4%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_288 +ast-stats-2 Total 7_304 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size @@ -132,11 +132,11 @@ hir-stats Body 72 ( 0.8%) 3 24 hir-stats ImplItemRef 72 ( 0.8%) 2 36 hir-stats InlineAsm 72 ( 0.8%) 1 72 hir-stats Arm 80 ( 0.9%) 2 40 -hir-stats FieldDef 96 ( 1.1%) 2 48 hir-stats Stmt 96 ( 1.1%) 3 32 hir-stats - Let 32 ( 0.4%) 1 hir-stats - Semi 32 ( 0.4%) 1 hir-stats - Expr 32 ( 0.4%) 1 +hir-stats FieldDef 112 ( 1.2%) 2 56 hir-stats FnDecl 120 ( 1.3%) 3 40 hir-stats Attribute 128 ( 1.4%) 4 32 hir-stats GenericArgs 144 ( 1.6%) 3 48 @@ -162,17 +162,17 @@ hir-stats - Match 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 -hir-stats - Block 384 ( 4.3%) 6 +hir-stats - Block 384 ( 4.2%) 6 hir-stats Item 968 (10.7%) 11 88 hir-stats - Enum 88 ( 1.0%) 1 hir-stats - Trait 88 ( 1.0%) 1 hir-stats - Impl 88 ( 1.0%) 1 hir-stats - ExternCrate 88 ( 1.0%) 1 hir-stats - ForeignMod 88 ( 1.0%) 1 -hir-stats - Fn 176 ( 2.0%) 2 +hir-stats - Fn 176 ( 1.9%) 2 hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.7%) 31 40 -hir-stats PathSegment 1_920 (21.3%) 40 48 +hir-stats PathSegment 1_920 (21.2%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_024 +hir-stats Total 9_040 hir-stats diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 8cff788766189..6a59e39132400 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -92,7 +92,7 @@ body: adt_def: AdtDef { did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) - variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } args: [] @@ -154,7 +154,7 @@ body: adt_def: AdtDef { did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) - variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } args: [] @@ -206,7 +206,7 @@ body: adt_def: AdtDef { did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) - variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } args: [] diff --git a/tests/ui/unsafe-fields.rs b/tests/ui/unsafe-fields.rs new file mode 100644 index 0000000000000..8df68b40c5953 --- /dev/null +++ b/tests/ui/unsafe-fields.rs @@ -0,0 +1,38 @@ +//@ compile-flags: --crate-type=lib +#![feature(unsafe_fields)] + +struct WithUnsafeField { + unsafe unsafe_field: u32, + safe_field: u32, +} + +impl WithUnsafeField { + fn new() -> WithUnsafeField { + unsafe { + WithUnsafeField { + unsafe_field: 0, + safe_field: 0, + } + } + } + + fn new_without_unsafe() -> WithUnsafeField { + WithUnsafeField { //~ ERROR + unsafe_field: 0, + safe_field: 0, + } + } + + fn set_safe_field(&mut self) { + self.safe_field = 2; + } + fn set_unsafe_field(&mut self) { + unsafe { + self.unsafe_field = 2; + } + } + fn set_unsafe_field_without_unsafe(&mut self) { + self.unsafe_field = 2; + //~^ ERROR + } +} diff --git a/tests/ui/unsafe-fields.stderr b/tests/ui/unsafe-fields.stderr new file mode 100644 index 0000000000000..f18fba5265f31 --- /dev/null +++ b/tests/ui/unsafe-fields.stderr @@ -0,0 +1,22 @@ +error[E0133]: initializing type with an unsafe field is unsafe and requires unsafe block + --> $DIR/unsafe-fields.rs:20:9 + | +LL | / WithUnsafeField { +LL | | unsafe_field: 0, +LL | | safe_field: 0, +LL | | } + | |_________^ initialization of struct with unsafe field + | + = note: unsafe fields may carry library invariants + +error[E0133]: use of unsafe field is unsafe and requires unsafe block + --> $DIR/unsafe-fields.rs:35:9 + | +LL | self.unsafe_field = 2; + | ^^^^^^^^^^^^^^^^^ use of unsafe field + | + = note: unsafe fields may carry library invariants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`.