authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-19 03:52:53-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-04-19 03:52:53-04:00
log051620dcaf7df2f0dafb721a192dc5fb9f899987
tree59a35d4c4a7a9f613a5b618f62764b2fb14c589b
parentd415ffd7d95f9c88210154c19e64dabd6b546809
parentb6fe839248751f6e2cfbdbe2cc31e47aee154555
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5097 from Vexu/field

Disallow declarations between fields

11 files changed, 153 insertions(+), 40 deletions(-)

lib/std/json.zig+14-18
...@@ -77,7 +77,7 @@ test "encodesTo" {...@@ -77,7 +77,7 @@ test "encodesTo" {
77 testing.expectEqual(true, encodesTo("false", "false"));77 testing.expectEqual(true, encodesTo("false", "false"));
78 // totally different78 // totally different
79 testing.expectEqual(false, encodesTo("false", "true"));79 testing.expectEqual(false, encodesTo("false", "true"));
80 // differnt lengths80 // different lengths
81 testing.expectEqual(false, encodesTo("false", "other"));81 testing.expectEqual(false, encodesTo("false", "other"));
82 // with escape82 // with escape
83 testing.expectEqual(true, encodesTo("\\", "\\\\"));83 testing.expectEqual(true, encodesTo("\\", "\\\\"));
...@@ -1771,22 +1771,20 @@ test "parse into struct with misc fields" {...@@ -1771,22 +1771,20 @@ test "parse into struct with misc fields" {
1771 static_array: [3]f64,1771 static_array: [3]f64,
1772 dynamic_array: []f64,1772 dynamic_array: []f64,
17731773
1774 const Bar = struct {1774 complex: struct {
1775 nested: []const u8,1775 nested: []const u8,
1776 };1776 },
1777 complex: Bar,
17781777
1779 const Baz = struct {1778 veryComplex: []struct {
1780 foo: []const u8,1779 foo: []const u8,
1781 };1780 },
1782 veryComplex: []Baz,
17831781
1782 a_union: Union,
1784 const Union = union(enum) {1783 const Union = union(enum) {
1785 x: u8,1784 x: u8,
1786 float: f64,1785 float: f64,
1787 string: []const u8,1786 string: []const u8,
1788 };1787 };
1789 a_union: Union,
1790 };1788 };
1791 const r = try parse(T, &TokenStream.init(1789 const r = try parse(T, &TokenStream.init(
1792 \\{1790 \\{
...@@ -2323,13 +2321,14 @@ pub const StringifyOptions = struct {...@@ -2323,13 +2321,14 @@ pub const StringifyOptions = struct {
2323 /// How many indentation levels deep are we?2321 /// How many indentation levels deep are we?
2324 indent_level: usize = 0,2322 indent_level: usize = 0,
23252323
2326 pub const Indentation = union(enum) {2324 /// What character(s) should be used for indentation?
2325 indent: union(enum) {
2327 Space: u8,2326 Space: u8,
2328 Tab: void,2327 Tab: void,
2329 };2328 } = .{ .Space = 4 },
23302329
2331 /// What character(s) should be used for indentation?2330 /// After a colon, should whitespace be inserted?
2332 indent: Indentation = Indentation{ .Space = 4 },2331 separator: bool = true,
23332332
2334 fn outputIndent(2333 fn outputIndent(
2335 whitespace: @This(),2334 whitespace: @This(),
...@@ -2350,17 +2349,17 @@ pub const StringifyOptions = struct {...@@ -2350,17 +2349,17 @@ pub const StringifyOptions = struct {
2350 n_chars *= whitespace.indent_level;2349 n_chars *= whitespace.indent_level;
2351 try out_stream.writeByteNTimes(char, n_chars);2350 try out_stream.writeByteNTimes(char, n_chars);
2352 }2351 }
2353
2354 /// After a colon, should whitespace be inserted?
2355 separator: bool = true,
2356 };2352 };
23572353
2358 /// Controls the whitespace emitted2354 /// Controls the whitespace emitted
2359 whitespace: ?Whitespace = null,2355 whitespace: ?Whitespace = null,
23602356
2357 string: StringOptions = StringOptions{ .String = .{} },
2358
2361 /// Should []u8 be serialised as a string? or an array?2359 /// Should []u8 be serialised as a string? or an array?
2362 pub const StringOptions = union(enum) {2360 pub const StringOptions = union(enum) {
2363 Array,2361 Array,
2362 String: StringOutputOptions,
23642363
2365 /// String output options2364 /// String output options
2366 const StringOutputOptions = struct {2365 const StringOutputOptions = struct {
...@@ -2370,10 +2369,7 @@ pub const StringifyOptions = struct {...@@ -2370,10 +2369,7 @@ pub const StringifyOptions = struct {
2370 /// Should unicode characters be escaped in strings?2369 /// Should unicode characters be escaped in strings?
2371 escape_unicode: bool = false,2370 escape_unicode: bool = false,
2372 };2371 };
2373 String: StringOutputOptions,
2374 };2372 };
2375
2376 string: StringOptions = StringOptions{ .String = .{} },
2377};2373};
23782374
2379fn outputUnicodeEscape(2375fn outputUnicodeEscape(
lib/std/mem.zig+4-7
...@@ -374,7 +374,7 @@ test "mem.zeroes" {...@@ -374,7 +374,7 @@ test "mem.zeroes" {
374 testing.expect(a.y == 10);374 testing.expect(a.y == 10);
375375
376 const ZigStruct = struct {376 const ZigStruct = struct {
377 const IntegralTypes = struct {377 integral_types: struct {
378 integer_0: i0,378 integer_0: i0,
379 integer_8: i8,379 integer_8: i8,
380 integer_16: i16,380 integer_16: i16,
...@@ -390,16 +390,13 @@ test "mem.zeroes" {...@@ -390,16 +390,13 @@ test "mem.zeroes" {
390390
391 float_32: f32,391 float_32: f32,
392 float_64: f64,392 float_64: f64,
393 };393 },
394
395 integral_types: IntegralTypes,
396394
397 const Pointers = struct {395 pointers: struct {
398 optional: ?*u8,396 optional: ?*u8,
399 c_pointer: [*c]u8,397 c_pointer: [*c]u8,
400 slice: []u8,398 slice: []u8,
401 };399 },
402 pointers: Pointers,
403400
404 array: [2]u32,401 array: [2]u32,
405 optional_int: ?u8,402 optional_int: ?u8,
lib/std/os/bits/linux.zig+19-9
...@@ -1226,17 +1226,11 @@ pub const io_cqring_offsets = extern struct {...@@ -1226,17 +1226,11 @@ pub const io_cqring_offsets = extern struct {
1226};1226};
12271227
1228pub const io_uring_sqe = extern struct {1228pub const io_uring_sqe = extern struct {
1229 opcode: IORING_OP,
1230 flags: u8,
1231 ioprio: u16,
1232 fd: i32,
1233 pub const union1 = extern union {1229 pub const union1 = extern union {
1234 off: u64,1230 off: u64,
1235 addr2: u64,1231 addr2: u64,
1236 };1232 };
1237 union1: union1,1233
1238 addr: u64,
1239 len: u32,
1240 pub const union2 = extern union {1234 pub const union2 = extern union {
1241 rw_flags: kernel_rwf,1235 rw_flags: kernel_rwf,
1242 fsync_flags: u32,1236 fsync_flags: u32,
...@@ -1250,8 +1244,7 @@ pub const io_uring_sqe = extern struct {...@@ -1250,8 +1244,7 @@ pub const io_uring_sqe = extern struct {
1250 statx_flags: u32,1244 statx_flags: u32,
1251 fadvise_flags: u32,1245 fadvise_flags: u32,
1252 };1246 };
1253 union2: union2,1247
1254 user_data: u64,
1255 pub const union3 = extern union {1248 pub const union3 = extern union {
1256 struct1: extern struct {1249 struct1: extern struct {
1257 /// index into fixed buffers, if used1250 /// index into fixed buffers, if used
...@@ -1262,6 +1255,23 @@ pub const io_uring_sqe = extern struct {...@@ -1262,6 +1255,23 @@ pub const io_uring_sqe = extern struct {
1262 },1255 },
1263 __pad2: [3]u64,1256 __pad2: [3]u64,
1264 };1257 };
1258 opcode: IORING_OP,
1259 flags: u8,
1260 ioprio: u16,
1261 fd: i32,
1262
1263 opcode: u8,
1264 flags: u8,
1265 ioprio: u16,
1266 fd: i32,
1267
1268 union1: union1,
1269 addr: u64,
1270 len: u32,
1271
1272 union2: union2,
1273 user_data: u64,
1274
1265 union3: union3,1275 union3: union3,
1266};1276};
12671277
lib/std/os/bits/linux/errno-generic.zig+2
...@@ -384,8 +384,10 @@ pub const EKEYREVOKED = 128;...@@ -384,8 +384,10 @@ pub const EKEYREVOKED = 128;
384pub const EKEYREJECTED = 129;384pub const EKEYREJECTED = 129;
385385
386// for robust mutexes386// for robust mutexes
387
387/// Owner died388/// Owner died
388pub const EOWNERDEAD = 130;389pub const EOWNERDEAD = 130;
390
389/// State not recoverable391/// State not recoverable
390pub const ENOTRECOVERABLE = 131;392pub const ENOTRECOVERABLE = 131;
391393
lib/std/os/bits/linux/netlink.zig+3-3
...@@ -122,6 +122,9 @@ pub const NLM_F_CAPPED = 0x100;...@@ -122,6 +122,9 @@ pub const NLM_F_CAPPED = 0x100;
122pub const NLM_F_ACK_TLVS = 0x200;122pub const NLM_F_ACK_TLVS = 0x200;
123123
124pub const NetlinkMessageType = extern enum(u16) {124pub const NetlinkMessageType = extern enum(u16) {
125 /// < 0x10: reserved control messages
126 pub const MIN_TYPE = 0x10;
127
125 /// Nothing.128 /// Nothing.
126 NOOP = 0x1,129 NOOP = 0x1,
127130
...@@ -134,9 +137,6 @@ pub const NetlinkMessageType = extern enum(u16) {...@@ -134,9 +137,6 @@ pub const NetlinkMessageType = extern enum(u16) {
134 /// Data lost137 /// Data lost
135 OVERRUN = 0x4,138 OVERRUN = 0x4,
136139
137 /// < 0x10: reserved control messages
138 pub const MIN_TYPE = 0x10;
139
140 // rtlink types140 // rtlink types
141141
142 RTM_NEWLINK = 16,142 RTM_NEWLINK = 16,
lib/std/os/bits/linux/riscv64.zig+2-1
...@@ -5,6 +5,8 @@ const gid_t = std.os.linux.gid_t;...@@ -5,6 +5,8 @@ const gid_t = std.os.linux.gid_t;
5const pid_t = std.os.linux.pid_t;5const pid_t = std.os.linux.pid_t;
66
7pub const SYS = extern enum(usize) {7pub const SYS = extern enum(usize) {
8 pub const arch_specific_syscall = 244;
9
8 io_setup = 0,10 io_setup = 0,
9 io_destroy = 1,11 io_destroy = 1,
10 io_submit = 2,12 io_submit = 2,
...@@ -249,7 +251,6 @@ pub const SYS = extern enum(usize) {...@@ -249,7 +251,6 @@ pub const SYS = extern enum(usize) {
249 accept4 = 242,251 accept4 = 242,
250 recvmmsg = 243,252 recvmmsg = 243,
251253
252 pub const arch_specific_syscall = 244;
253 riscv_flush_icache = arch_specific_syscall + 15,254 riscv_flush_icache = arch_specific_syscall + 15,
254255
255 wait4 = 260,256 wait4 = 260,
lib/std/zig/ast.zig+4
...@@ -164,6 +164,7 @@ pub const Error = union(enum) {...@@ -164,6 +164,7 @@ pub const Error = union(enum) {
164 ExpectedLoopExpr: ExpectedLoopExpr,164 ExpectedLoopExpr: ExpectedLoopExpr,
165 ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,165 ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,
166 ExpectedSuffixOp: ExpectedSuffixOp,166 ExpectedSuffixOp: ExpectedSuffixOp,
167 DeclBetweenFields: DeclBetweenFields,
167168
168 pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {169 pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
169 switch (self.*) {170 switch (self.*) {
...@@ -211,6 +212,7 @@ pub const Error = union(enum) {...@@ -211,6 +212,7 @@ pub const Error = union(enum) {
211 .ExpectedLoopExpr => |*x| return x.render(tokens, stream),212 .ExpectedLoopExpr => |*x| return x.render(tokens, stream),
212 .ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),213 .ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
213 .ExpectedSuffixOp => |*x| return x.render(tokens, stream),214 .ExpectedSuffixOp => |*x| return x.render(tokens, stream),
215 .DeclBetweenFields => |*x| return x.render(tokens, stream),
214 }216 }
215 }217 }
216218
...@@ -260,6 +262,7 @@ pub const Error = union(enum) {...@@ -260,6 +262,7 @@ pub const Error = union(enum) {
260 .ExpectedLoopExpr => |x| return x.token,262 .ExpectedLoopExpr => |x| return x.token,
261 .ExpectedDerefOrUnwrap => |x| return x.token,263 .ExpectedDerefOrUnwrap => |x| return x.token,
262 .ExpectedSuffixOp => |x| return x.token,264 .ExpectedSuffixOp => |x| return x.token,
265 .DeclBetweenFields => |x| return x.token,
263 }266 }
264 }267 }
265268
...@@ -304,6 +307,7 @@ pub const Error = union(enum) {...@@ -304,6 +307,7 @@ pub const Error = union(enum) {
304 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");307 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
305 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");308 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
306 pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");309 pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
310 pub const DeclBetweenFields = SimpleError("Declarations are not allowed between container fields");
307311
308 pub const ExpectedCall = struct {312 pub const ExpectedCall = struct {
309 node: *Node,313 node: *Node,
lib/std/zig/parse.zig+33
...@@ -88,6 +88,18 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Roo...@@ -88,6 +88,18 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Roo
88fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Root.DeclList {88fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Root.DeclList {
89 var list = Node.Root.DeclList.init(arena);89 var list = Node.Root.DeclList.init(arena);
9090
91 var field_state: union(enum) {
92 /// no fields have been seen
93 none,
94 /// currently parsing fields
95 seen,
96 /// saw fields and then a declaration after them.
97 /// payload is first token of previous declaration.
98 end: TokenIndex,
99 /// ther was a declaration between fields, don't report more errors
100 err,
101 } = .none;
102
91 while (true) {103 while (true) {
92 if (try parseContainerDocComments(arena, it, tree)) |node| {104 if (try parseContainerDocComments(arena, it, tree)) |node| {
93 try list.push(node);105 try list.push(node);
...@@ -97,12 +109,18 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -97,12 +109,18 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
97 const doc_comments = try parseDocComment(arena, it, tree);109 const doc_comments = try parseDocComment(arena, it, tree);
98110
99 if (try parseTestDecl(arena, it, tree)) |node| {111 if (try parseTestDecl(arena, it, tree)) |node| {
112 if (field_state == .seen) {
113 field_state = .{ .end = node.firstToken() };
114 }
100 node.cast(Node.TestDecl).?.doc_comments = doc_comments;115 node.cast(Node.TestDecl).?.doc_comments = doc_comments;
101 try list.push(node);116 try list.push(node);
102 continue;117 continue;
103 }118 }
104119
105 if (try parseTopLevelComptime(arena, it, tree)) |node| {120 if (try parseTopLevelComptime(arena, it, tree)) |node| {
121 if (field_state == .seen) {
122 field_state = .{ .end = node.firstToken() };
123 }
106 node.cast(Node.Comptime).?.doc_comments = doc_comments;124 node.cast(Node.Comptime).?.doc_comments = doc_comments;
107 try list.push(node);125 try list.push(node);
108 continue;126 continue;
...@@ -111,6 +129,9 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -111,6 +129,9 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
111 const visib_token = eatToken(it, .Keyword_pub);129 const visib_token = eatToken(it, .Keyword_pub);
112130
113 if (try parseTopLevelDecl(arena, it, tree)) |node| {131 if (try parseTopLevelDecl(arena, it, tree)) |node| {
132 if (field_state == .seen) {
133 field_state = .{ .end = visib_token orelse node.firstToken() };
134 }
114 switch (node.id) {135 switch (node.id) {
115 .FnProto => {136 .FnProto => {
116 node.cast(Node.FnProto).?.doc_comments = doc_comments;137 node.cast(Node.FnProto).?.doc_comments = doc_comments;
...@@ -146,6 +167,18 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -146,6 +167,18 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
146 }167 }
147168
148 if (try parseContainerField(arena, it, tree)) |node| {169 if (try parseContainerField(arena, it, tree)) |node| {
170 switch (field_state) {
171 .none => field_state = .seen,
172 .err, .seen => {},
173 .end => |tok| {
174 try tree.errors.push(.{
175 .DeclBetweenFields = .{ .token = tok },
176 });
177 // continue parsing, error will be reported later
178 field_state = .err;
179 },
180 }
181
149 const field = node.cast(Node.ContainerField).?;182 const field = node.cast(Node.ContainerField).?;
150 field.doc_comments = doc_comments;183 field.doc_comments = doc_comments;
151 try list.push(node);184 try list.push(node);
lib/std/zig/parser_test.zig+17-2
...@@ -1,3 +1,18 @@...@@ -1,3 +1,18 @@
1test "zig fmt: decl between fields" {
2 try testError(
3 \\const S = struct {
4 \\ const foo = 2;
5 \\ const bar = 2;
6 \\ const baz = 2;
7 \\ a: usize,
8 \\ const foo1 = 2;
9 \\ const bar1 = 2;
10 \\ const baz1 = 2;
11 \\ b: usize,
12 \\};
13 );
14}
15
1test "zig fmt: errdefer with payload" {16test "zig fmt: errdefer with payload" {
2 try testCanonical(17 try testCanonical(
3 \\pub fn main() anyerror!void {18 \\pub fn main() anyerror!void {
...@@ -2001,11 +2016,11 @@ test "zig fmt: struct declaration" {...@@ -2001,11 +2016,11 @@ test "zig fmt: struct declaration" {
2001 \\ f1: u8,2016 \\ f1: u8,
2002 \\ f3: u8,2017 \\ f3: u8,
2003 \\2018 \\
2019 \\ f2: u8,
2020 \\
2004 \\ fn method(self: *Self) Self {2021 \\ fn method(self: *Self) Self {
2005 \\ return self.*;2022 \\ return self.*;
2006 \\ }2023 \\ }
2007 \\
2008 \\ f2: u8,
2009 \\};2024 \\};
2010 \\2025 \\
2011 \\const Ps = packed struct {2026 \\const Ps = packed struct {
src/parser.cpp+37
...@@ -526,6 +526,15 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) {...@@ -526,6 +526,15 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) {
526 }526 }
527}527}
528528
529enum ContainerFieldState {
530 // no fields have been seen
531 ContainerFieldStateNone,
532 // currently parsing fields
533 ContainerFieldStateSeen,
534 // saw fields and then a declaration after them
535 ContainerFieldStateEnd,
536};
537
529// ContainerMembers538// ContainerMembers
530// <- TestDecl ContainerMembers539// <- TestDecl ContainerMembers
531// / TopLevelComptime ContainerMembers540// / TopLevelComptime ContainerMembers
...@@ -537,17 +546,29 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {...@@ -537,17 +546,29 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
537 AstNodeContainerDecl res = {};546 AstNodeContainerDecl res = {};
538 Buf tld_doc_comment_buf = BUF_INIT;547 Buf tld_doc_comment_buf = BUF_INIT;
539 buf_resize(&tld_doc_comment_buf, 0);548 buf_resize(&tld_doc_comment_buf, 0);
549 ContainerFieldState field_state = ContainerFieldStateNone;
550 Token *first_token = nullptr;
540 for (;;) {551 for (;;) {
541 ast_parse_container_doc_comments(pc, &tld_doc_comment_buf);552 ast_parse_container_doc_comments(pc, &tld_doc_comment_buf);
542553
554 Token *peeked_token = peek_token(pc);
555
543 AstNode *test_decl = ast_parse_test_decl(pc);556 AstNode *test_decl = ast_parse_test_decl(pc);
544 if (test_decl != nullptr) {557 if (test_decl != nullptr) {
558 if (field_state == ContainerFieldStateSeen) {
559 field_state = ContainerFieldStateEnd;
560 first_token = peeked_token;
561 }
545 res.decls.append(test_decl);562 res.decls.append(test_decl);
546 continue;563 continue;
547 }564 }
548565
549 AstNode *top_level_comptime = ast_parse_top_level_comptime(pc);566 AstNode *top_level_comptime = ast_parse_top_level_comptime(pc);
550 if (top_level_comptime != nullptr) {567 if (top_level_comptime != nullptr) {
568 if (field_state == ContainerFieldStateSeen) {
569 field_state = ContainerFieldStateEnd;
570 first_token = peeked_token;
571 }
551 res.decls.append(top_level_comptime);572 res.decls.append(top_level_comptime);
552 continue;573 continue;
553 }574 }
...@@ -555,11 +576,17 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {...@@ -555,11 +576,17 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
555 Buf doc_comment_buf = BUF_INIT;576 Buf doc_comment_buf = BUF_INIT;
556 ast_parse_doc_comments(pc, &doc_comment_buf);577 ast_parse_doc_comments(pc, &doc_comment_buf);
557578
579 peeked_token = peek_token(pc);
580
558 Token *visib_token = eat_token_if(pc, TokenIdKeywordPub);581 Token *visib_token = eat_token_if(pc, TokenIdKeywordPub);
559 VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate;582 VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate;
560583
561 AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf);584 AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf);
562 if (top_level_decl != nullptr) {585 if (top_level_decl != nullptr) {
586 if (field_state == ContainerFieldStateSeen) {
587 field_state = ContainerFieldStateEnd;
588 first_token = peeked_token;
589 }
563 res.decls.append(top_level_decl);590 res.decls.append(top_level_decl);
564 continue;591 continue;
565 }592 }
...@@ -572,6 +599,16 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {...@@ -572,6 +599,16 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
572599
573 AstNode *container_field = ast_parse_container_field(pc);600 AstNode *container_field = ast_parse_container_field(pc);
574 if (container_field != nullptr) {601 if (container_field != nullptr) {
602 switch (field_state) {
603 case ContainerFieldStateNone:
604 field_state = ContainerFieldStateSeen;
605 break;
606 case ContainerFieldStateSeen:
607 break;
608 case ContainerFieldStateEnd:
609 ast_error(pc, first_token, "declarations are not allowed between container fields");
610 }
611
575 assert(container_field->type == NodeTypeStructField);612 assert(container_field->type == NodeTypeStructField);
576 container_field->data.struct_field.doc_comments = doc_comment_buf;613 container_field->data.struct_field.doc_comments = doc_comment_buf;
577 container_field->data.struct_field.comptime_token = comptime_token;614 container_field->data.struct_field.comptime_token = comptime_token;
test/compile_errors.zig+18
...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
2const std = @import("std");2const std = @import("std");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add("declaration between fields",
6 \\const S = struct {
7 \\ const foo = 2;
8 \\ const bar = 2;
9 \\ const baz = 2;
10 \\ a: usize,
11 \\ const foo1 = 2;
12 \\ const bar1 = 2;
13 \\ const baz1 = 2;
14 \\ b: usize,
15 \\};
16 \\comptime {
17 \\ _ = S;
18 \\}
19 , &[_][]const u8{
20 "tmp.zig:6:5: error: declarations are not allowed between container fields",
21 });
22
5 cases.add("non-extern function with var args",23 cases.add("non-extern function with var args",
6 \\fn foo(args: ...) void {}24 \\fn foo(args: ...) void {}
7 \\export fn entry() void {25 \\export fn entry() void {