Skip to content

Commit c21867f

Browse files
Check that closure's by-value captures are sized
1 parent 2d08657 commit c21867f

File tree

6 files changed

+62
-0
lines changed

6 files changed

+62
-0
lines changed

Diff for: compiler/rustc_hir_typeck/src/upvar.rs

+15
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use rustc_hir::intravisit::{self, Visitor};
4141
use rustc_infer::infer::UpvarRegion;
4242
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
4343
use rustc_middle::mir::FakeReadCause;
44+
use rustc_middle::traits::ObligationCauseCode;
4445
use rustc_middle::ty::{
4546
self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
4647
};
@@ -295,6 +296,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
295296
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
296297
debug!(?closure_hir_id, ?args, ?final_upvar_tys);
297298

299+
if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params {
300+
for capture in
301+
self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
302+
{
303+
if let UpvarCapture::ByValue = capture.info.capture_kind {
304+
self.require_type_is_sized(
305+
capture.place.ty(),
306+
capture.get_path_span(self.tcx),
307+
ObligationCauseCode::SizedClosureCapture(closure_def_id),
308+
);
309+
}
310+
}
311+
}
312+
298313
// Build a tuple (U0..Un) of the final upvar types U0..Un
299314
// and unify the upvar tuple type in the closure with it:
300315
let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);

Diff for: compiler/rustc_middle/src/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ pub enum ObligationCauseCode<'tcx> {
299299
SizedYieldType,
300300
/// Inline asm operand type must be `Sized`.
301301
InlineAsmSized,
302+
/// Captured closure type type must be `Sized`.
303+
SizedClosureCapture(LocalDefId),
302304
/// `[expr; N]` requires `type_of(expr): Copy`.
303305
RepeatElementCopy {
304306
/// If element is a `const fn` we display a help message suggesting to move the

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+11
Original file line numberDiff line numberDiff line change
@@ -3007,6 +3007,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30073007
ObligationCauseCode::InlineAsmSized => {
30083008
err.note("all inline asm arguments must have a statically known size");
30093009
}
3010+
ObligationCauseCode::SizedClosureCapture(closure_def_id) => {
3011+
err.note("all values captured by value by a closure must have a statically known size");
3012+
let hir::ExprKind::Closure(closure) = self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind else {
3013+
bug!("expected closure in SizedClosureCapture obligation");
3014+
};
3015+
if let hir::CaptureBy::Value = closure.capture_clause
3016+
&& let Some(span) = closure.fn_arg_span
3017+
{
3018+
err.span_label(span, "this closure captures all values by move");
3019+
}
3020+
}
30103021
ObligationCauseCode::ConstPatternStructural => {
30113022
err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
30123023
}

Diff for: tests/ui/closures/capture-unsized-by-move.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: --crate-type=lib
2+
3+
#![feature(unsized_fn_params)]
4+
5+
pub fn f(k: dyn std::fmt::Display) {
6+
let k2 = move || {
7+
k.to_string();
8+
//~^ ERROR the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
9+
};
10+
}

Diff for: tests/ui/closures/capture-unsized-by-move.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
2+
--> $DIR/capture-unsized-by-move.rs:7:9
3+
|
4+
LL | let k2 = move || {
5+
| -- this closure captures all values by move
6+
LL | k.to_string();
7+
| ^ doesn't have a size known at compile-time
8+
|
9+
= help: the trait `Sized` is not implemented for `(dyn std::fmt::Display + 'static)`
10+
= note: all values captured by value by a closure must have a statically known size
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.

Diff for: tests/ui/closures/capture-unsized-by-ref.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// build-pass
2+
// compile-flags: --crate-type=lib
3+
4+
#![feature(unsized_fn_params)]
5+
6+
pub fn f(k: dyn std::fmt::Display) {
7+
let k2 = || {
8+
k.to_string();
9+
};
10+
}

0 commit comments

Comments
 (0)