mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 04:26:48 +00:00
Auto merge of #132915 - veluca93:unsafe-fields, r=jswrenn
Implement the unsafe-fields RFC. RFC: rust-lang/rfcs#3458 Tracking: - https://github.com/rust-lang/rust/issues/132922 r? jswrenn
This commit is contained in:
commit
6e1c11591f
@ -3063,6 +3063,7 @@ pub struct FieldDef {
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub vis: Visibility,
|
||||
pub safety: Safety,
|
||||
pub ident: Option<Ident>,
|
||||
|
||||
pub ty: P<Ty>,
|
||||
|
@ -1115,10 +1115,11 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
|
||||
}
|
||||
|
||||
pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = fd;
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = 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);
|
||||
|
@ -961,7 +961,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);
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,6 +557,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) {
|
||||
|
@ -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(),
|
||||
|
@ -629,6 +629,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`.
|
||||
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
|
||||
/// Allows const generic parameters to be defined with types that
|
||||
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
|
||||
(incomplete, unsized_const_params, "1.82.0", Some(95174)),
|
||||
|
@ -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<'_> {
|
||||
|
@ -253,6 +253,13 @@ hir_analysis_invalid_union_field =
|
||||
hir_analysis_invalid_union_field_sugg =
|
||||
wrap the field type in `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_invalid_unsafe_field =
|
||||
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be unsafe
|
||||
.note = unsafe fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_invalid_unsafe_field_sugg =
|
||||
wrap the field type in `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
|
||||
.label = const parameter declared here
|
||||
|
||||
|
@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::{Node, intravisit};
|
||||
use rustc_hir::{Node, Safety, intravisit};
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{Obligation, ObligationCauseCode};
|
||||
use rustc_lint_defs::builtin::{
|
||||
@ -70,6 +70,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
|
||||
check_transparent(tcx, def);
|
||||
check_packed(tcx, span, def);
|
||||
check_unsafe_fields(tcx, def_id);
|
||||
}
|
||||
|
||||
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
@ -81,38 +82,45 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
check_packed(tcx, span, def);
|
||||
}
|
||||
|
||||
fn allowed_union_or_unsafe_field<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
// We don't just accept all !needs_drop fields, due to semver concerns.
|
||||
let allowed = match ty.kind() {
|
||||
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
|
||||
ty::Tuple(tys) => {
|
||||
// allow tuples of allowed types
|
||||
tys.iter().all(|ty| allowed_union_or_unsafe_field(tcx, ty, typing_env, span))
|
||||
}
|
||||
ty::Array(elem, _len) => {
|
||||
// Like `Copy`, we do *not* special-case length 0.
|
||||
allowed_union_or_unsafe_field(tcx, *elem, typing_env, span)
|
||||
}
|
||||
_ => {
|
||||
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
|
||||
// also no need to report an error if the type is unresolved.
|
||||
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
||||
|| ty.is_copy_modulo_regions(tcx, typing_env)
|
||||
|| ty.references_error()
|
||||
}
|
||||
};
|
||||
if allowed && ty.needs_drop(tcx, typing_env) {
|
||||
// This should never happen. But we can get here e.g. in case of name resolution errors.
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(span, "we should never accept maybe-dropping union or unsafe fields");
|
||||
}
|
||||
allowed
|
||||
}
|
||||
|
||||
/// Check that the fields of the `union` do not need dropping.
|
||||
fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
|
||||
let item_type = tcx.type_of(item_def_id).instantiate_identity();
|
||||
if let ty::Adt(def, args) = item_type.kind() {
|
||||
assert!(def.is_union());
|
||||
|
||||
fn allowed_union_field<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
) -> bool {
|
||||
// We don't just accept all !needs_drop fields, due to semver concerns.
|
||||
match ty.kind() {
|
||||
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
|
||||
ty::Tuple(tys) => {
|
||||
// allow tuples of allowed types
|
||||
tys.iter().all(|ty| allowed_union_field(ty, tcx, typing_env))
|
||||
}
|
||||
ty::Array(elem, _len) => {
|
||||
// Like `Copy`, we do *not* special-case length 0.
|
||||
allowed_union_field(*elem, tcx, typing_env)
|
||||
}
|
||||
_ => {
|
||||
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
|
||||
// also no need to report an error if the type is unresolved.
|
||||
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
||||
|| ty.is_copy_modulo_regions(tcx, typing_env)
|
||||
|| ty.references_error()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
|
||||
for field in &def.non_enum_variant().fields {
|
||||
let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args))
|
||||
@ -121,7 +129,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
||||
continue;
|
||||
};
|
||||
|
||||
if !allowed_union_field(field_ty, tcx, typing_env) {
|
||||
if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) {
|
||||
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
|
||||
// We are currently checking the type this field came from, so it must be local.
|
||||
Some(Node::Field(field)) => (field.span, field.ty.span),
|
||||
@ -136,10 +144,6 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
||||
note: (),
|
||||
});
|
||||
return false;
|
||||
} else if field_ty.needs_drop(tcx, typing_env) {
|
||||
// This should never happen. But we can get here e.g. in case of name resolution errors.
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(span, "we should never accept maybe-dropping union fields");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -148,6 +152,41 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
||||
true
|
||||
}
|
||||
|
||||
/// Check that the unsafe fields do not need dropping.
|
||||
fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) {
|
||||
let span = tcx.def_span(item_def_id);
|
||||
let item_type = tcx.type_of(item_def_id).instantiate_identity();
|
||||
let ty::Adt(def, args) = item_type.kind() else {
|
||||
span_bug!(span, "structs/enums must be ty::Adt, but got {:?}", item_type.kind());
|
||||
};
|
||||
let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
|
||||
for field in def.all_fields() {
|
||||
if field.safety != Safety::Unsafe {
|
||||
continue;
|
||||
}
|
||||
let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args))
|
||||
else {
|
||||
tcx.dcx().span_delayed_bug(span, "could not normalize field type");
|
||||
continue;
|
||||
};
|
||||
|
||||
if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) {
|
||||
let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else {
|
||||
unreachable!("field has to correspond to hir field")
|
||||
};
|
||||
let ty_span = field.ty.span;
|
||||
tcx.dcx().emit_err(errors::InvalidUnsafeField {
|
||||
field_span: field.span,
|
||||
sugg: errors::InvalidUnsafeFieldSuggestion {
|
||||
lo: ty_span.shrink_to_lo(),
|
||||
hi: ty_span.shrink_to_hi(),
|
||||
},
|
||||
note: (),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that a `static` is inhabited.
|
||||
fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
// Make sure statics are inhabited.
|
||||
@ -1464,6 +1503,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
|
||||
detect_discriminant_duplicate(tcx, def);
|
||||
check_transparent(tcx, def);
|
||||
check_unsafe_fields(tcx, def_id);
|
||||
}
|
||||
|
||||
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
|
||||
|
@ -1040,6 +1040,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 {
|
||||
|
@ -734,6 +734,17 @@ pub(crate) struct InvalidUnionField {
|
||||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_unsafe_field, code = E0740)]
|
||||
pub(crate) struct InvalidUnsafeField {
|
||||
#[primary_span]
|
||||
pub field_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: InvalidUnsafeFieldSuggestion,
|
||||
#[note]
|
||||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_on_non_rpitit)]
|
||||
pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
|
||||
@ -755,6 +766,18 @@ pub(crate) struct InvalidUnionFieldSuggestion {
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
hir_analysis_invalid_unsafe_field_sugg,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidUnsafeFieldSuggestion {
|
||||
#[suggestion_part(code = "std::mem::ManuallyDrop<")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = ">")]
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_equality_bound)]
|
||||
pub(crate) struct ReturnTypeNotationEqualityBound {
|
||||
|
@ -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<DefId> {
|
||||
self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
|
||||
}
|
||||
|
@ -1599,6 +1599,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
f.did.index
|
||||
}));
|
||||
|
||||
for field in &variant.fields {
|
||||
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
|
||||
|
@ -411,6 +411,7 @@ define_tables! {
|
||||
associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
def_kind: Table<DefIndex, DefKind>,
|
||||
visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
|
||||
safety: Table<DefIndex, hir::Safety>,
|
||||
def_span: Table<DefIndex, LazyValue<Span>>,
|
||||
def_ident_span: Table<DefIndex, LazyValue<Span>>,
|
||||
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
|
||||
|
@ -198,6 +198,13 @@ fixed_size_enum! {
|
||||
}
|
||||
}
|
||||
|
||||
fixed_size_enum! {
|
||||
hir::Safety {
|
||||
( Unsafe )
|
||||
( Safe )
|
||||
}
|
||||
}
|
||||
|
||||
fixed_size_enum! {
|
||||
ty::Asyncness {
|
||||
( Yes )
|
||||
|
@ -34,9 +34,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||
use rustc_hir::{LangItem, Safety};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{
|
||||
Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
|
||||
@ -1365,6 +1365,11 @@ impl VariantDef {
|
||||
pub fn tail(&self) -> &FieldDef {
|
||||
self.tail_opt().expect("expected unsized ADT to have a tail field")
|
||||
}
|
||||
|
||||
/// Returns whether this variant has unsafe fields.
|
||||
pub fn has_unsafe_fields(&self) -> bool {
|
||||
self.fields.iter().any(|x| x.safety == Safety::Unsafe)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VariantDef {
|
||||
@ -1447,6 +1452,7 @@ pub struct FieldDef {
|
||||
pub did: DefId,
|
||||
pub name: Symbol,
|
||||
pub vis: Visibility<DefId>,
|
||||
pub safety: hir::Safety,
|
||||
}
|
||||
|
||||
impl PartialEq for FieldDef {
|
||||
@ -1459,15 +1465,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");
|
||||
}
|
||||
|
||||
@ -1487,7 +1494,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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
@ -347,6 +357,16 @@ mir_build_unreachable_pattern = unreachable pattern
|
||||
.unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
|
||||
.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
|
||||
|
||||
@ -395,6 +415,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
|
||||
@ -415,6 +440,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
|
||||
|
@ -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;
|
||||
@ -339,8 +339,13 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
};
|
||||
|
||||
match &pat.kind {
|
||||
PatKind::Leaf { .. } => {
|
||||
PatKind::Leaf { subpatterns, .. } => {
|
||||
if let ty::Adt(adt_def, ..) = pat.ty.kind() {
|
||||
for pat in subpatterns {
|
||||
if adt_def.non_enum_variant().fields[pat.field].safety == Safety::Unsafe {
|
||||
self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
|
||||
}
|
||||
}
|
||||
if adt_def.is_union() {
|
||||
let old_in_union_destructure =
|
||||
std::mem::replace(&mut self.in_union_destructure, true);
|
||||
@ -359,6 +364,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
}
|
||||
PatKind::Variant { adt_def, args: _, variant_index, subpatterns } => {
|
||||
for pat in subpatterns {
|
||||
let field = &pat.field;
|
||||
if adt_def.variant(*variant_index).fields[*field].safety == Safety::Unsafe {
|
||||
self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
|
||||
}
|
||||
}
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _), ty, .. } => {
|
||||
if self.inside_adt {
|
||||
let ty::Ref(_, ty, _) = ty.kind() else {
|
||||
@ -579,15 +593,20 @@ 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).has_unsafe_fields() {
|
||||
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: _,
|
||||
@ -601,23 +620,24 @@ 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.typing_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}"
|
||||
);
|
||||
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.typing_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -689,8 +709,10 @@ enum UnsafeOpKind {
|
||||
CallToUnsafeFunction(Option<DefId>),
|
||||
UseOfInlineAssembly,
|
||||
InitializingTypeWith,
|
||||
InitializingTypeWithUnsafeField,
|
||||
UseOfMutableStatic,
|
||||
UseOfExternStatic,
|
||||
UseOfUnsafeField,
|
||||
DerefOfRawPointer,
|
||||
AccessToUnionField,
|
||||
MutationOfLayoutConstrainedField,
|
||||
@ -770,6 +792,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,
|
||||
@ -788,6 +819,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,
|
||||
@ -927,6 +967,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,
|
||||
@ -945,6 +999,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,
|
||||
|
@ -86,6 +86,16 @@ pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
|
||||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = E0133)]
|
||||
#[note]
|
||||
|
@ -1791,6 +1791,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.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<FieldDef>> {
|
||||
// This is the case where we find `struct Foo<T>(T) where T: Copy;`
|
||||
// Unit like structs are handled in parse_item_struct function
|
||||
@ -1814,6 +1825,8 @@ impl<'a> Parser<'a> {
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
// Unsafe fields are not supported in tuple structs, as doing so would result in a
|
||||
// parsing ambiguity for `struct X(unsafe fn())`.
|
||||
let ty = match p.parse_ty() {
|
||||
Ok(ty) => ty,
|
||||
Err(err) => {
|
||||
@ -1828,6 +1841,7 @@ impl<'a> Parser<'a> {
|
||||
FieldDef {
|
||||
span: lo.to(ty.span),
|
||||
vis,
|
||||
safety: Safety::Default,
|
||||
ident: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
ty,
|
||||
@ -1850,7 +1864,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))
|
||||
})
|
||||
}
|
||||
@ -1861,10 +1876,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;
|
||||
}
|
||||
@ -1992,6 +2008,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)?;
|
||||
@ -2017,6 +2034,7 @@ impl<'a> Parser<'a> {
|
||||
span: lo.to(self.prev_token.span),
|
||||
ident: Some(name),
|
||||
vis,
|
||||
safety,
|
||||
id: DUMMY_NODE_ID,
|
||||
ty,
|
||||
attrs,
|
||||
|
@ -2087,6 +2087,7 @@ symbols! {
|
||||
unsafe_cell,
|
||||
unsafe_cell_raw_get,
|
||||
unsafe_extern_blocks,
|
||||
unsafe_fields,
|
||||
unsafe_no_drop_flag,
|
||||
unsafe_pin_internals,
|
||||
unsize,
|
||||
|
@ -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}"),
|
||||
})
|
||||
}
|
||||
|
||||
|
16
src/tools/rustfmt/tests/source/unsafe-field.rs
Normal file
16
src/tools/rustfmt/tests/source/unsafe-field.rs
Normal file
@ -0,0 +1,16 @@
|
||||
struct Foo {
|
||||
unsafe
|
||||
field: (),
|
||||
}
|
||||
|
||||
enum Bar {
|
||||
Variant {
|
||||
unsafe
|
||||
field: (),
|
||||
},
|
||||
}
|
||||
|
||||
union Baz {
|
||||
unsafe
|
||||
field: (),
|
||||
}
|
11
src/tools/rustfmt/tests/target/unsafe-field.rs
Normal file
11
src/tools/rustfmt/tests/target/unsafe-field.rs
Normal file
@ -0,0 +1,11 @@
|
||||
struct Foo {
|
||||
unsafe field: (),
|
||||
}
|
||||
|
||||
enum Bar {
|
||||
Variant { unsafe field: () },
|
||||
}
|
||||
|
||||
union Baz {
|
||||
unsafe field: (),
|
||||
}
|
7
tests/ui/auxiliary/unsafe-fields-crate-dep.rs
Normal file
7
tests/ui/auxiliary/unsafe-fields-crate-dep.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsafe_fields)]
|
||||
|
||||
pub struct WithUnsafeField {
|
||||
pub unsafe unsafe_field: u32,
|
||||
pub safe_field: u32,
|
||||
}
|
25
tests/ui/feature-gates/feature-gate-unsafe_fields.rs
Normal file
25
tests/ui/feature-gates/feature-gate-unsafe_fields.rs
Normal file
@ -0,0 +1,25 @@
|
||||
//@ compile-flags: --crate-type=lib
|
||||
//@ revisions: with_gate without_gate
|
||||
//@ [with_gate] check-pass
|
||||
|
||||
#![cfg_attr(with_gate, feature(unsafe_fields))] //[with_gate]~ WARNING
|
||||
|
||||
#[cfg(any())]
|
||||
struct Foo {
|
||||
unsafe field: (), //[without_gate]~ ERROR
|
||||
}
|
||||
|
||||
// This should not parse as an unsafe field definition.
|
||||
struct FooTuple(unsafe fn());
|
||||
|
||||
#[cfg(any())]
|
||||
enum Bar {
|
||||
Variant { unsafe field: () }, //[without_gate]~ ERROR
|
||||
// This should not parse as an unsafe field definition.
|
||||
VariantTuple(unsafe fn()),
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
union Baz {
|
||||
unsafe field: (), //[without_gate]~ ERROR
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
warning: the feature `unsafe_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/feature-gate-unsafe_fields.rs:5:32
|
||||
|
|
||||
LL | #![cfg_attr(with_gate, feature(unsafe_fields))]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #132922 <https://github.com/rust-lang/rust/issues/132922> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
@ -0,0 +1,33 @@
|
||||
error[E0658]: `unsafe` fields are experimental
|
||||
--> $DIR/feature-gate-unsafe_fields.rs:9:5
|
||||
|
|
||||
LL | unsafe field: (),
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: see issue #132922 <https://github.com/rust-lang/rust/issues/132922> 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:17:15
|
||||
|
|
||||
LL | Variant { unsafe field: () },
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: see issue #132922 <https://github.com/rust-lang/rust/issues/132922> 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:24:5
|
||||
|
|
||||
LL | unsafe field: (),
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: see issue #132922 <https://github.com/rust-lang/rust/issues/132922> 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 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -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 116
|
||||
ast-stats-1 Total 6_656 116
|
||||
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 127
|
||||
ast-stats-2 Total 7_304 127
|
||||
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 180
|
||||
hir-stats Total 9_040 180
|
||||
hir-stats
|
||||
|
@ -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: []
|
||||
|
62
tests/ui/unsafe-fields-crate.rs
Normal file
62
tests/ui/unsafe-fields-crate.rs
Normal file
@ -0,0 +1,62 @@
|
||||
//@ compile-flags: --crate-type=lib
|
||||
//@ aux-build: unsafe-fields-crate-dep.rs
|
||||
|
||||
extern crate unsafe_fields_crate_dep;
|
||||
|
||||
use unsafe_fields_crate_dep::WithUnsafeField;
|
||||
|
||||
fn new_without_unsafe() -> WithUnsafeField {
|
||||
WithUnsafeField {
|
||||
//~^ ERROR
|
||||
unsafe_field: 0,
|
||||
safe_field: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn operate_on_safe_field(s: &mut WithUnsafeField) {
|
||||
s.safe_field = 2;
|
||||
&s.safe_field;
|
||||
s.safe_field;
|
||||
}
|
||||
|
||||
fn set_unsafe_field(s: &mut WithUnsafeField) {
|
||||
unsafe {
|
||||
s.unsafe_field = 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn read_unsafe_field(s: &WithUnsafeField) -> u32 {
|
||||
unsafe { s.unsafe_field }
|
||||
}
|
||||
|
||||
fn ref_unsafe_field(s: &WithUnsafeField) -> &u32 {
|
||||
unsafe { &s.unsafe_field }
|
||||
}
|
||||
|
||||
fn destructure(s: &WithUnsafeField) {
|
||||
unsafe {
|
||||
let WithUnsafeField { safe_field, unsafe_field } = s;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_unsafe_field_without_unsafe(s: &mut WithUnsafeField) {
|
||||
s.unsafe_field = 2;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn read_unsafe_field_without_unsafe(s: &WithUnsafeField) -> u32 {
|
||||
s.unsafe_field
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn ref_unsafe_field_without_unsafe(s: &WithUnsafeField) -> &u32 {
|
||||
&s.unsafe_field
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn destructure_without_unsafe(s: &WithUnsafeField) {
|
||||
let WithUnsafeField { safe_field, unsafe_field } = s;
|
||||
//~^ ERROR
|
||||
|
||||
let WithUnsafeField { safe_field, .. } = s;
|
||||
}
|
47
tests/ui/unsafe-fields-crate.stderr
Normal file
47
tests/ui/unsafe-fields-crate.stderr
Normal file
@ -0,0 +1,47 @@
|
||||
error[E0133]: initializing type with an unsafe field is unsafe and requires unsafe block
|
||||
--> $DIR/unsafe-fields-crate.rs:9:5
|
||||
|
|
||||
LL | / WithUnsafeField {
|
||||
LL | |
|
||||
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-crate.rs:43:5
|
||||
|
|
||||
LL | s.unsafe_field = 2;
|
||||
| ^^^^^^^^^^^^^^ use of unsafe field
|
||||
|
|
||||
= note: unsafe fields may carry library invariants
|
||||
|
||||
error[E0133]: use of unsafe field is unsafe and requires unsafe block
|
||||
--> $DIR/unsafe-fields-crate.rs:48:5
|
||||
|
|
||||
LL | s.unsafe_field
|
||||
| ^^^^^^^^^^^^^^ use of unsafe field
|
||||
|
|
||||
= note: unsafe fields may carry library invariants
|
||||
|
||||
error[E0133]: use of unsafe field is unsafe and requires unsafe block
|
||||
--> $DIR/unsafe-fields-crate.rs:53:6
|
||||
|
|
||||
LL | &s.unsafe_field
|
||||
| ^^^^^^^^^^^^^^ use of unsafe field
|
||||
|
|
||||
= note: unsafe fields may carry library invariants
|
||||
|
||||
error[E0133]: use of unsafe field is unsafe and requires unsafe block
|
||||
--> $DIR/unsafe-fields-crate.rs:58:39
|
||||
|
|
||||
LL | let WithUnsafeField { safe_field, unsafe_field } = s;
|
||||
| ^^^^^^^^^^^^ use of unsafe field
|
||||
|
|
||||
= note: unsafe fields may carry library invariants
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
10
tests/ui/unsafe-fields-parse.rs
Normal file
10
tests/ui/unsafe-fields-parse.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ compile-flags: --crate-type=lib
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsafe_fields)]
|
||||
|
||||
// Parse errors even *with* unsafe_fields, which would make the compiler early-exit otherwise.
|
||||
enum A {
|
||||
TupleLike(unsafe u32), //~ ERROR
|
||||
}
|
||||
|
||||
struct B(unsafe u32); //~ ERROR
|
18
tests/ui/unsafe-fields-parse.stderr
Normal file
18
tests/ui/unsafe-fields-parse.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error: expected type, found keyword `unsafe`
|
||||
--> $DIR/unsafe-fields-parse.rs:7:15
|
||||
|
|
||||
LL | enum A {
|
||||
| - while parsing this enum
|
||||
LL | TupleLike(unsafe u32),
|
||||
| ^^^^^^ expected type
|
||||
|
|
||||
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||
|
||||
error: expected type, found keyword `unsafe`
|
||||
--> $DIR/unsafe-fields-parse.rs:10:10
|
||||
|
|
||||
LL | struct B(unsafe u32);
|
||||
| ^^^^^^ expected type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
109
tests/ui/unsafe-fields.rs
Normal file
109
tests/ui/unsafe-fields.rs
Normal file
@ -0,0 +1,109 @@
|
||||
//@ compile-flags: --crate-type=lib
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsafe_fields)]
|
||||
|
||||
struct WithUnsafeField {
|
||||
unsafe unsafe_field: u32,
|
||||
safe_field: u32,
|
||||
}
|
||||
|
||||
enum A {
|
||||
WithUnsafeField { unsafe unsafe_field: u32, safe_field: u32 },
|
||||
}
|
||||
|
||||
fn f(a: A) {
|
||||
let A::WithUnsafeField { unsafe_field, safe_field } = a;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
struct WithInvalidUnsafeField {
|
||||
unsafe unsafe_noncopy_field: Vec<u32>, //~ ERROR
|
||||
}
|
||||
|
||||
struct WithManuallyDropUnsafeField {
|
||||
unsafe unsafe_noncopy_field: std::mem::ManuallyDrop<Vec<u32>>,
|
||||
}
|
||||
|
||||
union WithUnsafeFieldUnion {
|
||||
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 operate_on_safe_field(&mut self) {
|
||||
self.safe_field = 2;
|
||||
&self.safe_field;
|
||||
self.safe_field;
|
||||
}
|
||||
|
||||
fn set_unsafe_field(&mut self) {
|
||||
unsafe {
|
||||
self.unsafe_field = 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn read_unsafe_field(&self) -> u32 {
|
||||
unsafe {
|
||||
self.unsafe_field
|
||||
}
|
||||
}
|
||||
|
||||
fn ref_unsafe_field(&self) -> &u32 {
|
||||
unsafe {
|
||||
&self.unsafe_field
|
||||
}
|
||||
}
|
||||
|
||||
fn destructure(&self) {
|
||||
unsafe {
|
||||
let Self { safe_field, unsafe_field } = self;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_unsafe_field_without_unsafe(&mut self) {
|
||||
self.unsafe_field = 2;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn read_unsafe_field_without_unsafe(&self) -> u32 {
|
||||
self.unsafe_field
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn ref_unsafe_field_without_unsafe(&self) -> &u32 {
|
||||
&self.unsafe_field
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn destructure_without_unsafe(&self) {
|
||||
let Self { safe_field, unsafe_field } = self;
|
||||
//~^ ERROR
|
||||
|
||||
let WithUnsafeField { safe_field, .. } = self;
|
||||
}
|
||||
|
||||
fn offset_of(&self) -> usize {
|
||||
std::mem::offset_of!(WithUnsafeField, unsafe_field)
|
||||
}
|
||||
|
||||
fn raw_const(&self) -> *const u32 {
|
||||
&raw const self.unsafe_field
|
||||
//~^ ERROR
|
||||
}
|
||||
}
|
75
tests/ui/unsafe-fields.stderr
Normal file
75
tests/ui/unsafe-fields.stderr
Normal file
@ -0,0 +1,75 @@
|
||||
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be unsafe
|
||||
--> $DIR/unsafe-fields.rs:20:5
|
||||
|
|
||||
LL | unsafe unsafe_noncopy_field: Vec<u32>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: unsafe fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
help: wrap the field type in `ManuallyDrop<...>`
|
||||
|
|
||||
LL | unsafe unsafe_noncopy_field: std::mem::ManuallyDrop<Vec<u32>>,
|
||||
| +++++++++++++++++++++++ +
|
||||
|
||||
error[E0133]: use of unsafe field is unsafe and requires unsafe block
|
||||
--> $DIR/unsafe-fields.rs:15:30
|
||||
|
|
||||
LL | let A::WithUnsafeField { unsafe_field, safe_field } = a;
|
||||
| ^^^^^^^^^^^^ use of unsafe field
|
||||
|
|
||||
= note: unsafe fields may carry library invariants
|
||||
|
||||
error[E0133]: initializing type with an unsafe field is unsafe and requires unsafe block
|
||||
--> $DIR/unsafe-fields.rs:43: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:80:9
|
||||
|
|
||||
LL | self.unsafe_field = 2;
|
||||
| ^^^^^^^^^^^^^^^^^ use of 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:85:9
|
||||
|
|
||||
LL | self.unsafe_field
|
||||
| ^^^^^^^^^^^^^^^^^ use of 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:90:10
|
||||
|
|
||||
LL | &self.unsafe_field
|
||||
| ^^^^^^^^^^^^^^^^^ use of 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:95:32
|
||||
|
|
||||
LL | let Self { safe_field, unsafe_field } = self;
|
||||
| ^^^^^^^^^^^^ use of 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:106:20
|
||||
|
|
||||
LL | &raw const self.unsafe_field
|
||||
| ^^^^^^^^^^^^^^^^^ use of unsafe field
|
||||
|
|
||||
= note: unsafe fields may carry library invariants
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0133, E0740.
|
||||
For more information about an error, try `rustc --explain E0133`.
|
Loading…
Reference in New Issue
Block a user