Skip to content

Commit 56011eb

Browse files
committed
Make partially assignment of uninitialized projection produce an error
1 parent e1643a8 commit 56011eb

File tree

8 files changed

+178
-19
lines changed

8 files changed

+178
-19
lines changed

src/librustc/mir/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,16 @@ impl<'tcx> Place<'tcx> {
19781978
_ => None,
19791979
}
19801980
}
1981+
1982+
/// Returns the local variable at the "base" of this place, if any. e.g., for a place like
1983+
/// a.b.c, returns Some(a). For a place based in a static or constant, returns None.
1984+
pub fn base_local(&self) -> Option<Local> {
1985+
match self {
1986+
Place::Projection(box Projection { base, .. }) => base.base_local(),
1987+
Place::Local(local) => Some(*local),
1988+
Place::Static(..) | Place::Promoted(..) => None,
1989+
}
1990+
}
19811991
}
19821992

19831993
impl<'tcx> Debug for Place<'tcx> {

src/librustc_mir/borrow_check/mod.rs

+56-13
Original file line numberDiff line numberDiff line change
@@ -1096,20 +1096,63 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10961096
}
10971097
}
10981098

1099-
// Special case: you can assign a immutable local variable
1100-
// (e.g., `x = ...`) so long as it has never been initialized
1101-
// before (at this point in the flow).
1102-
if let &Place::Local(local) = place_span.0 {
1103-
if let Mutability::Not = self.mir.local_decls[local].mutability {
1104-
// check for reassignments to immutable local variables
1105-
self.check_if_reassignment_to_immutable_state(
1106-
context,
1107-
local,
1108-
place_span,
1109-
flow_state,
1110-
);
1111-
return;
1099+
match place_span.0 {
1100+
// Special case: you can assign a immutable local variable
1101+
// (e.g., `x = ...`) so long as it has never been initialized
1102+
// before (at this point in the flow).
1103+
&Place::Local(local) => {
1104+
if let Mutability::Not = self.mir.local_decls[local].mutability {
1105+
// check for reassignments to immutable local variables
1106+
self.check_if_reassignment_to_immutable_state(
1107+
context,
1108+
local,
1109+
place_span,
1110+
flow_state,
1111+
);
1112+
return;
1113+
}
11121114
}
1115+
1116+
// FIXME(#21232). For now, error if assigning to a projection from an uninitialized
1117+
// local variable -- so e.g. doing a.b = 22 when a is not yet initialized is simply an
1118+
// error. In the future, we could sometimes support this.
1119+
place @ &Place::Projection(_) => {
1120+
if let Some(local) = place.base_local() {
1121+
let mpi = self.move_data.rev_lookup.find_local(local);
1122+
if flow_state.uninits.contains(mpi) {
1123+
let name = self.mir.local_decls[local].name.unwrap();
1124+
let msg = match self.describe_place(place) {
1125+
Some(desc) => format!(
1126+
"cannot assign to `{}` when `{}` is not initialized",
1127+
desc,
1128+
name,
1129+
),
1130+
1131+
None => format!(
1132+
"use of uninitialized variable `{}",
1133+
name,
1134+
),
1135+
};
1136+
1137+
let mut diag =
1138+
struct_span_err!(self.infcx.tcx.sess, place_span.1, E0718, "{}", msg);
1139+
1140+
if let Mutability::Mut = self.mir.local_decls[local].mutability {
1141+
// Pre-emptively insert local into the used_mut set to avoid any
1142+
// warnings related to whether the mut declaration is used.
1143+
self.used_mut.insert(local);
1144+
} else {
1145+
diag.span_label(place_span.1, "will also have to be declared `mut`");
1146+
}
1147+
1148+
diag.buffer(&mut self.errors_buffer);
1149+
1150+
return;
1151+
}
1152+
}
1153+
}
1154+
1155+
_ => {}
11131156
}
11141157

11151158
// Otherwise, use the normal access permission rules.

src/librustc_mir/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2344,4 +2344,5 @@ register_diagnostics! {
23442344
E0594, // cannot assign to {}
23452345
E0598, // lifetime of {} is too short to guarantee its contents can be...
23462346
E0625, // thread-local statics cannot be accessed at compile-time
2347+
E0718,
23472348
}

src/test/ui/borrowck/borrowck-issue-48962.stderr

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error[E0718]: cannot assign to `src.next` when `src` is not initialized
2+
--> $DIR/borrowck-issue-48962.rs:26:5
3+
|
4+
LL | src.next = None; //~ ERROR use of moved value: `src` [E0382]
5+
| ^^^^^^^^
6+
17
error[E0382]: use of moved value: `src`
28
--> $DIR/borrowck-issue-48962.rs:26:5
39
|
@@ -8,6 +14,12 @@ LL | src.next = None; //~ ERROR use of moved value: `src` [E0382]
814
|
915
= note: move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
1016

17+
error[E0718]: cannot assign to `src.0` when `src` is not initialized
18+
--> $DIR/borrowck-issue-48962.rs:32:5
19+
|
20+
LL | src.0 = 66; //~ ERROR use of moved value: `src` [E0382]
21+
| ^^^^^^^^^^
22+
1123
error[E0382]: use of moved value: `src`
1224
--> $DIR/borrowck-issue-48962.rs:32:5
1325
|
@@ -18,6 +30,7 @@ LL | src.0 = 66; //~ ERROR use of moved value: `src` [E0382]
1830
|
1931
= note: move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
2032

21-
error: aborting due to 2 previous errors
33+
error: aborting due to 4 previous errors
2234

23-
For more information about this error, try `rustc --explain E0382`.
35+
Some errors occurred: E0382, E0718.
36+
For more information about an error, try `rustc --explain E0382`.

src/test/ui/borrowck/borrowck-uninit-ref-chain.mir.stderr

+27-2
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,43 @@ error[E0381]: borrow of possibly uninitialized variable: `**x`
1616
LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
1717
| ^^^^ use of possibly uninitialized `**x`
1818

19+
error[E0718]: cannot assign to `a.x` when `a` is not initialized
20+
--> $DIR/borrowck-uninit-ref-chain.rs:34:5
21+
|
22+
LL | a.x = 0;
23+
| ^^^^^^^
24+
25+
error[E0718]: cannot assign to `a.x` when `a` is not initialized
26+
--> $DIR/borrowck-uninit-ref-chain.rs:39:5
27+
|
28+
LL | a.x = &&0;
29+
| ^^^^^^^^^
30+
31+
error[E0718]: cannot assign to `a.x` when `a` is not initialized
32+
--> $DIR/borrowck-uninit-ref-chain.rs:45:5
33+
|
34+
LL | a.x = 0;
35+
| ^^^^^^^
36+
1937
error[E0381]: borrow of possibly uninitialized variable: `a.y`
2038
--> $DIR/borrowck-uninit-ref-chain.rs:46:14
2139
|
2240
LL | let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381]
2341
| ^^^^ use of possibly uninitialized `a.y`
2442

43+
error[E0718]: cannot assign to `a.x` when `a` is not initialized
44+
--> $DIR/borrowck-uninit-ref-chain.rs:50:5
45+
|
46+
LL | a.x = &&0;
47+
| ^^^^^^^^^
48+
2549
error[E0381]: borrow of possibly uninitialized variable: `**a.y`
2650
--> $DIR/borrowck-uninit-ref-chain.rs:51:14
2751
|
2852
LL | let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381]
2953
| ^^^^^^ use of possibly uninitialized `**a.y`
3054

