Commit db890dbae7

mlugg <mlugg@mlugg.co.uk>
2024-05-02 02:59:38
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
1 parent 5bbb2f9
Changed files (6)
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),
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,
 
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())) {
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);
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,
 
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,