Skip to content

Commit ab7155d

Browse files
authored
Rollup merge of rust-lang#63230 - tmandry:disallow-possibly-uninitialized, r=Centril
Make use of possibly uninitialized data [E0381] a hard error This is one of the behaviors we no longer allow in NLL. Since it can lead to undefined behavior, I think it's definitely worth making it a hard error without waiting to turn off migration mode (rust-lang#58781). Closes rust-lang#60450. My ulterior motive here is making it impossible to leave variables partially initialized across a yield (see rust-lang#60889, discussion at rust-lang#63035), so tests are included for that. cc rust-lang#54987 --- I'm not sure if bypassing the buffer is a good way of doing this. We could also make a `force_errors_buffer` or similar that gets recombined with all the errors as they are emitted. But this is simpler and seems fine to me. r? @Centril cc @cramertj @nikomatsakis @pnkfelix @RalfJung
2 parents e988230 + 9058bf2 commit ab7155d

20 files changed

+209
-131
lines changed

src/librustc_mir/borrow_check/conflict_errors.rs

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
105105
format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
106106
);
107107

108+
// This error should not be downgraded to a warning,
109+
// even in migrate mode.
110+
self.disable_error_downgrading();
108111
err.buffer(&mut self.errors_buffer);
109112
} else {
110113
if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {

src/librustc_mir/borrow_check/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ fn do_mir_borrowck<'a, 'tcx>(
253253
move_error_reported: BTreeMap::new(),
254254
uninitialized_error_reported: Default::default(),
255255
errors_buffer,
256+
disable_error_downgrading: false,
256257
nonlexical_regioncx: regioncx,
257258
used_mut: Default::default(),
258259
used_mut_upvars: SmallVec::new(),
@@ -364,7 +365,7 @@ fn do_mir_borrowck<'a, 'tcx>(
364365
if !mbcx.errors_buffer.is_empty() {
365366
mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span());
366367

367-
if tcx.migrate_borrowck() {
368+
if !mbcx.disable_error_downgrading && tcx.migrate_borrowck() {
368369
// When borrowck=migrate, check if AST-borrowck would
369370
// error on the given code.
370371

@@ -481,6 +482,9 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
481482
uninitialized_error_reported: FxHashSet<PlaceRef<'cx, 'tcx>>,
482483
/// Errors to be reported buffer
483484
errors_buffer: Vec<Diagnostic>,
485+
/// If there are no errors reported by the HIR borrow checker, we downgrade
486+
/// all NLL errors to warnings. Setting this flag disables downgrading.
487+
disable_error_downgrading: bool,
484488
/// This field keeps track of all the local variables that are declared mut and are mutated.
485489
/// Used for the warning issued by an unused mutable local variable.
486490
used_mut: FxHashSet<Local>,
@@ -921,6 +925,12 @@ impl InitializationRequiringAction {
921925
}
922926

923927
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
928+
/// If there are no errors reported by the HIR borrow checker, we downgrade
929+
/// all NLL errors to warnings. Calling this disables downgrading.
930+
crate fn disable_error_downgrading(&mut self) {
931+
self.disable_error_downgrading = true;
932+
}
933+
924934
/// Checks an access to the given place to see if it is allowed. Examines the set of borrows
925935
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
926936
/// place is initialized and (b) it is not borrowed in some way that would prevent this
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Test that we don't allow awaiting from an async fn while a local is partially
2+
// initialized.
3+
4+
// edition:2018
5+
6+
#![feature(async_await)]
7+
8+
struct S { x: i32, y: i32 }
9+
struct T(i32, i32);
10+
11+
async fn noop() {}
12+
13+
async fn test_tuple() {
14+
let mut t: (i32, i32);
15+
t.0 = 42;
16+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
17+
noop().await;
18+
t.1 = 88;
19+
let _ = t;
20+
}
21+
22+
async fn test_tuple_struct() {
23+
let mut t: T;
24+
t.0 = 42;
25+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
26+
noop().await;
27+
t.1 = 88;
28+
let _ = t;
29+
}
30+
31+
async fn test_struct() {
32+
let mut t: S;
33+
t.x = 42;
34+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
35+
noop().await;
36+
t.y = 88;
37+
let _ = t;
38+
}
39+
40+
fn main() {
41+
let _ = test_tuple();
42+
let _ = test_tuple_struct();
43+
let _ = test_struct();
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0381]: assign to part of possibly uninitialized variable: `t`
2+
--> $DIR/partial-initialization-across-await.rs:15:5
3+
|
4+
LL | t.0 = 42;
5+
| ^^^^^^^^ use of possibly uninitialized `t`
6+
7+
error[E0381]: assign to part of possibly uninitialized variable: `t`
8+
--> $DIR/partial-initialization-across-await.rs:24:5
9+
|
10+
LL | t.0 = 42;
11+
| ^^^^^^^^ use of possibly uninitialized `t`
12+
13+
error[E0381]: assign to part of possibly uninitialized variable: `t`
14+
--> $DIR/partial-initialization-across-await.rs:33:5
15+
|
16+
LL | t.x = 42;
17+
| ^^^^^^^^ use of possibly uninitialized `t`
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0381`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Test that we don't allow partial initialization.
2+
// This may be relaxed in the future (see #54987).
3+
4+
fn main() {
5+
let mut t: (u64, u64);
6+
t.0 = 1;
7+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
8+
t.1 = 1;
9+
10+
let mut t: (u64, u64);
11+
t.1 = 1;
12+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
13+
t.0 = 1;
14+
15+
let mut t: (u64, u64);
16+
t.0 = 1;
17+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
18+
19+
let mut t: (u64,);
20+
t.0 = 1;
21+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0381]: assign to part of possibly uninitialized variable: `t`
2+
--> $DIR/disallow-possibly-uninitialized.rs:6:5
3+
|
4+
LL | t.0 = 1;
5+
| ^^^^^^^ use of possibly uninitialized `t`
6+
7+
error[E0381]: assign to part of possibly uninitialized variable: `t`
8+
--> $DIR/disallow-possibly-uninitialized.rs:11:5
9+
|
10+
LL | t.1 = 1;
11+
| ^^^^^^^ use of possibly uninitialized `t`
12+
13+
error[E0381]: assign to part of possibly uninitialized variable: `t`
14+
--> $DIR/disallow-possibly-uninitialized.rs:16:5
15+
|
16+
LL | t.0 = 1;
17+
| ^^^^^^^ use of possibly uninitialized `t`
18+
19+
error[E0381]: assign to part of possibly uninitialized variable: `t`
20+
--> $DIR/disallow-possibly-uninitialized.rs:20:5
21+
|
22+
LL | t.0 = 1;
23+
| ^^^^^^^ use of possibly uninitialized `t`
24+
25+
error: aborting due to 4 previous errors
26+
27+
For more information about this error, try `rustc --explain E0381`.

src/test/ui/consts/const_let_refutable.nll.stderr

-31
This file was deleted.

src/test/ui/consts/const_let_refutable.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ fn main() {}
22

33
const fn slice([a, b]: &[i32]) -> i32 { //~ ERROR refutable pattern in function argument
44
a + b //~ ERROR can only call other `const fn` within a `const fn`
5-
//~^ WARN use of possibly uninitialized variable: `a`
6-
//~| WARN this error has been downgraded to a warning for backwards compatibility
7-
//~| WARN this represents potential undefined behavior in your code and this warning will
8-
//~| WARN use of possibly uninitialized variable: `b`
9-
//~| WARN this error has been downgraded to a warning for backwards compatibility
10-
//~| WARN this represents potential undefined behavior in your code and this warning will
5+
//~^ ERROR use of possibly uninitialized variable: `a`
6+
//~| ERROR use of possibly uninitialized variable: `b`
117
}

src/test/ui/consts/const_let_refutable.stderr

+3-11
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,19 @@ LL | a + b
1313
= note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
1414
= help: add `#![feature(const_fn)]` to the crate attributes to enable
1515

16-
warning[E0381]: use of possibly uninitialized variable: `a`
16+
error[E0381]: use of possibly uninitialized variable: `a`
1717
--> $DIR/const_let_refutable.rs:4:5
1818
|
1919
LL | a + b
2020
| ^ use of possibly uninitialized `a`
21-
|
22-
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
23-
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
24-
= note: for more information, try `rustc --explain E0729`
2521

26-
warning[E0381]: use of possibly uninitialized variable: `b`
22+
error[E0381]: use of possibly uninitialized variable: `b`
2723
--> $DIR/const_let_refutable.rs:4:9
2824
|
2925
LL | a + b
3026
| ^ use of possibly uninitialized `b`
31-
|
32-
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
33-
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
34-
= note: for more information, try `rustc --explain E0729`
3527

36-
error: aborting due to 2 previous errors
28+
error: aborting due to 4 previous errors
3729

3830
Some errors have detailed explanations: E0005, E0381, E0723.
3931
For more information about an error, try `rustc --explain E0005`.

src/test/ui/empty/empty-never-array.nll.stderr

-23
This file was deleted.

src/test/ui/empty/empty-never-array.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ fn transmute<T, U>(t: T) -> U {
1010
let Helper::U(u) = Helper::T(t, []);
1111
//~^ ERROR refutable pattern in local binding: `T(_, _)` not covered
1212
u
13-
//~^ WARN use of possibly uninitialized variable: `u`
14-
//~| WARN this error has been downgraded to a warning for backwards compatibility
15-
//~| WARN this represents potential undefined behavior in your code and this warning will
13+
//~^ ERROR use of possibly uninitialized variable: `u`
1614
}
1715

1816
fn main() {

src/test/ui/empty/empty-never-array.stderr

+2-6
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,13 @@ LL | | }
1111
LL | let Helper::U(u) = Helper::T(t, []);
1212
| ^^^^^^^^^^^^ pattern `T(_, _)` not covered
1313

14-
warning[E0381]: use of possibly uninitialized variable: `u`
14+
error[E0381]: use of possibly uninitialized variable: `u`
1515
--> $DIR/empty-never-array.rs:12:5
1616
|
1717
LL | u
1818
| ^ use of possibly uninitialized `u`
19-
|
20-
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
21-
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
22-
= note: for more information, try `rustc --explain E0729`
2319

24-
error: aborting due to previous error
20+
error: aborting due to 2 previous errors
2521

2622
Some errors have detailed explanations: E0005, E0381.
2723
For more information about an error, try `rustc --explain E0005`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Test that we don't allow yielding from a generator while a local is partially
2+
// initialized.
3+
4+
#![feature(generators)]
5+
6+
struct S { x: i32, y: i32 }
7+
struct T(i32, i32);
8+
9+
fn test_tuple() {
10+
let _ = || {
11+
let mut t: (i32, i32);
12+
t.0 = 42;
13+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
14+
yield;
15+
t.1 = 88;
16+
let _ = t;
17+
};
18+
}
19+
20+
fn test_tuple_struct() {
21+
let _ = || {
22+
let mut t: T;
23+
t.0 = 42;
24+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
25+
yield;
26+
t.1 = 88;
27+
let _ = t;
28+
};
29+
}
30+
31+
fn test_struct() {
32+
let _ = || {
33+
let mut t: S;
34+
t.x = 42;
35+
//~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
36+
yield;
37+
t.y = 88;
38+
let _ = t;
39+
};
40+
}
41+
42+
fn main() {
43+
test_tuple();
44+
test_tuple_struct();
45+
test_struct();
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0381]: assign to part of possibly uninitialized variable: `t`
2+
--> $DIR/partial-initialization-across-yield.rs:12:9
3+
|
4+
LL | t.0 = 42;
5+
| ^^^^^^^^ use of possibly uninitialized `t`
6+
7+
error[E0381]: assign to part of possibly uninitialized variable: `t`
8+
--> $DIR/partial-initialization-across-yield.rs:23:9
9+
|
10+
LL | t.0 = 42;
11+
| ^^^^^^^^ use of possibly uninitialized `t`
12+
13+
error[E0381]: assign to part of possibly uninitialized variable: `t`
14+
--> $DIR/partial-initialization-across-yield.rs:34:9
15+
|
16+
LL | t.x = 42;
17+
| ^^^^^^^^ use of possibly uninitialized `t`
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0381`.

src/test/ui/issues/issue-15381.nll.stderr

-16
This file was deleted.

src/test/ui/issues/issue-15381.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ fn main() {
44
for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
55
//~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered
66
println!("y={}", y);
7-
//~^ WARN borrow of possibly uninitialized variable: `y`
8-
//~| WARN this error has been downgraded to a warning for backwards compatibility
9-
//~| WARN this represents potential undefined behavior in your code and this warning will
7+
//~^ ERROR borrow of possibly uninitialized variable: `y`
108
}
119
}

0 commit comments

Comments
 (0)