Commit abfee12735

Andrew Kelley <andrew@ziglang.org>
2021-07-02 00:42:21
AstGen: pass more compile error tests
* Implement "initializing array with struct syntax" * Implement "'_' used as an identifier without @\"_\" syntax" * Fix source location of "missing parameter name" * Update test cases where appropriate
1 parent 24c4326
Changed files (2)
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);
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 {