Skip to content

Impossible to remove #![must_use] from a value #36675

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

Closed
alexchandel opened this issue Sep 23, 2016 · 13 comments
Closed

Impossible to remove #![must_use] from a value #36675

alexchandel opened this issue Sep 23, 2016 · 13 comments
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@alexchandel
Copy link

I want to write a macro wrapping something marked #![must_use] which doesn't spam the build output with "unused_must_use", but also doesn't destroy the result. I don't want to unwrap these values either, nor mark every single invocation with #![allow(unused_must_use)], nor allow unused_must_see for the entire program (because with this macro's one exception, it is useful): I simply want to strip this return value's compiler-spamming must_use.

This:

macro_rules! println_out(
    ($($arg:tt)*) => ( {let _ = writeln!(&mut ::std::io::stdout(), $($arg)* )} )
);

doesn't work because the result is unavailable if I need to check it, which I do on occasion.

Even this: fails to work:

macro_rules! println_err(
    ($($arg:tt)*) => ( {
        let _x = writeln!(&mut ::std::io::stderr(), $($arg)* );
        _x.is_ok();
        _x
    } )
);

because the final line can be unused in the calling context

stdout/stderr/write_ln! are used as examples here, but I need to do this generically with certain things that spam must_use.

This isn't an unsafety issue. I simply shouldn't have to be bound ubiquitously by the particular compiler-warning policy preached by a module's author. I may (and do) have valid cases where must_use is semantically wrong.

It should not be impossible to do this.

@durka
Copy link
Contributor

durka commented Sep 23, 2016

Statement attributes will hopefully be stabilized soon, which should offer a nice way to do this (I say "should" because the current implementation doesn't work with lints).

Anyway, how about a simple wrapper type?

struct Unused<T>(T);

fn return_ok() -> Result<(), ()> {
    Ok(())
}

fn main() {
    Unused(return_ok()); // no warning
}

@Thiez
Copy link
Contributor

Thiez commented Sep 23, 2016

Wrapping in a tuple works too: (return_ok(),)

@durka
Copy link
Contributor

durka commented Sep 23, 2016

@Thiez though of course neither suggestion works if we ever make the lint smart enough to see through such things :)

@alexchandel
Copy link
Author

I suppose using a wrapper or tuple at the invocation would be equivalent to calling is_ok(); or something every time, and the goal is to avoid putting dressings around the macro every invocation where I don't want compiler spam.

@alexchandel
Copy link
Author

I don't think statement attributes work either, since even if they're on the macro, the problem is the invocation's warning happens outside the macro

@durka
Copy link
Contributor

durka commented Sep 23, 2016

In my ideal world you would write

#[allow(unused_must_use)] println_err!("whatever");

or

#[allow(unused_must_use)] {
    println_err!("one");
    println_err!("two");
}

or have a macro generate such code. Outside of that, or the wrapper struct/tuple trick, I chalk this up to working as designed -- the whole point of #[must_use] is to remind you in case you forget to handle something. False positives are why it's a warning and not an error.

@alexchandel
Copy link
Author

@durka

That's precisely what I don't want. And no macro can generate such code that also returns the value, because the value eventually escapes the attributed statement.

It's not "working as designed". This isn't an unsafety issue, or a lifetime issue, even syntactic. The Type's author may want to remind the user with compiler warnings, but if the user knows these warnings are incorrect (like for a particular semantic case of Result), they become spam. The fact that statement-based #[allow(unused_must_use)] is being added supports that it's a valid desire to selectively silence warnings.

I don't want to and shouldn't have to disable all must_use warnings, because that would defeat the purpose of it. I simply want to do it for invocations of this function. It's roughly analogous to this:

extern crate bob;

unsafe fn not_safe() -> u8 { bob::s::unsafe_function(0, "foo") }

fn guaranteed_to_always_be_safe() -> u8 { unsafe { bob::s::unsafe_function(1, "foo") } }

which is entirely permissible.

@Thiez
Copy link
Contributor

Thiez commented Sep 23, 2016

@Thiez though of course neither suggestion works if we ever make the lint smart enough to see through such things :)

Why would we want that, though? I thought the lint was there to prevent accidents, not to enforce some strange variation on checked exceptions.

@bluss
Copy link
Member

bluss commented Sep 24, 2016

You'd can use the wrapper type in the macro, to keep the Result value silent but reachable on demand. (If you'd just want to silence each macro invocation manually, then the more popular let _ = .. and drop(..) solutions would be enough.)

@alexchandel
Copy link
Author

@Thiez For the exact same reason unsafe { } blocks exist. Being there to prevent accidents doesn't mean you should tell users you know better than them in all cases. Type and memory safety is "there to prevent accidents" too, yet I can put an unsafe block inside a safe function if I, the user of another unsafe function, know that my usage is guaranteed to be safe. That's how the entire standard library and every single system binding works.

@bluss I considered a wrapper type, but accessing it with a .0 every time became silly. I ended up just calling .err() in the macro, which returns an Option that thankfully isn't tagged with the #![must_use]. This worked for most cases where I didn't care about the Ok variant.

@durka
Copy link
Contributor

durka commented Sep 26, 2016

The point of #[must_use] is to introduce friction encouraging you to
use the value or explicitly decline to do so (like with the wrapper type).
I realize in this specific case that was annoying, though.

On Mon, Sep 26, 2016 at 6:24 PM, Alex [email protected] wrote:

@Thiez https://github.com/Thiez For the exact same reason unsafe { }
blocks exist. Being there to prevent accidents doesn't mean you should tell
users you know better than them in all cases. Type and memory safety is
"there to prevent accidents" too, yet I can put an unsafe block inside a
safe function if I, the user of another unsafe function, know that my usage
is guaranteed to be safe. That's how the entire standard library and every
single system binding works.

@bluss https://github.com/bluss I considered a wrapper type, but
accessing it with a .0 every time became silly. I ended up just calling
.err() in the macro, which returns an Option that thankfully isn't tagged
with the #![must_use]. This worked for most cases where I didn't care
about the Ok variant.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#36675 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAC3n6X7XxTwkZ3tV7L7ypo7d8R5SC-bks5quEYqgaJpZM4KFP33
.

@Mark-Simulacrum Mark-Simulacrum added A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jun 23, 2017
@Mark-Simulacrum Mark-Simulacrum added C-enhancement Category: An issue proposing an enhancement or a PR with one. C-feature-request Category: A feature request, i.e: not implemented / a PR. and removed C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Jul 26, 2017
@steveklabnik
Copy link
Member

Triage: no changes here.

Personal note: not sure if this is enough of a paint point to address. Not my call though.

@Dylan-DPC
Copy link
Member

closing this as it feels like a niche request that hasn't got much attention in the last few years

@Dylan-DPC Dylan-DPC closed this as not planned Won't fix, can't repro, duplicate, stale Nov 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants