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
This commit is contained in:
Andrew Kelley 2021-07-01 15:42:21 -07:00
parent 24c432608f
commit abfee12735
2 changed files with 50 additions and 26 deletions

View file

@ -1313,22 +1313,23 @@ fn structInitExpr(
const astgen = gz.astgen; const astgen = gz.astgen;
const tree = astgen.tree; 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); return rvalue(gz, rl, .empty_struct, node);
} }
array: { } else array: {
const node_tags = tree.nodes.items(.tag); const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token); const main_tokens = tree.nodes.items(.main_token);
const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { 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 => tree.arrayType(struct_init.ast.type_expr),
.array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),
else => break :array, else => break :array,
}; };
const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and
// This intentionally does not support `@"_"` syntax. // 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 elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
const array_type_inst = if (array_type.ast.sentinel == 0) blk: { const array_type_inst = if (array_type.ast.sentinel == 0) blk: {
break :blk try gz.addBin(.array_type, .zero_usize, elem_type); 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); const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node);
return rvalue(gz, rl, result, 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) { switch (rl) {
.discard => { .discard => {
if (struct_init.ast.type_expr != 0) if (struct_init.ast.type_expr != 0)
@ -2266,6 +2274,10 @@ fn varDecl(
const token_tags = tree.tokens.items(.tag); const token_tags = tree.tokens.items(.tag);
const name_token = var_decl.ast.mut_token + 1; 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); const ident_name = try astgen.identAsString(name_token);
// Local variables shadowing detection, including function parameters. // Local variables shadowing detection, including function parameters.
@ -3003,7 +3015,11 @@ fn fnDecl(
var it = fn_proto.iterate(tree.*); var it = fn_proto.iterate(tree.*);
while (it.next()) |param| : (i += 1) { while (it.next()) |param| : (i += 1) {
const name_token = param.name_token orelse { 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) if (param.type_expr != 0)
_ = try typeExpr(&fn_gz, params_scope, param.type_expr); _ = try typeExpr(&fn_gz, params_scope, param.type_expr);
@ -6197,10 +6213,11 @@ fn identifier(
const main_tokens = tree.nodes.items(.main_token); const main_tokens = tree.nodes.items(.main_token);
const ident_token = main_tokens[ident]; const ident_token = main_tokens[ident];
const ident_name = try astgen.identifierTokenString(ident_token); const ident_name_raw = tree.tokenSlice(ident_token);
if (mem.eql(u8, ident_name, "_")) { if (mem.eql(u8, ident_name_raw, "_")) {
return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{}); 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| { if (simple_types.get(ident_name)) |zir_const_ref| {
return rvalue(gz, rl, zir_const_ref, ident); return rvalue(gz, rl, zir_const_ref, ident);

View file

@ -2130,8 +2130,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x; \\ _ = x;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:3:13: error: structs and unions, not enums, support field alignment", "tmp.zig:3:7: error: expected ',', found 'align'",
"tmp.zig:1:16: note: consider 'union(enum)' here",
}); });
ctx.objErrStage1("bad alignment type", ctx.objErrStage1("bad alignment type",
@ -3765,8 +3764,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ return _; \\ return _;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:2:5: error: '_' used as an identifier without @\"_\" syntax", "tmp.zig:2:9: error: '_' used as an identifier without @\"_\" syntax",
"tmp.zig:3:12: error: '_' used as an identifier without @\"_\" syntax",
}); });
ctx.objErrStage1("`_` should not be usable inside for", ctx.objErrStage1("`_` should not be usable inside for",
@ -4908,7 +4906,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() void { a(); } \\export fn entry() void { a(); }
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:2:1: error: redeclaration of 'a'", "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", ctx.objErrStage1("unreachable with return",
@ -5218,6 +5216,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ .z = 4, \\ .z = 4,
\\ .y = 2, \\ .y = 2,
\\ }; \\ };
\\ _ = a;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:9:17: error: missing field: 'x'", "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| { \\ for ([_]Mode { Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast }) |mode| {
\\ _ = mode;
\\ inline for (tests) |test_case| { \\ inline for (tests) |test_case| {
\\ const foo = test_case.filename ++ ".zig"; \\ const foo = test_case.filename ++ ".zig";
\\ _ = foo;
\\ } \\ }
\\ } \\ }
\\} \\}
, &[_][]const u8{ , &[_][]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", ctx.objErrStage1("invalid legacy unicode escape",
@ -7980,6 +7981,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}; \\};
\\export fn foo() void { \\export fn foo() void {
\\ const fieldOffset = @offsetOf(Empty, "val",); \\ const fieldOffset = @offsetOf(Empty, "val",);
\\ _ = fieldOffset;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset", "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 { \\export fn foo() void {
\\ const fieldOffset = @bitOffsetOf(Empty, "val",); \\ const fieldOffset = @bitOffsetOf(Empty, "val",);
\\ _ = fieldOffset;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset", "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 { \\comptime {
\\ var foo = Foo {.Baz = {}}; \\ var foo = Foo {.Baz = {}};
\\ const bar_val = foo.Bar; \\ const bar_val = foo.Bar;
\\ _ = bar_val;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set", "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 x: *const i32 = &w;
\\ var y: *[1]i32 = x; \\ var y: *[1]i32 = x;
\\ y[0] += 1; \\ y[0] += 1;
\\ _ = byte;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32'", "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 { \\export fn f2() void {
\\ var x: anyerror!i32 = error.Bad; \\ var x: anyerror!i32 = error.Bad;
\\ for ("hello") |_| returns() else unreachable; \\ for ("hello") |_| returns() else unreachable;
\\ _ = x;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:5:30: error: expression value is ignored", "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", ctx.objErrStage1("aligned variable of zero-bit type",
\\export fn f() void { \\export fn f() void {
\\ var s: struct {} align(4) = undefined; \\ var s: struct {} align(4) = undefined;
\\ _ = s;
\\} \\}
, &[_][]const u8{ , &[_][]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", "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", 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 { \\export fn foo() void {
\\ const MyStruct = struct { \\ const MyStruct = struct {