Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access individual fields of tuples, closures and generators on drop. #49822

Merged
merged 1 commit into from
Apr 28, 2018

Conversation

matthewjasper
Copy link
Contributor

@matthewjasper matthewjasper commented Apr 9, 2018

Fixes #48623, by extending the change in #47917 to closures. Also does this for tuples and generators for consistency.

Enums are unchanged because there is no way to borrow *enum.field without borrowing enum.field at the moment, so any error would be reported when the enum goes out of scope. Unions aren't changed because unions they don't automatically drop their fields.

r? @nikomatsakis

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @nikomatsakis (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 9, 2018
// Closures and generators also have disjoint fields, but they are only
// directly accessed in the body of the closure/generator.
ty::TyClosure(def, substs)
| ty::TyGenerator(def, substs, ..)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generators are a bit funny -- I'm not sure if upvar_tys is correct for that case?

Maybe @Zoxc can comment how to get the list of fields for a generator type, else I'll dig in later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is correct here. upvar_tys gives you just the upvars for a generator. Pre-transform generators have an additional u32 state field, but it's only used when constructing a generator and it is never accessed.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good (modulo generators), though I keep having this nagging feeling we can refactor this another way. But this seems like it is extending the existing fix, which is fine.

@@ -740,6 +740,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
}
}
// Same as above, but for tuples.
ty::TyTuple(tys) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe we can extract a helper function here? If feels a bit silly to have basically the same code repeated so many times.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I preferred a closure to avoid having to pass all of the captured variables as arguments.

@nikomatsakis nikomatsakis added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 11, 2018
@matthewjasper matthewjasper force-pushed the dropck-closures branch 2 times, most recently from 6023d6c to dab4884 Compare April 14, 2018 19:25
@pietroalbini pietroalbini added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 23, 2018
@pietroalbini
Copy link
Member

Ping from triage! Could @nikomatsakis (or someone else from @rust-lang/compiler) review this?

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Apr 25, 2018

📌 Commit dab4884 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 25, 2018
@bors
Copy link
Contributor

bors commented Apr 27, 2018

⌛ Testing commit dab488406f5f948e6f61e793f0f498233a781cfc with merge 6e9d3f14539a96ebcfcb7ee4312592b490318750...

@bors
Copy link
Contributor

bors commented Apr 27, 2018

