From 79d685325c170f0aed483e4c50c1f2b7d5b2bdc1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Sep 2023 04:03:24 +0000 Subject: [PATCH] Check types live across yields in generators too --- .../rustc_hir_analysis/src/check/check.rs | 21 +++++++++++- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 11 ++++-- .../src/generator_interior/mod.rs | 14 +++++++- compiler/rustc_middle/src/traits/mod.rs | 4 ++- .../src/traits/error_reporting/suggestions.rs | 7 ++++ ...ing-unsized-param.drop_tracking_mir.stderr | 21 ++++++++++++ ...ting-unsized-param.no_drop_tracking.stderr | 21 ++++++++++++ .../ui/async-await/awaiting-unsized-param.rs | 15 ++++++++ ...ized-across-await.drop_tracking_mir.stderr | 21 ++++++++++++ ...sized-across-await.no_drop_tracking.stderr | 21 ++++++++++++ tests/ui/async-await/unsized-across-await.rs | 18 ++++++++++ tests/ui/generator/unsized-across-yield.rs | 34 +++++++++++++++++++ .../ui/generator/unsized-across-yield.stderr | 32 +++++++++++++++++ 13 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr create mode 100644 tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr create mode 100644 tests/ui/async-await/awaiting-unsized-param.rs create mode 100644 tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr create mode 100644 tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr create mode 100644 tests/ui/async-await/unsized-across-await.rs create mode 100644 tests/ui/generator/unsized-across-yield.rs create mode 100644 tests/ui/generator/unsized-across-yield.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 13826264a22..116222ba56e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -18,7 +18,7 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::traits::DefiningAnchor; +use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, IntTypeExt}; @@ -1626,6 +1626,25 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); fulfillment_cx.register_predicate_obligation(&infcx, obligation); } + + if (tcx.features().unsized_locals || tcx.features().unsized_fn_params) + && let Some(generator) = tcx.mir_generator_witnesses(def_id) + { + for field_ty in generator.field_tys.iter() { + fulfillment_cx.register_bound( + &infcx, + param_env, + field_ty.ty, + tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)), + ObligationCause::new( + field_ty.source_info.span, + def_id, + ObligationCauseCode::SizedGeneratorInterior(def_id), + ), + ); + } + } + let errors = fulfillment_cx.select_all_or_error(&infcx); debug!(?errors); if !errors.is_empty() { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c94cfde0670..fea726ff8ca 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -518,8 +518,15 @@ pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) { self.select_obligations_where_possible(|_| {}); let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (_, body_id, interior, kind) in generators.drain(..) { - crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); + for (generator_def_id, body_id, interior, kind) in generators.drain(..) { + crate::generator_interior::resolve_interior( + self, + def_id, + generator_def_id, + body_id, + interior, + kind, + ); self.select_obligations_where_possible(|_| {}); } } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 566dc09cdd2..d2ab5aa6bae 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -9,12 +9,13 @@ use rustc_errors::{pluralize, DelayDm}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin}; use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; @@ -188,6 +189,7 @@ fn is_dropped_at_yield_location(&self, value_hir_id: HirId, yield_location: usiz pub fn resolve_interior<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, def_id: DefId, + generator_def_id: LocalDefId, body_id: hir::BodyId, interior: Ty<'tcx>, kind: hir::GeneratorKind, @@ -214,6 +216,16 @@ pub fn resolve_interior<'a, 'tcx>( // The types are already kept in insertion order. let types = visitor.types; + if fcx.tcx.features().unsized_locals || fcx.tcx.features().unsized_fn_params { + for interior_ty in &types { + fcx.require_type_is_sized( + interior_ty.ty, + interior_ty.span, + ObligationCauseCode::SizedGeneratorInterior(generator_def_id), + ); + } + } + // The types in the generator interior contain lifetimes local to the generator itself, // which should not be exposed outside of the generator. Therefore, we replace these // lifetimes with existentially-bound lifetimes, which reflect the exact value of the diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a5e0e4942ab..99b750c9afc 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -299,8 +299,10 @@ pub enum ObligationCauseCode<'tcx> { SizedYieldType, /// Inline asm operand type must be `Sized`. InlineAsmSized, - /// Captured closure type type must be `Sized`. + /// Captured closure type must be `Sized`. SizedClosureCapture(LocalDefId), + /// Types live across generator yields must be `Sized`. + SizedGeneratorInterior(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 74345169179..bb96e135741 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3018,6 +3018,13 @@ fn note_obligation_cause_code( err.span_label(span, "this closure captures all values by move"); } } + ObligationCauseCode::SizedGeneratorInterior(generator_def_id) => { + let what = match self.tcx.generator_kind(generator_def_id) { + None | Some(hir::GeneratorKind::Gen) => "yield", + Some(hir::GeneratorKind::Async(..)) => "await", + }; + err.note(format!("all values live across `{what}` must have a statically known size")); + } ObligationCauseCode::ConstPatternStructural => { err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); } diff --git a/tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr b/tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr new file mode 100644 index 00000000000..02cf8310a50 --- /dev/null +++ b/tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr @@ -0,0 +1,21 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/awaiting-unsized-param.rs:5:31 + | +LL | #![feature(unsized_fn_params, unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #48055 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the size for values of type `(dyn Future + Unpin + 'static)` cannot be known at compilation time + --> $DIR/awaiting-unsized-param.rs:10:17 + | +LL | async fn bug(mut f: dyn Future + Unpin) -> T { + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Future + Unpin + 'static)` + = note: all values captured by value by a closure must have a statically known size + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr b/tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr new file mode 100644 index 00000000000..02cf8310a50 --- /dev/null +++ b/tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr @@ -0,0 +1,21 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/awaiting-unsized-param.rs:5:31 + | +LL | #![feature(unsized_fn_params, unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #48055 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the size for values of type `(dyn Future + Unpin + 'static)` cannot be known at compilation time + --> $DIR/awaiting-unsized-param.rs:10:17 + | +LL | async fn bug(mut f: dyn Future + Unpin) -> T { + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Future + Unpin + 'static)` + = note: all values captured by value by a closure must have a statically known size + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/awaiting-unsized-param.rs b/tests/ui/async-await/awaiting-unsized-param.rs new file mode 100644 index 00000000000..2af8723b312 --- /dev/null +++ b/tests/ui/async-await/awaiting-unsized-param.rs @@ -0,0 +1,15 @@ +// edition: 2021 +// revisions: no_drop_tracking drop_tracking_mir +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + +#![feature(unsized_fn_params, unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete + +use std::future::Future; + +async fn bug(mut f: dyn Future + Unpin) -> T { + //~^ ERROR the size for values of type `(dyn Future + Unpin + 'static)` cannot be known at compilation time + (&mut f).await +} + +fn main() {} diff --git a/tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr b/tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr new file mode 100644 index 00000000000..c606df8e031 --- /dev/null +++ b/tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr @@ -0,0 +1,21 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized-across-await.rs:5:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #48055 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time + --> $DIR/unsized-across-await.rs:11:9 + | +LL | let _x = *x; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn std::fmt::Display` + = note: all values live across `await` must have a statically known size + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr b/tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr new file mode 100644 index 00000000000..c606df8e031 --- /dev/null +++ b/tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr @@ -0,0 +1,21 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized-across-await.rs:5:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #48055 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time + --> $DIR/unsized-across-await.rs:11:9 + | +LL | let _x = *x; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn std::fmt::Display` + = note: all values live across `await` must have a statically known size + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/unsized-across-await.rs b/tests/ui/async-await/unsized-across-await.rs new file mode 100644 index 00000000000..9934e9db6d2 --- /dev/null +++ b/tests/ui/async-await/unsized-across-await.rs @@ -0,0 +1,18 @@ +// edition: 2021 +// revisions: no_drop_tracking drop_tracking_mir +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + +#![feature(unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete + +async fn f() {} + +async fn g(x: Box) { + let _x = *x; + //~^ ERROR the size for values of type `dyn std::fmt::Display` cannot be known at compilation time + f().await; +} + +fn main() { + let _a = g(Box::new(5)); +} diff --git a/tests/ui/generator/unsized-across-yield.rs b/tests/ui/generator/unsized-across-yield.rs new file mode 100644 index 00000000000..876d08ac1f0 --- /dev/null +++ b/tests/ui/generator/unsized-across-yield.rs @@ -0,0 +1,34 @@ +#![feature(generator_trait)] +#![feature(generators)] +#![feature(unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + +use std::ops::Generator; + +fn across() -> impl Generator { + move || { + let b: [u8] = *(Box::new([]) as Box<[u8]>); + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + + yield; + + for elem in b.iter() {} + } +} + +fn capture() -> impl Generator { + let b: [u8] = *(Box::new([]) as Box<[u8]>); + move || { + println!("{:?}", &b); + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + + yield; + + for elem in b.iter() {} + } +} + +fn main() { + across(); + capture(); +} diff --git a/tests/ui/generator/unsized-across-yield.stderr b/tests/ui/generator/unsized-across-yield.stderr new file mode 100644 index 00000000000..82375a0ec2d --- /dev/null +++ b/tests/ui/generator/unsized-across-yield.stderr @@ -0,0 +1,32 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized-across-yield.rs:3:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #48055 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-across-yield.rs:10:13 + | +LL | let b: [u8] = *(Box::new([]) as Box<[u8]>); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all values live across `yield` must have a statically known size + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-across-yield.rs:22:27 + | +LL | move || { + | -- this closure captures all values by move +LL | println!("{:?}", &b); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all values captured by value by a closure must have a statically known size + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`.