From db890dbae72bc31e50d4ec641f2afce683df772d Mon Sep 17 00:00:00 2001 From: mlugg Date: Thu, 2 May 2024 01:59:38 +0100 Subject: [PATCH] InternPool: eliminate `var_args_param_type` This was a "fake" type used to handle C varargs parameters, much like generic poison. In fact, it is treated identically to generic poison in all cases other than one (the final coercion of a call argument), which is trivially special-cased. Thus, it makes sense to remove this special tag and instead use `generic_poison_type` in its place. This fixes several bugs in Sema related to missing handling of this tag. Resolves: #19781 --- lib/std/zig/Zir.zig | 3 --- src/Air.zig | 10 ++-------- src/InternPool.zig | 4 ---- src/Sema.zig | 31 +++++++++++++------------------ src/codegen/c/Type.zig | 1 - src/codegen/llvm.zig | 1 - 6 files changed, 15 insertions(+), 35 deletions(-) diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 64e8a1c805..9453790fcf 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -2194,9 +2194,6 @@ pub const Inst = struct { empty_struct, generic_poison, - /// This tag is here to match Air and InternPool, however it is unused - /// for ZIR purposes. - var_args_param_type = std.math.maxInt(u32) - 1, /// This Ref does not correspond to any ZIR instruction or constant /// value and may instead be used as a sentinel to indicate null. none = std.math.maxInt(u32), diff --git a/src/Air.zig b/src/Air.zig index 9554c55561..16c20f5a18 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -891,8 +891,7 @@ pub const Inst = struct { /// The most-significant bit of the value is a tag bit. This bit is 1 if the value represents an /// instruction index and 0 if it represents an InternPool index. /// - /// The hardcoded refs `none` and `var_args_param_type` are exceptions to this rule: they have - /// their tag bit set but refer to the InternPool. + /// The ref `none` is an exception: it has the tag bit set but refers to the InternPool. pub const Ref = enum(u32) { u0_type = @intFromEnum(InternPool.Index.u0_type), i0_type = @intFromEnum(InternPool.Index.i0_type), @@ -979,9 +978,6 @@ pub const Inst = struct { empty_struct = @intFromEnum(InternPool.Index.empty_struct), generic_poison = @intFromEnum(InternPool.Index.generic_poison), - /// This Ref does not correspond to any AIR instruction or constant - /// value. It is used to handle argument types of var args functions. - var_args_param_type = @intFromEnum(InternPool.Index.var_args_param_type), /// This Ref does not correspond to any AIR instruction or constant /// value and may instead be used as a sentinel to indicate null. none = @intFromEnum(InternPool.Index.none), @@ -994,7 +990,6 @@ pub const Inst = struct { pub fn toInternedAllowNone(ref: Ref) ?InternPool.Index { return switch (ref) { - .var_args_param_type => .var_args_param_type, .none => .none, else => if (@intFromEnum(ref) >> 31 == 0) @enumFromInt(@as(u31, @truncate(@intFromEnum(ref)))) @@ -1010,7 +1005,7 @@ pub const Inst = struct { pub fn toIndexAllowNone(ref: Ref) ?Index { return switch (ref) { - .var_args_param_type, .none => null, + .none => null, else => if (@intFromEnum(ref) >> 31 != 0) @enumFromInt(@as(u31, @truncate(@intFromEnum(ref)))) else @@ -1557,7 +1552,6 @@ pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { pub fn internedToRef(ip_index: InternPool.Index) Inst.Ref { return switch (ip_index) { - .var_args_param_type => .var_args_param_type, .none => .none, else => { assert(@intFromEnum(ip_index) >> 31 == 0); diff --git a/src/InternPool.zig b/src/InternPool.zig index a63c81f2ba..b6d5e77f53 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -2818,7 +2818,6 @@ pub const Index = enum(u32) { generic_poison, /// Used by Air/Sema only. - var_args_param_type = std.math.maxInt(u32) - 1, none = std.math.maxInt(u32), _, @@ -8938,7 +8937,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { .memoized_call => unreachable, }, - .var_args_param_type => unreachable, .none => unreachable, }; } @@ -9153,8 +9151,6 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois .empty_struct => unreachable, .generic_poison => unreachable, - .var_args_param_type => unreachable, // special tag - _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) { .removed => unreachable, diff --git a/src/Sema.zig b/src/Sema.zig index 74cea620e3..86d3378aee 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1901,7 +1901,6 @@ pub fn resolveConstStringIntern( pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { const air_inst = try sema.resolveInst(zir_ref); - assert(air_inst != .var_args_param_type); const ty = try sema.analyzeAsType(block, src, air_inst); if (ty.isGenericPoison()) return error.GenericPoison; return ty; @@ -4572,12 +4571,10 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const src = un_tok.src(); // In case of GenericPoison, we don't actually have a type, so this will be // treated as an untyped address-of operator. - if (un_tok.operand == .var_args_param_type) return; const operand_air_inst = sema.resolveInst(un_tok.operand) catch |err| switch (err) { error.GenericPoison => return, else => |e| return e, }; - if (operand_air_inst == .var_args_param_type) return; const ty_operand = sema.analyzeAsType(block, src, operand_air_inst) catch |err| switch (err) { error.GenericPoison => return, else => |e| return e, @@ -7363,7 +7360,7 @@ const CallArgsInfo = union(enum) { } /// Analyzes the arg at `arg_index` and coerces it to `param_ty`. - /// `param_ty` may be `generic_poison` or `var_args_param`. + /// `param_ty` may be `generic_poison`. A value of `null` indicates a varargs parameter. /// `func_ty_info` may be the type before instantiation, even if a generic /// instantiation has been partially completed. fn analyzeArg( @@ -7371,16 +7368,16 @@ const CallArgsInfo = union(enum) { sema: *Sema, block: *Block, arg_index: usize, - param_ty: Type, + maybe_param_ty: ?Type, func_ty_info: InternPool.Key.FuncType, func_inst: Air.Inst.Ref, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const param_count = func_ty_info.param_types.len; - switch (param_ty.toIntern()) { - .generic_poison_type, .var_args_param_type => {}, + if (maybe_param_ty) |param_ty| switch (param_ty.toIntern()) { + .generic_poison_type => {}, else => try sema.queueFullTypeResolution(param_ty), - } + }; const uncoerced_arg: Air.Inst.Ref = switch (cai) { inline .resolved, .call_builtin => |resolved| resolved.args[arg_index], .zir_call => |zir_call| arg_val: { @@ -7409,7 +7406,8 @@ const CallArgsInfo = union(enum) { // TODO set comptime_reason } // Give the arg its result type - sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(param_ty.toIntern())); + const provide_param_ty = if (maybe_param_ty) |t| t else Type.generic_poison; + sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(provide_param_ty.toIntern())); // Resolve the arg! const uncoerced_arg = try sema.resolveInlineBody(block, arg_body, zir_call.call_inst); @@ -7426,9 +7424,11 @@ const CallArgsInfo = union(enum) { break :arg_val uncoerced_arg; }, }; + const param_ty = maybe_param_ty orelse { + return sema.coerceVarArgParam(block, uncoerced_arg, cai.argSrc(block, arg_index)); + }; switch (param_ty.toIntern()) { .generic_poison_type => return uncoerced_arg, - .var_args_param_type => return sema.coerceVarArgParam(block, uncoerced_arg, cai.argSrc(block, arg_index)), else => return sema.coerceExtra( block, param_ty, @@ -7970,10 +7970,10 @@ fn analyzeCall( const args = try sema.arena.alloc(Air.Inst.Ref, args_info.count()); for (args, 0..) |*arg_out, arg_idx| { // Non-generic, so param types are already resolved - const param_ty = if (arg_idx < func_ty_info.param_types.len) ty: { + const param_ty: ?Type = if (arg_idx < func_ty_info.param_types.len) ty: { break :ty Type.fromInterned(func_ty_info.param_types.get(ip)[arg_idx]); - } else Type.fromInterned(InternPool.Index.var_args_param_type); - assert(!param_ty.isGenericPoison()); + } else null; + if (param_ty) |t| assert(!t.isGenericPoison()); arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func); try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg_out.*); if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) { @@ -10226,12 +10226,10 @@ fn analyzeAs( ) CompileError!Air.Inst.Ref { const mod = sema.mod; const operand = try sema.resolveInst(zir_operand); - if (zir_dest_type == .var_args_param_type) return operand; const operand_air_inst = sema.resolveInst(zir_dest_type) catch |err| switch (err) { error.GenericPoison => return operand, else => |e| return e, }; - if (operand_air_inst == .var_args_param_type) return operand; const dest_ty = sema.analyzeAsType(block, src, operand_air_inst) catch |err| switch (err) { error.GenericPoison => return operand, else => |e| return e, @@ -35664,8 +35662,6 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { const ty_ip = ty.toIntern(); switch (ty_ip) { - .var_args_param_type => unreachable, - .none => unreachable, .u0_type, @@ -37184,7 +37180,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .empty_struct, .generic_poison, // invalid - .var_args_param_type, .none, => unreachable, diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig index 5068073f32..e6a9dc69a3 100644 --- a/src/codegen/c/Type.zig +++ b/src/codegen/c/Type.zig @@ -1468,7 +1468,6 @@ pub const Pool = struct { .bool_false, .empty_struct, .generic_poison, - .var_args_param_type, .none, => unreachable, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 9be2316a55..3529e9f411 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3235,7 +3235,6 @@ pub const Object = struct { .bool_false, .empty_struct, .generic_poison, - .var_args_param_type, .none, => unreachable, else => switch (ip.indexToKey(t.toIntern())) {