mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
stage2: fix 0-bit function parameters
Before this commit, Zig would incorrectly emit `arg` AIR instructions for parameters whose types were 0-bit.
This commit is contained in:
parent
886df772f0
commit
9dd4fb4130
@ -4327,16 +4327,16 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
|
||||
var runtime_param_index: usize = 0;
|
||||
var total_param_index: usize = 0;
|
||||
for (fn_info.param_body) |inst| {
|
||||
const name = switch (zir_tags[inst]) {
|
||||
const param: struct { name: u32, src: LazySrcLoc } = switch (zir_tags[inst]) {
|
||||
.param, .param_comptime => blk: {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
|
||||
const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data;
|
||||
break :blk extra.name;
|
||||
const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok;
|
||||
const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index).data;
|
||||
break :blk .{ .name = extra.name, .src = pl_tok.src() };
|
||||
},
|
||||
|
||||
.param_anytype, .param_anytype_comptime => blk: {
|
||||
const str_tok = sema.code.instructions.items(.data)[inst].str_tok;
|
||||
break :blk str_tok.start;
|
||||
break :blk .{ .name = str_tok.start, .src = str_tok.src() };
|
||||
},
|
||||
|
||||
else => continue,
|
||||
@ -4352,6 +4352,18 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
|
||||
}
|
||||
}
|
||||
const param_type = fn_ty.fnParamType(runtime_param_index);
|
||||
const opt_opv = sema.typeHasOnePossibleValue(&inner_block, param.src, param_type) catch |err| switch (err) {
|
||||
error.NeededSourceLocation => unreachable,
|
||||
error.GenericPoison => unreachable,
|
||||
error.ComptimeReturn => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
if (opt_opv) |opv| {
|
||||
const arg = try sema.addConstant(param_type, opv);
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
|
||||
total_param_index += 1;
|
||||
continue;
|
||||
}
|
||||
const ty_ref = try sema.addType(param_type);
|
||||
const arg_index = @intCast(u32, sema.air_instructions.len);
|
||||
inner_block.instructions.appendAssumeCapacity(arg_index);
|
||||
@ -4359,7 +4371,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
|
||||
.tag = .arg,
|
||||
.data = .{ .ty_str = .{
|
||||
.ty = ty_ref,
|
||||
.str = name,
|
||||
.str = param.name,
|
||||
} },
|
||||
});
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
|
||||
|
||||
@ -266,7 +266,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addBinOp(
|
||||
fn addBinOp(
|
||||
block: *Block,
|
||||
tag: Air.Inst.Tag,
|
||||
lhs: Air.Inst.Ref,
|
||||
@ -281,7 +281,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addArg(block: *Block, ty: Type, name: u32) error{OutOfMemory}!Air.Inst.Ref {
|
||||
fn addArg(block: *Block, ty: Type, name: u32) error{OutOfMemory}!Air.Inst.Ref {
|
||||
return block.addInst(.{
|
||||
.tag = .arg,
|
||||
.data = .{ .ty_str = .{
|
||||
@ -291,7 +291,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addStructFieldPtr(
|
||||
fn addStructFieldPtr(
|
||||
block: *Block,
|
||||
struct_ptr: Air.Inst.Ref,
|
||||
field_index: u32,
|
||||
@ -15339,7 +15339,7 @@ fn getBuiltinType(
|
||||
/// in `Sema` is for calling during semantic analysis, and performs field resolution
|
||||
/// to get the answer. The one in `Type` is for calling during codegen and asserts
|
||||
/// that the types are already resolved.
|
||||
fn typeHasOnePossibleValue(
|
||||
pub fn typeHasOnePossibleValue(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
|
||||
@ -90,3 +90,35 @@ fn getB(data: *const BitFieldOfEnums) B {
|
||||
fn getC(data: *const BitFieldOfEnums) C {
|
||||
return data.c;
|
||||
}
|
||||
|
||||
const EnumWithOneMember = enum { Eof };
|
||||
|
||||
fn doALoopThing(id: EnumWithOneMember) void {
|
||||
while (true) {
|
||||
if (id == EnumWithOneMember.Eof) {
|
||||
break;
|
||||
}
|
||||
@compileError("above if condition should be comptime");
|
||||
}
|
||||
}
|
||||
|
||||
test "comparison operator on enum with one member is comptime known" {
|
||||
doALoopThing(EnumWithOneMember.Eof);
|
||||
}
|
||||
|
||||
const State = enum { Start };
|
||||
test "switch on enum with one member is comptime known" {
|
||||
var state = State.Start;
|
||||
switch (state) {
|
||||
State.Start => return,
|
||||
}
|
||||
@compileError("analysis should not reach here");
|
||||
}
|
||||
|
||||
test "enum literal in array literal" {
|
||||
const Items = enum { one, two };
|
||||
const array = [_]Items{ .one, .two };
|
||||
|
||||
try expect(array[0] == .one);
|
||||
try expect(array[1] == .two);
|
||||
}
|
||||
|
||||
@ -2,38 +2,6 @@ const expect = @import("std").testing.expect;
|
||||
const mem = @import("std").mem;
|
||||
const Tag = @import("std").meta.Tag;
|
||||
|
||||
const EnumWithOneMember = enum { Eof };
|
||||
|
||||
fn doALoopThing(id: EnumWithOneMember) void {
|
||||
while (true) {
|
||||
if (id == EnumWithOneMember.Eof) {
|
||||
break;
|
||||
}
|
||||
@compileError("above if condition should be comptime");
|
||||
}
|
||||
}
|
||||
|
||||
test "comparison operator on enum with one member is comptime known" {
|
||||
doALoopThing(EnumWithOneMember.Eof);
|
||||
}
|
||||
|
||||
const State = enum { Start };
|
||||
test "switch on enum with one member is comptime known" {
|
||||
var state = State.Start;
|
||||
switch (state) {
|
||||
State.Start => return,
|
||||
}
|
||||
@compileError("analysis should not reach here");
|
||||
}
|
||||
|
||||
test "enum literal in array literal" {
|
||||
const Items = enum { one, two };
|
||||
const array = [_]Items{ .one, .two };
|
||||
|
||||
try expect(array[0] == .one);
|
||||
try expect(array[1] == .two);
|
||||
}
|
||||
|
||||
test "enum value allocation" {
|
||||
const LargeEnum = enum(u32) {
|
||||
A0 = 0x80000000,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user