Error on moving unsized values rather than ICE'ing
This commit is contained in:
@@ -141,7 +141,12 @@ enum LocalRef<'tcx, V> {
|
|||||||
/// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
|
/// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
|
||||||
/// `*p` is the wide pointer that references the actual unsized place.
|
/// `*p` is the wide pointer that references the actual unsized place.
|
||||||
///
|
///
|
||||||
/// Rust has no alloca and thus no ability to move the unsized place.
|
/// MIR only supports unsized args, not dynamically-sized locals, so
|
||||||
|
/// new unsized temps don't exist and we must reuse the referred-to place.
|
||||||
|
///
|
||||||
|
/// FIXME: Since the removal of unsized locals in <https://github.com/rust-lang/rust/pull/142911>,
|
||||||
|
/// can we maybe use `Place` here? Or refactor it in another way? There are quite a few
|
||||||
|
/// `UnsizedPlace => bug` branches now.
|
||||||
UnsizedPlace(PlaceRef<'tcx, V>),
|
UnsizedPlace(PlaceRef<'tcx, V>),
|
||||||
/// The backend [`OperandValue`] has already been generated.
|
/// The backend [`OperandValue`] has already been generated.
|
||||||
Operand(OperandRef<'tcx, V>),
|
Operand(OperandRef<'tcx, V>),
|
||||||
|
|||||||
@@ -241,6 +241,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
arg_expr.span,
|
arg_expr.span,
|
||||||
ObligationCauseCode::WellFormed(None),
|
ObligationCauseCode::WellFormed(None),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.check_place_expr_if_unsized(fn_input_ty, arg_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, let's unify the formal method signature with the expectation eagerly.
|
// First, let's unify the formal method signature with the expectation eagerly.
|
||||||
@@ -543,6 +545,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `unsized_fn_params` is active, check that unsized values are place expressions. Since
|
||||||
|
/// the removal of `unsized_locals` in <https://github.com/rust-lang/rust/pull/142911> we can't
|
||||||
|
/// store them in MIR locals as temporaries.
|
||||||
|
///
|
||||||
|
/// If `unsized_fn_params` is inactive, this will be checked in borrowck instead.
|
||||||
|
fn check_place_expr_if_unsized(&self, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
|
if self.tcx.features().unsized_fn_params() && !expr.is_syntactic_place_expr() {
|
||||||
|
self.require_type_is_sized(
|
||||||
|
ty,
|
||||||
|
expr.span,
|
||||||
|
ObligationCauseCode::UnsizedNonPlaceExpr(expr.span),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn report_arg_errors(
|
fn report_arg_errors(
|
||||||
&self,
|
&self,
|
||||||
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
|
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
|
||||||
@@ -1873,7 +1890,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
hir::StmtKind::Semi(expr) => {
|
hir::StmtKind::Semi(expr) => {
|
||||||
self.check_expr(expr);
|
let ty = self.check_expr(expr);
|
||||||
|
self.check_place_expr_if_unsized(ty, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -412,6 +412,10 @@ pub enum ObligationCauseCode<'tcx> {
|
|||||||
|
|
||||||
/// Obligations emitted during the normalization of a free type alias.
|
/// Obligations emitted during the normalization of a free type alias.
|
||||||
TypeAlias(ObligationCauseCodeHandle<'tcx>, Span, DefId),
|
TypeAlias(ObligationCauseCodeHandle<'tcx>, Span, DefId),
|
||||||
|
|
||||||
|
/// Only reachable if the `unsized_fn_params` feature is used. Unsized function arguments must
|
||||||
|
/// be place expressions because we can't store them in MIR locals as temporaries.
|
||||||
|
UnsizedNonPlaceExpr(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether a value can be extracted into a const.
|
/// Whether a value can be extracted into a const.
|
||||||
|
|||||||
@@ -3624,6 +3624,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
suggest_remove_deref(err, &expr);
|
suggest_remove_deref(err, &expr);
|
||||||
}
|
}
|
||||||
|
ObligationCauseCode::UnsizedNonPlaceExpr(span) => {
|
||||||
|
err.span_note(
|
||||||
|
span,
|
||||||
|
"unsized values must be place expressions and cannot be put in temporaries",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,6 @@ impl std::ops::Add<i32> for A<[u8]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
udrop::<[u8]>(loop {
|
|
||||||
break *foo();
|
|
||||||
});
|
|
||||||
udrop::<[u8]>(if true { *foo() } else { *foo() });
|
|
||||||
udrop::<[u8]>({ *foo() });
|
|
||||||
udrop::<[u8]>((*foo()));
|
udrop::<[u8]>((*foo()));
|
||||||
*afoo() + 42;
|
*afoo() + 42;
|
||||||
udrop as fn([u8]);
|
udrop as fn([u8]);
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ note: required because it appears within the type `A<[u8]>`
|
|||||||
|
|
|
|
||||||
LL | struct A<X: ?Sized>(X);
|
LL | struct A<X: ?Sized>(X);
|
||||||
| ^
|
| ^
|
||||||
= note: structs must have a statically known size to be initialized
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-exprs.rs:19:22
|
||||||
|
|
|
||||||
|
LL | udrop::<A<[u8]>>(A { 0: *foo() });
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
--> $DIR/unsized-exprs.rs:21:22
|
--> $DIR/unsized-exprs.rs:21:22
|
||||||
@@ -24,7 +28,11 @@ note: required because it appears within the type `A<[u8]>`
|
|||||||
|
|
|
|
||||||
LL | struct A<X: ?Sized>(X);
|
LL | struct A<X: ?Sized>(X);
|
||||||
| ^
|
| ^
|
||||||
= note: the return type of a function must have a statically known size
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-exprs.rs:21:22
|
||||||
|
|
|
||||||
|
LL | udrop::<A<[u8]>>(A(*foo()));
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|||||||
27
tests/ui/unsized-locals/unsized-non-place-exprs.rs
Normal file
27
tests/ui/unsized-locals/unsized-non-place-exprs.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//! `#![feature(unsized_fn_params)]` lets you use unsized function parameters. In particular this
|
||||||
|
//! is load bearing for `Box<dyn FnOnce()>: FnOnce()`. To do that, borrowck relaxes the requirement
|
||||||
|
//! that certain places must be `Sized`. But in #142911 we removed alloca support, so these
|
||||||
|
//! arguments cannot be put in temporaries (or ICE at codegen) That means when `unsized_fn_params`
|
||||||
|
//! is enabled, we must explicitly check that unsized function arguments are place expressions.
|
||||||
|
//!
|
||||||
|
//! Also see tests/ui/unsized_locals/unsized-exprs-rpass.rs
|
||||||
|
|
||||||
|
#![feature(unsized_fn_params)]
|
||||||
|
|
||||||
|
fn foo() -> Box<[u8]> {
|
||||||
|
Box::new(*b"foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn udrop<T: ?Sized>(_x: T) {}
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
// NB The ordering of the following operations matters, otherwise errors get swallowed somehow.
|
||||||
|
|
||||||
|
udrop::<[u8]>(if true { *foo() } else { *foo() }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
udrop::<[u8]>({ *foo() }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
udrop(match foo() { x => *x }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
udrop::<[u8]>({ loop { break *foo(); } }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
|
||||||
|
{ *foo() }; //~ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
{ loop { break *foo(); } }; //~ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
}
|
||||||
81
tests/ui/unsized-locals/unsized-non-place-exprs.stderr
Normal file
81
tests/ui/unsized-locals/unsized-non-place-exprs.stderr
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:20:19
|
||||||
|
|
|
||||||
|
LL | udrop::<[u8]>(if true { *foo() } else { *foo() });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:20:19
|
||||||
|
|
|
||||||
|
LL | udrop::<[u8]>(if true { *foo() } else { *foo() });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:21:19
|
||||||
|
|
|
||||||
|
LL | udrop::<[u8]>({ *foo() });
|
||||||
|
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:21:19
|
||||||
|
|
|
||||||
|
LL | udrop::<[u8]>({ *foo() });
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:22:11
|
||||||
|
|
|
||||||
|
LL | udrop(match foo() { x => *x });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:22:11
|
||||||
|
|
|
||||||
|
LL | udrop(match foo() { x => *x });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:23:19
|
||||||
|
|
|
||||||
|
LL | udrop::<[u8]>({ loop { break *foo(); } });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:23:19
|
||||||
|
|
|
||||||
|
LL | udrop::<[u8]>({ loop { break *foo(); } });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:25:5
|
||||||
|
|
|
||||||
|
LL | { *foo() };
|
||||||
|
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:25:5
|
||||||
|
|
|
||||||
|
LL | { *foo() };
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:26:5
|
||||||
|
|
|
||||||
|
LL | { loop { break *foo(); } };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: unsized values must be place expressions and cannot be put in temporaries
|
||||||
|
--> $DIR/unsized-non-place-exprs.rs:26:5
|
||||||
|
|
|
||||||
|
LL | { loop { break *foo(); } };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
Reference in New Issue
Block a user