31-
error: aborting due to 5 previous errors
55+
error: aborting due to 9 previous errors
3256

33-
For more information about this error, try `rustc --explain E0381`.
57+
Some errors occurred: E0381, E0718.
58+
For more information about an error, try `rustc --explain E0381`.

src/test/ui/borrowck/borrowck-use-in-index-lvalue.mir.stderr

+15-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,25 @@ error[E0381]: use of possibly uninitialized variable: `*w`
44
LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
55
| ^^^^ use of possibly uninitialized `*w`
66

7+
error[E0718]: cannot assign to `w[..]` when `w` is not initialized
8+
--> $DIR/borrowck-use-in-index-lvalue.rs:16:5
9+
|
10+
LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
11+
| ^^^^^^^^ will also have to be declared `mut`
12+
713
error[E0381]: use of possibly uninitialized variable: `*w`
814
--> $DIR/borrowck-use-in-index-lvalue.rs:20:5
915
|
1016
LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
1117
| ^^^^ use of possibly uninitialized `*w`
1218

13-
error: aborting due to 2 previous errors
19+
error[E0718]: cannot assign to `w[..]` when `w` is not initialized
20+
--> $DIR/borrowck-use-in-index-lvalue.rs:20:5
21+
|
22+
LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
23+
| ^^^^^^^^
24+
25+
error: aborting due to 4 previous errors
1426

15-
For more information about this error, try `rustc --explain E0381`.
27+
Some errors occurred: E0381, E0718.
28+
For more information about an error, try `rustc --explain E0381`.

src/test/ui/nll/issue-54499.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2018 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+
#![feature(nll)]
12+
13+
fn foo() {
14+
let mut s: (i32, i32);
15+
s.0 = 1;
16+
s.1 = 2;
17+
println!("{} {}", s.0, s.1);
18+
}
19+
20+
fn bar() {
21+
let s: (i32, i32);
22+
s.0 = 3;
23+
s.1 = 4;
24+
println!("{} {}", s.0, s.1);
25+
}
26+
27+
fn main() {}

src/test/ui/nll/issue-54499.stderr

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0718]: cannot assign to `s.0` when `s` is not initialized
2+
--> $DIR/issue-54499.rs:15:5
3+
|
4+
LL | s.0 = 1;
5+
| ^^^^^^^
6+
7+
error[E0718]: cannot assign to `s.1` when `s` is not initialized
8+
--> $DIR/issue-54499.rs:16:5
9+
|
10+
LL | s.1 = 2;
11+
| ^^^^^^^
12+
13+
error[E0718]: cannot assign to `s.0` when `s` is not initialized
14+
--> $DIR/issue-54499.rs:22:5
15+
|
16+
LL | s.0 = 3;
17+
| ^^^^^^^ will also have to be declared `mut`
18+
19+
error[E0718]: cannot assign to `s.1` when `s` is not initialized
20+
--> $DIR/issue-54499.rs:23:5
21+
|
22+
LL | s.1 = 4;
23+
| ^^^^^^^ will also have to be declared `mut`
24+
25+
error: aborting due to 4 previous errors
26+
27+
For more information about this error, try `rustc --explain E0718`.

0 commit comments

Comments
 (0)