Skip to content

"a temporary value which is freed while still in use" in nightly but not on stable #105891

Closed

Description

@poliorcetics

Code

I tried this code:

// Do: cargo add obfstr

fn main() {
    let product = "macos";
    let is_not = |s| !product.eq_ignore_ascii_case(s);

    let _res = is_not(obfstr::obfstr!("windows")) && is_not(obfstr::obfstr!("macos"));
}

I expected to see this happen: the code compiles without problems on stable and nightly

Instead, this happened: compilation failed but only on nightly

RUSTFLAGS="-Z macro-backtrace" cg +nightly build -q

error[E0716]: temporary value dropped while borrowed
   --> /Users/alexis/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/obfstr-0.4.1/src/bytes.rs:93:16
    |
54  |   macro_rules! obfstr {
    |   ------------------- in this expansion of `obfstr::obfstr!` (#1)
...
66  |           $crate::unsafe_as_str($crate::obfbytes!($s.as_bytes()))
    |                                 -------------------------------- in this macro invocation (#2)
...
72  |   macro_rules! obfbytes {
    |   --------------------- in this expansion of `$crate::obfbytes!` (#2)
...
86  |           &$crate::__obfbytes!($s)
    |            ----------------------- in this macro invocation (#3)
...
92  |   macro_rules! __obfbytes {
    |   ----------------------- in this expansion of `$crate::__obfbytes!` (#3)
93  |       ($s:expr) => {{
    |  ___________________^
94  | |         const _OBFBYTES_STRING: &[u8] = $s;
95  | |         const _OBFBYTES_LEN: usize = _OBFBYTES_STRING.len();
96  | |         const _OBFBYTES_KEYSTREAM: [u8; _OBFBYTES_LEN] = $crate::bytes::keystream::<_OBFBYTES_LEN>($crate::__entropy!("key", stringify!($...
...   |
103 | |             &_OBFBYTES_KEYSTREAM)
104 | |     }};
    | |_____^ creates a temporary value which is freed while still in use
    |
   ::: src/main.rs:5:49
    |
5   |       let _res = is_not(obfstr::obfstr!("windows")) && is_not(obfstr::obfstr!("macos"));
    |                         ---------------------------    ------ borrow later used here
    |                         |                         |
    |                         |                         temporary value is freed at the end of this statement
    |                         in this macro invocation (#1)
    |
    = note: consider using a `let` binding to create a longer lived value

For more information about this error, try `rustc --explain E0716`.
error: could not compile `pg2` due to previous error

Version it worked on

It most recently worked on: Rust 1.66

Version with regression

rustc --version --verbose:

rustc 1.68.0-nightly (d0dc9efff 2022-12-18)
binary: rustc
commit-hash: d0dc9efff14ac0a1eeceffd1e605e37eeb8362a0
commit-date: 2022-12-18
host: aarch64-apple-darwin
release: 1.68.0-nightly
LLVM version: 15.0.6

Backtrace

Backtrace

<backtrace>

Activity

  1. added
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    and removed
    regression-untriagedUntriaged performance or correctness regression.
    on Dec 19, 2022
  2. poliorcetics commented on Dec 19, 2022

    @poliorcetics
    ContributorAuthor

    This also fails in beta, (Rust 1.67 beta)

    @rustbot label +regression-from-stable-to-beta

  3. zachs18 commented on Dec 19, 2022

    @zachs18
  4. albertlarsan68 commented on Dec 19, 2022

    @albertlarsan68
    Member

    searched nightlies: from nightly-2022-10-29 to nightly-2022-12-08 (around where beta branched)
    regressed nightly: nightly-2022-12-05
    searched commit range: 2341517...53e4b9d
    regressed commit: 19c250a (#103293, cc @est31 and @nagisa)

    bisected with cargo-bisect-rustc v0.6.5

    Host triple: x86_64-pc-windows-msvc
    Reproduce with:

    cargo bisect-rustc --preserve --access github --start 1.66.0 --regress=error --end 2022-12-08 -- check

    @rustbot label -regression-from-stable-to-nightly

  5. est31 commented on Dec 19, 2022

    @est31
    Member

    This also fails on stable if you have a three-chain. E.g.:

    let _res = is_not(obfstr::obfstr!("linux")) && is_not(obfstr::obfstr!("windows")) && is_not(obfstr::obfstr!("macos"));

    gives:

    error[E0716]: temporary value dropped while borrowed
     --> src/main.rs:5:59
      |
    5 |     let _res = is_not(obfstr::obfstr!("linux")) && is_not(obfstr::obfstr!("windows")) && is_not(obfstr::obfstr!("macos"));
      |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^-    ------ borrow later used here
      |                                                           |                         |
      |                                                           |                         temporary value is freed at the end of this statement
      |                                                           creates a temporary which is freed while still in use
      |
      = note: consider using a `let` binding to create a longer lived value
      = note: this error originates in the macro `$crate::__obfbytes` which comes from the expansion of the macro `obfstr::obfstr` (in Nightly builds, run with -Z macro-backtrace for more info)
    

    I need to investigate more on what obfstr is doing, but it's likely that this is an expected breakage. With #103293, it was known that it is going to cause some breakage. crater runs showed only one regression at build time.

    A workaround is easy, you can add &str:

    fn main() {
        let product = "macos";
        let is_not = |s: &str| !product.eq_ignore_ascii_case(s);
    
        let _res = is_not(obfstr::obfstr!("windows")) && is_not(obfstr::obfstr!("macos"));
    }

    That way, your code will also work with three-chains.

  6. jruderman commented on Dec 19, 2022

    @jruderman
    Contributor

    I guess adding &str changes the closure to borrow instead of move? Should the compiler suggest adding &str?

  7. est31 commented on Dec 19, 2022

    @est31
    Member

    Hmm this is basically the same regression as the one that broke spaad_internal.

    Reducing the example from above to not need obfstr:

    fn main() {
        let product = "macos";
        let is_not = |s| !product.eq_ignore_ascii_case(s);
    
        let _res = is_not(&"windows".to_string()) && is_not(&"macos".to_string());
    }

    Should the compiler suggest adding &str?

    The best would be to fix the underlying closure lifetime (or type?) inference issue that got surfaced (not caused) by my PR in these instances. If that doesn't work, a suggestion would definitely improve things I think. I don't really know how those parts of the compiler work tho.

  8. apiraino commented on Dec 21, 2022

    @apiraino
    Contributor

    WG-prioritization assigning priority (Zulip discussion).

    @rustbot label -I-prioritize +P-medium

  9. added and removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Dec 21, 2022
  10. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Dec 21, 2022
  11. added
    regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
    and removed on Mar 3, 2023
  12. added this to the 1.67.0 milestone on Mar 3, 2023
  13. poliorcetics commented on Aug 7, 2026

    @poliorcetics
    ContributorAuthor

    Lint is now (using est31's reduced example above)

     --> src/main.rs:5:24
      |
    5 |     let _res = is_not(&"windows".to_string()) && is_not(&"macos".to_string());
      |                        ^^^^^^^^^^^^^^^^^^^^^-    ------ borrow later used here
      |                        |                    |
      |                        |                    temporary value is freed at the end of this statement
      |                        creates a temporary value which is freed while still in use
      |
    help: consider using a `let` binding to create a longer lived value
      |
    5 ~     let binding = "windows".to_string();
    6 ~     let _res = is_not(&binding) && is_not(&"macos".to_string());
      |

    which I feel is a lot clearer and fixes the issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions