about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSimonas Kazlauskas <github@kazlauskas.me>2015-12-31 17:28:57 +0200
committerSimonas Kazlauskas <git@kazlauskas.me>2015-12-31 18:52:20 +0200
commit7448f4861a8ee41b0a6d62b6bdaf623b3eeba453 (patch)
treee897e9492882c3f2633b0bfd30a4c7433707b684
parent1aa4abdb3bef48e706605650a60a43146bb3998f (diff)
parentf8b61340e33bbb24709a862fd834ec10c871413c (diff)
downloadrust-7448f4861a8ee41b0a6d62b6bdaf623b3eeba453.tar.gz
rust-7448f4861a8ee41b0a6d62b6bdaf623b3eeba453.zip
Rollup merge of #30630 - tsion:mir-closure-args, r=nagisa
Previously, all references to closure arguments went to the argument before the one they should (e.g. to `arg1` when it was supposed to go to `arg2`). This was because the MIR builder did not account for the implicit arguments that come before the explicit arguments, and closures have one implicit argument - the struct containing the captures.

This is my test code and a diff of the MIR generated for the closure:

```rust
let a = 2i32;
let _f = |b: i32| -> i32 { a + b }:
```

```diff
--- old	2015-12-29 23:16:32.027926372 -0600
+++ new	2015-12-29 23:16:42.975400757 -0600
@@ -1,22 +1,22 @@
 fn(arg0: &[closure@closure-args.rs:8:14: 8:39 a:&i32], arg1: i32) -> i32 {
     let var0: i32; // b
     let tmp0: ();
     let tmp1: i32;
     let tmp2: i32;

     bb0: {
-        var0 = arg0;
+        var0 = arg1;
         tmp1 = (*(*arg0).0);
         tmp2 = var0;
         ReturnPointer = Add(tmp1, tmp2);
         goto -> bb1;
     }

     bb1: {
         return;
     }

     bb2: {
         diverge;
     }
 }
```

(If you're wondering where this text MIR output comes from, it's from another branch of mine waiting on https://github.com/rust-lang/rust/pull/30602 to get merged.)
-rw-r--r--src/librustc_mir/build/mod.rs29
1 files changed, 13 insertions, 16 deletions
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index bd94f4e5bf2..8347a03cda6 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -138,28 +138,25 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                      -> BlockAnd<Vec<ArgDecl<'tcx>>>
     {
         self.in_scope(argument_extent, block, |this| {
-            let arg_decls = {
-                let implicit_arg_decls = implicit_arguments.into_iter()
-                                                           .map(|ty| ArgDecl { ty: ty });
-
-                // to start, translate the argument patterns and collect the
-                // argument types.
-                let explicit_arg_decls =
-                    explicit_arguments
-                    .into_iter()
-                    .enumerate()
-                    .map(|(index, (ty, pattern))| {
+            // to start, translate the argument patterns and collect the argument types.
+            let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
+            let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
+            let arg_decls =
+                implicits
+                .chain(explicits)
+                .enumerate()
+                .map(|(index, (ty, pattern))| {
+                    if let Some(pattern) = pattern {
                         let lvalue = Lvalue::Arg(index as u32);
                         let pattern = this.hir.irrefutable_pat(pattern);
                         unpack!(block = this.lvalue_into_pattern(block,
                                                                  argument_extent,
                                                                  pattern,
                                                                  &lvalue));
-                        ArgDecl { ty: ty }
-                    });
-
-                implicit_arg_decls.chain(explicit_arg_decls).collect()
-            };
+                    }
+                    ArgDecl { ty: ty }
+                })
+                .collect();
 
             // start the first basic block and translate the body
             unpack!(block = this.ast_block(&Lvalue::ReturnPointer, block, ast_block));