diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1e86d159668ff..122967f916daa 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -161,6 +161,7 @@ E0309: include_str!("./error_codes/E0309.md"), E0310: include_str!("./error_codes/E0310.md"), E0311: include_str!("./error_codes/E0311.md"), E0312: include_str!("./error_codes/E0312.md"), +E0313: include_str!("./error_codes/E0313.md"), E0316: include_str!("./error_codes/E0316.md"), E0317: include_str!("./error_codes/E0317.md"), E0321: include_str!("./error_codes/E0321.md"), @@ -569,8 +570,6 @@ E0790: include_str!("./error_codes/E0790.md"), // E0300, // unexpanded macro // E0304, // expected signed integer constant // E0305, // expected constant - E0313, // lifetime of borrowed pointer outlives lifetime of captured - // variable // E0314, // closure outlives stack frame // E0315, // cannot invoke closure outside of its lifetime // E0319, // trait impls for defaulted traits allowed just for structs/enums diff --git a/compiler/rustc_error_codes/src/error_codes/E0313.md b/compiler/rustc_error_codes/src/error_codes/E0313.md new file mode 100644 index 0000000000000..a03db42d0bca8 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0313.md @@ -0,0 +1,43 @@ +Lifetime of borrowed pointer outlives lifetime of captured variable. + +Erroneous code example: + +```compile_fail,E0313 +fn foo(bar: &'static mut ()) { + || foo(bar); +} +``` + +This error is raised because the body of the closure, which implements `FnMut`, +has a lifetime shorter than `'static`. Let's name this lifetime `'fooc`. This is +problematic because `foo`'s argument requires that `'fooc` must outlive +`'static`, but references to captured variables in a `FnMut` closure can't +escape the closure. + +To fix this error, define a temporary variable inside the closure that takes +ownership of `foo`'s argument. Then, pass this into `foo`: + +``` +fn foo(bar: &'static mut ()) { + || { + let baz = bar; + foo(baz); + }; +} +``` + +This works because `bar` must be moved into the closure for the body to be +sensical. The closure now implements `FnOnce` because the value is moved in +then moved out in order to call the function, meaning it can only be called +once. + +Additionally, it seems like the following would also work: + +``` +fn foo(bar: &'static mut ()) { + move || foo(bar); +} +``` + +Although the closure is forced to capture its environment by value, which is +what `FnOnce` does, `move` closures can still implement `FnMut` (or `Fn`). diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 610e322e12963..938c151497f1a 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -11,8 +11,8 @@ use regex::Regex; // A few of those error codes can't be tested but all the others can and *should* be tested! const EXEMPTED_FROM_TEST: &[&str] = &[ - "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523", - "E0554", "E0640", "E0717", "E0729", "E0789", + "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523", "E0554", + "E0640", "E0717", "E0729", "E0789", ]; // Some error codes don't have any tests apparently...