Skip to content

Commit d830f46

Browse files
committed
Auto merge of #51274 - nikomatsakis:issue-46557-promote-ref-mut, r=eddyb
also check `let` arms and nested patterns for mutable borrows Fixes #46557 r? @eddyb
2 parents 1b3d737 + a667049 commit d830f46

5 files changed

+211
-5
lines changed

src/librustc/middle/mem_categorization.rs

+16
Original file line numberDiff line numberDiff line change
@@ -936,16 +936,32 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
936936
span: Span,
937937
expr_ty: Ty<'tcx>)
938938
-> cmt_<'tcx> {
939+
debug!(
940+
"cat_rvalue_node(id={:?}, span={:?}, expr_ty={:?})",
941+
id,
942+
span,
943+
expr_ty,
944+
);
939945
let hir_id = self.tcx.hir.node_to_hir_id(id);
940946
let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id))
941947
.unwrap_or(false);
942948

949+
debug!(
950+
"cat_rvalue_node: promotable = {:?}",
951+
promotable,
952+
);
953+
943954
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
944955
let promotable = match expr_ty.sty {
945956
ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
946957
_ => promotable,
947958
};
948959

960+
debug!(
961+
"cat_rvalue_node: promotable = {:?} (2)",
962+
promotable,
963+
);
964+
949965
// Compute maximum lifetime of this rvalue. This is 'static if
950966
// we can promote to a constant, otherwise equal to enclosing temp
951967
// lifetime.

src/librustc_passes/rvalue_promotion.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,23 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
150150
span.allows_unstable();
151151
}
152152
}
153+
154+
/// While the `ExprUseVisitor` walks, we will identify which
155+
/// expressions are borrowed, and insert their ids into this
156+
/// table. Actually, we insert the "borrow-id", which is normally
157+
/// the id of the expession being borrowed: but in the case of
158+
/// `ref mut` borrows, the `id` of the pattern is
159+
/// inserted. Therefore later we remove that entry from the table
160+
/// and transfer it over to the value being matched. This will
161+
/// then prevent said value from being promoted.
162+
fn remove_mut_rvalue_borrow(&mut self, pat: &hir::Pat) -> bool {
163+
let mut any_removed = false;
164+
pat.walk(|p| {
165+
any_removed |= self.mut_rvalue_borrows.remove(&p.id);
166+
true
167+
});
168+
any_removed
169+
}
153170
}
154171

