diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index ba469bd029d..4d641390368 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -41,6 +41,7 @@ use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind}; use rustc_middle::mir::FakeReadCause; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{ 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); 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 // and unify the upvar tuple type in the closure with it: let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index eef193a657d..a5e0e4942ab 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -299,6 +299,8 @@ pub enum ObligationCauseCode<'tcx> { SizedYieldType, /// Inline asm operand type must be `Sized`. InlineAsmSized, + /// Captured closure type type must be `Sized`. + SizedClosureCapture(LocalDefId), /// `[expr; N]` requires `type_of(expr): Copy`. RepeatElementCopy { /// If element is a `const fn` we display a help message suggesting to move the diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index cd1dadde1ba..74345169179 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3007,6 +3007,17 @@ fn note_obligation_cause_code( ObligationCauseCode::InlineAsmSized => { 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 => { err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); } diff --git a/tests/ui/closures/capture-unsized-by-move.rs b/tests/ui/closures/capture-unsized-by-move.rs new file mode 100644 index 00000000000..1148e34ac67 --- /dev/null +++ b/tests/ui/closures/capture-unsized-by-move.rs @@ -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 + }; +} diff --git a/tests/ui/closures/capture-unsized-by-move.stderr b/tests/ui/closures/capture-unsized-by-move.stderr new file mode 100644 index 00000000000..d7fafc8cadd --- /dev/null +++ b/tests/ui/closures/capture-unsized-by-move.stderr @@ -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`. diff --git a/tests/ui/closures/capture-unsized-by-ref.rs b/tests/ui/closures/capture-unsized-by-ref.rs new file mode 100644 index 00000000000..c9e4a5903d9 --- /dev/null +++ b/tests/ui/closures/capture-unsized-by-ref.rs @@ -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(); + }; +}