diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-12-27 17:56:33 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-12-27 17:56:33 -0700 |
| commit | 9dd4fb4130a71d2aaaaa361d8ee0b7135cb84162 (patch) | |
| tree | 569ebd4a536b1df12976d6c6c19e3725ef6b7e98 | |
| parent | 886df772f06377df95f867e8b18ee47bbd0fcd8b (diff) | |
| download | zig-9dd4fb4130a71d2aaaaa361d8ee0b7135cb84162.tar.gz zig-9dd4fb4130a71d2aaaaa361d8ee0b7135cb84162.zip | |
stage2: fix 0-bit function parameters
Before this commit, Zig would incorrectly emit `arg` AIR instructions
for parameters whose types were 0-bit.
| -rw-r--r-- | src/Module.zig | 24 | ||||
| -rw-r--r-- | src/Sema.zig | 8 | ||||
| -rw-r--r-- | test/behavior/enum_llvm.zig | 32 | ||||
| -rw-r--r-- | test/behavior/enum_stage1.zig | 32 |
4 files changed, 54 insertions, 42 deletions
diff --git a/src/Module.zig b/src/Module.zig index 25e262855c..2c5c01bb7a 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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)); diff --git a/src/Sema.zig b/src/Sema.zig index d273d1d6e8..f1431272db 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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, diff --git a/test/behavior/enum_llvm.zig b/test/behavior/enum_llvm.zig index c0d536c029..700e396087 100644 --- a/test/behavior/enum_llvm.zig +++ b/test/behavior/enum_llvm.zig @@ -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); +} diff --git a/test/behavior/enum_stage1.zig b/test/behavior/enum_stage1.zig index 59c1b93586..50955d4388 100644 --- a/test/behavior/enum_stage1.zig +++ b/test/behavior/enum_stage1.zig @@ -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, |
