Check that closure's by-value captures are sized
This commit is contained in:
parent
2d08657901
commit
c21867f9f6
@ -41,6 +41,7 @@
|
|||||||
use rustc_infer::infer::UpvarRegion;
|
use rustc_infer::infer::UpvarRegion;
|
||||||
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
|
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
|
||||||
use rustc_middle::mir::FakeReadCause;
|
use rustc_middle::mir::FakeReadCause;
|
||||||
|
use rustc_middle::traits::ObligationCauseCode;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
|
self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
|
||||||
};
|
};
|
||||||
@ -295,6 +296,20 @@ fn analyze_closure(
|
|||||||
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
|
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
|
||||||
debug!(?closure_hir_id, ?args, ?final_upvar_tys);
|
debug!(?closure_hir_id, ?args, ?final_upvar_tys);
|
||||||
|
|
||||||
|
if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params {
|
||||||
|
for capture in
|
||||||
|
self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
|
||||||
|
{
|
||||||
|
if let UpvarCapture::ByValue = capture.info.capture_kind {
|
||||||
|
self.require_type_is_sized(
|
||||||
|
capture.place.ty(),
|
||||||
|
capture.get_path_span(self.tcx),
|
||||||
|
ObligationCauseCode::SizedClosureCapture(closure_def_id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build a tuple (U0..Un) of the final upvar types U0..Un
|
// Build a tuple (U0..Un) of the final upvar types U0..Un
|
||||||
// and unify the upvar tuple type in the closure with it:
|
// and unify the upvar tuple type in the closure with it:
|
||||||
let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);
|
let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);
|
||||||
|
@ -299,6 +299,8 @@ pub enum ObligationCauseCode<'tcx> {
|
|||||||
SizedYieldType,
|
SizedYieldType,
|
||||||
/// Inline asm operand type must be `Sized`.
|
/// Inline asm operand type must be `Sized`.
|
||||||
InlineAsmSized,
|
InlineAsmSized,
|
||||||
|
/// Captured closure type type must be `Sized`.
|
||||||
|
SizedClosureCapture(LocalDefId),
|
||||||
/// `[expr; N]` requires `type_of(expr): Copy`.
|
/// `[expr; N]` requires `type_of(expr): Copy`.
|
||||||
RepeatElementCopy {
|
RepeatElementCopy {
|
||||||
/// If element is a `const fn` we display a help message suggesting to move the
|
/// If element is a `const fn` we display a help message suggesting to move the
|
||||||
|
@ -3007,6 +3007,17 @@ fn note_obligation_cause_code<T>(
|
|||||||
ObligationCauseCode::InlineAsmSized => {
|
ObligationCauseCode::InlineAsmSized => {
|
||||||
err.note("all inline asm arguments must have a statically known size");
|
err.note("all inline asm arguments must have a statically known size");
|
||||||
}
|
}
|
||||||
|
ObligationCauseCode::SizedClosureCapture(closure_def_id) => {
|
||||||
|
err.note("all values captured by value by a closure must have a statically known size");
|
||||||
|
let hir::ExprKind::Closure(closure) = self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind else {
|
||||||
|
bug!("expected closure in SizedClosureCapture obligation");
|
||||||
|
};
|
||||||
|
if let hir::CaptureBy::Value = closure.capture_clause
|
||||||
|
&& let Some(span) = closure.fn_arg_span
|
||||||
|
{
|
||||||
|
err.span_label(span, "this closure captures all values by move");
|
||||||
|
}
|
||||||
|
}
|
||||||
ObligationCauseCode::ConstPatternStructural => {
|
ObligationCauseCode::ConstPatternStructural => {
|
||||||
err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
|
err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
|
||||||
}
|
}
|
||||||
|
10
tests/ui/closures/capture-unsized-by-move.rs
Normal file
10
tests/ui/closures/capture-unsized-by-move.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// compile-flags: --crate-type=lib
|
||||||
|
|
||||||
|
#![feature(unsized_fn_params)]
|
||||||
|
|
||||||
|
pub fn f(k: dyn std::fmt::Display) {
|
||||||
|
let k2 = move || {
|
||||||
|
k.to_string();
|
||||||
|
//~^ ERROR the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
|
||||||
|
};
|
||||||
|
}
|
14
tests/ui/closures/capture-unsized-by-move.stderr
Normal file
14
tests/ui/closures/capture-unsized-by-move.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0277]: the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
|
||||||
|
--> $DIR/capture-unsized-by-move.rs:7:9
|
||||||
|
|
|
||||||
|
LL | let k2 = move || {
|
||||||
|
| -- this closure captures all values by move
|
||||||
|
LL | k.to_string();
|
||||||
|
| ^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `(dyn std::fmt::Display + 'static)`
|
||||||
|
= note: all values captured by value by a closure must have a statically known size
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
10
tests/ui/closures/capture-unsized-by-ref.rs
Normal file
10
tests/ui/closures/capture-unsized-by-ref.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// build-pass
|
||||||
|
// compile-flags: --crate-type=lib
|
||||||
|
|
||||||
|
#![feature(unsized_fn_params)]
|
||||||
|
|
||||||
|
pub fn f(k: dyn std::fmt::Display) {
|
||||||
|
let k2 = || {
|
||||||
|
k.to_string();
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user