diff --git a/src/AstGen.zig b/src/AstGen.zig index 5b9851b0ae..1e9abda660 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1313,22 +1313,23 @@ fn structInitExpr( const astgen = gz.astgen; const tree = astgen.tree; - if (struct_init.ast.fields.len == 0) { - if (struct_init.ast.type_expr == 0) { + if (struct_init.ast.type_expr == 0) { + if (struct_init.ast.fields.len == 0) { return rvalue(gz, rl, .empty_struct, node); } - array: { - const node_tags = tree.nodes.items(.tag); - const main_tokens = tree.nodes.items(.main_token); - const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { - .array_type => tree.arrayType(struct_init.ast.type_expr), - .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), - else => break :array, - }; + } else array: { + const node_tags = tree.nodes.items(.tag); + const main_tokens = tree.nodes.items(.main_token); + const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { + .array_type => tree.arrayType(struct_init.ast.type_expr), + .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), + else => break :array, + }; + const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and // This intentionally does not support `@"_"` syntax. - if (node_tags[array_type.ast.elem_count] == .identifier and - mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_")) - { + mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"); + if (struct_init.ast.fields.len == 0) { + if (is_inferred_array_len) { const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); const array_type_inst = if (array_type.ast.sentinel == 0) blk: { break :blk try gz.addBin(.array_type, .zero_usize, elem_type); @@ -1339,11 +1340,18 @@ fn structInitExpr( const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node); return rvalue(gz, rl, result, node); } + const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); + const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); + return rvalue(gz, rl, result, node); + } else { + return astgen.failNode( + struct_init.ast.type_expr, + "initializing array with struct syntax", + .{}, + ); } - const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); - const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); - return rvalue(gz, rl, result, node); } + switch (rl) { .discard => { if (struct_init.ast.type_expr != 0) @@ -2266,6 +2274,10 @@ fn varDecl( const token_tags = tree.tokens.items(.tag); const name_token = var_decl.ast.mut_token + 1; + const ident_name_raw = tree.tokenSlice(name_token); + if (mem.eql(u8, ident_name_raw, "_")) { + return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{}); + } const ident_name = try astgen.identAsString(name_token); // Local variables shadowing detection, including function parameters. @@ -3003,7 +3015,11 @@ fn fnDecl( var it = fn_proto.iterate(tree.*); while (it.next()) |param| : (i += 1) { const name_token = param.name_token orelse { - return astgen.failNode(param.type_expr, "missing parameter name", .{}); + if (param.anytype_ellipsis3) |tok| { + return astgen.failTok(tok, "missing parameter name", .{}); + } else { + return astgen.failNode(param.type_expr, "missing parameter name", .{}); + } }; if (param.type_expr != 0) _ = try typeExpr(&fn_gz, params_scope, param.type_expr); @@ -6197,10 +6213,11 @@ fn identifier( const main_tokens = tree.nodes.items(.main_token); const ident_token = main_tokens[ident]; - const ident_name = try astgen.identifierTokenString(ident_token); - if (mem.eql(u8, ident_name, "_")) { + const ident_name_raw = tree.tokenSlice(ident_token); + if (mem.eql(u8, ident_name_raw, "_")) { return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{}); } + const ident_name = try astgen.identifierTokenString(ident_token); if (simple_types.get(ident_name)) |zir_const_ref| { return rvalue(gz, rl, zir_const_ref, ident); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 232dd942cc..540c37c549 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2130,8 +2130,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = x; \\} , &[_][]const u8{ - "tmp.zig:3:13: error: structs and unions, not enums, support field alignment", - "tmp.zig:1:16: note: consider 'union(enum)' here", + "tmp.zig:3:7: error: expected ',', found 'align'", }); ctx.objErrStage1("bad alignment type", @@ -3765,8 +3764,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ return _; \\} , &[_][]const u8{ - "tmp.zig:2:5: error: '_' used as an identifier without @\"_\" syntax", - "tmp.zig:3:12: error: '_' used as an identifier without @\"_\" syntax", + "tmp.zig:2:9: error: '_' used as an identifier without @\"_\" syntax", }); ctx.objErrStage1("`_` should not be usable inside for", @@ -4908,7 +4906,7 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() void { a(); } , &[_][]const u8{ "tmp.zig:2:1: error: redeclaration of 'a'", - "tmp.zig:1:1: error: other declaration here", + "tmp.zig:1:1: note: other declaration here", }); ctx.objErrStage1("unreachable with return", @@ -5218,6 +5216,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .z = 4, \\ .y = 2, \\ }; + \\ _ = a; \\} , &[_][]const u8{ "tmp.zig:9:17: error: missing field: 'x'", @@ -7549,13 +7548,15 @@ pub fn addCases(ctx: *TestContext) !void { \\ }; \\ \\ for ([_]Mode { Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast }) |mode| { + \\ _ = mode; \\ inline for (tests) |test_case| { \\ const foo = test_case.filename ++ ".zig"; + \\ _ = foo; \\ } \\ } \\} , &[_][]const u8{ - "tmp.zig:37:29: error: cannot store runtime value in compile time variable", + "tmp.zig:38:29: error: cannot store runtime value in compile time variable", }); ctx.objErrStage1("invalid legacy unicode escape", @@ -7980,6 +7981,7 @@ pub fn addCases(ctx: *TestContext) !void { \\}; \\export fn foo() void { \\ const fieldOffset = @offsetOf(Empty, "val",); + \\ _ = fieldOffset; \\} , &[_][]const u8{ "tmp.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset", @@ -7991,6 +7993,7 @@ pub fn addCases(ctx: *TestContext) !void { \\}; \\export fn foo() void { \\ const fieldOffset = @bitOffsetOf(Empty, "val",); + \\ _ = fieldOffset; \\} , &[_][]const u8{ "tmp.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset", @@ -8004,6 +8007,7 @@ pub fn addCases(ctx: *TestContext) !void { \\comptime { \\ var foo = Foo {.Baz = {}}; \\ const bar_val = foo.Bar; + \\ _ = bar_val; \\} , &[_][]const u8{ "tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set", @@ -8119,6 +8123,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ var x: *const i32 = &w; \\ var y: *[1]i32 = x; \\ y[0] += 1; + \\ _ = byte; \\} , &[_][]const u8{ "tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32'", @@ -8145,6 +8150,7 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn f2() void { \\ var x: anyerror!i32 = error.Bad; \\ for ("hello") |_| returns() else unreachable; + \\ _ = x; \\} , &[_][]const u8{ "tmp.zig:5:30: error: expression value is ignored", @@ -8154,6 +8160,7 @@ pub fn addCases(ctx: *TestContext) !void { ctx.objErrStage1("aligned variable of zero-bit type", \\export fn f() void { \\ var s: struct {} align(4) = undefined; + \\ _ = s; \\} , &[_][]const u8{ "tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned", @@ -8637,7 +8644,7 @@ pub fn addCases(ctx: *TestContext) !void { }); ctx.objErrStage1("issue #5221: invalid struct init type referenced by @typeInfo and passed into function", - \\fn ignore(comptime param: anytype) void {} + \\fn ignore(comptime param: anytype) void {_ = param;} \\ \\export fn foo() void { \\ const MyStruct = struct {