Bug 94389 - __attribute__((warn_unused_result)) will warn if the result is discarded as an optimisation
Summary: __attribute__((warn_unused_result)) will warn if the result is discarded as a...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 9.3.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on: 66425
Blocks:
  Show dependency treegraph
 
Reported: 2020-03-29 15:36 UTC by felix
Modified: 2020-03-30 23:25 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-03-30 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description felix 2020-03-29 15:36:12 UTC
With the code below, the compiler warns about an unused result, even though the result is used:

    #define O_TEXT 0  /* defined on Windows and DOS, but not needed on Unix */

    __attribute__((warn_unused_result))
    extern int text_mode(void);

    int get_flags(void) {
        return text_mode() ? O_TEXT : 0;
    }

Similarly, there is a warning if the result of a function marked with __attribute__((warn_unused_result)) is multiplied by 0, and probably with other expressions that are easily constant-folded. If the function also has __attribute__((const)), there is no warning.

I think this issue could be resolved as a by-product of fixing bug 66425.
Comment 1 Martin Liška 2020-03-30 09:02:51 UTC
We end up during gimplification with:

get_flags ()
{
  int D.1939;

  text_mode ();
  D.1939 = 0;
  return D.1939;
}

which then leads to unused value. While:

int get_flags2(void) {
  return text_mode() ? O_TEXT : foo ();
}

is fine and no warning is reported.
Comment 2 Segher Boessenkool 2020-03-30 11:49:40 UTC
Earlier than that, we have


;; Function get_flags (null)
;; enabled by -tree-original


{
  return text_mode ();, 0;
}


which already has lost (and looks funny btw).

Confirmed btw.
Comment 3 Segher Boessenkool 2020-03-30 12:04:24 UTC
The C frontend dumps nothing for -fdump-lang-all, but the C++ frontend
shows (in .002l.raw) that the ?: is optimised to just a constant zero
there, already.
Comment 4 Jakub Jelinek 2020-03-30 14:16:58 UTC
Compared to [[nodiscard]], warn_unused_result attempts to force users harder not to ignore the return value.  So, it doesn't allow just (void) cast to shut up the warning, and this foo () ? 0 : 0 or 0 * foo () is similar obfuscation to ignore the result when whomever that added the warn_unused_result attribute wanted users not to do that.
So, use [[nodiscard]] instead of you want less aggressive checking, or change your code, like O_TEXT != 0 ? text_mode () ? O_TEXT : 0 : 0 where you wouldn't even call the function if you want to ignore the return value.
Comment 5 Segher Boessenkool 2020-03-30 14:26:50 UTC
The language frontend shouldn't do this kind of code transformations, whether
you think the warning should warn or not here, imo.
Comment 6 felix 2020-03-30 19:00:52 UTC
I don’t mind the transformation being applied. I think it is entirely sound and may be beneficial; I imagine it may be harder to allocate registers for the naïve translation of (foo() ? X : X) than it is for (foo(), X). It’s just the warning that is wrong.

> So, use [[nodiscard]] instead

This is filed against the C frontend, where [[nodiscard]] has not been implemented. Not even on trunk (as provided today by godbolt.org, at least). You are asking people to use a feature that does not exist.

Even if [[nodiscard]] is going to be added eventually, most code in the wild uses __attribute__((warn_unused_result)) and will do so for a while. Which means it will still be subject to false positives like this one.

Moreover, the attribute often appears in library headers, which the library user is not really at liberty to change. Are you suggesting that everyone compile their code with -Dwarn_unused_result=nodiscard -D__warn_unused_result__=nodiscard passed on the command line? Will that even work?

Maybe you should reflect for a while on why the C++ and C committees considered it more useful to standardise [[nodiscard]] with the semantics they did, instead of the semantics of GCC’s __attribute__((warn_unused_result)) as of today.

> O_TEXT != 0 ? text_mode () ? O_TEXT : 0 : 0

First of all, that is not equivalent:

    int text_mode(void) {
        if (mode == MODE_TEXT) {
            fprintf(log_file, "text mode selected\n");
            return 1;
        } else {
            fprintf(log_file, "binary mode selected\n");
            return 0;
        }
    }

Maybe I care about that log message, even in the case where the return value itself happens to be ultimately irrelevant.

Second of all, I should not be faulted for not adding redundant special cases to my already correct code. I am not going to add convoluted hacks just to avoid an asinine compiler warning. I do not want to hand-optimise platform-specific cases like this either; taking care of platform-specific serendipities that can be exploited for optimisation purposes is the compiler’s job.

And finally, just because a faulty workaround exists doesn’t make the warning not wrong. If GCC cannot tell a legitimate use from ‘obfuscation’, it should err on the side of the former. (I believe a case could be made for multiplying by zero as well.)

Though I think it would be simpler to just make the semantics of __attribute__((warn_unused_result)) be exactly like [[nodiscard]].
Comment 7 Segher Boessenkool 2020-03-30 23:25:05 UTC
(In reply to felix from comment #6)
> I don’t mind the transformation being applied.

That is not what I said.  I said the **language frontend** should not
do this.  A language frontend should give an as faithful as possible
description of the source code to the rest of the compiler.