Skip to content

Commit a7f375a

Browse files
committed
Do not ICE when combining unsized locals and async
1 parent a44881d commit a7f375a

File tree

6 files changed

+85
-20
lines changed

6 files changed

+85
-20
lines changed

src/librustc/mir/interpret/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
137137
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
138138
let must_error = match self.error {
139139
err_inval!(Layout(LayoutError::Unknown(_))) |
140+
err_inval!(Layout(LayoutError::Unsized(_))) |
140141
err_inval!(TooGeneric) =>
141142
return Err(ErrorHandled::TooGeneric),
142143
err_inval!(TypeckError) =>

src/librustc/ty/layout.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,16 @@ pub const FAT_PTR_EXTRA: usize = 1;
155155
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
156156
pub enum LayoutError<'tcx> {
157157
Unknown(Ty<'tcx>),
158-
SizeOverflow(Ty<'tcx>)
158+
SizeOverflow(Ty<'tcx>),
159+
Unsized(Ty<'tcx>),
159160
}
160161

161162
impl<'tcx> fmt::Display for LayoutError<'tcx> {
162163
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163164
match *self {
165+
LayoutError::Unsized(ty) => {
166+
write!(f, "the type `{:?}` has unknown size", ty)
167+
}
164168
LayoutError::Unknown(ty) => {
165169
write!(f, "the type `{:?}` has an unknown layout", ty)
166170
}
@@ -745,7 +749,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
745749
let mut abi = Abi::Aggregate { sized: true };
746750
let index = VariantIdx::new(0);
747751
for field in &variants[index] {
748-
assert!(!field.is_unsized());
752+
if field.is_unsized() {
753+
// Instead of asserting, return an error because this can happen with
754+
// generators/async-await and unsized locals.
755+
return Err(LayoutError::Unsized(field.ty));
756+
}
749757
align = align.max(field.align);
750758

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

24942502
match *self {
2503+
Unsized(t) |
24952504
Unknown(t) |
24962505
SizeOverflow(t) => t.hash_stable(hcx, hasher)
24972506
}

src/librustc_lint/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
999999
let ty = cx.tcx.erase_regions(&t);
10001000
let layout = match cx.layout_of(ty) {
10011001
Ok(layout) => layout,
1002+
Err(ty::layout::LayoutError::Unsized(_)) |
10021003
Err(ty::layout::LayoutError::Unknown(_)) => return,
10031004
Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => {
10041005
bug!("failed to get layout for `{}`: {}", t, err);

src/librustc_mir/transform/const_prop.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -669,28 +669,43 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
669669
let place_ty: Ty<'tcx> = place
670670
.ty(&self.local_decls, self.tcx)
671671
.ty;
672-
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
673-
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
674-
if let Place {
675-
base: PlaceBase::Local(local),
676-
projection: box [],
677-
} = *place {
678-
trace!("checking whether {:?} can be stored to {:?}", value, local);
679-
if self.can_const_prop[local] {
680-
trace!("storing {:?} to {:?}", value, local);
681-
assert!(self.get_const(local).is_none());
682-
self.set_const(local, value);
683-
684-
if self.should_const_prop() {
685-
self.replace_with_const(
686-
rval,
687-
value,
688-
statement.source_info,
689-
);
672+
673+
match self.tcx.layout_of(self.param_env.and(place_ty)) {
674+
Ok(place_layout) => {
675+
if let Some(value) = self.const_prop(
676+
rval,
677+
place_layout,
678+
statement.source_info,
679+
) {
680+
if let Place {
681+
base: PlaceBase::Local(local),
682+
projection: box [],
683+
} = *place {
684+
trace!("checking whether {:?} can be stored to {:?}", value, local);
685+
if self.can_const_prop[local] {
686+
trace!("storing {:?} to {:?}", value, local);
687+
assert!(self.get_const(local).is_none());
688+
self.set_const(local, value);
689+
690+
if self.should_const_prop() {
691+
self.replace_with_const(
692+
rval,
693+
value,
694+
statement.source_info,
695+
);
690696
}
691697
}
692698
}
693699
}
700+
Err(LayoutError::Unsized(_ty)) => {
701+
let sp = statement.source_info.span; // async fn block
702+
self.tcx.sess.struct_span_err(
703+
sp,
704+
"unsized values can't be used in `async` functions",
705+
).span_label(sp, "contains unsized values")
706+
.emit();
707+
}
708+
Err(_) => {}
694709
}
695710
}
696711
self.super_statement(statement, location);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// edition:2018
2+
3+
#![feature(unsized_locals)]
4+
#![feature(gen_future)]
5+
6+
use std::future::poll_with_tls_context;
7+
use std::pin::Pin;
8+
use std::fmt::Display;
9+
10+
async fn foo2() {}
11+
12+
async fn foo(x: Box<dyn Display>) { //~ ERROR unsized values can't be used in `async` functions
13+
let x = *x;
14+
foo2().await;
15+
println!("hello {}", &x);
16+
}
17+
18+
fn main() {
19+
let mut a = foo(Box::new(5));
20+
let b = unsafe {
21+
Pin::new_unchecked(&mut a)
22+
};
23+
match poll_with_tls_context(b) {
24+
_ => ()
25+
};
26+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: unsized values can't be used in `async` functions
2+
--> $DIR/unsized-locals.rs:12:35
3+
|
4+
LL | async fn foo(x: Box<dyn Display>) {
5+
| ___________________________________^
6+
LL | | let x = *x;
7+
LL | | foo2().await;
8+
LL | | println!("hello {}", &x);
9+
LL | | }
10+
| |_^ contains unsized values
11+
12+
error: aborting due to previous error
13+

0 commit comments

Comments
 (0)