Skip to content

Commit

Permalink
Do not ICE when combining unsized locals and async
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Sep 16, 2019
1 parent a44881d commit a7f375a
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
let must_error = match self.error {
err_inval!(Layout(LayoutError::Unknown(_))) |
err_inval!(Layout(LayoutError::Unsized(_))) |
err_inval!(TooGeneric) =>
return Err(ErrorHandled::TooGeneric),
err_inval!(TypeckError) =>
Expand Down
13 changes: 11 additions & 2 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,16 @@ pub const FAT_PTR_EXTRA: usize = 1;
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>)
SizeOverflow(Ty<'tcx>),
Unsized(Ty<'tcx>),
}

impl<'tcx> fmt::Display for LayoutError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
LayoutError::Unsized(ty) => {
write!(f, "the type `{:?}` has unknown size", ty)
}
LayoutError::Unknown(ty) => {
write!(f, "the type `{:?}` has an unknown layout", ty)
}
Expand Down Expand Up @@ -745,7 +749,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let mut abi = Abi::Aggregate { sized: true };
let index = VariantIdx::new(0);
for field in &variants[index] {
assert!(!field.is_unsized());
if field.is_unsized() {
// Instead of asserting, return an error because this can happen with
// generators/async-await and unsized locals.
return Err(LayoutError::Unsized(field.ty));
}
align = align.max(field.align);

// If all non-ZST fields have the same ABI, forward this ABI
Expand Down Expand Up @@ -2492,6 +2500,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
mem::discriminant(self).hash_stable(hcx, hasher);

match *self {
Unsized(t) |
Unknown(t) |
SizeOverflow(t) => t.hash_stable(hcx, hasher)
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
let ty = cx.tcx.erase_regions(&t);
let layout = match cx.layout_of(ty) {
Ok(layout) => layout,
Err(ty::layout::LayoutError::Unsized(_)) |
Err(ty::layout::LayoutError::Unknown(_)) => return,
Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => {
bug!("failed to get layout for `{}`: {}", t, err);
Expand Down
51 changes: 33 additions & 18 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,28 +669,43 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
let place_ty: Ty<'tcx> = place
.ty(&self.local_decls, self.tcx)
.ty;
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
if let Place {
base: PlaceBase::Local(local),
projection: box [],
} = *place {
trace!("checking whether {:?} can be stored to {:?}", value, local);
if self.can_const_prop[local] {
trace!("storing {:?} to {:?}", value, local);
assert!(self.get_const(local).is_none());
self.set_const(local, value);

if self.should_const_prop() {
self.replace_with_const(
rval,
value,
statement.source_info,
);

match self.tcx.layout_of(self.param_env.and(place_ty)) {
Ok(place_layout) => {
if let Some(value) = self.const_prop(
rval,
place_layout,
statement.source_info,
) {
if let Place {
base: PlaceBase::Local(local),
projection: box [],
} = *place {
trace!("checking whether {:?} can be stored to {:?}", value, local);
if self.can_const_prop[local] {
trace!("storing {:?} to {:?}", value, local);
assert!(self.get_const(local).is_none());
self.set_const(local, value);

if self.should_const_prop() {
self.replace_with_const(
rval,
value,
statement.source_info,
);
}
}
}
}
Err(LayoutError::Unsized(_ty)) => {
let sp = statement.source_info.span; // async fn block
self.tcx.sess.struct_span_err(
sp,
"unsized values can't be used in `async` functions",
).span_label(sp, "contains unsized values")
.emit();
}
Err(_) => {}
}
}
self.super_statement(statement, location);
Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/async-await/unsized-locals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// edition:2018

#![feature(unsized_locals)]
#![feature(gen_future)]

use std::future::poll_with_tls_context;
use std::pin::Pin;
use std::fmt::Display;

async fn foo2() {}

async fn foo(x: Box<dyn Display>) { //~ ERROR unsized values can't be used in `async` functions
let x = *x;
foo2().await;
println!("hello {}", &x);
}

fn main() {
let mut a = foo(Box::new(5));
let b = unsafe {
Pin::new_unchecked(&mut a)
};
match poll_with_tls_context(b) {
_ => ()
};
}
13 changes: 13 additions & 0 deletions src/test/ui/async-await/unsized-locals.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: unsized values can't be used in `async` functions
--> $DIR/unsized-locals.rs:12:35
|
LL | async fn foo(x: Box<dyn Display>) {
| ___________________________________^
LL | | let x = *x;
LL | | foo2().await;
LL | | println!("hello {}", &x);
LL | | }
| |_^ contains unsized values

error: aborting due to previous error

0 comments on commit a7f375a

Please sign in to comment.