Inspired by a tangent in another thread, I think we should add an attribute to indicate that a function purely edits values in-place without other side-effects.
But foo1 raises a lint for the foo += 1 assignment being unused, whereas foo2 does the same thing but raises no such lint, since rustc can't see across both functions to conclude that there's an issue.
I think it'd be useful to add an attribute #[pure_inplace_edit] (feel free to bikeshed the name) to functions to indicate that the function should be treated as an inplace edit of any &mut _ arguments for the purposes of the lint. This attribute doesn't change the behavior of the code, only whether rustc raises this lint. You could think of this attribute as the equivalent to #[must_use], but for &mut arguments instead of the return value.
maybe a better name would be #[must_use(<the-arg-name>)], which allows you to indicate that whatever argument was passed in as <the-arg-name> should be treated as a #[must_use] output, since that describes what you want to happen, rather than the imo more confusing approach of labeling whatever purity property the function might or might not have.
that way it's also useful for things like the following, where you only want one arg to be must_use, and the function call itself isn't pure (it runs an external program):
#[must_use(stderr, "you shouldn't ignore the error output")]
/// it's ok to ignore `stdout` because ...todo...
///
/// `stdout` and `stderr` are passed as `&mut Vec<u8>` so
/// you can reuse buffers instead of allocating a new buffer each time.
pub fn run_program(args: &[impl AsRef<OsStr>], stdout: &mut Vec<u8>, stderr: &mut Vec<u8>) -> io::Result<()> {
todo!("run the program, collecting stdout into stdout and stderr into stderr")
}