diff --git a/doc/langref/grammar.peg b/doc/langref/grammar.peg index b4831516d99f03dec90e2a9794946b5e0ee7b7a0..a92fa2f9ce85bb28212c597ceed62280a50e92cf 100644 --- a/doc/langref/grammar.peg +++ b/doc/langref/grammar.peg @@ -129,12 +129,12 @@ PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr PrimaryExpr <- AsmExpr / IfExpr - / KEYWORD_break BreakLabel? Expr? + / KEYWORD_break BreakLabel? (Expr / !ExprPrefix) / KEYWORD_comptime Expr / KEYWORD_nosuspend Expr - / KEYWORD_continue BreakLabel? Expr? + / KEYWORD_continue BreakLabel? (Expr / !ExprPrefix) / KEYWORD_resume Expr - / KEYWORD_return Expr? + / KEYWORD_return (Expr / !ExprPrefix) / BlockLabel? LoopExpr / Block / CurlySuffixExpr @@ -265,7 +265,7 @@ SwitchItem <- Expr (DOT3 Expr)? # For specific ForArgumentsList <- ForItem (COMMA ForItem)* COMMA? -ForItem <- Expr (DOT2 Expr?)? +ForItem <- Expr (DOT2 (Expr / !ExprPrefix) / !DOT2) # Operators AssignOp @@ -363,7 +363,7 @@ PrefixTypeOpPrefix / ASTERISK SuffixOp - <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET + <- LBRACKET Expr (DOT2 (Expr / !ExprPrefix) (COLON Expr)?)? RBRACKET / DOT IDENTIFIER / DOTASTERISK / DOTQUESTIONMARK @@ -412,7 +412,9 @@ AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)? -ExprList <- (Expr COMMA)* Expr? +ExprList <- (Expr COMMA)* (Expr / !ExprPrefix) + +ExprPrefix <- ASTERISK # *** Tokens *** diff --git a/lib/std/zig/parser_fuzz.zig b/lib/std/zig/parser_fuzz.zig index 024384306449b0083321e42bae7dce3f9e5a3b76..cf05f3acbc5eae2bce06e877c749e4c189a619a1 100644 --- a/lib/std/zig/parser_fuzz.zig +++ b/lib/std/zig/parser_fuzz.zig @@ -68,6 +68,11 @@ test "comptime fn" { try checkAgainstOracle("comptime fn()0"); } +// Found using AFL++ +test "return asterisk" { + try checkAgainstOracle("test{return*!0;}"); +} + fn checkAgainstOracle(source: [:0]const u8) !void { var fba_buf: [1 << 18]u8 = undefined; var fba: std.heap.FixedBufferAllocator = .init(&fba_buf); diff --git a/lib/std/zig/parser_generated_oracle.zig b/lib/std/zig/parser_generated_oracle.zig index b4c9f708845793b8da979bdcae2310d6326f714f..3ecae3e31c8e8c065202516150a4d4d05462e976 100644 --- a/lib/std/zig/parser_generated_oracle.zig +++ b/lib/std/zig/parser_generated_oracle.zig @@ -661,17 +661,53 @@ const Parser = struct { p.i = pos_0; if (p.parseIfExpr()) break :blk_0 true; p.i = pos_0; - if (p.parseKEYWORD_break() and (p.parseBreakLabel() or true) and (p.parseExpr() or true)) break :blk_0 true; + if (p.parseKEYWORD_break() and (p.parseBreakLabel() or true) and blk_2: { + const pos_2 = p.i; + if (p.parseExpr()) break :blk_2 true; + p.i = pos_2; + if (blk_3: { + const pos_3 = p.i; + const match_3 = p.parseExprPrefix(); + p.i = pos_3; + break :blk_3 !match_3; + }) break :blk_2 true; + p.i = pos_2; + break :blk_2 false; + }) break :blk_0 true; p.i = pos_0; if (p.parseKEYWORD_comptime() and p.parseExpr()) break :blk_0 true; p.i = pos_0; if (p.parseKEYWORD_nosuspend() and p.parseExpr()) break :blk_0 true; p.i = pos_0; - if (p.parseKEYWORD_continue() and (p.parseBreakLabel() or true) and (p.parseExpr() or true)) break :blk_0 true; + if (p.parseKEYWORD_continue() and (p.parseBreakLabel() or true) and blk_2: { + const pos_2 = p.i; + if (p.parseExpr()) break :blk_2 true; + p.i = pos_2; + if (blk_3: { + const pos_3 = p.i; + const match_3 = p.parseExprPrefix(); + p.i = pos_3; + break :blk_3 !match_3; + }) break :blk_2 true; + p.i = pos_2; + break :blk_2 false; + }) break :blk_0 true; p.i = pos_0; if (p.parseKEYWORD_resume() and p.parseExpr()) break :blk_0 true; p.i = pos_0; - if (p.parseKEYWORD_return() and (p.parseExpr() or true)) break :blk_0 true; + if (p.parseKEYWORD_return() and blk_2: { + const pos_2 = p.i; + if (p.parseExpr()) break :blk_2 true; + p.i = pos_2; + if (blk_3: { + const pos_3 = p.i; + const match_3 = p.parseExprPrefix(); + p.i = pos_3; + break :blk_3 !match_3; + }) break :blk_2 true; + p.i = pos_2; + break :blk_2 false; + }) break :blk_0 true; p.i = pos_0; if ((p.parseBlockLabel() or true) and p.parseLoopExpr()) break :blk_0 true; p.i = pos_0; @@ -1314,12 +1350,31 @@ const Parser = struct { pub fn parseForItem(p: *Parser) bool { return blk_0: { const pos_0 = p.i; - if (p.parseExpr() and (blk_3: { - const pos_3 = p.i; - if (p.parseDOT2() and (p.parseExpr() or true)) break :blk_3 true; - p.i = pos_3; - break :blk_3 false; - } or true)) break :blk_0 true; + if (p.parseExpr() and blk_2: { + const pos_2 = p.i; + if (p.parseDOT2() and blk_4: { + const pos_4 = p.i; + if (p.parseExpr()) break :blk_4 true; + p.i = pos_4; + if (blk_5: { + const pos_5 = p.i; + const match_5 = p.parseExprPrefix(); + p.i = pos_5; + break :blk_5 !match_5; + }) break :blk_4 true; + p.i = pos_4; + break :blk_4 false; + }) break :blk_2 true; + p.i = pos_2; + if (blk_3: { + const pos_3 = p.i; + const match_3 = p.parseDOT2(); + p.i = pos_3; + break :blk_3 !match_3; + }) break :blk_2 true; + p.i = pos_2; + break :blk_2 false; + }) break :blk_0 true; p.i = pos_0; break :blk_0 false; }; @@ -1662,7 +1717,19 @@ const Parser = struct { const pos_0 = p.i; if (p.parseLBRACKET() and p.parseExpr() and (blk_3: { const pos_3 = p.i; - if (p.parseDOT2() and (p.parseExpr() or true) and (blk_6: { + if (p.parseDOT2() and blk_5: { + const pos_5 = p.i; + if (p.parseExpr()) break :blk_5 true; + p.i = pos_5; + if (blk_6: { + const pos_6 = p.i; + const match_6 = p.parseExprPrefix(); + p.i = pos_6; + break :blk_6 !match_6; + }) break :blk_5 true; + p.i = pos_5; + break :blk_5 false; + } and (blk_6: { const pos_6 = p.i; if (p.parseCOLON() and p.parseExpr()) break :blk_6 true; p.i = pos_6; @@ -1934,7 +2001,27 @@ const Parser = struct { break :blk_3 false; }) {} break :blk_1 true; - } and (p.parseExpr() or true)) break :blk_0 true; + } and blk_2: { + const pos_2 = p.i; + if (p.parseExpr()) break :blk_2 true; + p.i = pos_2; + if (blk_3: { + const pos_3 = p.i; + const match_3 = p.parseExprPrefix(); + p.i = pos_3; + break :blk_3 !match_3; + }) break :blk_2 true; + p.i = pos_2; + break :blk_2 false; + }) break :blk_0 true; + p.i = pos_0; + break :blk_0 false; + }; + } + pub fn parseExprPrefix(p: *Parser) bool { + return blk_0: { + const pos_0 = p.i; + if (p.parseASTERISK()) break :blk_0 true; p.i = pos_0; break :blk_0 false; };