https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95000
David Malcolm <dmalcolm at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Ever confirmed|0 |1 Status|UNCONFIRMED |ASSIGNED Last reconfirmed| |2020-05-08 Summary|-fanalyzer confused by |-fanalyzer confused by |switch |switch on non-int type --- Comment #4 from David Malcolm <dmalcolm at gcc dot gnu.org> --- This turns out to be a problem with tracking path-conditions with casts. Switch statements on a non-int type (such as char) have an implicit cast to int and trigger the issue. Consider this test case, using the not-quite-a-builtin "__analyzer_eval" to evaluate a condition. In each case we expect __analyzer_eval to emit "TRUE": ---------------------------------------------------------------------- extern void __analyzer_eval (int); void test_switch_char(char x) { switch (x) { case 'b': __analyzer_eval (x == 'b'); } } void test_switch_int(int x) { switch (x) { case 97: __analyzer_eval (x == 97); } } void test_if_char(char x) { if (x == 'b') __analyzer_eval (x == 'b'); } void test_if_int(int x) { if (x == 97) __analyzer_eval (x == 97); } ---------------------------------------------------------------------- I get this output (note that the output is in reverse order): s.c: In function ‘test_if_int’: s.c:24:5: warning: TRUE 24 | __analyzer_eval (x == 97); | ^~~~~~~~~~~~~~~~~~~~~~~~~ s.c: In function ‘test_if_char’: s.c:19:5: warning: TRUE 19 | __analyzer_eval (x == 'b'); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ s.c: In function ‘test_switch_int’: s.c:13:5: warning: TRUE 13 | __analyzer_eval (x == 97); | ^~~~~~~~~~~~~~~~~~~~~~~~~ s.c: In function ‘test_switch_char’: s.c:6:5: warning: UNKNOWN 6 | __analyzer_eval (x == 'b'); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ where we get it wrong for test_switch_char. At the gimple level, we have: test_switch_char (char x) { int _1; _Bool _2; int _3; <bb 2> : _1 = (int) x_5(D); if (_1 == 98) goto <bb 3>; [INV] else goto <bb 4>; [INV] <bb 3> : <L0>: _2 = x_5(D) == 98; _3 = (int) _2; __analyzer_eval (_3); <bb 4> : <L1>: return; } The cast here: _1 = (int) x_5(D); if (_1 == 98) seems to thwart my constraint-tracking. If I use -fno-analyzer-state-purge it at least "knows" that _1 == 98 within the "case" BB. I'm working on a rewrite of state-tracking for GCC 11 that ought to better handle casts.