155172
impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
@@ -200,9 +217,15 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
200217
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
201218
match stmt.node {
202219
hir::StmtDecl(ref decl, _) => {
203-
match decl.node {
204-
hir::DeclLocal(_) => {
220+
match &decl.node {
221+
hir::DeclLocal(local) => {
205222
self.promotable = false;
223+
224+
if self.remove_mut_rvalue_borrow(&local.pat) {
225+
if let Some(init) = &local.init {
226+
self.mut_rvalue_borrows.insert(init.id);
227+
}
228+
}
206229
}
207230
// Item statements are allowed
208231
hir::DeclItem(_) => {}
@@ -229,9 +252,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
229252
// patterns and set that on the discriminator.
230253
let mut mut_borrow = false;
231254
for pat in arms.iter().flat_map(|arm| &arm.pats) {
232-
if self.mut_rvalue_borrows.remove(&pat.id) {
233-
mut_borrow = true;
234-
}
255+
mut_borrow = self.remove_mut_rvalue_borrow(pat);
235256
}
236257
if mut_borrow {
237258
self.mut_rvalue_borrows.insert(discr.id);
@@ -498,6 +519,14 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
498519
_loan_region: ty::Region<'tcx>,
499520
bk: ty::BorrowKind,
500521
loan_cause: euv::LoanCause) {
522+
debug!(
523+
"borrow(borrow_id={:?}, cmt={:?}, bk={:?}, loan_cause={:?})",
524+
borrow_id,
525+
cmt,
526+
bk,
527+
loan_cause,
528+
);
529+
501530
// Kind of hacky, but we allow Unsafe coercions in constants.
502531
// These occur when we convert a &T or *T to a *U, as well as
503532
// when making a thin pointer (e.g., `*T`) into a fat pointer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0597]: borrowed value does not live long enough
2+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:21
3+
|
4+
LL | fn gimme_static_mut_let() -> &'static mut u32 {
5+
| _______________________________________________-
6+
LL | | let ref mut x = 1234543; //~ ERROR
7+
| | ^^^^^^^ temporary value does not live long enough
8+
LL | | x
9+
LL | | }
10+
| | -
11+
| | |
12+
| |_temporary value only lives until here
13+
| borrow later used here
14+
15+
error[E0597]: borrowed value does not live long enough
16+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:20:25
17+
|
18+
LL | fn gimme_static_mut_let_nested() -> &'static mut u32 {
19+
| ______________________________________________________-
20+
LL | | let (ref mut x, ) = (1234543, ); //~ ERROR
21+
| | ^^^^^^^^^^^ temporary value does not live long enough
22+
LL | | x
23+
LL | | }
24+
| | -
25+
| | |
26+
| |_temporary value only lives until here
27+
| borrow later used here
28+
29+
error[E0597]: borrowed value does not live long enough
30+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:25:11
31+
|
32+
LL | match 1234543 {
33+
| ^^^^^^^ temporary value does not live long enough
34+
...
35+
LL | }
36+
| - temporary value only lives until here
37+
|
38+
= note: borrowed value must be valid for the static lifetime...
39+
40+
error[E0597]: borrowed value does not live long enough
41+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:31:11
42+
|
43+
LL | match (123443,) {
44+
| ^^^^^^^^^ temporary value does not live long enough
45+
...
46+
LL | }
47+
| - temporary value only lives until here
48+
|
49+
= note: borrowed value must be valid for the static lifetime...
50+
51+
error[E0597]: borrowed value does not live long enough
52+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:37:10
53+
|
54+
LL | &mut 1234543 //~ ERROR
55+
| ^^^^^^^ temporary value does not live long enough
56+
LL | }
57+
| - temporary value only lives until here
58+
|
59+
= note: borrowed value must be valid for the static lifetime...
60+
61+
error: aborting due to 5 previous errors
62+
63+
For more information about this error, try `rustc --explain E0597`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we fail to promote the constant here which has a `ref
12+
// mut` borrow.
13+
14+
fn gimme_static_mut_let() -> &'static mut u32 {
15+
let ref mut x = 1234543; //~ ERROR
16+
x
17+
}
18+
19+
fn gimme_static_mut_let_nested() -> &'static mut u32 {
20+
let (ref mut x, ) = (1234543, ); //~ ERROR
21+
x
22+
}
23+
24+
fn gimme_static_mut_match() -> &'static mut u32 {
25+
match 1234543 {
26+
ref mut x => x //~ ERROR
27+
}
28+
}
29+
30+
fn gimme_static_mut_match_nested() -> &'static mut u32 {
31+
match (123443,) {
32+
(ref mut x,) => x, //~ ERROR
33+
}
34+
}
35+
36+
fn gimme_static_mut_ampersand() -> &'static mut u32 {
37+
&mut 1234543 //~ ERROR
38+
}
39+
40+
fn main() {
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
error[E0597]: borrowed value does not live long enough
2+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:9
3+
|
4+
LL | let ref mut x = 1234543; //~ ERROR
5+
| ^^^^^^^^^ temporary value does not live long enough
6+
LL | x
7+
LL | }
8+
| - temporary value only lives until here
9+
|
10+
= note: borrowed value must be valid for the static lifetime...
11+
12+
error[E0597]: borrowed value does not live long enough
13+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:20:10
14+
|
15+
LL | let (ref mut x, ) = (1234543, ); //~ ERROR
16+
| ^^^^^^^^^ borrowed value does not live long enough
17+
LL | x
18+
LL | }
19+
| - borrowed value only lives until here
20+
|
21+
= note: borrowed value must be valid for the static lifetime...
22+
23+
error[E0597]: borrowed value does not live long enough
24+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:26:9
25+
|
26+
LL | ref mut x => x //~ ERROR
27+
| ^^^^^^^^^ temporary value does not live long enough
28+
LL | }
29+
LL | }
30+
| - temporary value only lives until here
31+
|
32+
= note: borrowed value must be valid for the static lifetime...
33+
34+
error[E0597]: borrowed value does not live long enough
35+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:32:10
36+
|
37+
LL | (ref mut x,) => x, //~ ERROR
38+
| ^^^^^^^^^ borrowed value does not live long enough
39+
LL | }
40+
LL | }
41+
| - borrowed value only lives until here
42+
|
43+
= note: borrowed value must be valid for the static lifetime...
44+
45+
error[E0597]: borrowed value does not live long enough
46+
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:37:10
47+
|
48+
LL | &mut 1234543 //~ ERROR
49+
| ^^^^^^^ temporary value does not live long enough
50+
LL | }
51+
| - temporary value only lives until here
52+
|
53+
= note: borrowed value must be valid for the static lifetime...
54+
55+
error: aborting due to 5 previous errors
56+
57+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)