Auto merge of #102256 - cjgillot:let-under, r=lcnr
Introduce a no-op `PlaceMention` statement for `let _ =`. Fixes https://github.com/rust-lang/rust/issues/54003 Fixes https://github.com/rust-lang/rust/issues/80059 Split from https://github.com/rust-lang/rust/pull/101500 This PR introduces a new `PlaceMention` statement dedicated to matches that neither introduce bindings nor ascribe types. Without this, all traces of the match would vanish from MIR, making it impossible to diagnose unsafety or use in #101500. This allows to mark `let _ = <unsafe union access or dereference>` as requiring an unsafe block. Nominating for lang team, as this introduces an extra error.
This commit is contained in:
commit
d5833423a0
@ -390,6 +390,7 @@ fn statement_effect(
|
||||
| mir::StatementKind::Deinit(..)
|
||||
| mir::StatementKind::StorageLive(..)
|
||||
| mir::StatementKind::Retag { .. }
|
||||
| mir::StatementKind::PlaceMention(..)
|
||||
| mir::StatementKind::AscribeUserType(..)
|
||||
| mir::StatementKind::Coverage(..)
|
||||
| mir::StatementKind::Intrinsic(..)
|
||||
|
@ -72,6 +72,8 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
|
||||
Some(DefUse::Drop),
|
||||
|
||||
// This statement exists to help unsafeck. It does not require the place to be live.
|
||||
PlaceContext::NonUse(NonUseContext::PlaceMention) => None,
|
||||
// Debug info is neither def nor use.
|
||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
|
||||
|
||||
|
@ -79,6 +79,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
}
|
||||
// Only relevant for mir typeck
|
||||
StatementKind::AscribeUserType(..)
|
||||
// Only relevant for unsafeck
|
||||
| StatementKind::PlaceMention(..)
|
||||
// Doesn't have any language semantics
|
||||
| StatementKind::Coverage(..)
|
||||
// Does not actually affect borrowck
|
||||
|
@ -690,6 +690,8 @@ fn visit_statement_before_primary_effect(
|
||||
}
|
||||
// Only relevant for mir typeck
|
||||
StatementKind::AscribeUserType(..)
|
||||
// Only relevant for unsafeck
|
||||
| StatementKind::PlaceMention(..)
|
||||
// Doesn't have any language semantics
|
||||
| StatementKind::Coverage(..)
|
||||
// These do not actually affect borrowck
|
||||
|
@ -772,7 +772,9 @@ fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance {
|
||||
|
||||
match context {
|
||||
PlaceContext::MutatingUse(_) => ty::Invariant,
|
||||
PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
|
||||
PlaceContext::NonUse(StorageDead | StorageLive | PlaceMention | VarDebugInfo) => {
|
||||
ty::Invariant
|
||||
}
|
||||
PlaceContext::NonMutatingUse(
|
||||
Inspect | Copy | Move | SharedBorrow | ShallowBorrow | UniqueBorrow | AddressOf
|
||||
| Projection,
|
||||
@ -1282,6 +1284,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Nop => {}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
|
@ -819,6 +819,7 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
| StatementKind::Nop
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::AscribeUserType(..) => {}
|
||||
|
||||
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
|
||||
|
@ -529,6 +529,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => {}
|
||||
|
@ -92,6 +92,7 @@ pub fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx
|
||||
| mir::StatementKind::Retag { .. }
|
||||
| mir::StatementKind::AscribeUserType(..)
|
||||
| mir::StatementKind::ConstEvalCounter
|
||||
| mir::StatementKind::PlaceMention(..)
|
||||
| mir::StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
|
||||
Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
|
||||
|
||||
// Statements we do not track.
|
||||
AscribeUserType(..) => {}
|
||||
PlaceMention(..) | AscribeUserType(..) => {}
|
||||
|
||||
// Currently, Miri discards Coverage statements. Coverage statements are only injected
|
||||
// via an optional compile time MIR pass and have no side effects. Since Coverage
|
||||
|
@ -690,6 +690,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Intrinsic(..)
|
||||
|
@ -679,6 +679,14 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
}
|
||||
}
|
||||
}
|
||||
StatementKind::PlaceMention(..) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
location,
|
||||
"`PlaceMention` should have been removed after drop lowering phase",
|
||||
);
|
||||
}
|
||||
}
|
||||
StatementKind::AscribeUserType(..) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
|
@ -1453,6 +1453,9 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
|
||||
}
|
||||
Deinit(ref place) => write!(fmt, "Deinit({:?})", place),
|
||||
PlaceMention(ref place) => {
|
||||
write!(fmt, "PlaceMention({:?})", place)
|
||||
}
|
||||
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
|
||||
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
||||
}
|
||||
|
@ -247,6 +247,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
|
||||
StorageLive(..) => "StorageLive",
|
||||
StorageDead(..) => "StorageDead",
|
||||
Retag(..) => "Retag",
|
||||
PlaceMention(..) => "PlaceMention",
|
||||
AscribeUserType(..) => "AscribeUserType",
|
||||
Coverage(..) => "Coverage",
|
||||
Intrinsic(..) => "Intrinsic",
|
||||
|
@ -325,6 +325,15 @@ pub enum StatementKind<'tcx> {
|
||||
/// Only `RetagKind::Default` and `RetagKind::FnEntry` are permitted.
|
||||
Retag(RetagKind, Box<Place<'tcx>>),
|
||||
|
||||
/// This statement exists to preserve a trace of a scrutinee matched against a wildcard binding.
|
||||
/// This is especially useful for `let _ = PLACE;` bindings that desugar to a single
|
||||
/// `PlaceMention(PLACE)`.
|
||||
///
|
||||
/// When executed at runtime this is a nop.
|
||||
///
|
||||
/// Disallowed after drop elaboration.
|
||||
PlaceMention(Box<Place<'tcx>>),
|
||||
|
||||
/// Encodes a user's type ascription. These need to be preserved
|
||||
/// intact so that NLL can respect them. For example:
|
||||
/// ```ignore (illustrative)
|
||||
|
@ -405,6 +405,13 @@ fn super_statement(&mut self,
|
||||
StatementKind::Retag(kind, place) => {
|
||||
self.visit_retag($(& $mutability)? *kind, place, location);
|
||||
}
|
||||
StatementKind::PlaceMention(place) => {
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonUse(NonUseContext::PlaceMention),
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::AscribeUserType(
|
||||
box (place, user_ty),
|
||||
variance
|
||||
@ -1288,6 +1295,8 @@ pub enum NonUseContext {
|
||||
AscribeUserTy,
|
||||
/// The data of a user variable, for debug info.
|
||||
VarDebugInfo,
|
||||
/// PlaceMention statement.
|
||||
PlaceMention,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -90,6 +90,17 @@ pub(crate) fn push_fake_read(
|
||||
self.push(block, stmt);
|
||||
}
|
||||
|
||||
pub(crate) fn push_place_mention(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
source_info: SourceInfo,
|
||||
place: Place<'tcx>,
|
||||
) {
|
||||
let kind = StatementKind::PlaceMention(Box::new(place));
|
||||
let stmt = Statement { source_info, kind };
|
||||
self.push(block, stmt);
|
||||
}
|
||||
|
||||
pub(crate) fn terminate(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
|
@ -556,6 +556,12 @@ pub(super) fn expr_into_pattern(
|
||||
|
||||
_ => {
|
||||
let place_builder = unpack!(block = self.as_place_builder(block, initializer));
|
||||
|
||||
if let Some(place) = place_builder.try_to_place(self) {
|
||||
let source_info = self.source_info(initializer.span);
|
||||
self.cfg.push_place_mention(block, source_info, place);
|
||||
}
|
||||
|
||||
self.place_into_pattern(block, &irrefutable_pat, place_builder, true)
|
||||
}
|
||||
}
|
||||
@ -576,6 +582,7 @@ pub(crate) fn place_into_pattern(
|
||||
false,
|
||||
&mut [&mut candidate],
|
||||
);
|
||||
|
||||
// For matches and function arguments, the place that is being matched
|
||||
// can be set when creating the variables. But the place for
|
||||
// let PATTERN = ... might not even exist until we do the assignment.
|
||||
|
@ -263,6 +263,7 @@ fn apply_statement_effect(
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Intrinsic(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
|
@ -139,6 +139,7 @@ fn before_statement_effect(
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
// variants are added.
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
|
@ -329,6 +329,7 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
||||
}
|
||||
StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Intrinsic(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
|
@ -86,6 +86,7 @@ fn super_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::V
|
||||
StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::AscribeUserType(..) => (),
|
||||
}
|
||||
|
@ -100,13 +100,16 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Intrinsic(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => {
|
||||
// safe (at least as emitted during MIR construction)
|
||||
}
|
||||
// `AscribeUserType` just exists to help MIR borrowck.
|
||||
// It has no semantics, and everything is already reported by `PlaceMention`.
|
||||
StatementKind::AscribeUserType(..) => return,
|
||||
}
|
||||
self.super_statement(statement, location);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
for statement in basic_block.statements.iter_mut() {
|
||||
match statement.kind {
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
|
||||
| StatementKind::FakeRead(..) => statement.make_nop(),
|
||||
_ => (),
|
||||
|
@ -832,6 +832,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::AscribeUserType(_, _) => {
|
||||
Some(statement.source_info.span)
|
||||
}
|
||||
|
@ -56,7 +56,9 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => (),
|
||||
|
||||
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
|
||||
StatementKind::FakeRead(_)
|
||||
| StatementKind::PlaceMention(_)
|
||||
| StatementKind::AscribeUserType(_, _) => {
|
||||
bug!("{:?} not found in this MIR phase!", &statement.kind)
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +583,9 @@ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_) => (),
|
||||
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
|
||||
StatementKind::FakeRead(_)
|
||||
| StatementKind::AscribeUserType(_, _)
|
||||
| StatementKind::PlaceMention(_) => {
|
||||
bug!("{:?} not found in this MIR phase", statement)
|
||||
}
|
||||
}
|
||||
|
@ -1647,6 +1647,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Intrinsic(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
|
@ -33,6 +33,7 @@ fn is_nop_landing_pad(
|
||||
StatementKind::FakeRead(..)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
|
@ -245,6 +245,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Intrinsic(_)
|
||||
@ -315,6 +316,7 @@ fn find_determining_place<'tcx>(
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::Intrinsic(_)
|
||||
| StatementKind::ConstEvalCounter
|
||||
|
@ -525,6 +525,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::AscribeUserType(..) => {
|
||||
self.super_statement(statement, location);
|
||||
}
|
||||
|
@ -241,6 +241,7 @@ fn check_statement<'tcx>(
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => Ok(()),
|
||||
|
@ -100,6 +100,7 @@ fn full_tested_match() -> () {
|
||||
}
|
||||
|
||||
bb11: {
|
||||
PlaceMention(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
|
||||
StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
|
||||
StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
|
||||
_0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:28: +6:2
|
||||
|
@ -100,6 +100,7 @@ fn full_tested_match2() -> () {
|
||||
}
|
||||
|
||||
bb11: {
|
||||
PlaceMention(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
|
||||
StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
|
||||
StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
|
||||
_0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:29: +6:2
|
||||
|
@ -162,6 +162,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb19: {
|
||||
PlaceMention(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6
|
||||
StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7
|
||||
StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7
|
||||
_0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:11: +7:2
|
||||
|
@ -77,6 +77,7 @@ fn move_out_by_subslice() -> () {
|
||||
bb6: {
|
||||
StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
|
||||
PlaceMention(_1); // scope 1 at $DIR/uniform_array_move_out.rs:+2:21: +2:22
|
||||
StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
|
||||
_12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
|
||||
_0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2
|
||||
|
@ -77,6 +77,7 @@ fn move_out_from_end() -> () {
|
||||
bb6: {
|
||||
StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
|
||||
FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
|
||||
PlaceMention(_1); // scope 1 at $DIR/uniform_array_move_out.rs:+2:20: +2:21
|
||||
StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
|
||||
_12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
|
||||
_0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +3:2
|
||||
|
@ -29,6 +29,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb1: {
|
||||
PlaceMention(_1); // scope 0 at $DIR/issue_72181.rs:+1:13: +1:34
|
||||
StorageDead(_1); // scope 0 at $DIR/issue_72181.rs:+1:34: +1:35
|
||||
StorageLive(_2); // scope 1 at $DIR/issue_72181.rs:+3:9: +3:10
|
||||
StorageLive(_3); // scope 1 at $DIR/issue_72181.rs:+3:14: +3:27
|
||||
@ -49,6 +50,7 @@ fn main() -> () {
|
||||
|
||||
bb2: {
|
||||
_5 = (_2[_6].0: u64); // scope 4 at $DIR/issue_72181.rs:+4:22: +4:28
|
||||
PlaceMention(_5); // scope 2 at $DIR/issue_72181.rs:+4:13: +4:30
|
||||
StorageDead(_6); // scope 2 at $DIR/issue_72181.rs:+4:30: +4:31
|
||||
StorageDead(_5); // scope 2 at $DIR/issue_72181.rs:+4:30: +4:31
|
||||
_0 = const (); // scope 0 at $DIR/issue_72181.rs:+0:11: +5:2
|
||||
|
@ -20,6 +20,7 @@ fn bar(_1: Box<[T]>) -> () {
|
||||
|
||||
bb1: {
|
||||
StorageDead(_3); // scope 0 at $DIR/issue_91633.rs:+4:18: +4:19
|
||||
PlaceMention((*_2)); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:19
|
||||
StorageDead(_2); // scope 0 at $DIR/issue_91633.rs:+4:19: +4:20
|
||||
_0 = const (); // scope 0 at $DIR/issue_91633.rs:+3:2: +5:3
|
||||
drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
|
||||
|
@ -23,6 +23,7 @@ fn hey(_1: &[T]) -> () {
|
||||
bb1: {
|
||||
StorageDead(_4); // scope 0 at $DIR/issue_91633.rs:+4:19: +4:20
|
||||
_2 = &(*_3); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:20
|
||||
PlaceMention(_2); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:20
|
||||
StorageDead(_2); // scope 0 at $DIR/issue_91633.rs:+4:20: +4:21
|
||||
_0 = const (); // scope 0 at $DIR/issue_91633.rs:+3:2: +5:3
|
||||
StorageDead(_3); // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
|
||||
|
@ -65,6 +65,6 @@
|
||||
65| | }
|
||||
66| 0| x = 3;
|
||||
67| | }
|
||||
68| | let _ = x;
|
||||
68| 1| let _ = x;
|
||||
69| 1|}
|
||||
|
||||
|
@ -21,7 +21,7 @@ fn let_wild_gets_unsafe_field() {
|
||||
let u2 = U { a: I(1) };
|
||||
let p = P { a: &2, b: &3 };
|
||||
let _ = &p.b; //~ ERROR reference to packed field
|
||||
let _ = u1.a; // #53114: should eventually signal error as well
|
||||
let _ = u1.a; //~ ERROR [E0133]
|
||||
let _ = &u2.a; //~ ERROR [E0133]
|
||||
|
||||
// variation on above with `_` in substructure
|
||||
@ -30,6 +30,20 @@ fn let_wild_gets_unsafe_field() {
|
||||
let (_,) = (&u2.a,); //~ ERROR [E0133]
|
||||
}
|
||||
|
||||
fn let_ascribe_gets_unsafe_field() {
|
||||
let u1 = U { a: I(0) };
|
||||
let u2 = U { a: I(1) };
|
||||
let p = P { a: &2, b: &3 };
|
||||
let _: _ = &p.b; //~ ERROR reference to packed field
|
||||
let _: _ = u1.a; //~ ERROR [E0133]
|
||||
let _: _ = &u2.a; //~ ERROR [E0133]
|
||||
|
||||
// variation on above with `_` in substructure
|
||||
let (_,): _ = (&p.b,); //~ ERROR reference to packed field
|
||||
let (_,): _ = (u1.a,); //~ ERROR [E0133]
|
||||
let (_,): _ = (&u2.a,); //~ ERROR [E0133]
|
||||
}
|
||||
|
||||
fn match_unsafe_field_to_wild() {
|
||||
let u1 = U { a: I(0) };
|
||||
let u2 = U { a: I(1) };
|
||||
|
@ -17,7 +17,25 @@ LL | let (_,) = (&p.b,);
|
||||
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
|
||||
|
||||
error[E0793]: reference to packed field is unaligned
|
||||
--> $DIR/issue-53114-safety-checks.rs:37:11
|
||||
--> $DIR/issue-53114-safety-checks.rs:37:16
|
||||
|
|
||||
LL | let _: _ = &p.b;
|
||||
| ^^^^
|
||||
|
|
||||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
|
||||
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
|
||||
|
||||
error[E0793]: reference to packed field is unaligned
|
||||
--> $DIR/issue-53114-safety-checks.rs:42:20
|
||||
|
|
||||
LL | let (_,): _ = (&p.b,);
|
||||
| ^^^^
|
||||
|
|
||||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
|
||||
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
|
||||
|
||||
error[E0793]: reference to packed field is unaligned
|
||||
--> $DIR/issue-53114-safety-checks.rs:51:11
|
||||
|
|
||||
LL | match &p.b { _ => { } }
|
||||
| ^^^^
|
||||
@ -26,7 +44,7 @@ LL | match &p.b { _ => { } }
|
||||
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
|
||||
|
||||
error[E0793]: reference to packed field is unaligned
|
||||
--> $DIR/issue-53114-safety-checks.rs:42:12
|
||||
--> $DIR/issue-53114-safety-checks.rs:56:12
|
||||
|
|
||||
LL | match (&p.b,) { (_,) => { } }
|
||||
| ^^^^
|
||||
@ -34,6 +52,14 @@ LL | match (&p.b,) { (_,) => { } }
|
||||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
|
||||
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:24:13
|
||||
|
|
||||
LL | let _ = u1.a;
|
||||
| ^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:25:13
|
||||
|
|
||||
@ -59,7 +85,39 @@ LL | let (_,) = (&u2.a,);
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:38:11
|
||||
--> $DIR/issue-53114-safety-checks.rs:38:16
|
||||
|
|
||||
LL | let _: _ = u1.a;
|
||||
| ^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:39:16
|
||||
|
|
||||
LL | let _: _ = &u2.a;
|
||||
| ^^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:43:20
|
||||
|
|
||||
LL | let (_,): _ = (u1.a,);
|
||||
| ^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:44:20
|
||||
|
|
||||
LL | let (_,): _ = (&u2.a,);
|
||||
| ^^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:52:11
|
||||
|
|
||||
LL | match u1.a { _ => { } }
|
||||
| ^^^^ access to union field
|
||||
@ -67,7 +125,7 @@ LL | match u1.a { _ => { } }
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:39:11
|
||||
--> $DIR/issue-53114-safety-checks.rs:53:11
|
||||
|
|
||||
LL | match &u2.a { _ => { } }
|
||||
| ^^^^^ access to union field
|
||||
@ -75,7 +133,7 @@ LL | match &u2.a { _ => { } }
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:43:12
|
||||
--> $DIR/issue-53114-safety-checks.rs:57:12
|
||||
|
|
||||
LL | match (u1.a,) { (_,) => { } }
|
||||
| ^^^^ access to union field
|
||||
@ -83,14 +141,14 @@ LL | match (u1.a,) { (_,) => { } }
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-53114-safety-checks.rs:44:12
|
||||
--> $DIR/issue-53114-safety-checks.rs:58:12
|
||||
|
|
||||
LL | match (&u2.a,) { (_,) => { } }
|
||||
| ^^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0133, E0793.
|
||||
For more information about an error, try `rustc --explain E0133`.
|
||||
|
27
tests/ui/borrowck/let_underscore_temporary.rs
Normal file
27
tests/ui/borrowck/let_underscore_temporary.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// check-pass
|
||||
|
||||
fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
|
||||
let _ = if let Some(s) = *string { s.len() } else { 0 };
|
||||
let _ = if let Some(s) = &num { s } else { &0 };
|
||||
let _ = if let Some(s) = &mut num {
|
||||
*s += 1;
|
||||
s
|
||||
} else {
|
||||
&mut 0
|
||||
};
|
||||
let _ = if let Some(ref s) = num { s } else { &0 };
|
||||
let _ = if let Some(mut s) = num {
|
||||
s += 1;
|
||||
s
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let _ = if let Some(ref mut s) = num {
|
||||
*s += 1;
|
||||
s
|
||||
} else {
|
||||
&mut 0
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -7,4 +7,7 @@ const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x
|
||||
const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x }
|
||||
//~^ dereferencing raw mutable pointers in constant functions
|
||||
|
||||
const unsafe fn bad_const_unsafe_deref_raw_underscore(x: *mut usize) { let _ = *x; }
|
||||
//~^ dereferencing raw mutable pointers in constant functions
|
||||
|
||||
fn main() {}
|
||||
|
@ -25,6 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u
|
||||
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0658]: dereferencing raw mutable pointers in constant functions is unstable
|
||||
--> $DIR/min_const_fn_unsafe_bad.rs:10:80
|
||||
|
|
||||
LL | const unsafe fn bad_const_unsafe_deref_raw_underscore(x: *mut usize) { let _ = *x; }
|
||||
| ^^
|
||||
|
|
||||
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,11 +1,35 @@
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:5:12
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:5:13
|
||||
|
|
||||
LL | let _ = *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:6:17
|
||||
|
|
||||
LL | let _: u8 = *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:7:9
|
||||
|
|
||||
LL | _ = *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:8:12
|
||||
|
|
||||
LL | return *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
||||
|
@ -2,6 +2,9 @@
|
||||
// [thir]compile-flags: -Z thir-unsafeck
|
||||
|
||||
fn f(p: *const u8) -> u8 {
|
||||
let _ = *p; //~ ERROR dereference of raw pointer is unsafe
|
||||
let _: u8 = *p; //~ ERROR dereference of raw pointer is unsafe
|
||||
_ = *p; //~ ERROR dereference of raw pointer is unsafe
|
||||
return *p; //~ ERROR dereference of raw pointer is unsafe
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,35 @@
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:5:12
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:5:13
|
||||
|
|
||||
LL | let _ = *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:6:17
|
||||
|
|
||||
LL | let _: u8 = *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:7:9
|
||||
|
|
||||
LL | _ = *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
--> $DIR/unsafe-fn-deref-ptr.rs:8:12
|
||||
|
|
||||
LL | return *p;
|
||||
| ^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
||||
|
Loading…
Reference in New Issue
Block a user