about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/cfg/construct.rs1
-rw-r--r--src/librustc/hir/intravisit.rs3
-rw-r--r--src/librustc/hir/lowering.rs45
-rw-r--r--src/librustc/hir/mod.rs6
-rw-r--r--src/librustc/hir/print.rs53
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/librustc/middle/liveness.rs8
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/region.rs6
-rw-r--r--src/librustc_mir/hair/cx/expr.rs3
-rw-r--r--src/librustc_passes/rvalue_promotion.rs9
-rw-r--r--src/librustc_typeck/check/mod.rs3
13 files changed, 92 insertions, 52 deletions
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<hir::Expr>, attrs: ThinVec<Attribute>) -> 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::Expr>,
-    ) -> (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::Expr>) -> 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<Expr>, P<Ty>),
     /// A type reference (e.g., `Foo`).
     Type(P<Expr>, P<Ty>),
+    /// Semantically equivalent to `{ let _t = expr; _t }`.
+    /// Maps directly to `hair::ExprKind::Use`.
+    /// Only exists to tweak the drop order in HIR.
+    Use(P<Expr>),
     /// An `if` block, with an optional else block.
     ///
     /// I.e., `if <expr> { <expr> } else { <expr> }`.
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 {