diff --git a/src/Compilation.zig b/src/Compilation.zig index 30dbfe9ce1..efc95bfe25 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3556,7 +3556,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v .gpa = gpa, .module = module, .error_msg = null, - .decl_index = decl_index.toOptional(), + .pass = .{ .decl = decl_index }, .is_naked_fn = false, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = .{}, diff --git a/src/Sema.zig b/src/Sema.zig index 922ae64861..2970e1f77b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5466,21 +5466,30 @@ fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref { .ty = array_ty.toIntern(), .storage = .{ .bytes = bytes }, } }); - const ptr_ty = try sema.ptrType(.{ - .child = array_ty.toIntern(), + return anonDeclRef(sema, val); +} + +fn anonDeclRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref { + return Air.internedToRef(try refValue(sema, val)); +} + +fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index { + const mod = sema.mod; + const ptr_ty = (try sema.ptrType(.{ + .child = mod.intern_pool.typeOf(val), .flags = .{ .alignment = .none, .is_const = true, .address_space = .generic, }, - }); - return Air.internedToRef((try mod.intern(.{ .ptr = .{ - .ty = ptr_ty.toIntern(), + })).toIntern(); + return mod.intern(.{ .ptr = .{ + .ty = ptr_ty, .addr = .{ .anon_decl = .{ .val = val, - .orig_ty = ptr_ty.toIntern(), + .orig_ty = ptr_ty, } }, - } }))); + } }); } fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -10740,7 +10749,7 @@ const SwitchProngAnalysis = struct { return block.addStructFieldVal(spa.operand, field_index, field_ty); } } else if (capture_byref) { - return sema.addConstantMaybeRef(block, operand_ty, item_val, true); + return anonDeclRef(sema, item_val.toIntern()); } else { return inline_case_capture; } @@ -13765,10 +13774,10 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const coerced_elem_val = try sema.resolveConstValue(block, .unneeded, coerced_elem_val_inst, undefined); element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); } - return sema.addConstantMaybeRef(block, result_ty, (try mod.intern(.{ .aggregate = .{ + return sema.addConstantMaybeRef(try mod.intern(.{ .aggregate = .{ .ty = result_ty.toIntern(), .storage = .{ .elems = element_vals }, - } })).toValue(), ptr_addrspace != null); + } }), ptr_addrspace != null); } else break :rs rhs_src; } else lhs_src; @@ -14034,7 +14043,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .storage = .{ .elems = element_vals }, } }); }; - return sema.addConstantMaybeRef(block, result_ty, val.toValue(), ptr_addrspace != null); + return sema.addConstantMaybeRef(val, ptr_addrspace != null); } try sema.requireRuntimeBlock(block, src, lhs_src); @@ -16724,54 +16733,49 @@ fn zirBuiltinSrc( const src = LazySrcLoc.nodeOffset(extra.node); if (sema.func_index == .none) return sema.fail(block, src, "@src outside function", .{}); const fn_owner_decl = mod.funcOwnerDeclPtr(sema.func_index); + const ip = &mod.intern_pool; + const gpa = sema.gpa; - const func_name_val = blk: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - // TODO: write something like getCoercedInts to avoid needing to dupe - const name = try sema.arena.dupe(u8, mod.intern_pool.stringToSlice(fn_owner_decl.name)); - const new_decl_ty = try mod.arrayType(.{ - .len = name.len, + const func_name_val = v: { + // This dupe prevents InternPool string pool memory from being reallocated + // while a reference exists. + const bytes = try sema.arena.dupe(u8, ip.stringToSlice(fn_owner_decl.name)); + const array_ty = try ip.get(gpa, .{ .array_type = .{ + .len = bytes.len, .sentinel = .zero_u8, .child = .u8_type, - }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); - break :blk try mod.intern(.{ .ptr = .{ + } }); + break :v try ip.get(gpa, .{ .ptr = .{ .ty = .slice_const_u8_sentinel_0_type, - .addr = .{ .decl = new_decl }, - .len = (try mod.intValue(Type.usize, name.len)).toIntern(), + .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(), + .addr = .{ .anon_decl = .{ + .orig_ty = .slice_const_u8_sentinel_0_type, + .val = try ip.get(gpa, .{ .aggregate = .{ + .ty = array_ty, + .storage = .{ .bytes = bytes }, + } }), + } }, } }); }; - const file_name_val = blk: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); + const file_name_val = v: { // The compiler must not call realpath anywhere. - const name = try fn_owner_decl.getFileScope(mod).fullPathZ(sema.arena); - const new_decl_ty = try mod.arrayType(.{ - .len = name.len, + const bytes = try fn_owner_decl.getFileScope(mod).fullPathZ(sema.arena); + const array_ty = try ip.get(gpa, .{ .array_type = .{ + .len = bytes.len, .sentinel = .zero_u8, .child = .u8_type, - }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); - break :blk try mod.intern(.{ .ptr = .{ + } }); + break :v try ip.get(gpa, .{ .ptr = .{ .ty = .slice_const_u8_sentinel_0_type, - .addr = .{ .decl = new_decl }, - .len = (try mod.intValue(Type.usize, name.len)).toIntern(), + .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(), + .addr = .{ .anon_decl = .{ + .orig_ty = .slice_const_u8_sentinel_0_type, + .val = try ip.get(gpa, .{ .aggregate = .{ + .ty = array_ty, + .storage = .{ .bytes = bytes }, + } }), + } }, } }); }; @@ -16818,10 +16822,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .val = .void_value, } }))), .Fn => { - // TODO: look into memoizing this result. - var params_anon_decl = try block.startAnonDecl(); - defer params_anon_decl.deinit(); - const fn_info_decl_index = (try sema.namespaceLookup( block, src, @@ -16878,23 +16878,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .len = param_vals.len, .child = param_info_ty.toIntern(), }); - const new_decl = try params_anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .elems = param_vals }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .elems = param_vals }, + } }); + const ptr_ty = (try sema.ptrType(.{ + .child = param_info_ty.toIntern(), + .flags = .{ + .size = .Slice, + .is_const = true, + }, + })).toIntern(); break :v try mod.intern(.{ .ptr = .{ - .ty = (try sema.ptrType(.{ - .child = param_info_ty.toIntern(), - .flags = .{ - .size = .Slice, - .is_const = true, - }, - })).toIntern(), - .addr = .{ .decl = new_decl }, + .ty = ptr_ty, + .addr = .{ .anon_decl = .{ + .orig_ty = ptr_ty, + .val = new_decl_val, + } }, .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(), } }); }; @@ -17035,7 +17035,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // is_allowzero: bool, Value.makeBool(info.flags.is_allowzero).toIntern(), // sentinel: ?*const anyopaque, - (try sema.optRefValue(block, info.child.toType(), switch (info.sentinel) { + (try sema.optRefValue(switch (info.sentinel) { .none => null, else => info.sentinel.toValue(), })).toIntern(), @@ -17070,7 +17070,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // child: type, info.elem_type.toIntern(), // sentinel: ?*const anyopaque, - (try sema.optRefValue(block, info.elem_type, info.sentinel)).toIntern(), + (try sema.optRefValue(info.sentinel)).toIntern(), }; return Air.internedToRef((try mod.intern(.{ .un = .{ .ty = type_info_ty.toIntern(), @@ -17139,9 +17139,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .ErrorSet => { - var fields_anon_decl = try block.startAnonDecl(); - defer fields_anon_decl.deinit(); - // Get the Error type const error_field_ty = t: { const set_field_ty_decl_index = (try sema.namespaceLookup( @@ -17170,23 +17167,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // TODO: write something like getCoercedInts to avoid needing to dupe const name = try sema.arena.dupe(u8, ip.stringToSlice(names.get(ip)[i])); const name_val = v: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .bytes = name }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = .slice_const_u8_type, - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .val = new_decl_val, + .orig_ty = .slice_const_u8_type, + } }, .len = (try mod.intValue(Type.usize, name.len)).toIntern(), } }); }; @@ -17219,17 +17213,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .len = vals.len, .child = error_field_ty.toIntern(), }); - const new_decl = try fields_anon_decl.finish( - array_errors_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = array_errors_ty.toIntern(), - .storage = .{ .elems = vals }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = array_errors_ty.toIntern(), + .storage = .{ .elems = vals }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = slice_errors_ty.toIntern(), - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .orig_ty = slice_errors_ty.toIntern(), + .val = new_decl_val, + } }, .len = (try mod.intValue(Type.usize, vals.len)).toIntern(), } }); } else .none; @@ -17275,12 +17268,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .Enum => { - // TODO: look into memoizing this result. const is_exhaustive = Value.makeBool(ip.indexToKey(ty.toIntern()).enum_type.tag_mode != .nonexhaustive); - var fields_anon_decl = try block.startAnonDecl(); - defer fields_anon_decl.deinit(); - const enum_field_ty = t: { const enum_field_ty_decl_index = (try sema.namespaceLookup( block, @@ -17308,23 +17297,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // TODO: write something like getCoercedInts to avoid needing to dupe const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i])); const name_val = v: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .bytes = name }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = .slice_const_u8_type, - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .val = new_decl_val, + .orig_ty = .slice_const_u8_type, + } }, .len = (try mod.intValue(Type.usize, name.len)).toIntern(), } }); }; @@ -17346,23 +17332,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .len = enum_field_vals.len, .child = enum_field_ty.toIntern(), }); - const new_decl = try fields_anon_decl.finish( - fields_array_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = fields_array_ty.toIntern(), - .storage = .{ .elems = enum_field_vals }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = fields_array_ty.toIntern(), + .storage = .{ .elems = enum_field_vals }, + } }); + const ptr_ty = (try sema.ptrType(.{ + .child = enum_field_ty.toIntern(), + .flags = .{ + .size = .Slice, + .is_const = true, + }, + })).toIntern(); break :v try mod.intern(.{ .ptr = .{ - .ty = (try sema.ptrType(.{ - .child = enum_field_ty.toIntern(), - .flags = .{ - .size = .Slice, - .is_const = true, - }, - })).toIntern(), - .addr = .{ .decl = new_decl }, + .ty = ptr_ty, + .addr = .{ .anon_decl = .{ + .val = new_decl_val, + .orig_ty = ptr_ty, + } }, .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(), } }); }; @@ -17402,11 +17388,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .Union => { - // TODO: look into memoizing this result. - - var fields_anon_decl = try block.startAnonDecl(); - defer fields_anon_decl.deinit(); - const type_union_ty = t: { const type_union_ty_decl_index = (try sema.namespaceLookup( block, @@ -17444,23 +17425,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // TODO: write something like getCoercedInts to avoid needing to dupe const name = try sema.arena.dupe(u8, ip.stringToSlice(union_obj.field_names.get(ip)[i])); const name_val = v: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .bytes = name }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = .slice_const_u8_type, - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .val = new_decl_val, + .orig_ty = .slice_const_u8_type, + } }, .len = (try mod.intValue(Type.usize, name.len)).toIntern(), } }); }; @@ -17490,23 +17468,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .len = union_field_vals.len, .child = union_field_ty.toIntern(), }); - const new_decl = try fields_anon_decl.finish( - array_fields_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = array_fields_ty.toIntern(), - .storage = .{ .elems = union_field_vals }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = array_fields_ty.toIntern(), + .storage = .{ .elems = union_field_vals }, + } }); + const ptr_ty = (try sema.ptrType(.{ + .child = union_field_ty.toIntern(), + .flags = .{ + .size = .Slice, + .is_const = true, + }, + })).toIntern(); break :v try mod.intern(.{ .ptr = .{ - .ty = (try sema.ptrType(.{ - .child = union_field_ty.toIntern(), - .flags = .{ - .size = .Slice, - .is_const = true, - }, - })).toIntern(), - .addr = .{ .decl = new_decl }, + .ty = ptr_ty, + .addr = .{ .anon_decl = .{ + .orig_ty = ptr_ty, + .val = new_decl_val, + } }, .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(), } }); }; @@ -17552,11 +17530,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .Struct => { - // TODO: look into memoizing this result. - - var fields_anon_decl = try block.startAnonDecl(); - defer fields_anon_decl.deinit(); - const type_struct_ty = t: { const type_struct_ty_decl_index = (try sema.namespaceLookup( block, @@ -17596,8 +17569,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const field_ty = anon_struct_type.types.get(ip)[i]; const field_val = anon_struct_type.values.get(ip)[i]; const name_val = v: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); // TODO: write something like getCoercedInts to avoid needing to dupe const bytes = if (tuple.names.len != 0) // https://github.com/ziglang/zig/issues/15709 @@ -17608,17 +17579,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .len = bytes.len, .child = .u8_type, }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = bytes }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .bytes = bytes }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = .slice_const_u8_type, - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .val = new_decl_val, + .orig_ty = .slice_const_u8_type, + } }, .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(), } }); }; @@ -17627,7 +17597,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const is_comptime = field_val != .none; const opt_default_val = if (is_comptime) field_val.toValue() else null; - const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val); + const default_val_ptr = try sema.optRefValue(opt_default_val); const struct_field_fields = .{ // name: []const u8, name_val, @@ -17662,29 +17632,26 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const field_init = struct_type.fieldInit(ip, i); const field_is_comptime = struct_type.fieldIsComptime(ip, i); const name_val = v: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .bytes = name }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = .slice_const_u8_type, - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .val = new_decl_val, + .orig_ty = .slice_const_u8_type, + } }, .len = (try mod.intValue(Type.usize, name.len)).toIntern(), } }); }; const opt_default_val = if (field_init == .none) null else field_init.toValue(); - const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); + const default_val_ptr = try sema.optRefValue(opt_default_val); const alignment = switch (struct_type.layout) { .Packed => .none, else => try sema.structFieldAlignment( @@ -17718,23 +17685,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .len = struct_field_vals.len, .child = struct_field_ty.toIntern(), }); - const new_decl = try fields_anon_decl.finish( - array_fields_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = array_fields_ty.toIntern(), - .storage = .{ .elems = struct_field_vals }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = array_fields_ty.toIntern(), + .storage = .{ .elems = struct_field_vals }, + } }); + const ptr_ty = (try sema.ptrType(.{ + .child = struct_field_ty.toIntern(), + .flags = .{ + .size = .Slice, + .is_const = true, + }, + })).toIntern(); break :v try mod.intern(.{ .ptr = .{ - .ty = (try sema.ptrType(.{ - .child = struct_field_ty.toIntern(), - .flags = .{ - .size = .Slice, - .is_const = true, - }, - })).toIntern(), - .addr = .{ .decl = new_decl }, + .ty = ptr_ty, + .addr = .{ .anon_decl = .{ + .orig_ty = ptr_ty, + .val = new_decl_val, + } }, .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(), } }); }; @@ -17786,8 +17753,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .Opaque => { - // TODO: look into memoizing this result. - const type_opaque_ty = t: { const type_opaque_ty_decl_index = (try sema.namespaceLookup( block, @@ -17832,9 +17797,6 @@ fn typeInfoDecls( const mod = sema.mod; const gpa = sema.gpa; - var decls_anon_decl = try block.startAnonDecl(); - defer decls_anon_decl.deinit(); - const declaration_ty = t: { const declaration_ty_decl_index = (try sema.namespaceLookup( block, @@ -17864,23 +17826,23 @@ fn typeInfoDecls( .len = decl_vals.items.len, .child = declaration_ty.toIntern(), }); - const new_decl = try decls_anon_decl.finish( - array_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = array_decl_ty.toIntern(), - .storage = .{ .elems = decl_vals.items }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = array_decl_ty.toIntern(), + .storage = .{ .elems = decl_vals.items }, + } }); + const ptr_ty = (try sema.ptrType(.{ + .child = declaration_ty.toIntern(), + .flags = .{ + .size = .Slice, + .is_const = true, + }, + })).toIntern(); return try mod.intern(.{ .ptr = .{ - .ty = (try sema.ptrType(.{ - .child = declaration_ty.toIntern(), - .flags = .{ - .size = .Slice, - .is_const = true, - }, - })).toIntern(), - .addr = .{ .decl = new_decl }, + .ty = ptr_ty, + .addr = .{ .anon_decl = .{ + .orig_ty = ptr_ty, + .val = new_decl_val, + } }, .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(), } }); } @@ -17909,25 +17871,22 @@ fn typeInfoNamespaceDecls( } if (decl.kind != .named or !decl.is_pub) continue; const name_val = v: { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); // TODO: write something like getCoercedInts to avoid needing to dupe const name = try sema.arena.dupe(u8, ip.stringToSlice(decl.name)); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, }); - const new_decl = try anon_decl.finish( - new_decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = name }, - } })).toValue(), - .none, // default alignment - ); + const new_decl_val = try mod.intern(.{ .aggregate = .{ + .ty = new_decl_ty.toIntern(), + .storage = .{ .bytes = name }, + } }); break :v try mod.intern(.{ .ptr = .{ .ty = .slice_const_u8_type, - .addr = .{ .decl = new_decl }, + .addr = .{ .anon_decl = .{ + .orig_ty = .slice_const_u8_type, + .val = new_decl_val, + } }, .len = (try mod.intValue(Type.usize, name.len)).toIntern(), } }); }; @@ -19072,10 +19031,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is if (is_byref) { const init_val = (try sema.resolveValue(init_ref)).?; - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - const decl = try anon_decl.finish(init_ty, init_val, .none); - return sema.analyzeDeclRef(decl); + return anonDeclRef(sema, init_val.toIntern()); } else { return init_ref; } @@ -19298,7 +19254,7 @@ fn zirStructInit( } })).toValue(); const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); const final_val = (try sema.resolveValue(final_val_inst)).?; - return sema.addConstantMaybeRef(block, resolved_ty, final_val, is_ref); + return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); } if (try sema.typeRequiresComptime(resolved_ty)) { @@ -19458,7 +19414,7 @@ fn finishStructInit( } }); const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val), init_src); const final_val = (try sema.resolveValue(final_val_inst)).?; - return sema.addConstantMaybeRef(block, result_ty, final_val, is_ref); + return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); }; if (try sema.typeRequiresComptime(struct_ty)) { @@ -19611,7 +19567,7 @@ fn structInitAnon( .ty = tuple_ty, .storage = .{ .elems = values }, } }); - return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); + return sema.addConstantMaybeRef(tuple_val, is_ref); }; sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { @@ -19777,7 +19733,8 @@ fn zirArrayInit( .storage = .{ .elems = elem_vals }, } }); const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val), src); - return sema.addConstantMaybeRef(block, result_ty, (try sema.resolveValue(result_ref)).?, is_ref); + const result_val = (try sema.resolveValue(result_ref)).?; + return sema.addConstantMaybeRef(result_val.toIntern(), is_ref); }; sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { @@ -19896,7 +19853,7 @@ fn arrayInitAnon( .ty = tuple_ty, .storage = .{ .elems = values }, } }); - return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); + return sema.addConstantMaybeRef(tuple_val, is_ref); }; try sema.requireRuntimeBlock(block, src, runtime_src); @@ -19931,23 +19888,8 @@ fn arrayInitAnon( return block.addAggregateInit(tuple_ty.toType(), element_refs); } -fn addConstantMaybeRef( - sema: *Sema, - block: *Block, - ty: Type, - val: Value, - is_ref: bool, -) !Air.Inst.Ref { - if (!is_ref) return Air.internedToRef(val.toIntern()); - - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - const decl = try anon_decl.finish( - ty, - val, - .none, // default alignment - ); - return sema.analyzeDeclRef(decl); +fn addConstantMaybeRef(sema: *Sema, val: InternPool.Index, is_ref: bool) !Air.Inst.Ref { + return if (is_ref) anonDeclRef(sema, val) else Air.internedToRef(val); } fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -21429,28 +21371,9 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const ty = try sema.resolveType(block, ty_src, inst_data.operand); - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - var bytes = std.ArrayList(u8).init(sema.arena); - defer bytes.deinit(); try ty.print(bytes.writer(), mod); - - const decl_ty = try mod.arrayType(.{ - .len = bytes.items.len, - .sentinel = .zero_u8, - .child = .u8_type, - }); - const new_decl = try anon_decl.finish( - decl_ty, - (try mod.intern(.{ .aggregate = .{ - .ty = decl_ty.toIntern(), - .storage = .{ .bytes = bytes.items }, - } })).toValue(), - .none, // default alignment - ); - - return sema.analyzeDeclRef(new_decl); + return addStrLitNoAlias(sema, bytes.items); } fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -26333,13 +26256,8 @@ fn fieldPtr( switch (inner_ty.zigTypeTag(mod)) { .Array => { if (ip.stringEqlSlice(field_name, "len")) { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - return sema.analyzeDeclRef(try anon_decl.finish( - Type.usize, - try mod.intValue(Type.usize, inner_ty.arrayLen(mod)), - .none, // default alignment - )); + const int_val = try mod.intValue(Type.usize, inner_ty.arrayLen(mod)); + return anonDeclRef(sema, int_val.toIntern()); } else { return sema.fail( block, @@ -26448,20 +26366,14 @@ fn fieldPtr( else => unreachable, } - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); const error_set_type = if (!child_type.isAnyError(mod)) child_type else try mod.singleErrorSetType(field_name); - return sema.analyzeDeclRef(try anon_decl.finish( - error_set_type, - (try mod.intern(.{ .err = .{ - .ty = error_set_type.toIntern(), - .name = field_name, - } })).toValue(), - .none, // default alignment - )); + return anonDeclRef(sema, try mod.intern(.{ .err = .{ + .ty = error_set_type.toIntern(), + .name = field_name, + } })); }, .Union => { if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { @@ -26473,13 +26385,8 @@ fn fieldPtr( if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { const field_index_u32: u32 = @intCast(field_index); - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - return sema.analyzeDeclRef(try anon_decl.finish( - enum_ty, - try mod.enumValueFieldIndex(enum_ty, field_index_u32), - .none, // default alignment - )); + const idx_val = try mod.enumValueFieldIndex(enum_ty, field_index_u32); + return anonDeclRef(sema, idx_val.toIntern()); } } return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); @@ -26494,13 +26401,8 @@ fn fieldPtr( return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }; const field_index_u32: u32 = @intCast(field_index); - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - return sema.analyzeDeclRef(try anon_decl.finish( - child_type, - try mod.enumValueFieldIndex(child_type, field_index_u32), - .none, // default alignment - )); + const idx_val = try mod.enumValueFieldIndex(child_type, field_index_u32); + return anonDeclRef(sema, idx_val.toIntern()); }, .Struct, .Opaque => { if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { @@ -31669,31 +31571,13 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: InternPool.Index) CompileError!void }; } -fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { - const mod = sema.mod; - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - const decl = try anon_decl.finish( - ty, - val, - .none, // default alignment - ); - try sema.maybeQueueFuncBodyAnalysis(decl); - try mod.declareDeclDependency(sema.owner_decl_index, decl); - const result = try mod.intern(.{ .ptr = .{ - .ty = (try mod.singleConstPtrType(ty)).toIntern(), - .addr = .{ .decl = decl }, - } }); - return result.toValue(); -} - -fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value { +fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { const mod = sema.mod; const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque); return (try mod.intern(.{ .opt = .{ .ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(), .val = if (opt_val) |val| (try mod.getCoerced( - try sema.refValue(block, ty, val), + (try sema.refValue(val.toIntern())).toValue(), ptr_anyopaque_ty, )).toIntern() else .none, } })).toValue(); @@ -31755,15 +31639,8 @@ fn analyzeRef( switch (mod.intern_pool.indexToKey(val.toIntern())) { .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl), .func => |func| return sema.analyzeDeclRef(func.owner_decl), - else => {}, + else => return anonDeclRef(sema, val.toIntern()), } - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - return sema.analyzeDeclRef(try anon_decl.finish( - operand_ty, - val, - .none, // default alignment - )); } try sema.requireRuntimeBlock(block, src, null); @@ -36848,7 +36725,7 @@ fn analyzeComptimeAlloc( }, }); - var anon_decl = try block.startAnonDecl(); + var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl defer anon_decl.deinit(); const decl_index = try anon_decl.finish( diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 4a9258d155..83d921ed9f 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -522,7 +522,7 @@ pub const Object = struct { pub const DeclGen = struct { gpa: mem.Allocator, module: *Module, - decl_index: Decl.OptionalIndex, + pass: Pass, is_naked_fn: bool, /// This is a borrowed reference from `link.C`. fwd_decl: std.ArrayList(u8), @@ -533,10 +533,16 @@ pub const DeclGen = struct { anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock), aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), + pub const Pass = union(enum) { + decl: Decl.Index, + anon: InternPool.Index, + flush, + }; + fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { @setCold(true); const mod = dg.module; - const decl_index = dg.decl_index.unwrap().?; + const decl_index = dg.pass.decl; const decl = mod.declPtr(decl_index); const src = LazySrcLoc.nodeOffset(0); const src_loc = src.toSrcLoc(decl, mod); @@ -1284,11 +1290,14 @@ pub const DeclGen = struct { var index: usize = 0; while (index < ai.len) : (index += 1) { const elem_val = try val.elemValue(mod, index); - const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @as(u8, @intCast(elem_val.toUnsignedInt(mod))); + const elem_val_u8: u8 = if (elem_val.isUndef(mod)) + undefPattern(u8) + else + @intCast(elem_val.toUnsignedInt(mod)); try literal.writeChar(elem_val_u8); } if (ai.sentinel) |s| { - const s_u8 = @as(u8, @intCast(s.toUnsignedInt(mod))); + const s_u8: u8 = @intCast(s.toUnsignedInt(mod)); if (s_u8 != 0) try literal.writeChar(s_u8); } try literal.end(); @@ -1298,7 +1307,10 @@ pub const DeclGen = struct { while (index < ai.len) : (index += 1) { if (index != 0) try writer.writeByte(','); const elem_val = try val.elemValue(mod, index); - const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @as(u8, @intCast(elem_val.toUnsignedInt(mod))); + const elem_val_u8: u8 = if (elem_val.isUndef(mod)) + undefPattern(u8) + else + @intCast(elem_val.toUnsignedInt(mod)); try writer.print("'\\x{x}'", .{elem_val_u8}); } if (ai.sentinel) |s| { @@ -1566,18 +1578,11 @@ pub const DeclGen = struct { else => unreachable, } } - if (fn_decl.val.getFunction(mod)) |func| if (func.analysis(ip).is_cold) try w.writeAll("zig_cold "); + if (fn_decl.val.getFunction(mod)) |func| if (func.analysis(ip).is_cold) + try w.writeAll("zig_cold "); if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); - const trailing = try renderTypePrefix( - dg.decl_index, - store.*, - mod, - w, - fn_cty_idx, - .suffix, - .{}, - ); + const trailing = try renderTypePrefix(dg.pass, store.*, mod, w, fn_cty_idx, .suffix, .{}); try w.print("{}", .{trailing}); if (toCallingConvention(fn_info.cc)) |call_conv| { @@ -1597,7 +1602,7 @@ pub const DeclGen = struct { } try renderTypeSuffix( - dg.decl_index, + dg.pass, store.*, mod, w, @@ -1652,8 +1657,8 @@ pub const DeclGen = struct { fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void { const store = &dg.ctypes.set; const mod = dg.module; - _ = try renderTypePrefix(dg.decl_index, store.*, mod, w, idx, .suffix, .{}); - try renderTypeSuffix(dg.decl_index, store.*, mod, w, idx, .suffix, .{}); + _ = try renderTypePrefix(dg.pass, store.*, mod, w, idx, .suffix, .{}); + try renderTypeSuffix(dg.pass, store.*, mod, w, idx, .suffix, .{}); } const IntCastContext = union(enum) { @@ -1799,11 +1804,10 @@ pub const DeclGen = struct { .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}), } - const trailing = - try renderTypePrefix(dg.decl_index, store.*, mod, w, cty_idx, .suffix, qualifiers); + const trailing = try renderTypePrefix(dg.pass, store.*, mod, w, cty_idx, .suffix, qualifiers); try w.print("{}", .{trailing}); try dg.writeCValue(w, name); - try renderTypeSuffix(dg.decl_index, store.*, mod, w, cty_idx, .suffix, .{}); + try renderTypeSuffix(dg.pass, store.*, mod, w, cty_idx, .suffix, .{}); } fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { @@ -2070,7 +2074,7 @@ fn renderTypeName( } } fn renderTypePrefix( - decl: Decl.OptionalIndex, + pass: DeclGen.Pass, store: CType.Store.Set, mod: *Module, w: anytype, @@ -2128,7 +2132,7 @@ fn renderTypePrefix( => |tag| { const child_idx = cty.cast(CType.Payload.Child).?.data; const child_trailing = try renderTypePrefix( - decl, + pass, store, mod, w, @@ -2152,15 +2156,8 @@ fn renderTypePrefix( .vector, => { const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type; - const child_trailing = try renderTypePrefix( - decl, - store, - mod, - w, - child_idx, - .suffix, - qualifiers, - ); + const child_trailing = + try renderTypePrefix(pass, store, mod, w, child_idx, .suffix, qualifiers); switch (parent_fix) { .prefix => { try w.print("{}(", .{child_trailing}); @@ -2172,10 +2169,11 @@ fn renderTypePrefix( .fwd_anon_struct, .fwd_anon_union, - => if (decl.unwrap()) |decl_index| - try w.print("anon__{d}_{d}", .{ @intFromEnum(decl_index), idx }) - else - try renderTypeName(mod, w, idx, cty, ""), + => switch (pass) { + .decl => |decl_index| try w.print("decl__{d}_{d}", .{ @intFromEnum(decl_index), idx }), + .anon => |anon_decl| try w.print("anon__{d}_{d}", .{ @intFromEnum(anon_decl), idx }), + .flush => try renderTypeName(mod, w, idx, cty, ""), + }, .fwd_struct, .fwd_union, @@ -2201,7 +2199,7 @@ fn renderTypePrefix( .packed_struct, .packed_union, => return renderTypePrefix( - decl, + pass, store, mod, w, @@ -2214,7 +2212,7 @@ fn renderTypePrefix( .varargs_function, => { const child_trailing = try renderTypePrefix( - decl, + pass, store, mod, w, @@ -2241,7 +2239,7 @@ fn renderTypePrefix( return trailing; } fn renderTypeSuffix( - decl: Decl.OptionalIndex, + pass: DeclGen.Pass, store: CType.Store.Set, mod: *Module, w: anytype, @@ -2295,7 +2293,7 @@ fn renderTypeSuffix( .pointer_volatile, .pointer_const_volatile, => try renderTypeSuffix( - decl, + pass, store, mod, w, @@ -2314,7 +2312,7 @@ fn renderTypeSuffix( try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len}); try renderTypeSuffix( - decl, + pass, store, mod, w, @@ -2356,9 +2354,9 @@ fn renderTypeSuffix( if (need_comma) try w.writeAll(", "); need_comma = true; const trailing = - try renderTypePrefix(decl, store, mod, w, param_type, .suffix, qualifiers); + try renderTypePrefix(pass, store, mod, w, param_type, .suffix, qualifiers); if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i }); - try renderTypeSuffix(decl, store, mod, w, param_type, .suffix, .{}); + try renderTypeSuffix(pass, store, mod, w, param_type, .suffix, .{}); } switch (tag) { .function => {}, @@ -2372,7 +2370,7 @@ fn renderTypeSuffix( if (!need_comma) try w.writeAll("void"); try w.writeByte(')'); - try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix, .{}); + try renderTypeSuffix(pass, store, mod, w, data.return_type, .suffix, .{}); }, } } @@ -2392,9 +2390,9 @@ fn renderAggregateFields( .eq => {}, .gt => try writer.print("zig_align({}) ", .{field.alignas.toByteUnits()}), } - const trailing = try renderTypePrefix(.none, store, mod, writer, field.type, .suffix, .{}); + const trailing = try renderTypePrefix(.flush, store, mod, writer, field.type, .suffix, .{}); try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) }); - try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix, .{}); + try renderTypeSuffix(.flush, store, mod, writer, field.type, .suffix, .{}); try writer.writeAll(";\n"); } try writer.writeByteNTimes(' ', indent); @@ -2406,18 +2404,18 @@ pub fn genTypeDecl( writer: anytype, global_store: CType.Store.Set, global_idx: CType.Index, - decl: Decl.OptionalIndex, + pass: DeclGen.Pass, decl_store: CType.Store.Set, decl_idx: CType.Index, found_existing: bool, ) !void { const global_cty = global_store.indexToCType(global_idx); switch (global_cty.tag()) { - .fwd_anon_struct => if (decl != .none) { + .fwd_anon_struct => if (pass != .flush) { try writer.writeAll("typedef "); - _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{}); + _ = try renderTypePrefix(.flush, global_store, mod, writer, global_idx, .suffix, .{}); try writer.writeByte(' '); - _ = try renderTypePrefix(decl, decl_store, mod, writer, decl_idx, .suffix, .{}); + _ = try renderTypePrefix(pass, decl_store, mod, writer, decl_idx, .suffix, .{}); try writer.writeAll(";\n"); }, @@ -2435,7 +2433,15 @@ pub fn genTypeDecl( .fwd_union, => { const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data; - _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{}); + _ = try renderTypePrefix( + .flush, + global_store, + mod, + writer, + global_idx, + .suffix, + .{}, + ); try writer.writeAll("; // "); try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer); try writer.writeByte('\n'); @@ -2552,7 +2558,7 @@ fn genExports(o: *Object) !void { const mod = o.dg.module; const ip = &mod.intern_pool; - const decl_index = o.dg.decl_index.unwrap().?; + const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() }; const fwd = o.dg.fwd_decl.writer(); @@ -2692,7 +2698,7 @@ pub fn genFunc(f: *Function) !void { const o = &f.object; const mod = o.dg.module; const gpa = o.dg.gpa; - const decl_index = o.dg.decl_index.unwrap().?; + const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); const tv: TypedValue = .{ .ty = decl.ty, @@ -2779,7 +2785,7 @@ pub fn genDecl(o: *Object) !void { defer tracy.end(); const mod = o.dg.module; - const decl_index = o.dg.decl_index.unwrap().?; + const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() }; @@ -2825,13 +2831,13 @@ pub fn genDeclValue( alignment: Alignment, link_section: InternPool.OptionalNullTerminatedString, ) !void { + const mod = o.dg.module; const fwd_decl_writer = o.dg.fwd_decl.writer(); try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete); try fwd_decl_writer.writeAll(";\n"); - const mod = o.dg.module; const w = o.writer(); if (!is_global) try w.writeAll("static "); if (mod.intern_pool.stringToSliceUnwrap(link_section)) |s| @@ -2848,7 +2854,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { defer tracy.end(); const mod = dg.module; - const decl_index = dg.decl_index.unwrap().?; + const decl_index = dg.pass.decl; const decl = mod.declPtr(decl_index); const tv: TypedValue = .{ .ty = decl.ty, @@ -2861,7 +2867,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { const is_global = dg.declIsGlobal(tv); if (is_global) { try writer.writeAll("zig_extern "); - try dg.renderFunctionSignature(writer, dg.decl_index.unwrap().?, .complete, .{ .export_index = 0 }); + try dg.renderFunctionSignature(writer, dg.pass.decl, .complete, .{ .export_index = 0 }); try dg.fwd_decl.appendSlice(";\n"); } }, @@ -7279,7 +7285,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { const mod = f.object.dg.module; const inst_ty = f.typeOfIndex(inst); - const decl_index = f.object.dg.decl_index.unwrap().?; + const decl_index = f.object.dg.pass.decl; const decl = mod.declPtr(decl_index); const fn_cty = try f.typeToCType(decl.ty, .complete); const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len; diff --git a/src/link/C.zig b/src/link/C.zig index 1d5672cf11..ee1d437b00 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -158,9 +158,7 @@ pub fn updateFunc( const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); const gop = try self.decl_table.getOrPut(gpa, decl_index); - if (!gop.found_existing) { - gop.value_ptr.* = .{}; - } + if (!gop.found_existing) gop.value_ptr.* = .{}; const ctypes = &gop.value_ptr.ctypes; const lazy_fns = &gop.value_ptr.lazy_fns; const fwd_decl = &self.fwd_decl_buf; @@ -180,7 +178,7 @@ pub fn updateFunc( .gpa = gpa, .module = module, .error_msg = null, - .decl_index = decl_index.toOptional(), + .pass = .{ .decl = decl_index }, .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, @@ -235,7 +233,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void { .gpa = gpa, .module = module, .error_msg = null, - .decl_index = .none, + .pass = .{ .anon = anon_decl }, .is_naked_fn = false, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = .{}, @@ -302,7 +300,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi .gpa = gpa, .module = module, .error_msg = null, - .decl_index = decl_index.toOptional(), + .pass = .{ .decl = decl_index }, .is_naked_fn = false, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, @@ -438,14 +436,14 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes. // This ensures that every lazy CType.Index exactly matches the global CType.Index. assert(f.ctypes.count() == 0); - try self.flushCTypes(&f, .none, f.lazy_ctypes); + try self.flushCTypes(&f, .flush, f.lazy_ctypes); - for (self.anon_decls.values()) |decl_block| { - try self.flushCTypes(&f, .none, decl_block.ctypes); + for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| { + try self.flushCTypes(&f, .{ .anon = anon_decl }, decl_block.ctypes); } for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| { - try self.flushCTypes(&f, decl_index.toOptional(), decl_block.ctypes); + try self.flushCTypes(&f, .{ .decl = decl_index }, decl_block.ctypes); } } @@ -516,7 +514,7 @@ const FlushDeclError = error{ fn flushCTypes( self: *C, f: *Flush, - decl_index: Module.Decl.OptionalIndex, + pass: codegen.DeclGen.Pass, decl_ctypes: codegen.CType.Store, ) FlushDeclError!void { const gpa = self.base.allocator; @@ -591,7 +589,7 @@ fn flushCTypes( writer, global_ctypes.set, global_idx, - decl_index, + pass, decl_ctypes.set, decl_idx, gop.found_existing, @@ -610,7 +608,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void { .gpa = gpa, .module = self.base.options.module.?, .error_msg = null, - .decl_index = .none, + .pass = .flush, .is_naked_fn = false, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, @@ -652,7 +650,7 @@ fn flushLazyFn( .gpa = gpa, .module = self.base.options.module.?, .error_msg = null, - .decl_index = .none, + .pass = .flush, .is_naked_fn = false, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index dccc90f1e5..91fe043317 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1737,46 +1737,51 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link return 0; } -pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result { - // This is basically the same as lowerUnnamedConst. - // example: - // const ty = mod.intern_pool.typeOf(decl_val).toType(); - // const val = decl_val.toValue(); - // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`. - // It doesn't have an owner decl because it's just an unnamed constant that might - // be used by more than one function, however, its address is being used so we need - // to put it in some location. - // ... +pub fn lowerAnonDecl( + self: *Coff, + decl_val: InternPool.Index, + explicit_alignment: InternPool.Alignment, + src_loc: Module.SrcLoc, +) !codegen.Result { const gpa = self.base.allocator; const mod = self.base.options.module.?; const ty = mod.intern_pool.typeOf(decl_val).toType(); - const gop = try self.anon_decls.getOrPut(gpa, decl_val); - const required_alignment = switch (decl_align) { + const decl_alignment = switch (explicit_alignment) { .none => ty.abiAlignment(mod), - else => decl_align, + else => explicit_alignment, }; - if (!gop.found_existing or - !required_alignment.check(self.getAtom(gop.value_ptr.*).getSymbol(self).value)) - { - const val = decl_val.toValue(); - const tv = TypedValue{ .ty = ty, .val = val }; - const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); - defer gpa.free(name); - const res = self.lowerConst(name, tv, required_alignment, self.rdata_section_index.?, src_loc) catch |err| switch (err) { - else => { - // TODO improve error message - const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ - @errorName(err), - }); - return .{ .fail = em }; - }, - }; - const atom_index = switch (res) { - .ok => |atom_index| atom_index, - .fail => |em| return .{ .fail = em }, - }; - gop.value_ptr.* = atom_index; + if (self.anon_decls.get(decl_val)) |atom_index| { + const existing_addr = self.getAtom(atom_index).getSymbol(self).value; + if (decl_alignment.check(existing_addr)) + return .ok; } + + const val = decl_val.toValue(); + const tv = TypedValue{ .ty = ty, .val = val }; + var name_buf: [32]u8 = undefined; + const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ + @intFromEnum(decl_val), + }) catch unreachable; + const res = self.lowerConst( + name, + tv, + decl_alignment, + self.rdata_section_index.?, + src_loc, + ) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return .{ .fail = try Module.ErrorMsg.create( + gpa, + src_loc, + "lowerAnonDecl failed with error: {s}", + .{@errorName(e)}, + ) }, + }; + const atom_index = switch (res) { + .ok => |atom_index| atom_index, + .fail => |em| return .{ .fail = em }, + }; + try self.anon_decls.put(gpa, decl_val, atom_index); return .ok; } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index bed7e60296..aa1df9365f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -484,46 +484,51 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link. return vaddr; } -pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result { - // This is basically the same as lowerUnnamedConst. - // example: - // const ty = mod.intern_pool.typeOf(decl_val).toType(); - // const val = decl_val.toValue(); - // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`. - // It doesn't have an owner decl because it's just an unnamed constant that might - // be used by more than one function, however, its address is being used so we need - // to put it in some location. - // ... +pub fn lowerAnonDecl( + self: *Elf, + decl_val: InternPool.Index, + explicit_alignment: InternPool.Alignment, + src_loc: Module.SrcLoc, +) !codegen.Result { const gpa = self.base.allocator; const mod = self.base.options.module.?; const ty = mod.intern_pool.typeOf(decl_val).toType(); - const gop = try self.anon_decls.getOrPut(gpa, decl_val); - const required_alignment = switch (decl_align) { + const decl_alignment = switch (explicit_alignment) { .none => ty.abiAlignment(mod), - else => decl_align, + else => explicit_alignment, }; - if (!gop.found_existing or - required_alignment.order(self.symbol(gop.value_ptr.*).atom(self).?.alignment).compare(.gt)) - { - const val = decl_val.toValue(); - const tv = TypedValue{ .ty = ty, .val = val }; - const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); - defer gpa.free(name); - const res = self.lowerConst(name, tv, required_alignment, self.zig_rodata_section_index.?, src_loc) catch |err| switch (err) { - else => { - // TODO improve error message - const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ - @errorName(err), - }); - return .{ .fail = em }; - }, - }; - const sym_index = switch (res) { - .ok => |sym_index| sym_index, - .fail => |em| return .{ .fail = em }, - }; - gop.value_ptr.* = sym_index; + if (self.anon_decls.get(decl_val)) |sym_index| { + const existing_alignment = self.symbol(sym_index).atom(self).?.alignment; + if (decl_alignment.order(existing_alignment).compare(.lte)) + return .ok; } + + const val = decl_val.toValue(); + const tv = TypedValue{ .ty = ty, .val = val }; + var name_buf: [32]u8 = undefined; + const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ + @intFromEnum(decl_val), + }) catch unreachable; + const res = self.lowerConst( + name, + tv, + decl_alignment, + self.zig_rodata_section_index.?, + src_loc, + ) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return .{ .fail = try Module.ErrorMsg.create( + gpa, + src_loc, + "unable to lower constant value: {s}", + .{@errorName(e)}, + ) }, + }; + const sym_index = switch (res) { + .ok => |sym_index| sym_index, + .fail => |em| return .{ .fail = em }, + }; + try self.anon_decls.put(gpa, decl_val, sym_index); return .ok; } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index eb82de7374..b863e7a0ac 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2866,46 +2866,51 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil return 0; } -pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result { - // This is basically the same as lowerUnnamedConst. - // example: - // const ty = mod.intern_pool.typeOf(decl_val).toType(); - // const val = decl_val.toValue(); - // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`. - // It doesn't have an owner decl because it's just an unnamed constant that might - // be used by more than one function, however, its address is being used so we need - // to put it in some location. - // ... +pub fn lowerAnonDecl( + self: *MachO, + decl_val: InternPool.Index, + explicit_alignment: InternPool.Alignment, + src_loc: Module.SrcLoc, +) !codegen.Result { const gpa = self.base.allocator; const mod = self.base.options.module.?; const ty = mod.intern_pool.typeOf(decl_val).toType(); - const gop = try self.anon_decls.getOrPut(gpa, decl_val); - const required_alignment = switch (decl_align) { + const decl_alignment = switch (explicit_alignment) { .none => ty.abiAlignment(mod), - else => decl_align, + else => explicit_alignment, }; - if (!gop.found_existing or - !required_alignment.check(self.getAtom(gop.value_ptr.*).getSymbol(self).n_value)) - { - const val = decl_val.toValue(); - const tv = TypedValue{ .ty = ty, .val = val }; - const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); - defer gpa.free(name); - const res = self.lowerConst(name, tv, required_alignment, self.data_const_section_index.?, src_loc) catch |err| switch (err) { - else => { - // TODO improve error message - const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ - @errorName(err), - }); - return .{ .fail = em }; - }, - }; - const atom_index = switch (res) { - .ok => |atom_index| atom_index, - .fail => |em| return .{ .fail = em }, - }; - gop.value_ptr.* = atom_index; + if (self.anon_decls.get(decl_val)) |atom_index| { + const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value; + if (decl_alignment.check(existing_addr)) + return .ok; } + + const val = decl_val.toValue(); + const tv = TypedValue{ .ty = ty, .val = val }; + var name_buf: [32]u8 = undefined; + const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ + @intFromEnum(decl_val), + }) catch unreachable; + const res = self.lowerConst( + name, + tv, + decl_alignment, + self.data_const_section_index.?, + src_loc, + ) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return .{ .fail = try Module.ErrorMsg.create( + gpa, + src_loc, + "unable to lower constant value: {s}", + .{@errorName(e)}, + ) }, + }; + const atom_index = switch (res) { + .ok => |atom_index| atom_index, + .fail => |em| return .{ .fail = em }, + }; + try self.anon_decls.put(gpa, decl_val, atom_index); return .ok; } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index f138cdc3e2..c51736ff28 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1702,27 +1702,34 @@ pub fn getDeclVAddr( return target_symbol_index; } -pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, decl_align: Alignment, src_loc: Module.SrcLoc) !codegen.Result { +pub fn lowerAnonDecl( + wasm: *Wasm, + decl_val: InternPool.Index, + explicit_alignment: Alignment, + src_loc: Module.SrcLoc, +) !codegen.Result { const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val); if (!gop.found_existing) { const mod = wasm.base.options.module.?; const ty = mod.intern_pool.typeOf(decl_val).toType(); const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() }; - const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)}); - defer wasm.base.allocator.free(name); + var name_buf: [32]u8 = undefined; + const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ + @intFromEnum(decl_val), + }) catch unreachable; switch (try wasm.lowerConst(name, tv, src_loc)) { - .ok => |atom_index| gop.value_ptr.* = atom_index, + .ok => |atom_index| wasm.anon_decls.values()[gop.index] = atom_index, .fail => |em| return .{ .fail = em }, } } - const atom = wasm.getAtomPtr(gop.value_ptr.*); + const atom = wasm.getAtomPtr(wasm.anon_decls.values()[gop.index]); atom.alignment = switch (atom.alignment) { - .none => decl_align, - else => switch (decl_align) { + .none => explicit_alignment, + else => switch (explicit_alignment) { .none => atom.alignment, - else => atom.alignment.maxStrict(decl_align), + else => atom.alignment.maxStrict(explicit_alignment), }, }; return .ok;