-
Notifications
You must be signed in to change notification settings - Fork 12.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339- Loading branch information
Showing
8 changed files
with
277 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
clang/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| // RUN: %clang_cc1 -fsyntax-only -Wextra -std=c++2a -verify %s | ||
| // RUN: %clang_cc1 -fsyntax-only -Wextra-semi-stmt -std=c++2a -verify %s | ||
| // RUN: %clang_cc1 -fsyntax-only -Wempty-init-stmt -std=c++2a -verify %s | ||
| // RUN: cp %s %t | ||
| // RUN: %clang_cc1 -x c++ -Wempty-init-stmt -std=c++2a -fixit %t | ||
| // RUN: %clang_cc1 -x c++ -Wempty-init-stmt -std=c++2a -Werror %t | ||
|
|
||
| struct S { | ||
| int *begin(); | ||
| int *end(); | ||
| }; | ||
|
|
||
| void naive(int x) { | ||
| if (; true) // expected-warning {{empty initialization statement of 'if' has no effect}} | ||
| ; | ||
|
|
||
| switch (; x) { // expected-warning {{empty initialization statement of 'switch' has no effect}} | ||
| } | ||
|
|
||
| for (; int y : S()) // expected-warning {{empty initialization statement of 'range-based for' has no effect}} | ||
| ; | ||
|
|
||
| for (;;) // OK | ||
| ; | ||
| } | ||
|
|
||
| #define NULLMACRO | ||
|
|
||
| void with_null_macro(int x) { | ||
| if (NULLMACRO; true) | ||
| ; | ||
|
|
||
| switch (NULLMACRO; x) { | ||
| } | ||
|
|
||
| for (NULLMACRO; int y : S()) | ||
| ; | ||
| } | ||
|
|
||
| #define SEMIMACRO ; | ||
|
|
||
| void with_semi_macro(int x) { | ||
| if (SEMIMACRO true) | ||
| ; | ||
|
|
||
| switch (SEMIMACRO x) { | ||
| } | ||
|
|
||
| for (SEMIMACRO int y : S()) | ||
| ; | ||
| } | ||
|
|
||
| #define PASSTHROUGHMACRO(x) x | ||
|
|
||
| void with_passthrough_macro(int x) { | ||
| if (PASSTHROUGHMACRO(;) true) | ||
| ; | ||
|
|
||
| switch (PASSTHROUGHMACRO(;) x) { | ||
| } | ||
|
|
||
| for (PASSTHROUGHMACRO(;) int y : S()) | ||
| ; | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| // RUN: %clang_cc1 -fsyntax-only -Wextra-semi-stmt -verify %s | ||
| // RUN: cp %s %t | ||
| // RUN: %clang_cc1 -x c++ -Wextra-semi-stmt -fixit %t | ||
| // RUN: %clang_cc1 -x c++ -Wextra-semi-stmt -Werror %t | ||
|
|
||
| #define GOODMACRO(varname) int varname | ||
| #define BETTERMACRO(varname) GOODMACRO(varname); | ||
| #define NULLMACRO(varname) | ||
|
|
||
| enum MyEnum { | ||
| E1, | ||
| E2 | ||
| }; | ||
|
|
||
| void test() { | ||
| ; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}} | ||
| ; | ||
|
|
||
| // This removal of extra semi also consumes all the comments. | ||
| // clang-format: off | ||
| ;;; | ||
| // clang-format: on | ||
|
|
||
| // clang-format: off | ||
| ;NULLMACRO(ZZ); | ||
| // clang-format: on | ||
|
|
||
| {}; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}} | ||
|
|
||
| { | ||
| ; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}} | ||
| } | ||
|
|
||
| if (true) { | ||
| ; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}} | ||
| } | ||
|
|
||
| GOODMACRO(v0); // OK | ||
|
|
||
| GOODMACRO(v1;) // OK | ||
|
|
||
| BETTERMACRO(v2) // OK | ||
|
|
||
| BETTERMACRO(v3;) // Extra ';', but within macro expansion, so ignored. | ||
|
|
||
| BETTERMACRO(v4); // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}} | ||
|
|
||
| BETTERMACRO(v5;); // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}} | ||
|
|
||
| NULLMACRO(v6) // OK | ||
|
|
||
| NULLMACRO(v7); // OK. This could be either GOODMACRO() or BETTERMACRO() situation, so we can't know we can drop it. | ||
|
|
||
| if (true) | ||
| ; // OK | ||
|
|
||
| while (true) | ||
| ; // OK | ||
|
|
||
| do | ||
| ; // OK | ||
| while (true); | ||
|
|
||
| for (;;) // OK | ||
| ; // OK | ||
|
|
||
| MyEnum my_enum; | ||
| switch (my_enum) { | ||
| case E1: | ||
| // stuff | ||
| break; | ||
| case E2:; // OK | ||
| } | ||
|
|
||
| for (;;) { | ||
| for (;;) { | ||
| goto contin_outer; | ||
| } | ||
| contin_outer:; // OK | ||
| } | ||
| } | ||
|
|
||
| ; | ||
|
|
||
| namespace NS {}; | ||
|
|
||
| void foo(int x) { | ||
| switch (x) { | ||
| case 0: | ||
| [[fallthrough]]; | ||
| case 1: | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| [[]]; |