diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c8a0ed3951100..ed874ae829b46 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1296,7 +1296,6 @@ pub struct Stmt<'hir> { #[derive(Debug, HashStable_Generic)] pub enum StmtKind<'hir> { /// A local (`let`) binding. - /// FIXME: bundle the last two components into another `struct` Local(&'hir Local<'hir>), /// An item binding. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index ef1a30e142cf6..b5d9769c578a5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1058,9 +1058,9 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) { pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { visitor.visit_id(statement.hir_id); - match &statement.kind { + match statement.kind { StmtKind::Local(ref local) => visitor.visit_local(local), - StmtKind::Item(item) => visitor.visit_nested_item(*item), + StmtKind::Item(item) => visitor.visit_nested_item(item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a0ec7f4fc6f84..4d29fc469462c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,13 +1,12 @@ use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::InferCtxt; -use hir::LocalSource; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local}; +use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 4079470c25518..dccaa61ed89d4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -48,7 +48,7 @@ impl<'tcx> Cx<'tcx> { .filter_map(|(index, stmt)| { let hir_id = stmt.hir_id; let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id); - match &stmt.kind { + match stmt.kind { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { let stmt = Stmt { kind: StmtKind::Expr { @@ -66,7 +66,7 @@ impl<'tcx> Cx<'tcx> { // ignore for purposes of the MIR None } - hir::StmtKind::Local(local) => { + hir::StmtKind::Local(ref local) => { let remainder_scope = region::Scope { id: block_id, data: region::ScopeData::Remainder(region::FirstStatementIndex::new( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 097b9c3f0f706..60ee2233ed9c0 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1215,12 +1215,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty); - } - /// Type check a `let` statement. - pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { - self.check_decl(local.into()); - if let Some(blk) = local.els { + if let Some(blk) = decl.els { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); @@ -1233,6 +1229,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Type check a `let` statement. + pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + self.check_decl(local.into()); + } + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { // Don't do all the complex logic below for `DeclItem`. match stmt.kind { diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 859fc91f517cb..8f34a970f6ff7 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -16,19 +16,20 @@ pub(super) struct Declaration<'a> { pub ty: Option<&'a hir::Ty<'a>>, pub span: Span, pub init: Option<&'a hir::Expr<'a>>, + pub els: Option<&'a hir::Block<'a>>, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { - let hir::Local { hir_id, pat, ty, span, init, .. } = *local; - Declaration { hir_id, pat, ty, span, init } + let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; + Declaration { hir_id, pat, ty, span, init, els } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { hir_id, pat, ty, span, init: Some(init) } + Declaration { hir_id, pat, ty, span, init: Some(init), els: None } } } diff --git a/src/test/ui/async-await/async-await-let-else.rs b/src/test/ui/async-await/async-await-let-else.rs new file mode 100644 index 0000000000000..7ea07ae9add1b --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.rs @@ -0,0 +1,53 @@ +// edition:2021 +#![feature(let_else)] +use std::rc::Rc; + +async fn foo(x: Option) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await + }; +} + +async fn bar() -> ! { + panic!() +} + +fn is_send(_: T) {} + +async fn foo2(x: Option) { + let Some(_) = x else { + bar2(Rc::new(())).await + }; +} + +async fn bar2(_: T) -> ! { + panic!() +} + +async fn foo3(x: Option) { + let Some(_) = x else { + (Rc::new(()), bar().await); + return; + }; +} + +async fn foo4(x: Option) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await; + println!("{:?}", r); + return; + }; +} + +fn main() { + is_send(foo(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo2(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo3(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo4(Some(true))); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr new file mode 100644 index 0000000000000..4d23e27c426b2 --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.stderr @@ -0,0 +1,94 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:45:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:8:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:47:13 + | +LL | is_send(foo2(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:20:26 + | +LL | bar2(Rc::new(())).await + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +LL | }; + | - `Rc::new(())` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:49:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:30:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +note: `Rc::new(())` is later dropped here + --> $DIR/async-await-let-else.rs:30:35 + | +LL | (Rc::new(()), bar().await); + | ^ +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:51:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:38:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +... +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors +