Skip to content

Commit f9f886c

Browse files
committed
Error on moving unsized values rather than ICE'ing
1 parent 49421d1 commit f9f886c

File tree

8 files changed

+151
-8
lines changed

8 files changed

+151
-8
lines changed

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ enum LocalRef<'tcx, V> {
142142
/// `*p` is the wide pointer that references the actual unsized place.
143143
///
144144
/// Rust has no alloca and thus no ability to move the unsized place.
145+
///
146+
/// FIXME: Since the removal of unsized locals in https://github.com/rust-lang/rust/pull/142911,
147+
/// can we maybe use `Place` here? Or refactor it in another way? There are quite a few
148+
/// `UnsizedPlace => bug` branches now.
145149
UnsizedPlace(PlaceRef<'tcx, V>),
146150
/// The backend [`OperandValue`] has already been generated.
147151
Operand(OperandRef<'tcx, V>),

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
241241
arg_expr.span,
242242
ObligationCauseCode::WellFormed(None),
243243
);
244+
245+
self.check_place_expr_if_unsized(fn_input_ty, arg_expr);
244246
}
245247

246248
// First, let's unify the formal method signature with the expectation eagerly.
@@ -543,6 +545,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
543545
}
544546
}
545547

548+
/// If `unsized_fn_params` is active, check that unsized values are place expressions. Since
549+
/// the removal of `unsized_locals` in https://github.com/rust-lang/rust/pull/142911 we can't
550+
/// store them in MIR locals as temporaries.
551+
///
552+
/// If `unsized_fn_params` is inactive, this will be checked in borrowck instead.
553+
fn check_place_expr_if_unsized(&self, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
554+
if self.tcx.features().unsized_fn_params() && !expr.is_syntactic_place_expr() {
555+
self.require_type_is_sized(
556+
ty,
557+
expr.span,
558+
ObligationCauseCode::UnsizedNonPlaceExpr(expr.span),
559+
);
560+
}
561+
}
562+
546563
fn report_arg_errors(
547564
&self,
548565
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
@@ -1873,7 +1890,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18731890
});
18741891
}
18751892
hir::StmtKind::Semi(expr) => {
1876-
self.check_expr(expr);
1893+
let ty = self.check_expr(expr);
1894+
self.check_place_expr_if_unsized(ty, expr);
18771895
}
18781896
}
18791897

compiler/rustc_middle/src/traits/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@ pub enum ObligationCauseCode<'tcx> {
412412

413413
/// Obligations emitted during the normalization of a free type alias.
414414
TypeAlias(ObligationCauseCodeHandle<'tcx>, Span, DefId),
415+
416+
/// Only reachable if the `unsized_fn_params` feature is used. Unsized function arguments must
417+
/// be place expressions because we can't store them in MIR locals as temporaries.
418+
UnsizedNonPlaceExpr(Span),
415419
}
416420

417421
/// Whether a value can be extracted into a const.

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3624,6 +3624,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
36243624
);
36253625
suggest_remove_deref(err, &expr);
36263626
}
3627+
ObligationCauseCode::UnsizedNonPlaceExpr(span) => {
3628+
err.span_note(
3629+
span,
3630+
"unsized values must be place expressions and cannot be put in temporaries",
3631+
);
3632+
}
36273633
}
36283634
}
36293635

tests/ui/unsized-locals/unsized-exprs-rpass.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ impl std::ops::Add<i32> for A<[u8]> {
1818
}
1919

