authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-28 16:43:09+03:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-30 09:57:38+02:00
log03b356e34af37d74cf92087c0303a1b2c74d3afc
tree3c1766f4e41c96ddc64fb65d6756453768b2bff6
parent3204d00a5e7fe119b690e921138a439fb84dff5b

Sema: improve `@call` errors


11 files changed, 115 insertions(+), 113 deletions(-)

src/Sema.zig+29-7
......@@ -5231,6 +5231,10 @@ fn analyzeCall(
52315231 .async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),
52325232 };
52335233
5234 if (modifier == .never_inline and func_ty_info.cc == .Inline) {
5235 return sema.fail(block, call_src, "no-inline call of inline function", .{});
5236 }
5237
52345238 const gpa = sema.gpa;
52355239
52365240 var is_generic_call = func_ty_info.is_generic;
......@@ -5270,6 +5274,10 @@ fn analyzeCall(
52705274 }
52715275 }
52725276
5277 if (is_comptime_call and modifier == .never_inline) {
5278 return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{});
5279 }
5280
52735281 const result: Air.Inst.Ref = if (is_inline_call) res: {
52745282 const func_val = try sema.resolveConstValue(block, func_src, func);
52755283 const module_fn = switch (func_val.tag()) {
......@@ -11612,8 +11620,13 @@ fn analyzeCmpUnionTag(
1161211620) CompileError!Air.Inst.Ref {
1161311621 const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un));
1161411622 const union_tag_ty = union_ty.unionTagType() orelse {
11615 // TODO note at declaration site that says "union foo is not tagged"
11616 return sema.fail(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
11623 const msg = msg: {
11624 const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
11625 errdefer msg.destroy(sema.gpa);
11626 try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)});
11627 break :msg msg;
11628 };
11629 return sema.failWithOwnedErrorMsg(block, msg);
1161711630 };
1161811631 // Coerce both the union and the tag to the union's tag type, and then execute the
1161911632 // enum comparison codepath.
......@@ -16878,10 +16891,15 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1687816891 break :modifier modifier_val.toEnum(std.builtin.CallOptions.Modifier);
1687916892 };
1688016893
16894 const is_comptime = extra.flags.is_comptime or block.is_comptime;
16895
1688116896 const modifier: std.builtin.CallOptions.Modifier = switch (wanted_modifier) {
1688216897 // These can be upgraded to comptime or nosuspend calls.
1688316898 .auto, .never_tail, .no_async => m: {
16884 if (extra.flags.is_comptime) {
16899 if (is_comptime) {
16900 if (wanted_modifier == .never_tail) {
16901 return sema.fail(block, options_src, "unable to perform 'never_tail' call at compile-time", .{});
16902 }
1688516903 break :m .compile_time;
1688616904 }
1688716905 if (extra.flags.is_nosuspend) {
......@@ -16891,7 +16909,11 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1689116909 },
1689216910 // These can be upgraded to comptime. nosuspend bit can be safely ignored.
1689316911 .always_tail, .always_inline, .compile_time => m: {
16894 if (extra.flags.is_comptime) {
16912 _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse {
16913 return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)});
16914 };
16915
16916 if (is_comptime) {
1689516917 break :m .compile_time;
1689616918 }
1689716919 break :m wanted_modifier;
......@@ -16900,14 +16922,14 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1690016922 if (extra.flags.is_nosuspend) {
1690116923 return sema.fail(block, options_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
1690216924 }
16903 if (extra.flags.is_comptime) {
16925 if (is_comptime) {
1690416926 return sema.fail(block, options_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
1690516927 }
1690616928 break :m wanted_modifier;
1690716929 },
1690816930 .never_inline => m: {
16909 if (extra.flags.is_comptime) {
16910 return sema.fail(block, options_src, "modifier 'never_inline' cannot be used in combination with comptime function call", .{});
16931 if (is_comptime) {
16932 return sema.fail(block, options_src, "unable to perform 'never_inline' call at compile-time", .{});
1691116933 }
1691216934 break :m wanted_modifier;
1691316935 },
test/cases/comparison_of_non-tagged_union_and_enum_literal.zig created+13
......@@ -0,0 +1,13 @@
1export fn entry() void {
2 const U = union { A: u32, B: u64 };
3 var u = U{ .A = 42 };
4 var ok = u == .A;
5 _ = ok;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :4:14: error: comparison of union and enum literal is only valid for tagged union types
13// :2:15: note: union 'tmp.entry.U' is not a tagged union
test/cases/compile_errors/bad_usage_of_call.zig created+35
......@@ -0,0 +1,35 @@
1export fn entry1() void {
2 @call(.{}, foo, {});
3}
4export fn entry2() void {
5 comptime @call(.{ .modifier = .never_inline }, foo, .{});
6}
7export fn entry3() void {
8 comptime @call(.{ .modifier = .never_tail }, foo, .{});
9}
10export fn entry4() void {
11 @call(.{ .modifier = .never_inline }, bar, .{});
12}
13export fn entry5(c: bool) void {
14 var baz = if (c) &baz1 else &baz2;
15 @call(.{ .modifier = .compile_time }, baz, .{});
16}
17pub export fn entry() void {
18 var call_me: *const fn () void = undefined;
19 @call(.{ .modifier = .always_inline }, call_me, .{});
20}
21fn foo() void {}
22fn bar() callconv(.Inline) void {}
23fn baz1() void {}
24fn baz2() void {}
25
26// error
27// backend=stage2
28// target=native
29//
30// :2:21: error: expected a tuple, found 'void'
31// :5:21: error: unable to perform 'never_inline' call at compile-time
32// :8:21: error: unable to perform 'never_tail' call at compile-time
33// :11:5: error: no-inline call of inline function
34// :15:43: error: modifier 'compile_time' requires a comptime-known function
35// :19:44: error: modifier 'always_inline' requires a comptime-known function
test/cases/compile_errors/stage1/alignCast_of_zero_sized_types.zig created+27
......@@ -0,0 +1,27 @@
1export fn foo() void {
2 const a: *void = undefined;
3 _ = @alignCast(2, a);
4}
5export fn bar() void {
6 const a: ?*void = undefined;
7 _ = @alignCast(2, a);
8}
9export fn baz() void {
10 const a: []void = undefined;
11 _ = @alignCast(2, a);
12}
13export fn qux() void {
14 const a = struct {
15 fn a(comptime b: u32) void { _ = b; }
16 }.a;
17 _ = @alignCast(2, a);
18}
19
20// error
21// backend=stage1
22// target=native
23//
24// tmp.zig:3:23: error: cannot adjust alignment of zero sized type '*void'
25// tmp.zig:7:23: error: cannot adjust alignment of zero sized type '?*void'
26// tmp.zig:11:23: error: cannot adjust alignment of zero sized type '[]void'
27// tmp.zig:17:23: error: cannot adjust alignment of zero sized type 'fn(u32) anytype'
test/cases/compile_errors/stage1/obj/bad_usage_of_call.zig deleted-30
......@@ -1,30 +0,0 @@
1export fn entry1() void {
2 @call(.{}, foo, {});
3}
4export fn entry2() void {
5 comptime @call(.{ .modifier = .never_inline }, foo, .{});
6}
7export fn entry3() void {
8 comptime @call(.{ .modifier = .never_tail }, foo, .{});
9}
10export fn entry4() void {
11 @call(.{ .modifier = .never_inline }, bar, .{});
12}
13export fn entry5(c: bool) void {
14 var baz = if (c) baz1 else baz2;
15 @call(.{ .modifier = .compile_time }, baz, .{});
16}
17fn foo() void {}
18fn bar() callconv(.Inline) void {}
19fn baz1() void {}
20fn baz2() void {}
21
22// error
23// backend=stage1
24// target=native
25//
26// tmp.zig:2:21: error: expected tuple or struct, found 'void'
27// tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time
28// tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time
29// tmp.zig:11:5: error: no-inline call of inline function
30// tmp.zig:15:5: error: the specified modifier requires a comptime-known function
test/cases/compile_errors/stage1/ptrToInt_with_pointer_to_zero-sized_type.zig created+11
......@@ -0,0 +1,11 @@
1export fn entry() void {
2 var pointer: ?*u0 = null;
3 var x = @ptrToInt(pointer);
4 _ = x;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:23: error: pointer to size 0 type has no address
test/cases/compile_errors/stage1/test/alignCast_of_zero_sized_types.zig deleted-28
......@@ -1,28 +0,0 @@
1export fn foo() void {
2 const a: *void = undefined;
3 _ = @alignCast(2, a);
4}
5export fn bar() void {
6 const a: ?*void = undefined;
7 _ = @alignCast(2, a);
8}
9export fn baz() void {
10 const a: []void = undefined;
11 _ = @alignCast(2, a);
12}
13export fn qux() void {
14 const a = struct {
15 fn a(comptime b: u32) void { _ = b; }
16 }.a;
17 _ = @alignCast(2, a);
18}
19
20// error
21// backend=stage1
22// target=native
23// is_test=1
24//
25// tmp.zig:3:23: error: cannot adjust alignment of zero sized type '*void'
26// tmp.zig:7:23: error: cannot adjust alignment of zero sized type '?*void'
27// tmp.zig:11:23: error: cannot adjust alignment of zero sized type '[]void'
28// tmp.zig:17:23: error: cannot adjust alignment of zero sized type 'fn(u32) anytype'
test/cases/compile_errors/stage1/test/call_rejects_non_comptime-known_fn-always_inline.zig deleted-11
......@@ -1,11 +0,0 @@
1pub export fn entry() void {
2 var call_me: fn () void = undefined;
3 @call(.{ .modifier = .always_inline }, call_me, .{});
4}
5
6// error
7// backend=stage1
8// target=native
9// is_test=1
10//
11// tmp.zig:3:5: error: the specified modifier requires a comptime-known function
test/cases/compile_errors/stage1/test/call_rejects_non_comptime-known_fn-compile_time.zig deleted-11
......@@ -1,11 +0,0 @@
1pub export fn entry() void {
2 var call_me: fn () void = undefined;
3 @call(.{ .modifier = .compile_time }, call_me, .{});
4}
5
6// error
7// backend=stage1
8// target=native
9// is_test=1
10//
11// tmp.zig:3:5: error: the specified modifier requires a comptime-known function
test/cases/compile_errors/stage1/test/comparison_of_non-tagged_union_and_enum_literal.zig deleted-14
......@@ -1,14 +0,0 @@
1export fn entry() void {
2 const U = union { A: u32, B: u64 };
3 var u = U{ .A = 42 };
4 var ok = u == .A;
5 _ = ok;
6}
7
8// error
9// backend=stage1
10// target=native
11// is_test=1
12//
13// tmp.zig:4:16: error: comparison of union and enum literal is only valid for tagged union types
14// tmp.zig:2:15: note: type U is not a tagged union
test/cases/compile_errors/stage1/test/ptrToInt_with_pointer_to_zero-sized_type.zig deleted-12
......@@ -1,12 +0,0 @@
1export fn entry() void {
2 var pointer: ?*u0 = null;
3 var x = @ptrToInt(pointer);
4 _ = x;
5}
6
7// error
8// backend=stage1
9// target=native
10// is_test=1
11//
12// tmp.zig:3:23: error: pointer to size 0 type has no address