Skip to content

Commit ddfa246

Browse files
committed
Evaluate place expression in PlaceMention.
1 parent 4096619 commit ddfa246

File tree

13 files changed

+159
-19
lines changed

13 files changed

+159
-19
lines changed

compiler/rustc_borrowck/src/def_use.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,16 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
5252
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
5353
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
5454

55+
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
56+
// contain dangling references.
57+
PlaceContext::NonUse(NonUseContext::PlaceMention) |
58+
PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
59+
5560
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
5661
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
5762
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
5863
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
5964
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
60-
PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
6165
PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
6266
Some(DefUse::Use),
6367

@@ -72,8 +76,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
7276
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
7377
Some(DefUse::Drop),
7478

75-
// This statement exists to help unsafeck. It does not require the place to be live.
76-
PlaceContext::NonUse(NonUseContext::PlaceMention) => None,
7779
// Debug info is neither def nor use.
7880
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
7981

compiler/rustc_borrowck/src/invalidation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
7979
}
8080
// Only relevant for mir typeck
8181
StatementKind::AscribeUserType(..)
82-
// Only relevant for unsafeck
82+
// Only relevant for liveness and unsafeck
8383
| StatementKind::PlaceMention(..)
8484
// Doesn't have any language semantics
8585
| StatementKind::Coverage(..)

compiler/rustc_borrowck/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
665665
}
666666
// Only relevant for mir typeck
667667
StatementKind::AscribeUserType(..)
668-
// Only relevant for unsafeck
668+
// Only relevant for liveness and unsafeck
669669
| StatementKind::PlaceMention(..)
670670
// Doesn't have any language semantics
671671
| StatementKind::Coverage(..)

compiler/rustc_const_eval/src/interpret/step.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
113113

114114
Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
115115

116-
// Statements we do not track.
117-
PlaceMention(..) | AscribeUserType(..) => {}
116+
// Evaluate the place expression, without reading from it.
117+
PlaceMention(box place) => {
118+
let _ = self.eval_place(*place)?;
119+
}
120+
121+
// This exists purely to guide borrowck lifetime inference, and does not have
122+
// an operational effect.
123+
AscribeUserType(..) => {}
118124

119125
// Currently, Miri discards Coverage statements. Coverage statements are only injected
120126
// via an optional compile time MIR pass and have no side effects. Since Coverage

