mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-07 14:24:43 +00:00
Sema: improve @call errors
This commit is contained in:
parent
3204d00a5e
commit
03b356e34a
9 changed files with 77 additions and 75 deletions
36
src/Sema.zig
36
src/Sema.zig
|
|
@ -5231,6 +5231,10 @@ fn analyzeCall(
|
||||||
.async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),
|
.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;
|
const gpa = sema.gpa;
|
||||||
|
|
||||||
var is_generic_call = func_ty_info.is_generic;
|
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 result: Air.Inst.Ref = if (is_inline_call) res: {
|
||||||
const func_val = try sema.resolveConstValue(block, func_src, func);
|
const func_val = try sema.resolveConstValue(block, func_src, func);
|
||||||
const module_fn = switch (func_val.tag()) {
|
const module_fn = switch (func_val.tag()) {
|
||||||
|
|
@ -11612,8 +11620,13 @@ fn analyzeCmpUnionTag(
|
||||||
) CompileError!Air.Inst.Ref {
|
) CompileError!Air.Inst.Ref {
|
||||||
const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un));
|
const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un));
|
||||||
const union_tag_ty = union_ty.unionTagType() orelse {
|
const union_tag_ty = union_ty.unionTagType() orelse {
|
||||||
// TODO note at declaration site that says "union foo is not tagged"
|
const msg = msg: {
|
||||||
return sema.fail(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
|
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
|
// Coerce both the union and the tag to the union's tag type, and then execute the
|
||||||
// enum comparison codepath.
|
// 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);
|
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) {
|
const modifier: std.builtin.CallOptions.Modifier = switch (wanted_modifier) {
|
||||||
// These can be upgraded to comptime or nosuspend calls.
|
// These can be upgraded to comptime or nosuspend calls.
|
||||||
.auto, .never_tail, .no_async => m: {
|
.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;
|
break :m .compile_time;
|
||||||
}
|
}
|
||||||
if (extra.flags.is_nosuspend) {
|
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.
|
// These can be upgraded to comptime. nosuspend bit can be safely ignored.
|
||||||
.always_tail, .always_inline, .compile_time => m: {
|
.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 .compile_time;
|
||||||
}
|
}
|
||||||
break :m wanted_modifier;
|
break :m wanted_modifier;
|
||||||
|
|
@ -16900,14 +16922,14 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||||
if (extra.flags.is_nosuspend) {
|
if (extra.flags.is_nosuspend) {
|
||||||
return sema.fail(block, options_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
|
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", .{});
|
return sema.fail(block, options_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
|
||||||
}
|
}
|
||||||
break :m wanted_modifier;
|
break :m wanted_modifier;
|
||||||
},
|
},
|
||||||
.never_inline => m: {
|
.never_inline => m: {
|
||||||
if (extra.flags.is_comptime) {
|
if (is_comptime) {
|
||||||
return sema.fail(block, options_src, "modifier 'never_inline' cannot be used in combination with comptime function call", .{});
|
return sema.fail(block, options_src, "unable to perform 'never_inline' call at compile-time", .{});
|
||||||
}
|
}
|
||||||
break :m wanted_modifier;
|
break :m wanted_modifier;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
35
test/cases/compile_errors/bad_usage_of_call.zig
Normal file
35
test/cases/compile_errors/bad_usage_of_call.zig
Normal 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
|
||||||
|
|
@ -20,7 +20,6 @@ export fn qux() void {
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage1
|
||||||
// target=native
|
// target=native
|
||||||
// is_test=1
|
|
||||||
//
|
//
|
||||||
// tmp.zig:3:23: error: cannot adjust alignment of zero sized type '*void'
|
// 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'
|
// tmp.zig:7:23: error: cannot adjust alignment of zero sized type '?*void'
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -7,6 +7,5 @@ export fn entry() void {
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage1
|
||||||
// target=native
|
// target=native
|
||||||
// is_test=1
|
|
||||||
//
|
//
|
||||||
// tmp.zig:3:23: error: pointer to size 0 type has no address
|
// tmp.zig:3:23: error: pointer to size 0 type has no address
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Add table
Reference in a new issue