2020
fn main() {
21-
udrop::<[u8]>(loop {
22-
break *foo();
23-
});
24-
udrop::<[u8]>(if true { *foo() } else { *foo() });
25-
udrop::<[u8]>({ *foo() });
2621
udrop::<[u8]>((*foo()));
2722
*afoo() + 42;
2823
udrop as fn([u8]);

tests/ui/unsized-locals/unsized-exprs.stderr

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ note: required because it appears within the type `A<[u8]>`
1010
|
1111
LL | struct A<X: ?Sized>(X);
1212
| ^
13-
= note: structs must have a statically known size to be initialized
13+
note: unsized values must be place expressions and cannot be put in temporaries
14+
--> $DIR/unsized-exprs.rs:19:22
15+
|
16+
LL | udrop::<A<[u8]>>(A { 0: *foo() });
17+
| ^^^^^^^^^^^^^^^
1418

1519
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
1620
--> $DIR/unsized-exprs.rs:21:22
@@ -24,7 +28,11 @@ note: required because it appears within the type `A<[u8]>`
2428
|
2529
LL | struct A<X: ?Sized>(X);
2630
| ^
27-
= note: the return type of a function must have a statically known size
31+
note: unsized values must be place expressions and cannot be put in temporaries
32+
--> $DIR/unsized-exprs.rs:21:22
33+
|
34+
LL | udrop::<A<[u8]>>(A(*foo()));
35+
| ^^^^^^^^^
2836

2937
error: aborting due to 2 previous errors
3038

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! `#![feature(unsized_fn_params)]` lets you use unsized function parameters. In particular this
2+
//! is load bearing for `Box<dyn FnOnce()>: FnOnce()`. To do that, borrowck relaxes the requirement
3+
//! that certain places must be `Sized`. But in #142911 we removed alloca support, so these
4+
//! arguments cannot be put in temporaries (or ICE at codegen) That means when `unsized_fn_params`
5+
//! is enabled, we must explicitly check that unsized function arguments are place expressions.
6+
//!
7+
//! Also see tests/ui/unsized_locals/unsized-exprs-rpass.rs
8+
9+
#![feature(unsized_fn_params)]
10+
11+
fn foo() -> Box<[u8]> {
12+
Box::new(*b"foo")
13+
}
14+
15+
fn udrop<T: ?Sized>(_x: T) {}
16+
17+
fn main(){
18+
// NB The ordering of the following operations matters, otherwise errors get swallowed somehow.
19+
20+
udrop::<[u8]>(if true { *foo() } else { *foo() }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
21+
udrop::<[u8]>({ *foo() }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
22+
udrop(match foo() { x => *x }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
23+
udrop::<[u8]>({ loop { break *foo(); } }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
24+
25+
{ *foo() }; //~ERROR the size for values of type `[u8]` cannot be known at compilation time
26+
{ loop { break *foo(); } }; //~ERROR the size for values of type `[u8]` cannot be known at compilation time
27+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2+
--> $DIR/unsized-non-place-exprs.rs:20:19
3+
|
4+
LL | udrop::<[u8]>(if true { *foo() } else { *foo() });
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `[u8]`
8+
note: unsized values must be place expressions and cannot be put in temporaries
9+
--> $DIR/unsized-non-place-exprs.rs:20:19
10+
|
11+
LL | udrop::<[u8]>(if true { *foo() } else { *foo() });
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
15+
--> $DIR/unsized-non-place-exprs.rs:21:19
16+
|
17+
LL | udrop::<[u8]>({ *foo() });
18+
| ^^^^^^^^^^ doesn't have a size known at compile-time
19+
|
20+
= help: the trait `Sized` is not implemented for `[u8]`
21+
note: unsized values must be place expressions and cannot be put in temporaries
22+
--> $DIR/unsized-non-place-exprs.rs:21:19
23+
|
24+
LL | udrop::<[u8]>({ *foo() });
25+
| ^^^^^^^^^^
26+
27+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
28+
--> $DIR/unsized-non-place-exprs.rs:22:11
29+
|
30+
LL | udrop(match foo() { x => *x });
31+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
32+
|
33+
= help: the trait `Sized` is not implemented for `[u8]`
34+
note: unsized values must be place expressions and cannot be put in temporaries
35+
--> $DIR/unsized-non-place-exprs.rs:22:11
36+
|
37+
LL | udrop(match foo() { x => *x });
38+
| ^^^^^^^^^^^^^^^^^^^^^^^
39+
40+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
41+
--> $DIR/unsized-non-place-exprs.rs:23:19
42+
|
43+
LL | udrop::<[u8]>({ loop { break *foo(); } });
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
45+
|
46+
= help: the trait `Sized` is not implemented for `[u8]`
47+
note: unsized values must be place expressions and cannot be put in temporaries
48+
--> $DIR/unsized-non-place-exprs.rs:23:19
49+
|
50+
LL | udrop::<[u8]>({ loop { break *foo(); } });
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
53+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
54+
--> $DIR/unsized-non-place-exprs.rs:25:5
55+
|
56+
LL | { *foo() };
57+
| ^^^^^^^^^^ doesn't have a size known at compile-time
58+
|
59+
= help: the trait `Sized` is not implemented for `[u8]`
60+
note: unsized values must be place expressions and cannot be put in temporaries
61+
--> $DIR/unsized-non-place-exprs.rs:25:5
62+
|
63+
LL | { *foo() };
64+
| ^^^^^^^^^^
65+
66+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
67+
--> $DIR/unsized-non-place-exprs.rs:26:5
68+
|
69+
LL | { loop { break *foo(); } };
70+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
71+
|
72+
= help: the trait `Sized` is not implemented for `[u8]`
73+
note: unsized values must be place expressions and cannot be put in temporaries
74+
--> $DIR/unsized-non-place-exprs.rs:26:5
75+
|
76+
LL | { loop { break *foo(); } };
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
78+
79+
error: aborting due to 6 previous errors
80+
81+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)