-
Notifications
You must be signed in to change notification settings - Fork 13.3k
E0716: confusing reference to borrow of Stdin
value when there's no obvious reference within StdinLock
#85383
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
Comments
@rustbot label +A-borrow-checker +A-lifetimes +D-confusing +D-incorrect +D-newcomer-roadblock |
IMO the intent is clear here. Without changing the API, why exactly is Rust unable to lift 'a &'static X to 'static & 'static X, if X also contains only 'static lifetimes? I don't think raw references have a meaningful dropper; borrowck is able to freely resolve any derived lifetimes on impls that don't depend on anything else to 'static; I'm pretty sure under current rules we should be able to substitute latter for earlier and get exactly the same behaviour. |
This is due to lifetime elision. pub fn lock(&self) -> StdinLock<'_> { ... } Because there is only one input lifetime (the elided lifetime of |
Thanks. I think this might be a bug in libstd (using What I think is a diagnostic inaccuracy is that the error message refers to a borrow, when, by inspection of the library source code, no borrow is taking place in |
As a simplified example: (playground) static NUM: i32 = 1;
struct A;
struct B<'a>(&'a i32);
impl A {
fn get(&self) -> B<'_> {
// Contains NO ref to self whatsoever!
B(&NUM)
}
}
fn a() -> A { A }
fn main() {
let b = a().get();
println!("{}", b.0.to_string());
}
The error message refers to a borrow even when the output type of |
@tlyu that's because of the elision rules: on the |
@estebank Thanks. I think the error messages could use a little more detail about how something that the borrow checker sees as a borrow may be an artifact of lifetime constraints in a function signature rather than an actual borrow in the function body. It certainly surprised me the first time I ran into it. (Maybe only in the explanatory text in the compiler error index. It looks like E0597 could also benefit from that detail, because it's a similar case, and an example in E0716 produces E0597.) |
Shorter example, probably better suited for an example in the compiler error index: (playground) fn main() {
static NUM: i32 = 17;
fn foo() -> i32 { 42 }
// output ref is totally unrelated to input
fn bar(_: &i32) -> &i32 { &NUM }
let x = bar(&foo());
println!("{}", x);
}
|
Given the following code: (playground)
The current output is:
I think it's typical for a newcomer to want to get a
Lines
iterator by chaining method calls likeio::stdin().lock().lines()
. There's no obvious reason why that shouldn't work. The examples in thestd::io
documentation do typically showio::stdin()
being assigned to a variable prior to calling its.lock()
method, but don't explain why that's necessary.I think the "borrow" terminology is misleading, but there might not be a concise way to describe what's actually going on to the user. The "temporary value is freed at the end of this statement" is probably correct. The "creates a temporary which is freed while still in use" is probably more correctly "creates a temporary that is required to outlive (or live exactly as long as) the result of...", followed by a pointer to the
.lock()
method invocation, with text of "...this method call". Maybe it should also point out the'_
lifetime argument in theStdinLock<'_>
return type.I tried and failed to find a satisfactory explanation of what exactly
StdinLock
was borrowing from the temporaryStdin
value produced byio::stdin()
. When I looked through the library source code, the only references inStdinLock
were those created by locking aMutex
, and theMutex
in question is static. I'm guessing the existence of a borrow is assumed rather than inferred from analyzing the function body ofio::Stdin::lock()
. The assumption might be the result of the anonymous lifetime argument on the output typeStdinLock<'_>
fromio::Stdin::lock()
, which imposes a requirement that theStdinLock
doesn't outlive (or has the same lifetime as?) theStdin
value that is the receiver oflock()
.The correct fix might be to change the locked stdin handles to all use
'static
lifetimes, but I will probably file that as a separate issue.The text was updated successfully, but these errors were encountered: