diff --git a/src/aro/Diagnostics.zig b/src/aro/Diagnostics.zig index a1350079..31cc4dac 100644 --- a/src/aro/Diagnostics.zig +++ b/src/aro/Diagnostics.zig @@ -223,6 +223,7 @@ pub const Options = struct { nonnull: Kind = .default, @"atomic-access": Kind = .default, @"gnu-designator": Kind = .default, + @"empty-body": Kind = .default, }; const Diagnostics = @This(); diff --git a/src/aro/Diagnostics/messages.def b/src/aro/Diagnostics/messages.def index 80089d26..49949fe8 100644 --- a/src/aro/Diagnostics/messages.def +++ b/src/aro/Diagnostics/messages.def @@ -2633,3 +2633,13 @@ gnu_missing_eq_designator .msg = "use of GNU 'missing =' extension in designator" .kind = .warning .opt = W("gnu-designator") + +empty_if_body + .msg = "if statement has empty body" + .kind = .warning + .opt = W("empty-body") + +empty_if_body_note + .msg = "put the semicolon on a separate line to silence this warning" + .kind = .note + .opt = W("empty-body") diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index f1e1ea49..7a251c2b 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -4720,6 +4720,17 @@ fn stmt(p: *Parser) Error!Node.Index { const then_body = try p.stmt(); const else_body = if (p.eatToken(.keyword_else)) |_| try p.stmt() else null; + if (p.nodeIs(then_body, .null_stmt) and else_body == null) { + const semicolon_tok = then_body.get(&p.tree).null_stmt.semicolon_or_r_brace_tok; + const locs = p.pp.tokens.items(.loc); + const if_loc = locs[kw_if]; + const semicolon_loc = locs[semicolon_tok]; + if (if_loc.line == semicolon_loc.line) { + try p.errTok(.empty_if_body, semicolon_tok); + try p.errTok(.empty_if_body_note, semicolon_tok); + } + } + return p.addNode(.{ .if_stmt = .{ .if_tok = kw_if, .cond = cond.node, diff --git a/test/cases/statements.c b/test/cases/statements.c index d55c6e5d..0b1e1bf3 100644 --- a/test/cases/statements.c +++ b/test/cases/statements.c @@ -35,9 +35,15 @@ void baz(int arg) { default: return; } + if (1) + ; } -#define EXPECTED_ERRORS "statements.c:3:9: error: statement requires expression with scalar type ('void' invalid)" \ +#define EXPECTED_ERRORS "statements.c:2:17: warning: if statement has empty body [-Wempty-body]" \ + "statements.c:2:17: note: put the semicolon on a separate line to silence this warning" \ + "statements.c:3:9: error: statement requires expression with scalar type ('void' invalid)" \ + "statements.c:3:17: warning: if statement has empty body [-Wempty-body]" \ + "statements.c:3:17: note: put the semicolon on a separate line to silence this warning" \ "statements.c:4:13: error: statement requires expression with integer type ('float' invalid)" \ "statements.c:5:10: warning: expression result unused [-Wunused-value]" \ "statements.c:5:10: error: statement requires expression with scalar type ('void' invalid)" \ @@ -45,3 +51,4 @@ void baz(int arg) { "statements.c:32:16: warning: use of GNU case range extension [-Wgnu-case-range]" \ "statements.c:33:14: error: duplicate case value '2'" \ "statements.c:32:14: note: previous case defined here" \ +