#[must_use], but requiring giving values a non-tempoary scope?


#1

I just wrote buggy code like this:

let path = TempDir::new("dir").path().join("file");

The problem is that Drop for TempDir runs on this line and deletes it immediately. This is obviously not the intended usage of TempDir. Could Rust warn against it?

There’s a similar bug with:

let _ = lock.lock();

if the programmer isn’t aware that _ is not just a wildcard variable name, but an immediate drop that makes the lock ineffective.

I suspect both of these cases could be improved by adding an annotation similar to #[must_use], but where “use” requires giving the value a non-temporary scope.


#2

This may be (very) far out, but I just wanted to mention that it looks to me as if linear types would also provide a solution to this API problem.

I do agree though, a way to give feedback in these cases seems valuable.

Edit: A fitting name might be #[must_keep].


#3

(Warning, this is just a pet peeve thing).

let _ is a no-op and not always an immediate drop. The difference is if something else is holding the variable already. let _ = s; does not drop s, because the variable s is holding it and continues to do so.


#4

At least for locking, this is usually fixed by have the protected content live inside the lock, so it always counts as borrowed data. It’s impossible to access the data without properly holding the lock alive.

I don’t know how you’d do the same for TempDir. You do get a borrow from fn path(&self) -> &Path, but the lifetime is disconnected as soon as you call join into a PathBuf. I think to really handle this properly, you’d need wrappers to carry a lifetime for all the things that could be created from the TempDirTempPath, TempFile, …