Skip to content

create a specific error for temporary values that are borrowed too long #54131

Closed

Description

@nikomatsakis

Carrying over a comment from #54088:

I feel like the temporary rules are a common source of confusion. I think we should consider using a distinct error code for them, so that --explain can have some extra text to introduce the rules. Maybe good for a follow-up to this PR though.

As a specific example, consider this test:

let x = gimme({
let v = 22;
&(v,)
//~^ ERROR borrowed value does not live long enough [E0597]
});

we give this error:

error[E0597]: borrowed value does not live long enough
--> $DIR/borrowed-temporary-error.rs:20:10
|
LL | &(v,)
| ^^^^ temporary value does not live long enough
LL | //~^ ERROR borrowed value does not live long enough [E0597]
LL | });
| - temporary value only lives until here
LL | println!("{:?}", x);
| - borrow later used here

but I think we should say something more like this:

error[E9999]: temporary value borrowed for too long
  --> $DIR/borrowed-temporary-error.rs:20:10
   |
LL |         &(v,)
   |          ^^^^ creates a temporary which is freed while still in use
LL |         //~^ ERROR borrowed value does not live long enough [E0597]
LL |     });
   |       - temporary value is freed at the end of this statement
LL |     println!("{:?}", x);
   |                      - but the borrow is later used here

Moreover, the extended error for E9999 ought to explain the temporary rules.

Activity

  1. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    A-NLLArea: Non-lexical lifetimes (NLL)
    NLL-diagnosticsWorking towards the "diagnostic parity" goal
    on Sep 11, 2018
  2. nikomatsakis commented on Sep 11, 2018

    @nikomatsakis
    ContributorAuthor

    Here are some notes on what we might say in the extended error:

    When you write &expr and expr is not a "path" rooted in some variable (e.g., &foo.bar) but rather something that creates a new value (e.g., &foo()), a temporary will be created:

    let x = foo();
    let y = &x;
    

    If this temporary expression is assigned directly into a let, or into a tuple or struct that is assigned into a let, it lives until the end of the block:

    Example:

    { 
        let x = &foo(); // <-- temporary is created here
        ...
    } // <-- and then freed here

    Otherwise, the temporary is freed at the end of the statement. This most commonly occurs with function call arguments:

    let p = bar(&foo()); // <-- temporary is freed after this statement
    

    If p here borrows from the temporary, then you are going to get an error, because the temporary gets freed while still in use. You can add a temporary to extend the lifetime:

    let tmp_ref = &foo(); // freed at end of block
    let p = bar(tmp_ref); 
    ...
    
  3. mikhail-m1 commented on Sep 11, 2018

    @mikhail-m1
    Contributor

    I can take it if no one already started

  4. added a commit that references this issue on Sep 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-NLLArea: Non-lexical lifetimes (NLL)NLL-diagnosticsWorking towards the "diagnostic parity" goalT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions