2

I'm trying to find a GCC compiler flag that would cause GCC to refuse to compile the following code:

# include <stdio.h>

int main()
{
    int x = 1;

    if( (x = 10) ) {
        printf("x is 10");
    } else {
        printf("x is not 10");
    }
    return 0;
}

The above code will compile with no warnings:

gcc -Wall -Werror -O3 -o x.exe x.c

Specifically, I want GCC to barf at the line if( (x = 10) ). If I remove the inner brackets, GCC will break due to -Werror

gcc -Wall -Werror -O3 -o x.exe x.c
x.c: In function 'main':
x.c:7:9: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
     if( x = 10 ) {
         ^
cc1.exe: all warnings being treated as errors

What I'm looking for is a way to force GCC to refuse to compile the code even when the brackets are present.

Thanks!

Leonardo
  • 1,533
  • 17
  • 28
  • 3
    I don't think you can. The extra parentheses are the way you tell GCC that it shouldn't warn about the assignment. And if it doesn't warn, it can't turn the warning into an error with `-Werror` – Barmar Jun 04 '21 at 16:08
  • Do you mean you *explicitly* want to use assignment `=` instead of comparison for equality `==`? Then either disable the warning (all warnings can be disable, with e.g. `-Wno-parentheses`) or use parentheses. – Some programmer dude Jun 04 '21 at 16:09
  • @Barmar, thanks for the answer! Yes, I understand this is more in the realm of a static analysis tool. – Leonardo Jun 04 '21 at 16:09
  • 2
    @Someprogrammerdude, no, I want the *exact* opposite: I want GCC to REFUSE to compile if someone forgot to add the second `=` in a comparison. – Leonardo Jun 04 '21 at 16:11
  • Not really. The point is that you explicitly indicated "This one is OK" by adding the extra parentheses. – Barmar Jun 04 '21 at 16:11
  • GCC is already doing static analysis when it issues the normal warning. Notice the wording in the message: "suggest parentheses around assignment used as truth value". That means that when you add another set of parentheses, you're saying that you really want to do this. – Barmar Jun 04 '21 at 16:13
  • 1
    Well it is both syntactically and semantically valid, since assignment is an expression and the condition can be any expression. A compiler should not disallow such code. As you mentioned, this is only something a static analysis tool will be able to handle the way you want. – Some programmer dude Jun 04 '21 at 16:15
  • Not exactly what you want, but... the easiest method is to use "reverse comparison" style, i.e. `-1 == retval`, this way it will always fail on assignment. But enforcing that still requires some external means, e.g. review or static analysis. – alagner Jun 04 '21 at 16:19
  • 1
    @Someprogrammerdude But the side effects of that extra parenthesis disabling a warning you explicitly ask for are pernicious. [GCC "hiding" the assignment-in-if when extra parenthesis are added is a ***BAD*** idea](https://www.approxion.com/a-gcc-compiler-mistake/). – Andrew Henle Jun 04 '21 at 16:19
  • 1
    @alagner But you can't always use Yoda conditions. Such as in `if ((a == b) && (c = d))`. ***OOOOPS!!!*** That's a mistake GCC will hide because of one nasty "feature" that can't be disabled. – Andrew Henle Jun 04 '21 at 16:22
  • 2
    @AndrewHenle True, but on the other hand sometimes you *want* to do an assignment in the condition, and then you don't want to disable it globally (using flags when building) or clutter the code with compiler-specific pragmas of the like. – Some programmer dude Jun 04 '21 at 16:25
  • 1
    @Barmar *Not really. The point is that you explicitly indicated "This one is OK" by adding the extra parentheses.* Not totally true. As I noted above, there are cases where no "extra" parenthesis are needed to trigger this behavior. It's one ***nasty*** feature when it's combined with complex code. – Andrew Henle Jun 04 '21 at 16:25
  • @AndrewHenle true, Yoda style's not perfect, but it offers some level of protection while being relatively cheap to introduce. – alagner Jun 04 '21 at 16:27
  • @Someprogrammerdude *True, but on the other hand sometimes you want to do an assignment in the condition* Then disable that warning when you want to do that. Having a feature that ***hides*** that warning even when it's ***explicitly*** asked for is a way to propagate insidious bugs. – Andrew Henle Jun 04 '21 at 16:27
  • A good IDE will also warn you about these things, so is it really necessary to depend on the compiler for it? And they often have better ways of suppressing the warning on a case by case basis. – Barmar Jun 04 '21 at 16:30
  • 1
    @alagner Yoda conditions not being complete protection against inadvertently performing an assignment in a conditional clause is another reason why having a "feature" to hide warnings in such situations is such a misguided, horrible idea. "Give me all warnings as errors, and I'm explicitly asking for failure if there's any assignment in an `if`-statement" GCC: "**HA HA!! NOPE! NOT GONNA DO IT!!!**" Tell me again how that's a good idea in any universe? – Andrew Henle Jun 04 '21 at 16:32
  • https://stackoverflow.com/a/18450261/315052 – jxh Jun 04 '21 at 17:54
  • 1
    @jxh Performing assignments in a conditional clause is a bug-prone, nasty idiom. Cramming as many operations into as few lines of code as possible is a sign of a misguided (at best...) developer. Saying it's "idiomatic" because it was a way to cram more operations into fewer lines of code because ancient C didn't allow initialization of automatic variables is no different than claiming the use of `gets()` is "idiomatic" because `gets()` is in ancient C. And using "It's an idiom" to justify a bug-prone construct is circular reasoning - if it's "reasoning" at all. – Andrew Henle Jun 06 '21 at 12:03
  • @AndrewHenle No one is saying you have to write code that way. It is just explaining why you would see code written that way. There is some advantage to fitting more than one operation on a single line, otherwise high level languages would look like machine code. – jxh Jun 06 '21 at 12:32
  • 1
    one common way to avoid such problems is to put the literal on the left. I.E. `if( (10 = x) ) {` – user3629249 Jun 06 '21 at 14:56
  • @jxh *There is some advantage to fitting more than one operation on a single line* Other than saving lines in printed textbooks, thereby reducing the page count by a few pages, allowing the publisher to make a few pennies more per book sold, and thereby helping to pay for the CEO's new swimming pool, I fail to see any benefit to cramming an assignment into an `if`- or `while`-statement. "It's idiomatic" isn't reasoning, it's regurgitating. The human brain only tracks a handful of states at any one time. Why throw two or three away in a quest to write harder-to-read, bug-prone code? – Andrew Henle Jun 06 '21 at 16:50
  • @AndrewHenle Because people change? What is unclear today may be more clear tomorrow? What was clear today may be unclear tomorrow? For a lot of things, I feel it is better to promote some amount of tolerance than to promote blanket condemnation. – jxh Jun 06 '21 at 17:42

1 Answers1

2

There doesn't seem to be any way to convince GCC to do this. -Wall -Wextra doesn't warn for your example code, and I didn't see any other warning options that would seem relevant. (As noted in comments, by GCC's design, generally the only way to make it reject otherwise legal code is to find a warning option that the code triggers, and then use -Werror to upgrade the warning to an error.)

As another data point, clang offers a fairly similar set of warnings as GCC, and it has the bonus of the -Weverything option that enables every warning it provides. (It'd be nice if GCC had such a thing too.) But clang -Weverything doesn't give any warnings for your code either.. That seems like pretty good evidence that nobody in these communities has implemented a warning for code like yours.

I agree it seems like something that would be useful, so it might be worth filing a feature request for GCC and/or clang (or seeing if someone already has).

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82