compiler/rustc_middle/src/mir/syntax.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ pub enum StatementKind<'tcx> {
331331
/// This is especially useful for `let _ = PLACE;` bindings that desugar to a single
332332
/// `PlaceMention(PLACE)`.
333333
///
334-
/// When executed at runtime this is a nop.
334+
/// When executed at runtime, this computes the given place, but then discards
335+
/// it without doing a load. It is UB if the place is not pointing to live memory.
335336
///
336337
/// Disallowed after drop elaboration.
337338
PlaceMention(Box<Place<'tcx>>),

src/tools/clippy/tests/ui/option_if_let_else.fixed

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
2525
fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
2626
let _ = string.map_or(0, |s| s.len());
2727
let _ = num.as_ref().map_or(&0, |s| s);
28-
let _ = num.as_mut().map_or(&mut 0, |s| {
28+
let _ = num.as_mut().map_or(&0, |s| {
2929
*s += 1;
3030
s
3131
});
@@ -34,7 +34,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
3434
s += 1;
3535
s
3636
});
37-
let _ = num.as_mut().map_or(&mut 0, |s| {
37+
let _ = num.as_mut().map_or(&0, |s| {
3838
*s += 1;
3939
s
4040
});

src/tools/clippy/tests/ui/option_if_let_else.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
3333
*s += 1;
3434
s
3535
} else {
36-
&mut 0
36+
&0
3737
};
3838
let _ = if let Some(ref s) = num { s } else { &0 };
3939
let _ = if let Some(mut s) = num {
@@ -46,7 +46,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
4646
*s += 1;
4747
s
4848
} else {
49-
&mut 0
49+
&0
5050
};
5151
}
5252

src/tools/clippy/tests/ui/option_if_let_else.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ LL | let _ = if let Some(s) = &mut num {
3030
LL | | *s += 1;
3131
LL | | s
3232
LL | | } else {
33-
LL | | &mut 0
33+
LL | | &0
3434
LL | | };
3535
| |_____^
3636
|
3737
help: try
3838
|
39-
LL ~ let _ = num.as_mut().map_or(&mut 0, |s| {
39+
LL ~ let _ = num.as_mut().map_or(&0, |s| {
4040
LL + *s += 1;
4141
LL + s
4242
LL ~ });
@@ -76,13 +76,13 @@ LL | let _ = if let Some(ref mut s) = num {
7676
LL | | *s += 1;
7777
LL | | s
7878
LL | | } else {
79-
LL | | &mut 0
79+
LL | | &0
8080
LL | | };
8181
| |_____^
8282
|
8383
help: try
8484
|
85-
LL ~ let _ = num.as_mut().map_or(&mut 0, |s| {
85+
LL ~ let _ = num.as_mut().map_or(&0, |s| {
8686
LL + *s += 1;
8787
LL + s
8888
LL ~ });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Make sure we find these even with many checks disabled.
2+
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
3+
4+
fn main() {
5+
let p = {
6+
let b = Box::new(42);
7+
&*b as *const i32
8+
};
9+
let _ = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed
10+
panic!("this should never print");
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
2+
--> $DIR/dangling_pointer_deref_underscore.rs:LL:CC
3+
|
4+
LL | let _ = unsafe { *p };
5+
| ^^ pointer to ALLOC was dereferenced after this allocation got freed
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/dangling_pointer_deref_underscore.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+

tests/ui/borrowck/let_underscore_temporary.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// check-pass
1+
// check-fail
22

33
fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
44
let _ = if let Some(s) = *string { s.len() } else { 0 };
@@ -8,6 +8,7 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
88
s
99
} else {
1010
&mut 0
11+
//~^ ERROR temporary value dropped while borrowed
1112
};
1213
let _ = if let Some(ref s) = num { s } else { &0 };
1314
let _ = if let Some(mut s) = num {
@@ -21,6 +22,33 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
2122
s
2223
} else {
2324
&mut 0
25+
//~^ ERROR temporary value dropped while borrowed
26+
};
27+
}
28+
29+
fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) {
30+
let _: _ = if let Some(s) = *string { s.len() } else { 0 };
31+
let _: _ = if let Some(s) = &num { s } else { &0 };
32+
let _: _ = if let Some(s) = &mut num {
33+
*s += 1;
34+
s
35+
} else {
36+
&mut 0
37+
//~^ ERROR temporary value dropped while borrowed
38+
};
39+
let _: _ = if let Some(ref s) = num { s } else { &0 };
40+
let _: _ = if let Some(mut s) = num {
41+
s += 1;
42+
s
43+
} else {
44+
0
45+
};
46+
let _: _ = if let Some(ref mut s) = num {
47+
*s += 1;
48+
s
49+
} else {
50+
&mut 0
51+
//~^ ERROR temporary value dropped while borrowed
2452
};
2553
}
2654

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/let_underscore_temporary.rs:10:14
3+
|
4+
LL | let _ = if let Some(s) = &mut num {
5+
| _____________-
6+
LL | | *s += 1;
7+
LL | | s
8+
LL | | } else {
9+
LL | | &mut 0
10+
| | ^ creates a temporary value which is freed while still in use
11+
LL | |
12+
LL | | };
13+
| | -
14+
| | |
15+
| |_____temporary value is freed at the end of this statement
16+
| borrow later used here
17+
|
18+
= note: consider using a `let` binding to create a longer lived value
19+
20+
error[E0716]: temporary value dropped while borrowed
21+
--> $DIR/let_underscore_temporary.rs:24:14
22+
|
23+
LL | let _ = if let Some(ref mut s) = num {
24+
| _____________-
25+
LL | | *s += 1;
26+
LL | | s
27+
LL | | } else {
28+
LL | | &mut 0
29+
| | ^ creates a temporary value which is freed while still in use
30+
LL | |
31+
LL | | };
32+
| | -
33+
| | |
34+
| |_____temporary value is freed at the end of this statement
35+
| borrow later used here
36+
|
37+
= note: consider using a `let` binding to create a longer lived value
38+
39+
error[E0716]: temporary value dropped while borrowed
40+
--> $DIR/let_underscore_temporary.rs:36:14
41+
|
42+
LL | let _: _ = if let Some(s) = &mut num {
43+
| ________________-
44+
LL | | *s += 1;
45+
LL | | s
46+
LL | | } else {
47+
LL | | &mut 0
48+
| | ^ creates a temporary value which is freed while still in use
49+
LL | |
50+
LL | | };
51+
| | -
52+
| | |
53+
| |_____temporary value is freed at the end of this statement
54+
| borrow later used here
55+
|
56+
= note: consider using a `let` binding to create a longer lived value
57+
58+
error[E0716]: temporary value dropped while borrowed
59+
--> $DIR/let_underscore_temporary.rs:50:14
60+
|
61+
LL | let _: _ = if let Some(ref mut s) = num {
62+
| ________________-
63+
LL | | *s += 1;
64+
LL | | s
65+
LL | | } else {
66+
LL | | &mut 0
67+
| | ^ creates a temporary value which is freed while still in use
68+
LL | |
69+
LL | | };
70+
| | -
71+
| | |
72+
| |_____temporary value is freed at the end of this statement
73+
| borrow later used here
74+
|
75+
= note: consider using a `let` binding to create a longer lived value
76+
77+
error: aborting due to 4 previous errors
78+
79+
For more information about this error, try `rustc --explain E0716`.

tests/ui/span/send-is-not-static-std-sync-2.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ LL | };
2525
error[E0597]: `x` does not live long enough
2626
--> $DIR/send-is-not-static-std-sync-2.rs:31:25
2727
|
28-
LL | let (_tx, rx) = {
29-
| --- borrow later used here
3028
LL | let x = 1;
3129
| - binding `x` declared here
3230
LL | let (tx, rx) = mpsc::channel();

0 commit comments

Comments
 (0)