Auto merge of #66321 - ninjasource:async-fn-resume-after-completion, r=oli-obk
Async fn resume after completion #65419 -- Attempting to run an async fn after completion mentions generators Not yet ready for review - work in progress Just need to run the tests on a proper build server
This commit is contained in:
commit
25d8a9494c
@ -13,7 +13,7 @@ use rustc_macros::HashStable;
|
|||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use syntax_pos::{Pos, Span};
|
use syntax_pos::{Pos, Span};
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
|
use hir::GeneratorKind;
|
||||||
use std::{fmt, env};
|
use std::{fmt, env};
|
||||||
|
|
||||||
use rustc_error_codes::*;
|
use rustc_error_codes::*;
|
||||||
@ -264,8 +264,8 @@ pub enum PanicInfo<O> {
|
|||||||
OverflowNeg,
|
OverflowNeg,
|
||||||
DivisionByZero,
|
DivisionByZero,
|
||||||
RemainderByZero,
|
RemainderByZero,
|
||||||
GeneratorResumedAfterReturn,
|
ResumedAfterReturn(GeneratorKind),
|
||||||
GeneratorResumedAfterPanic,
|
ResumedAfterPanic(GeneratorKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type for MIR `Assert` terminator error messages.
|
/// Type for MIR `Assert` terminator error messages.
|
||||||
@ -300,10 +300,14 @@ impl<O> PanicInfo<O> {
|
|||||||
"attempt to divide by zero",
|
"attempt to divide by zero",
|
||||||
RemainderByZero =>
|
RemainderByZero =>
|
||||||
"attempt to calculate the remainder with a divisor of zero",
|
"attempt to calculate the remainder with a divisor of zero",
|
||||||
GeneratorResumedAfterReturn =>
|
ResumedAfterReturn(GeneratorKind::Gen) =>
|
||||||
"generator resumed after completion",
|
"generator resumed after completion",
|
||||||
GeneratorResumedAfterPanic =>
|
ResumedAfterReturn(GeneratorKind::Async(_)) =>
|
||||||
|
"`async fn` resumed after completion",
|
||||||
|
ResumedAfterPanic(GeneratorKind::Gen) =>
|
||||||
"generator resumed after panicking",
|
"generator resumed after panicking",
|
||||||
|
ResumedAfterPanic(GeneratorKind::Async(_)) =>
|
||||||
|
"`async fn` resumed after panicking",
|
||||||
Panic { .. } | BoundsCheck { .. } =>
|
Panic { .. } | BoundsCheck { .. } =>
|
||||||
bug!("Unexpected PanicInfo"),
|
bug!("Unexpected PanicInfo"),
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
use crate::hir::def::{CtorKind, Namespace};
|
use crate::hir::def::{CtorKind, Namespace};
|
||||||
use crate::hir::def_id::DefId;
|
use crate::hir::def_id::DefId;
|
||||||
use crate::hir;
|
use crate::hir::{self, GeneratorKind};
|
||||||
use crate::mir::interpret::{GlobalAlloc, PanicInfo, Scalar};
|
use crate::mir::interpret::{GlobalAlloc, PanicInfo, Scalar};
|
||||||
use crate::mir::visit::MirVisitable;
|
use crate::mir::visit::MirVisitable;
|
||||||
use crate::ty::adjustment::PointerCast;
|
use crate::ty::adjustment::PointerCast;
|
||||||
@ -117,6 +117,10 @@ pub struct Body<'tcx> {
|
|||||||
/// The layout of a generator. Produced by the state transformation.
|
/// The layout of a generator. Produced by the state transformation.
|
||||||
pub generator_layout: Option<GeneratorLayout<'tcx>>,
|
pub generator_layout: Option<GeneratorLayout<'tcx>>,
|
||||||
|
|
||||||
|
/// If this is a generator then record the type of source expression that caused this generator
|
||||||
|
/// to be created.
|
||||||
|
pub generator_kind: Option<GeneratorKind>,
|
||||||
|
|
||||||
/// Declarations of locals.
|
/// Declarations of locals.
|
||||||
///
|
///
|
||||||
/// The first local is the return value pointer, followed by `arg_count`
|
/// The first local is the return value pointer, followed by `arg_count`
|
||||||
@ -170,6 +174,7 @@ impl<'tcx> Body<'tcx> {
|
|||||||
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
control_flow_destroyed: Vec<(Span, String)>,
|
control_flow_destroyed: Vec<(Span, String)>,
|
||||||
|
generator_kind : Option<GeneratorKind>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// We need `arg_count` locals, and one for the return place.
|
// We need `arg_count` locals, and one for the return place.
|
||||||
assert!(
|
assert!(
|
||||||
@ -187,6 +192,7 @@ impl<'tcx> Body<'tcx> {
|
|||||||
yield_ty: None,
|
yield_ty: None,
|
||||||
generator_drop: None,
|
generator_drop: None,
|
||||||
generator_layout: None,
|
generator_layout: None,
|
||||||
|
generator_kind,
|
||||||
local_decls,
|
local_decls,
|
||||||
user_type_annotations,
|
user_type_annotations,
|
||||||
arg_count,
|
arg_count,
|
||||||
@ -2975,7 +2981,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||||||
index: index.fold_with(folder),
|
index: index.fold_with(folder),
|
||||||
},
|
},
|
||||||
Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
|
Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
|
||||||
GeneratorResumedAfterReturn | GeneratorResumedAfterPanic =>
|
ResumedAfterReturn(_) | ResumedAfterPanic(_) =>
|
||||||
msg.clone(),
|
msg.clone(),
|
||||||
};
|
};
|
||||||
Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
|
Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
|
||||||
@ -3021,7 +3027,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||||||
len.visit_with(visitor) || index.visit_with(visitor),
|
len.visit_with(visitor) || index.visit_with(visitor),
|
||||||
Panic { .. } | Overflow(_) | OverflowNeg |
|
Panic { .. } | Overflow(_) | OverflowNeg |
|
||||||
DivisionByZero | RemainderByZero |
|
DivisionByZero | RemainderByZero |
|
||||||
GeneratorResumedAfterReturn | GeneratorResumedAfterPanic =>
|
ResumedAfterReturn(_) | ResumedAfterPanic(_) =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3040,6 +3046,16 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
|
||||||
|
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
|
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
|
||||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||||
Place {
|
Place {
|
||||||
|
@ -517,7 +517,7 @@ macro_rules! make_mir_visitor {
|
|||||||
self.visit_operand(index, location);
|
self.visit_operand(index, location);
|
||||||
}
|
}
|
||||||
Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
|
Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
|
||||||
GeneratorResumedAfterReturn | GeneratorResumedAfterPanic => {
|
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
|
||||||
// Nothing to visit
|
// Nothing to visit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use crate::hair::{LintLevel, BindingMode, PatKind};
|
|||||||
use crate::transform::MirSource;
|
use crate::transform::MirSource;
|
||||||
use crate::util as mir_util;
|
use crate::util as mir_util;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::Node;
|
use rustc::hir::{Node, GeneratorKind};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
@ -279,7 +279,7 @@ struct Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
fn_span: Span,
|
fn_span: Span,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
is_generator: bool,
|
generator_kind: Option<GeneratorKind>,
|
||||||
|
|
||||||
/// The current set of scopes, updated as we traverse;
|
/// The current set of scopes, updated as we traverse;
|
||||||
/// see the `scope` module for more details.
|
/// see the `scope` module for more details.
|
||||||
@ -570,7 +570,7 @@ where
|
|||||||
safety,
|
safety,
|
||||||
return_ty,
|
return_ty,
|
||||||
return_ty_span,
|
return_ty_span,
|
||||||
body.generator_kind.is_some());
|
body.generator_kind);
|
||||||
|
|
||||||
let call_site_scope = region::Scope {
|
let call_site_scope = region::Scope {
|
||||||
id: body.value.hir_id.local_id,
|
id: body.value.hir_id.local_id,
|
||||||
@ -647,7 +647,7 @@ fn construct_const<'a, 'tcx>(
|
|||||||
Safety::Safe,
|
Safety::Safe,
|
||||||
const_ty,
|
const_ty,
|
||||||
const_ty_span,
|
const_ty_span,
|
||||||
false,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut block = START_BLOCK;
|
let mut block = START_BLOCK;
|
||||||
@ -678,7 +678,7 @@ fn construct_error<'a, 'tcx>(
|
|||||||
let owner_id = hir.tcx().hir().body_owner(body_id);
|
let owner_id = hir.tcx().hir().body_owner(body_id);
|
||||||
let span = hir.tcx().hir().span(owner_id);
|
let span = hir.tcx().hir().span(owner_id);
|
||||||
let ty = hir.tcx().types.err;
|
let ty = hir.tcx().types.err;
|
||||||
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, false);
|
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None);
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
||||||
builder.finish()
|
builder.finish()
|
||||||
@ -691,7 +691,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
safety: Safety,
|
safety: Safety,
|
||||||
return_ty: Ty<'tcx>,
|
return_ty: Ty<'tcx>,
|
||||||
return_span: Span,
|
return_span: Span,
|
||||||
is_generator: bool)
|
generator_kind: Option<GeneratorKind>)
|
||||||
-> Builder<'a, 'tcx> {
|
-> Builder<'a, 'tcx> {
|
||||||
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
||||||
let mut builder = Builder {
|
let mut builder = Builder {
|
||||||
@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
cfg: CFG { basic_blocks: IndexVec::new() },
|
cfg: CFG { basic_blocks: IndexVec::new() },
|
||||||
fn_span: span,
|
fn_span: span,
|
||||||
arg_count,
|
arg_count,
|
||||||
is_generator,
|
generator_kind,
|
||||||
scopes: Default::default(),
|
scopes: Default::default(),
|
||||||
block_context: BlockContext::new(),
|
block_context: BlockContext::new(),
|
||||||
source_scopes: IndexVec::new(),
|
source_scopes: IndexVec::new(),
|
||||||
@ -748,6 +748,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
self.var_debug_info,
|
self.var_debug_info,
|
||||||
self.fn_span,
|
self.fn_span,
|
||||||
self.hir.control_flow_destroyed(),
|
self.hir.control_flow_destroyed(),
|
||||||
|
self.generator_kind
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ use syntax_pos::{DUMMY_SP, Span};
|
|||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use rustc::hir::GeneratorKind;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Scope {
|
struct Scope {
|
||||||
@ -219,7 +220,12 @@ impl Scope {
|
|||||||
/// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
|
/// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
|
||||||
/// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
|
/// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
|
||||||
/// top-of-scope (as opposed to dependent scopes).
|
/// top-of-scope (as opposed to dependent scopes).
|
||||||
fn invalidate_cache(&mut self, storage_only: bool, is_generator: bool, this_scope_only: bool) {
|
fn invalidate_cache(
|
||||||
|
&mut self,
|
||||||
|
storage_only: bool,
|
||||||
|
generator_kind: Option<GeneratorKind>,
|
||||||
|
this_scope_only: bool
|
||||||
|
) {
|
||||||
// FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
|
// FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
|
||||||
// with lots of `try!`?
|
// with lots of `try!`?
|
||||||
|
|
||||||
@ -229,7 +235,7 @@ impl Scope {
|
|||||||
// the current generator drop and unwind refer to top-of-scope
|
// the current generator drop and unwind refer to top-of-scope
|
||||||
self.cached_generator_drop = None;
|
self.cached_generator_drop = None;
|
||||||
|
|
||||||
let ignore_unwinds = storage_only && !is_generator;
|
let ignore_unwinds = storage_only && generator_kind.is_none();
|
||||||
if !ignore_unwinds {
|
if !ignore_unwinds {
|
||||||
self.cached_unwind.invalidate();
|
self.cached_unwind.invalidate();
|
||||||
}
|
}
|
||||||
@ -481,7 +487,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
unpack!(block = build_scope_drops(
|
unpack!(block = build_scope_drops(
|
||||||
&mut self.cfg,
|
&mut self.cfg,
|
||||||
self.is_generator,
|
self.generator_kind,
|
||||||
&scope,
|
&scope,
|
||||||
block,
|
block,
|
||||||
unwind_to,
|
unwind_to,
|
||||||
@ -574,7 +580,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
unpack!(block = build_scope_drops(
|
unpack!(block = build_scope_drops(
|
||||||
&mut self.cfg,
|
&mut self.cfg,
|
||||||
self.is_generator,
|
self.generator_kind,
|
||||||
scope,
|
scope,
|
||||||
block,
|
block,
|
||||||
unwind_to,
|
unwind_to,
|
||||||
@ -625,7 +631,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
unpack!(block = build_scope_drops(
|
unpack!(block = build_scope_drops(
|
||||||
&mut self.cfg,
|
&mut self.cfg,
|
||||||
self.is_generator,
|
self.generator_kind,
|
||||||
scope,
|
scope,
|
||||||
block,
|
block,
|
||||||
unwind_to,
|
unwind_to,
|
||||||
@ -809,7 +815,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
// invalidating caches of each scope visited. This way bare minimum of the
|
// invalidating caches of each scope visited. This way bare minimum of the
|
||||||
// caches gets invalidated. i.e., if a new drop is added into the middle scope, the
|
// caches gets invalidated. i.e., if a new drop is added into the middle scope, the
|
||||||
// cache of outer scope stays intact.
|
// cache of outer scope stays intact.
|
||||||
scope.invalidate_cache(!needs_drop, self.is_generator, this_scope);
|
scope.invalidate_cache(!needs_drop, self.generator_kind, this_scope);
|
||||||
if this_scope {
|
if this_scope {
|
||||||
let region_scope_span = region_scope.span(self.hir.tcx(),
|
let region_scope_span = region_scope.span(self.hir.tcx(),
|
||||||
&self.hir.region_scope_tree);
|
&self.hir.region_scope_tree);
|
||||||
@ -958,7 +964,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
top_scope.invalidate_cache(true, self.is_generator, true);
|
top_scope.invalidate_cache(true, self.generator_kind, true);
|
||||||
} else {
|
} else {
|
||||||
bug!("Expected as_local_operand to produce a temporary");
|
bug!("Expected as_local_operand to produce a temporary");
|
||||||
}
|
}
|
||||||
@ -1016,7 +1022,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
for scope in self.scopes.top_scopes(first_uncached) {
|
for scope in self.scopes.top_scopes(first_uncached) {
|
||||||
target = build_diverge_scope(&mut self.cfg, scope.region_scope_span,
|
target = build_diverge_scope(&mut self.cfg, scope.region_scope_span,
|
||||||
scope, target, generator_drop, self.is_generator);
|
scope, target, generator_drop, self.generator_kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
target
|
target
|
||||||
@ -1079,14 +1085,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
assert_eq!(top_scope.region_scope, region_scope);
|
assert_eq!(top_scope.region_scope, region_scope);
|
||||||
|
|
||||||
top_scope.drops.clear();
|
top_scope.drops.clear();
|
||||||
top_scope.invalidate_cache(false, self.is_generator, true);
|
top_scope.invalidate_cache(false, self.generator_kind, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds drops for pop_scope and exit_scope.
|
/// Builds drops for pop_scope and exit_scope.
|
||||||
fn build_scope_drops<'tcx>(
|
fn build_scope_drops<'tcx>(
|
||||||
cfg: &mut CFG<'tcx>,
|
cfg: &mut CFG<'tcx>,
|
||||||
is_generator: bool,
|
generator_kind: Option<GeneratorKind>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
last_unwind_to: BasicBlock,
|
last_unwind_to: BasicBlock,
|
||||||
@ -1130,7 +1136,7 @@ fn build_scope_drops<'tcx>(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let unwind_to = get_unwind_to(scope, is_generator, drop_idx, generator_drop)
|
let unwind_to = get_unwind_to(scope, generator_kind, drop_idx, generator_drop)
|
||||||
.unwrap_or(last_unwind_to);
|
.unwrap_or(last_unwind_to);
|
||||||
|
|
||||||
let next = cfg.start_new_block();
|
let next = cfg.start_new_block();
|
||||||
@ -1156,19 +1162,19 @@ fn build_scope_drops<'tcx>(
|
|||||||
|
|
||||||
fn get_unwind_to(
|
fn get_unwind_to(
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
is_generator: bool,
|
generator_kind: Option<GeneratorKind>,
|
||||||
unwind_from: usize,
|
unwind_from: usize,
|
||||||
generator_drop: bool,
|
generator_drop: bool,
|
||||||
) -> Option<BasicBlock> {
|
) -> Option<BasicBlock> {
|
||||||
for drop_idx in (0..unwind_from).rev() {
|
for drop_idx in (0..unwind_from).rev() {
|
||||||
let drop_data = &scope.drops[drop_idx];
|
let drop_data = &scope.drops[drop_idx];
|
||||||
match (is_generator, &drop_data.kind) {
|
match (generator_kind, &drop_data.kind) {
|
||||||
(true, DropKind::Storage) => {
|
(Some(_), DropKind::Storage) => {
|
||||||
return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
|
return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
|
||||||
span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
|
span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
(false, DropKind::Value) => {
|
(None, DropKind::Value) => {
|
||||||
return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
|
return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
|
||||||
span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
|
span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
|
||||||
}));
|
}));
|
||||||
@ -1184,7 +1190,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mut target: BasicBlock,
|
mut target: BasicBlock,
|
||||||
generator_drop: bool,
|
generator_drop: bool,
|
||||||
is_generator: bool)
|
generator_kind: Option<GeneratorKind>)
|
||||||
-> BasicBlock
|
-> BasicBlock
|
||||||
{
|
{
|
||||||
// Build up the drops in **reverse** order. The end result will
|
// Build up the drops in **reverse** order. The end result will
|
||||||
@ -1224,7 +1230,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
|
|||||||
// match the behavior of clang, but on inspection eddyb says
|
// match the behavior of clang, but on inspection eddyb says
|
||||||
// this is not what clang does.
|
// this is not what clang does.
|
||||||
match drop_data.kind {
|
match drop_data.kind {
|
||||||
DropKind::Storage if is_generator => {
|
DropKind::Storage if generator_kind.is_some() => {
|
||||||
storage_deads.push(Statement {
|
storage_deads.push(Statement {
|
||||||
source_info: source_info(drop_data.span),
|
source_info: source_info(drop_data.span),
|
||||||
kind: StatementKind::StorageDead(drop_data.local)
|
kind: StatementKind::StorageDead(drop_data.local)
|
||||||
|
@ -142,8 +142,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
OverflowNeg => err_panic!(OverflowNeg),
|
OverflowNeg => err_panic!(OverflowNeg),
|
||||||
DivisionByZero => err_panic!(DivisionByZero),
|
DivisionByZero => err_panic!(DivisionByZero),
|
||||||
RemainderByZero => err_panic!(RemainderByZero),
|
RemainderByZero => err_panic!(RemainderByZero),
|
||||||
GeneratorResumedAfterReturn => err_panic!(GeneratorResumedAfterReturn),
|
ResumedAfterReturn(generator_kind)
|
||||||
GeneratorResumedAfterPanic => err_panic!(GeneratorResumedAfterPanic),
|
=> err_panic!(ResumedAfterReturn(*generator_kind)),
|
||||||
|
ResumedAfterPanic(generator_kind)
|
||||||
|
=> err_panic!(ResumedAfterPanic(*generator_kind)),
|
||||||
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
|
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
|
@ -196,19 +196,14 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
|||||||
block(&mut blocks, TerminatorKind::Goto { target: return_block });
|
block(&mut blocks, TerminatorKind::Goto { target: return_block });
|
||||||
block(&mut blocks, TerminatorKind::Return);
|
block(&mut blocks, TerminatorKind::Return);
|
||||||
|
|
||||||
let mut body = Body::new(
|
let mut body = new_body(
|
||||||
blocks,
|
blocks,
|
||||||
IndexVec::from_elem_n(
|
IndexVec::from_elem_n(
|
||||||
SourceScopeData { span: span, parent_scope: None }, 1
|
SourceScopeData { span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
|
||||||
local_decls_for_sig(&sig, span),
|
local_decls_for_sig(&sig, span),
|
||||||
IndexVec::new(),
|
|
||||||
sig.inputs().len(),
|
sig.inputs().len(),
|
||||||
vec![],
|
span);
|
||||||
span,
|
|
||||||
vec![],
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(..) = ty {
|
if let Some(..) = ty {
|
||||||
// The first argument (index 0), but add 1 for the return value.
|
// The first argument (index 0), but add 1 for the return value.
|
||||||
@ -247,6 +242,27 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
|||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_body<'tcx>(
|
||||||
|
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||||
|
source_scopes: IndexVec<SourceScope, SourceScopeData>,
|
||||||
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
||||||
|
arg_count: usize,
|
||||||
|
span: Span,
|
||||||
|
) -> Body<'tcx> {
|
||||||
|
Body::new(
|
||||||
|
basic_blocks,
|
||||||
|
source_scopes,
|
||||||
|
ClearCrossCrate::Clear,
|
||||||
|
local_decls,
|
||||||
|
IndexVec::new(),
|
||||||
|
arg_count,
|
||||||
|
vec![],
|
||||||
|
span,
|
||||||
|
vec![],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DropShimElaborator<'a, 'tcx> {
|
pub struct DropShimElaborator<'a, 'tcx> {
|
||||||
pub body: &'a Body<'tcx>,
|
pub body: &'a Body<'tcx>,
|
||||||
pub patch: MirPatch<'tcx>,
|
pub patch: MirPatch<'tcx>,
|
||||||
@ -362,18 +378,14 @@ impl CloneShimBuilder<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn into_mir(self) -> Body<'tcx> {
|
fn into_mir(self) -> Body<'tcx> {
|
||||||
Body::new(
|
new_body(
|
||||||
self.blocks,
|
self.blocks,
|
||||||
IndexVec::from_elem_n(
|
IndexVec::from_elem_n(
|
||||||
SourceScopeData { span: self.span, parent_scope: None }, 1
|
SourceScopeData { span: self.span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
|
||||||
self.local_decls,
|
self.local_decls,
|
||||||
IndexVec::new(),
|
|
||||||
self.sig.inputs().len(),
|
self.sig.inputs().len(),
|
||||||
vec![],
|
|
||||||
self.span,
|
self.span,
|
||||||
vec![],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,19 +834,16 @@ fn build_call_shim<'tcx>(
|
|||||||
block(&mut blocks, vec![], TerminatorKind::Resume, true);
|
block(&mut blocks, vec![], TerminatorKind::Resume, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut body = Body::new(
|
let mut body = new_body(
|
||||||
blocks,
|
blocks,
|
||||||
IndexVec::from_elem_n(
|
IndexVec::from_elem_n(
|
||||||
SourceScopeData { span: span, parent_scope: None }, 1
|
SourceScopeData { span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
|
||||||
local_decls,
|
local_decls,
|
||||||
IndexVec::new(),
|
|
||||||
sig.inputs().len(),
|
sig.inputs().len(),
|
||||||
vec![],
|
|
||||||
span,
|
span,
|
||||||
vec![],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Abi::RustCall = sig.abi {
|
if let Abi::RustCall = sig.abi {
|
||||||
body.spread_arg = Some(Local::new(sig.inputs().len()));
|
body.spread_arg = Some(Local::new(sig.inputs().len()));
|
||||||
}
|
}
|
||||||
@ -908,18 +917,14 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
|
|||||||
is_cleanup: false
|
is_cleanup: false
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = Body::new(
|
let body = new_body(
|
||||||
IndexVec::from_elem_n(start_block, 1),
|
IndexVec::from_elem_n(start_block, 1),
|
||||||
IndexVec::from_elem_n(
|
IndexVec::from_elem_n(
|
||||||
SourceScopeData { span: span, parent_scope: None }, 1
|
SourceScopeData { span, parent_scope: None }, 1
|
||||||
),
|
),
|
||||||
ClearCrossCrate::Clear,
|
|
||||||
local_decls,
|
local_decls,
|
||||||
IndexVec::new(),
|
|
||||||
sig.inputs().len(),
|
sig.inputs().len(),
|
||||||
vec![],
|
|
||||||
span,
|
span,
|
||||||
vec![],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::util::dump_mir(
|
crate::util::dump_mir(
|
||||||
|
@ -91,6 +91,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
|
|||||||
Default::default(),
|
Default::default(),
|
||||||
tcx.def_span(source.def_id()),
|
tcx.def_span(source.def_id()),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
body.generator_kind,
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
|
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
|
||||||
|
@ -1056,16 +1056,23 @@ fn create_generator_resume_function<'tcx>(
|
|||||||
let mut cases = create_cases(body, &transform, |point| Some(point.resume));
|
let mut cases = create_cases(body, &transform, |point| Some(point.resume));
|
||||||
|
|
||||||
use rustc::mir::interpret::PanicInfo::{
|
use rustc::mir::interpret::PanicInfo::{
|
||||||
GeneratorResumedAfterPanic,
|
ResumedAfterPanic,
|
||||||
GeneratorResumedAfterReturn,
|
ResumedAfterReturn,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Jump to the entry point on the unresumed
|
// Jump to the entry point on the unresumed
|
||||||
cases.insert(0, (UNRESUMED, BasicBlock::new(0)));
|
cases.insert(0, (UNRESUMED, BasicBlock::new(0)));
|
||||||
// Panic when resumed on the returned state
|
|
||||||
cases.insert(1, (RETURNED, insert_panic_block(tcx, body, GeneratorResumedAfterReturn)));
|
// Panic when resumed on the returned or poisoned state
|
||||||
// Panic when resumed on the poisoned state
|
let generator_kind = body.generator_kind.unwrap();
|
||||||
cases.insert(2, (POISONED, insert_panic_block(tcx, body, GeneratorResumedAfterPanic)));
|
cases.insert(1, (RETURNED, insert_panic_block(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
ResumedAfterReturn(generator_kind))));
|
||||||
|
cases.insert(2, (POISONED, insert_panic_block(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
ResumedAfterPanic(generator_kind))));
|
||||||
|
|
||||||
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
||||||
|
|
||||||
|
@ -1088,6 +1088,7 @@ pub fn promote_candidates<'tcx>(
|
|||||||
vec![],
|
vec![],
|
||||||
body.span,
|
body.span,
|
||||||
vec![],
|
vec![],
|
||||||
|
body.generator_kind,
|
||||||
),
|
),
|
||||||
tcx,
|
tcx,
|
||||||
source: body,
|
source: body,
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
// issue 65419 - Attempting to run an async fn after completion mentions generators when it should
|
||||||
|
// be talking about `async fn`s instead.
|
||||||
|
|
||||||
|
// run-fail
|
||||||
|
// error-pattern: thread 'main' panicked at '`async fn` resumed after completion'
|
||||||
|
// edition:2018
|
||||||
|
// ignore-wasm no panic or subprocess support
|
||||||
|
// ignore-emscripten no panic or subprocess support
|
||||||
|
|
||||||
|
#![feature(generators, generator_trait)]
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut future = Box::pin(foo());
|
||||||
|
executor::block_on(future.as_mut());
|
||||||
|
executor::block_on(future.as_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
mod executor {
|
||||||
|
use core::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||||
|
let mut future = unsafe { Pin::new_unchecked(&mut future) };
|
||||||
|
|
||||||
|
static VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||||
|
|_| unimplemented!("clone"),
|
||||||
|
|_| unimplemented!("wake"),
|
||||||
|
|_| unimplemented!("wake_by_ref"),
|
||||||
|
|_| (),
|
||||||
|
);
|
||||||
|
let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
|
||||||
|
let mut context = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
|
||||||
|
break val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
// issue 65419 - Attempting to run an async fn after completion mentions generators when it should
|
||||||
|
// be talking about `async fn`s instead. Should also test what happens when it panics.
|
||||||
|
|
||||||
|
// run-fail
|
||||||
|
// error-pattern: thread 'main' panicked at '`async fn` resumed after panicking'
|
||||||
|
// edition:2018
|
||||||
|
// ignore-wasm no panic or subprocess support
|
||||||
|
// ignore-emscripten no panic or subprocess support
|
||||||
|
|
||||||
|
#![feature(generators, generator_trait)]
|
||||||
|
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut future = Box::pin(foo());
|
||||||
|
panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||||
|
executor::block_on(future.as_mut());
|
||||||
|
}));
|
||||||
|
|
||||||
|
executor::block_on(future.as_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
mod executor {
|
||||||
|
use core::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||||
|
let mut future = unsafe { Pin::new_unchecked(&mut future) };
|
||||||
|
|
||||||
|
static VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||||
|
|_| unimplemented!("clone"),
|
||||||
|
|_| unimplemented!("wake"),
|
||||||
|
|_| unimplemented!("wake_by_ref"),
|
||||||
|
|_| (),
|
||||||
|
);
|
||||||
|
let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
|
||||||
|
let mut context = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
|
||||||
|
break val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
// issue 65419 - Attempting to run an `async fn` after completion mentions generators when it should
|
||||||
|
// be talking about `async fn`s instead. Regression test added to make sure generators still
|
||||||
|
// panic when resumed after completion.
|
||||||
|
|
||||||
|
// run-fail
|
||||||
|
// error-pattern:generator resumed after completion
|
||||||
|
// edition:2018
|
||||||
|
// ignore-wasm no panic or subprocess support
|
||||||
|
// ignore-emscripten no panic or subprocess support
|
||||||
|
|
||||||
|
#![feature(generators, generator_trait)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ops::Generator,
|
||||||
|
pin::Pin,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut g = || {
|
||||||
|
yield;
|
||||||
|
};
|
||||||
|
Pin::new(&mut g).resume(); // Yields once.
|
||||||
|
Pin::new(&mut g).resume(); // Completes here.
|
||||||
|
Pin::new(&mut g).resume(); // Panics here.
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user