Sema: improve @call errors

This commit is contained in:
Veikka Tuominen 2022-06-28 16:43:09 +03:00 committed by Jakub Konka
parent 3204d00a5e
commit 03b356e34a
9 changed files with 77 additions and 75 deletions

View file

@ -5231,6 +5231,10 @@ fn analyzeCall(
.async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),
};
if (modifier == .never_inline and func_ty_info.cc == .Inline) {
return sema.fail(block, call_src, "no-inline call of inline function", .{});
}
const gpa = sema.gpa;
var is_generic_call = func_ty_info.is_generic;
@ -5270,6 +5274,10 @@ fn analyzeCall(
}
}
if (is_comptime_call and modifier == .never_inline) {
return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{});
}
const result: Air.Inst.Ref = if (is_inline_call) res: {
const func_val = try sema.resolveConstValue(block, func_src, func);
const module_fn = switch (func_val.tag()) {
@ -11612,8 +11620,13 @@ fn analyzeCmpUnionTag(
) CompileError!Air.Inst.Ref {
const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un));
const union_tag_ty = union_ty.unionTagType() orelse {
// TODO note at declaration site that says "union foo is not tagged"
return sema.fail(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
const msg = msg: {
const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
errdefer msg.destroy(sema.gpa);
try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
};
// Coerce both the union and the tag to the union's tag type, and then execute the
// enum comparison codepath.
@ -16878,10 +16891,15 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
break :modifier modifier_val.toEnum(std.builtin.CallOptions.Modifier);
};
const is_comptime = extra.flags.is_comptime or block.is_comptime;
const modifier: std.builtin.CallOptions.Modifier = switch (wanted_modifier) {
// These can be upgraded to comptime or nosuspend calls.
.auto, .never_tail, .no_async => m: {
if (extra.flags.is_comptime) {
if (is_comptime) {
if (wanted_modifier == .never_tail) {
return sema.fail(block, options_src, "unable to perform 'never_tail' call at compile-time", .{});
}
break :m .compile_time;
}
if (extra.flags.is_nosuspend) {
@ -16891,7 +16909,11 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
},
// These can be upgraded to comptime. nosuspend bit can be safely ignored.
.always_tail, .always_inline, .compile_time => m: {
if (extra.flags.is_comptime) {
_ = (try sema.resolveDefinedValue(block, func_src, func)) orelse {
return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)});
};
if (is_comptime) {
break :m .compile_time;
}
break :m wanted_modifier;
@ -16900,14 +16922,14 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (extra.flags.is_nosuspend) {
return sema.fail(block, options_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
}
if (extra.flags.is_comptime) {
if (is_comptime) {
return sema.fail(block, options_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
}
break :m wanted_modifier;
},
.never_inline => m: {
if (extra.flags.is_comptime) {
return sema.fail(block, options_src, "modifier 'never_inline' cannot be used in combination with comptime function call", .{});
if (is_comptime) {
return sema.fail(block, options_src, "unable to perform 'never_inline' call at compile-time", .{});
}
break :m wanted_modifier;
},

View file

@ -0,0 +1,13 @@
export fn entry() void {
const U = union { A: u32, B: u64 };
var u = U{ .A = 42 };
var ok = u == .A;
_ = ok;
}
// error
// backend=stage2
// target=native
//
// :4:14: error: comparison of union and enum literal is only valid for tagged union types
// :2:15: note: union 'tmp.entry.U' is not a tagged union

View file

@ -0,0 +1,35 @@
export fn entry1() void {
@call(.{}, foo, {});
}
export fn entry2() void {
comptime @call(.{ .modifier = .never_inline }, foo, .{});
}
export fn entry3() void {
comptime @call(.{ .modifier = .never_tail }, foo, .{});
}
export fn entry4() void {
@call(.{ .modifier = .never_inline }, bar, .{});
}
export fn entry5(c: bool) void {
var baz = if (c) &baz1 else &baz2;
@call(.{ .modifier = .compile_time }, baz, .{});
}
pub export fn entry() void {
var call_me: *const fn () void = undefined;
@call(.{ .modifier = .always_inline }, call_me, .{});
}
fn foo() void {}
fn bar() callconv(.Inline) void {}
fn baz1() void {}
fn baz2() void {}
// error
// backend=stage2
// target=native
//
// :2:21: error: expected a tuple, found 'void'
// :5:21: error: unable to perform 'never_inline' call at compile-time
// :8:21: error: unable to perform 'never_tail' call at compile-time
// :11:5: error: no-inline call of inline function
// :15:43: error: modifier 'compile_time' requires a comptime-known function
// :19:44: error: modifier 'always_inline' requires a comptime-known function

View file

@ -20,7 +20,6 @@ export fn qux() void {
// error
// backend=stage1
// target=native
// is_test=1
//
// tmp.zig:3:23: error: cannot adjust alignment of zero sized type '*void'
// tmp.zig:7:23: error: cannot adjust alignment of zero sized type '?*void'

View file

@ -1,30 +0,0 @@
export fn entry1() void {
@call(.{}, foo, {});
}
export fn entry2() void {
comptime @call(.{ .modifier = .never_inline }, foo, .{});
}
export fn entry3() void {
comptime @call(.{ .modifier = .never_tail }, foo, .{});
}
export fn entry4() void {
@call(.{ .modifier = .never_inline }, bar, .{});
}
export fn entry5(c: bool) void {
var baz = if (c) baz1 else baz2;
@call(.{ .modifier = .compile_time }, baz, .{});
}
fn foo() void {}
fn bar() callconv(.Inline) void {}
fn baz1() void {}
fn baz2() void {}
// error
// backend=stage1
// target=native
//
// tmp.zig:2:21: error: expected tuple or struct, found 'void'
// tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time
// tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time
// tmp.zig:11:5: error: no-inline call of inline function
// tmp.zig:15:5: error: the specified modifier requires a comptime-known function

View file

@ -7,6 +7,5 @@ export fn entry() void {
// error
// backend=stage1
// target=native
// is_test=1
//
// tmp.zig:3:23: error: pointer to size 0 type has no address

View file

@ -1,11 +0,0 @@
pub export fn entry() void {
var call_me: fn () void = undefined;
@call(.{ .modifier = .always_inline }, call_me, .{});
}
// error
// backend=stage1
// target=native
// is_test=1
//
// tmp.zig:3:5: error: the specified modifier requires a comptime-known function

View file

@ -1,11 +0,0 @@
pub export fn entry() void {
var call_me: fn () void = undefined;
@call(.{ .modifier = .compile_time }, call_me, .{});
}
// error
// backend=stage1
// target=native
// is_test=1
//
// tmp.zig:3:5: error: the specified modifier requires a comptime-known function

View file

@ -1,14 +0,0 @@
export fn entry() void {
const U = union { A: u32, B: u64 };
var u = U{ .A = 42 };
var ok = u == .A;
_ = ok;
}
// error
// backend=stage1
// target=native
// is_test=1
//
// tmp.zig:4:16: error: comparison of union and enum literal is only valid for tagged union types
// tmp.zig:2:15: note: type U is not a tagged union