💔 Test failed - status-appveyor

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Apr 27, 2018
@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-3.9 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:44:39] 
[00:44:39] ---- [ui (nll)] ui/generator/yield-while-iterating.rs stdout ----
[00:44:39]  diff of stderr:
[00:44:39] 
[00:44:39] 6 LL |             yield();
[00:44:39] 7    |             ------- possible yield occurs here
[00:44:39] 8 
[00:44:39] - error[E0597]: borrowed value does not live long enough
[00:44:39] -   --> $DIR/yield-while-iterating.rs:50:17
[00:44:39] -    |
[00:44:39] - LL |       let mut b = || {
[00:44:39] -    |  _________________^
[00:44:39] - LL | |         for p in &mut x {
[00:44:39] - LL | |             yield p;
[00:44:39] - LL | |         }
[00:44:39] - LL | |     };
[00:44:39] -    | |     |
[00:44:39] -    | |     |
[00:44:39] -    | |_____temporary value only lives until here
[00:44:39] -    |       temporary value does not live long enough
[00:44:39] - 
[00:44:39] 23 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
[00:44:39] 24   --> $DIR/yield-while-iterating.rs:67:20
[00:44:39] 
[00:44:39] 
[00:44:39] 35 LL |       b.resume();
[00:44:39] 36    |       - borrow later used here
[00:44:39] 37 
[00:44:39] - error[E0597]: borrowed value does not live long enough
[00:44:39] -   --> $DIR/yield-while-iterating.rs:62:17
[00:44:39] -    |
[00:44:39] - LL |       let mut b = || {
[00:44:39] -    |  _________________^
[00:44:39] - LL | |         for p in &mut x {
[00:44:39] - LL | |             yield p;
[00:44:39] - LL | |         }
[00:44:39] - LL | |     };
[00:44:39] -    | |     |
[00:44:39] -    | |     |
[00:44:39] -    | |_____temporary value only lives until here
[00:44:39] -    |       temporary value does not live long enough
[00:44:39] + error: aborting due to 2 previous errors
[00:44:39] - error: aborting due to 4 previous errors
[00:44:39] - 
[00:44:39] - Some errors occurred: E0502, E0597, E0626.
[00:44:39] + Some errors occurred: E0502, E0626.
[00:44:39] + Some errors occurred: E0502, E0626.
[00:44:39] 55 For more information about an error, try `rustc --explain E0502`.
[00:44:39] 56 
[00:44:39] 
[00:44:39] 
[00:44:39] The actual stderr differed from the expected stderr.
[00:44:39] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/generator/yield-while-iterating.nll.stderr
[00:44:39] /checkout/src/test/ui/update-references.sh '/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui' 'generator/yield-while-iterating.rs'
[00:44:39] 
[00:44:39] error: 1 errors occurred comparing output.
[00:44:39] status: exit code: 101
[00:44:39] status: exit code: 101
[00:44:39] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/generator/yield-while-iterating.rs" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/generator/yield-while-iterating.stage2-x86_64-unknown-linux-gnu" "-Zborrowck=mir" "-Ztwo-phase-borrows" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/generator/yield-while-iterating.stage2-x86_64-unknown-linux-gnu.aux" "-A" "unused"
[00:44:39] ------------------------------------------
[00:44:39] 
[00:44:39] ------------------------------------------
[00:44:39] stderr:
[00:44:39] stderr:
[00:44:39] ------------------------------------------
[00:44:39] {"message":"borrow may still be in use when generator yields","code":{"code":"E0626","explanation":"\nThis error occurs because a borrow in a generator persists across a\nyield point.\n\n```compile_fail,E0626\n# #![feature(generators, generator_trait)]\n# use std::ops::Generator;\nlet mut b = || {\n    let a = &String::new(); // <-- This borrow...\n    yield (); // ...is still in scope here, when the yield occurs.\n    println!(\"{}\", a);\n};\nunsafe { b.resume() };\n```\n\nAt present, it is not permitted to have a yield that occurs while a\nborrow is still in scope. To resolve this error, the borrow must\neither be \"contained\" to a smaller scope that does not overlap the\nyield or else eliminated in another way. So, for example, we might\nresolve the previous example by removing the borrow and just storing\nthe integer by value:\n\n```\n# #![feature(generators, generator_trait)]\n# use std::ops::Generator;\nlet mut b = || {\n    let a = 3;\n    yield ();\n    println!(\"{}\", a);\n};\nunsafe { b.resume() };\n```\n\nThis is a very simple case, of course. In more complex cases, we may\nwish to have more than one reference to the value that was borrowed --\nin those cases, something like the `Rc` or `Arc` types may be useful.\n\nThis error also frequently arises with iteration:\n\n```compile_fail,E0626\n# #![feature(generators, generator_trait)]\n# use std::ops::Generator;\nlet mut b = || {\n  let v = vec![1,2,3];\n  for &x in &v { // <-- borrow of `v` is still in scope...\n    yield x; // ...when this yield occurs.\n  }\n};\nunsafe { b.resume() };\n```\n\nSuch cases can sometimes be resolved by iterating \"by value\" (or using\n`into_iter()`) to avoid borrowing:\n\n```\n# #![feature(generators, generator_trait)]\n# use std::ops::Generator;\nlet mut b = || {\n  let v = vec![1,2,3];\n  for x in v { // <-- Take ownership of the values instead!\n    yield x; // <-- Now yield is OK.\n  }\n};\nunsafe { b.resume() };\n```\n\nIf taking ownership is not an option, using indices can work too:\n\n```\n# #![feature(generators, generator_trait)]\n# use std::ops::Generator;\nlet mut b = || {\n  let v = vec![1,2,3];\n  let len = v.len(); // (*)\n  for i in 0..len {\n    let x = v[i]; // (*)\n    yield x; // <-- Now yield is OK.\n  }\n};\nunsafe { b.resume() };\n\n// (*) -- Unfortunately, these temporaries are currently required.\n// See <https://github.com/rust-lang/rust/issues/43122>.\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/generator/yield-while-iterating.rs","byte_start":948,"byte_end":955,"line_start":23,"line_end":23,"column_start":13,"column_end":20,"is_primary":false,"text":[{"text":"            yield();","highlight_start":13,"highlight_end":20}],"label":"possible yield occurs here","suggested_replacement":null,"expansion":null},{"file_name":"/checkout/src/test/ui/generator/yield-while-iterating.rs","byte_start":921,"byte_end":923,"line_start":22,"line_end":22,"column_start":18,"column_end":20,"is_primary":true,"text":[{"text":"        for p in &x { //~ ERROR","highlight_start":18,"highlight_end":20}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[],"rendered":"error[E0626]: borrow may still be in use when generator yields\n  --> /checkout/src/test/ui/generator/yield-while-iterating.rs:22:18\n   |\nLL |         for p in &x { //~ ERROR\n   |                  ^^\nLL |             yield();\n   |             ------- possible yield occurs here\n\n"}
[00:44:39] {"message":"cannot borrow `x` as immutable because it is also borrowed as mutable","code":{"code":"E0502","explanation":"\nThis error indicates that you are trying to borrow a variable as mutable when it\nhas already been borrowed as immutable.\n\nExample of erroneous code:\n\n```compile_fail,E0502\nfn bar(x: &mut i32) {}\nfn foo(a: &mut i32) {\n    let ref y = a; // a is borrowed as immutable.\n    bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed\n            //        as immutable\n}\n```\n\nTo fix this error, ensure that you don't have any other references to the\nvariable before trying to access it mutably:\n\n```\nfn bar(x: &mut i32) {}\nfn foo(a: &mut i32) {\n    bar(a);\n    let ref y = a; // ok!\n}\n```\n\nFor more information on the rust ownership system, take a look at\nhttps://doc.rust-lang.org/stable/book/references-and-borrowing.html.\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/generator/yield-while-iterating.rs","byte_start":1798,"byte_end":1799,"line_start":67,"line_end":67,"column_start":20,"column_end":21,"is_primary":true,"text":[{"text":"    println!(\"{}\", x[0]); //~ ERROR","highlight_start":20,"highlight_end":21}],"label":"immutable borrow occurs here","suggested_replacement":null,"expansion":null},{"file_name":"/checkout/src/test/ui/generator/yield-while-iterating.rs","byte_start":1710,"byte_end":1777,"line_start":62,"line_end":66,"column_start":17,"column_end":6,"is_primary":false,"text":[{"text":"    let mut b = || {","highlight_start":17,"highlight_end":21},{"text":"        for p in &mut x {","highlight_start":1,"highlight_end":26},{"text":"            yield p;","highlight_start":1,"highlight_end":21},{"text":"        }","highlight_start":1,"highlight_end":10},{"text":"    };","highlight_start":1,"highlight_end":6}],"label":"mutable borrow occurs here","suggested_replacement":null,"expansion":null},{"file_name":"/checkout/src/test/ui/generator/yield-while-iterating.rs","byte_start":1819,"byte_end":1820,"line_start":68,"line_end":68,"column_start":5,"column_end":6,"is_primary":false,"text":[{"text":"    b.resume();","highlight_start":5,"highlight_end":6}],"label":"borrow later used here","suggested_replacement":null,"expansion":null}],"children":[],"rendered":"error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable\n  --> /checkout/src/test/ui/generator/yield-while-iterating.rs:67:20\n   |\nLL |       let mut b = || {\n   |  _________________-\nLL | |         for p in &mut x {\nLL | |             yield p;\nLL | |         }\nLL | |     };\n   | |_____- mutable borrow occurs here\nLL |       println!(\"{}\", x[0]); //~ ERROR\n   |                      ^ immutable borrow occurs here\nLL |       b.resume();\n   |       - borrow later used here\n\n"}
[00:44:39] {"message":"aborting due to 2 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 2 previous errors\n\n"}
[00:44:39] {"message":"Some errors occurred: E0502, E0626.","code":null,"level":"","spans":[],"children":[],"rendered":"Some errors occurred: E0502, E0626.\n"}
[00:44:39] {"message":"For more information about an error, try `rustc --explain E0502`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about an error, try `rustc --explain E0502`.\n"}
[00:44:39] ------------------------------------------
[00:44:39] 
[00:44:39] thread '[ui (nll)] ui/generator/yield-while-iterating.rs' panicked at 'explicit panic', tools/compiletest/src/runtest.rs:2963:9
[00:44:39] note: Run with `RUST_BACKTRACE=1` for a backtrace.
---
[00:44:39] 
[00:44:39] thread 'main' panicked at 'Some tests failed', tools/compiletest/src/main.rs:488:22
[00:44:39] 
[00:44:39] 
[00:44:39] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-3.9/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Zunstable-options " "--target-rustcflags" "-Crpath -O -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--llvm-version" "3.9.1\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always" "--compare-mode" "nll"
[00:44:39] 
[00:44:39] 
[00:44:39] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[00:44:39] Build completed unsuccessfully in 0:03:42
[00:44:39] Build completed unsuccessfully in 0:03:42
[00:44:39] Makefile:58: recipe for target 'check' failed
[00:44:39] make: *** [check] Error 1

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:0bb5397b
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@kennytm kennytm added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 27, 2018
@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Apr 27, 2018

📌 Commit 902bc0f has been approved by nikomatsakis

@bors bors removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Apr 27, 2018
@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Apr 27, 2018
@kennytm
Copy link
Member

kennytm commented Apr 27, 2018

@bors p=6

@bors
Copy link
Contributor

bors commented Apr 27, 2018

⌛ Testing commit 902bc0f with merge ede7f94...

bors added a commit that referenced this pull request Apr 27, 2018
Access individual fields of tuples, closures and generators on drop.

Fixes #48623, by extending the change in #47917 to closures. Also does this for tuples and generators for consistency.

Enums are unchanged because there is now way to borrow `*enum.field` without borrowing `enum.field` at the moment, so any error would be reported when the enum goes out of scope. Unions aren't changed because unions they don't automatically drop their fields.

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented Apr 28, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing ede7f94 to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants