diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index e96709f6d14..8a4594fe0e8 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -369,6 +369,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprKind::AddrOf(_, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Use(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Field(ref e, _) | hir::ExprKind::Yield(ref e) | diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index a0c9e5983a1..3d727f7cd91 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1029,6 +1029,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } + ExprKind::Use(ref subexpression) => { + visitor.visit_expr(subexpression); + } ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); visitor.visit_expr(if_block); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 380dee5fcdc..37373da72fb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4738,16 +4738,11 @@ impl<'a> LoweringContext<'a> { hir::MatchSource::ForLoopDesugar, )); - // `{ let _result = ...; _result }` - // Underscore prevents an `unused_variables` lint if the head diverges. - let result_ident = self.str_to_ident("_result"); - let (let_stmt, let_stmt_binding) = - self.stmt_let(e.span, false, result_ident, match_expr); - - let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); - let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); - // Add the attributes to the outer returned expr node. - return self.expr_block(block, e.attrs.clone()); + // This is effectively `{ let _result = ...; _result }`. + // The construct was introduced in #21984. + // FIXME(60253): Is this still necessary? + // Also, add the attributes to the outer returned expr node. + return self.expr_use(head_sp, match_expr, e.attrs.clone()) } // Desugar `ExprKind::Try` @@ -5117,6 +5112,17 @@ impl<'a> LoweringContext<'a> { ) } + /// Wrap the given `expr` in `hir::ExprKind::Use`. + /// + /// In terms of drop order, it has the same effect as + /// wrapping `expr` in `{ let _t = $expr; _t }` but + /// should provide better compile-time performance. + /// + /// The drop order can be important in e.g. `if expr { .. }`. + fn expr_use(&mut self, span: Span, expr: P, attrs: ThinVec) -> hir::Expr { + self.expr(span, hir::ExprKind::Use(expr), attrs) + } + fn expr_match( &mut self, span: Span, @@ -5172,25 +5178,6 @@ impl<'a> LoweringContext<'a> { } } - fn stmt_let( - &mut self, - sp: Span, - mutbl: bool, - ident: Ident, - ex: P, - ) -> (hir::Stmt, hir::HirId) { - let (pat, pat_hid) = if mutbl { - self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable) - } else { - self.pat_ident(sp, ident) - }; - - ( - self.stmt_let_pat(sp, Some(ex), pat, hir::LocalSource::Normal), - pat_hid, - ) - } - fn block_expr(&mut self, expr: P) -> hir::Block { self.block_all(expr.span, hir::HirVec::new(), Some(expr)) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f114f0fc236..2e10300dced 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1366,6 +1366,7 @@ impl Expr { ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, + ExprKind::Use(ref expr, ..) => expr.precedence(), ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, ExprKind::Loop(..) => ExprPrecedence::Loop, @@ -1437,6 +1438,7 @@ impl Expr { ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::Cast(..) | + ExprKind::Use(..) | ExprKind::Err => { false } @@ -1486,6 +1488,10 @@ pub enum ExprKind { Cast(P, P), /// A type reference (e.g., `Foo`). Type(P, P), + /// Semantically equivalent to `{ let _t = expr; _t }`. + /// Maps directly to `hair::ExprKind::Use`. + /// Only exists to tweak the drop order in HIR. + Use(P), /// An `if` block, with an optional else block. /// /// I.e., `if { } else { }`. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index dc87e13b739..06225364f6c 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -995,23 +995,32 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ii.hir_id)) } + pub fn print_local( + &mut self, + init: Option<&hir::Expr>, + decl: impl Fn(&mut Self) -> io::Result<()> + ) -> io::Result<()> { + self.space_if_not_bol()?; + self.ibox(indent_unit)?; + self.word_nbsp("let")?; + + self.ibox(indent_unit)?; + decl(self)?; + self.end()?; + + if let Some(ref init) = init { + self.nbsp()?; + self.word_space("=")?; + self.print_expr(&init)?; + } + self.end() + } + pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> { self.maybe_print_comment(st.span.lo())?; match st.node { hir::StmtKind::Local(ref loc) => { - self.space_if_not_bol()?; - self.ibox(indent_unit)?; - self.word_nbsp("let")?; - - self.ibox(indent_unit)?; - self.print_local_decl(&loc)?; - self.end()?; - if let Some(ref init) = loc.init { - self.nbsp()?; - self.word_space("=")?; - self.print_expr(&init)?; - } - self.end()? + self.print_local(loc.init.deref(), |this| this.print_local_decl(&loc))?; } hir::StmtKind::Item(item) => { self.ann.nested(self, Nested::Item(item))? @@ -1379,6 +1388,24 @@ impl<'a> State<'a> { self.word_space(":")?; self.print_type(&ty)?; } + hir::ExprKind::Use(ref init) => { + // Print `{`: + self.cbox(indent_unit)?; + self.ibox(0)?; + self.bopen()?; + + // Print `let _t = $init;`: + let temp = ast::Ident::from_str("_t"); + self.print_local(Some(init), |this| this.print_ident(temp))?; + self.s.word(";")?; + + // Print `_t`: + self.space_if_not_bol()?; + self.print_ident(temp)?; + + // Print `}`: + self.bclose_maybe_open(expr.span, indent_unit, true)?; + } hir::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bd44b13b66..920f9780543 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -37,6 +37,7 @@ #![feature(box_syntax)] #![feature(core_intrinsics)] #![feature(drain_filter)] +#![feature(inner_deref)] #![cfg_attr(windows, feature(libc))] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 217af7eea96..52f105b8c40 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -521,6 +521,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } + hir::ExprKind::Use(ref expr) => { + self.consume_expr(&expr); + } + hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b8cde936bde..966bec8381a 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -521,6 +521,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Binary(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(_) | @@ -1221,6 +1222,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::AddrOf(_, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Use(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Yield(ref e) | hir::ExprKind::Repeat(ref e, _) => { @@ -1524,9 +1526,9 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Index(..) | hir::ExprKind::Field(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | - hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) | - hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) | - hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | + hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) | + hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | + hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a4a54ba1837..25fa19558de 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -678,7 +678,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) | - hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) | hir::ExprKind::Binary(..) | hir::ExprKind::While(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2b380238810..9a5af8a2537 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -909,6 +909,12 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: visitor.cx.var_parent = visitor.cx.parent; } + hir::ExprKind::Use(ref expr) => { + // `Use(expr)` does not denote a conditional scope. + // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. + terminating(expr.hir_id.local_id); + } + hir::ExprKind::AssignOp(..) | hir::ExprKind::Index(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => { // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 7ab33411275..e54a24f4df1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -759,6 +759,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } + hir::ExprKind::Use(ref source) => { + ExprKind::Use { source: source.to_ref() } + } hir::ExprKind::Box(ref value) => { ExprKind::Box { value: value.to_ref(), diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index e2c5c4ee374..2a423cc4166 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -436,7 +436,9 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Err => Promotable, hir::ExprKind::AddrOf(_, ref expr) | - hir::ExprKind::Repeat(ref expr, _) => { + hir::ExprKind::Repeat(ref expr, _) | + hir::ExprKind::Type(ref expr, _) | + hir::ExprKind::Use(ref expr) => { v.check_expr(&expr) } @@ -483,10 +485,6 @@ fn check_expr_kind<'a, 'tcx>( array_result } - hir::ExprKind::Type(ref expr, ref _ty) => { - v.check_expr(&expr) - } - hir::ExprKind::Tup(ref hirvec) => { let mut tup_result = Promotable; for index in hirvec.iter() { @@ -495,7 +493,6 @@ fn check_expr_kind<'a, 'tcx>( tup_result } - // Conditional control flow (possible to implement). hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => { // Compute the most demanding borrow from all the arms' diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bd715df6e9d..ff3245a467a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4533,6 +4533,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_eq_type(&e, ty); ty } + ExprKind::Use(ref e) => { + self.check_expr_with_expectation(e, expected) + } ExprKind::Array(ref args) => { let uty = expected.to_option(self).and_then(|uty| { match uty.sty {