Skip to content

Commit

Permalink
Check types live across yields in generators too
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Sep 23, 2023
1 parent a3a9406 commit 589917c
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 2 deletions.
21 changes: 20 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_infer::traits::{Obligation, TraitEngineExt as _};
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};
Expand Down Expand Up @@ -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() {
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_hir_typeck/src/generator_interior/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ 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;
Expand Down Expand Up @@ -214,6 +215,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(def_id.expect_local()),
);
}
}

// 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
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3018,6 +3018,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
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`");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/48055> for more information
= note: `#[warn(incomplete_features)]` on by default

error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
--> $DIR/awaiting-unsized-param.rs:10:17
|
LL | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + 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`.
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/48055> for more information
= note: `#[warn(incomplete_features)]` on by default

error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
--> $DIR/awaiting-unsized-param.rs:10:17
|
LL | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + 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`.
15 changes: 15 additions & 0 deletions tests/ui/async-await/awaiting-unsized-param.rs
Original file line number Diff line number Diff line change
@@ -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<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
//~^ ERROR the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
(&mut f).await
}

fn main() {}
21 changes: 21 additions & 0 deletions tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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`.
21 changes: 21 additions & 0 deletions tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 `yield` 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`.
18 changes: 18 additions & 0 deletions tests/ui/async-await/unsized-across-await.rs
Original file line number Diff line number Diff line change
@@ -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<dyn std::fmt::Display>) {
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));
}
19 changes: 19 additions & 0 deletions tests/ui/generator/unsized-across-yield.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![feature(generator_trait)]
#![feature(generators)]
#![feature(unsized_locals)]

use std::ops::Generator;

fn blah() -> impl Generator {
move || {
let b: [u8] = *(Box::new([]) as Box<[u8]>);

yield;

for elem in b.iter() {}
}
}

fn main() {
blah();
}

0 comments on commit 589917c

Please sign in to comment.