| author | |
| committer | |
| log | 4eb8360911d80d4891be6ed47792121a2ccde353 |
| tree | ebb5a857cb872564a36e390372e142ec5eedbc8a |
| parent | c64755fb2f3178b4f593ef9f2cb54beef03af36f |
| signature |
16 files changed, 312 insertions(+), 203 deletions(-)
lib/compiler/objcopy.zig+2-2| ... | @@ -388,8 +388,8 @@ const BinaryElfOutput = struct { | ... | @@ -388,8 +388,8 @@ const BinaryElfOutput = struct { |
| 388 | 388 | ||
| 389 | pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self { | 389 | pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self { |
| 390 | var self: Self = .{ | 390 | var self: Self = .{ |
| 391 | .segments = .{}, | 391 | .segments = .empty, |
| 392 | .sections = .{}, | 392 | .sections = .empty, |
| 393 | .allocator = allocator, | 393 | .allocator = allocator, |
| 394 | .shstrtab = null, | 394 | .shstrtab = null, |
| 395 | }; | 395 | }; |
lib/std/pdb.zig+2-2| ... | @@ -332,7 +332,7 @@ pub const ProcSym = extern struct { | ... | @@ -332,7 +332,7 @@ pub const ProcSym = extern struct { |
| 332 | name: [1]u8, // null-terminated | 332 | name: [1]u8, // null-terminated |
| 333 | }; | 333 | }; |
| 334 | 334 | ||
| 335 | pub const ProcSymFlags = packed struct { | 335 | pub const ProcSymFlags = packed struct(u8) { |
| 336 | has_fp: bool, | 336 | has_fp: bool, |
| 337 | has_iret: bool, | 337 | has_iret: bool, |
| 338 | has_fret: bool, | 338 | has_fret: bool, |
| ... | @@ -373,7 +373,7 @@ pub const LineFragmentHeader = extern struct { | ... | @@ -373,7 +373,7 @@ pub const LineFragmentHeader = extern struct { |
| 373 | code_size: u32, | 373 | code_size: u32, |
| 374 | }; | 374 | }; |
| 375 | 375 | ||
| 376 | pub const LineFlags = packed struct { | 376 | pub const LineFlags = packed struct(u16) { |
| 377 | /// CV_LINES_HAVE_COLUMNS | 377 | /// CV_LINES_HAVE_COLUMNS |
| 378 | have_columns: bool, | 378 | have_columns: bool, |
| 379 | unused: u15, | 379 | unused: u15, |
lib/std/zig/AstGen.zig+5| ... | @@ -5513,6 +5513,11 @@ fn containerDecl( | ... | @@ -5513,6 +5513,11 @@ fn containerDecl( |
| 5513 | if (next_field_idx != fields_len) { | 5513 | if (next_field_idx != fields_len) { |
| 5514 | return astgen.failNode(member_node, "'_' field of non-exhaustive enum must be last", .{}); | 5514 | return astgen.failNode(member_node, "'_' field of non-exhaustive enum must be last", .{}); |
| 5515 | } | 5515 | } |
| 5516 | if (tag_type_body_len == null) { | ||
| 5517 | return astgen.failNodeNotes(node, "non-exhaustive enum missing integer tag type", .{}, &.{ | ||
| 5518 | try astgen.errNoteNode(member_node, "marked non-exhaustive here", .{}), | ||
| 5519 | }); | ||
| 5520 | } | ||
| 5516 | opt_nonexhaustive_node = member_node.toOptional(); | 5521 | opt_nonexhaustive_node = member_node.toOptional(); |
| 5517 | continue; | 5522 | continue; |
| 5518 | } | 5523 | } |
src/Compilation.zig+2-1| ... | @@ -4180,7 +4180,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | ... | @@ -4180,7 +4180,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 4180 | if (!refs.contains(logging_unit)) continue; | 4180 | if (!refs.contains(logging_unit)) continue; |
| 4181 | try messages.append(gpa, .{ | 4181 | try messages.append(gpa, .{ |
| 4182 | .src_loc = compile_log.src(), | 4182 | .src_loc = compile_log.src(), |
| 4183 | .msg = undefined, // populated later | 4183 | .msg = "", // populated later, but must be valid for `sort` call below |
| 4184 | .notes = &.{}, | 4184 | .notes = &.{}, |
| 4185 | // We actually clear this later for most of these, but we populate | 4185 | // We actually clear this later for most of these, but we populate |
| 4186 | // this field for now to avoid having to allocate more data to track | 4186 | // this field for now to avoid having to allocate more data to track |
| ... | @@ -4221,6 +4221,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | ... | @@ -4221,6 +4221,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 4221 | 4221 | ||
| 4222 | break :compile_log_text try log_text.toOwnedSlice(gpa); | 4222 | break :compile_log_text try log_text.toOwnedSlice(gpa); |
| 4223 | }; | 4223 | }; |
| 4224 | defer gpa.free(compile_log_text); | ||
| 4224 | 4225 | ||
| 4225 | // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a | 4226 | // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a |
| 4226 | // very common way for incremental compilation bugs to manifest, so let's always check it. | 4227 | // very common way for incremental compilation bugs to manifest, so let's always check it. |
src/Sema.zig+90-101| ... | @@ -416,7 +416,7 @@ pub const Block = struct { | ... | @@ -416,7 +416,7 @@ pub const Block = struct { |
| 416 | return block.comptime_reason != null; | 416 | return block.comptime_reason != null; |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | fn builtinCallArgSrc(block: *Block, builtin_call_node: std.zig.Ast.Node.Offset, arg_index: u32) LazySrcLoc { | 419 | pub fn builtinCallArgSrc(block: *Block, builtin_call_node: std.zig.Ast.Node.Offset, arg_index: u32) LazySrcLoc { |
| 420 | return block.src(.{ .node_offset_builtin_call_arg = .{ | 420 | return block.src(.{ .node_offset_builtin_call_arg = .{ |
| 421 | .builtin_call_node = builtin_call_node, | 421 | .builtin_call_node = builtin_call_node, |
| 422 | .arg_index = arg_index, | 422 | .arg_index = arg_index, |
| ... | @@ -4654,47 +4654,14 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -4654,47 +4654,14 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 4654 | .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}), | 4654 | .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}), |
| 4655 | } | 4655 | } |
| 4656 | 4656 | ||
| 4657 | const elem_ty = operand_ty.childType(zcu); | ||
| 4658 | try sema.ensureLayoutResolved(elem_ty, src, .ptr_access); | ||
| 4659 | |||
| 4660 | const need_comptime = switch (elem_ty.classify(zcu)) { | ||
| 4661 | .no_possible_value => return sema.fail(block, src, "cannot load {s} type '{f}'", .{ | ||
| 4662 | if (elem_ty.zigTypeTag(zcu) == .@"opaque") "opaque" else "uninstantiable", | ||
| 4663 | elem_ty.fmt(pt), | ||
| 4664 | }), | ||
| 4665 | .one_possible_value => return, // no need to validate the actual pointer value! | ||
| 4666 | .runtime => false, | ||
| 4667 | .partially_comptime, .fully_comptime => true, | ||
| 4668 | }; | ||
| 4669 | |||
| 4670 | if (sema.resolveValue(operand)) |val| { | 4657 | if (sema.resolveValue(operand)) |val| { |
| 4671 | if (val.isUndef(zcu)) { | 4658 | // Error for deref of undef pointer, unless the pointee is OPV in which case it's legal. |
| 4659 | if (val.isUndef(zcu) and operand_ty.childType(zcu).classify(zcu) != .one_possible_value) { | ||
| 4672 | return sema.fail(block, src, "cannot dereference undefined value", .{}); | 4660 | return sema.fail(block, src, "cannot dereference undefined value", .{}); |
| 4673 | } | 4661 | } |
| 4674 | } else if (need_comptime) { | ||
| 4675 | const msg = msg: { | ||
| 4676 | const msg = try sema.errMsg( | ||
| 4677 | src, | ||
| 4678 | "values of type '{f}' must be comptime-known, but operand value is runtime-known", | ||
| 4679 | .{elem_ty.fmt(pt)}, | ||
| 4680 | ); | ||
| 4681 | errdefer msg.destroy(sema.gpa); | ||
| 4682 | |||
| 4683 | try sema.explainWhyTypeIsComptime(msg, src, elem_ty); | ||
| 4684 | break :msg msg; | ||
| 4685 | }; | ||
| 4686 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 4687 | } | 4662 | } |
| 4688 | } | 4663 | } |
| 4689 | 4664 | ||
| 4690 | fn typeIsDestructurable(ty: Type, zcu: *const Zcu) bool { | ||
| 4691 | return switch (ty.zigTypeTag(zcu)) { | ||
| 4692 | .array, .vector => true, | ||
| 4693 | .@"struct" => ty.isTuple(zcu), | ||
| 4694 | else => false, | ||
| 4695 | }; | ||
| 4696 | } | ||
| 4697 | |||
| 4698 | fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 4665 | fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 4699 | const pt = sema.pt; | 4666 | const pt = sema.pt; |
| 4700 | const zcu = pt.zcu; | 4667 | const zcu = pt.zcu; |
| ... | @@ -4705,14 +4672,14 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp | ... | @@ -4705,14 +4672,14 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 4705 | const operand = sema.resolveInst(extra.operand); | 4672 | const operand = sema.resolveInst(extra.operand); |
| 4706 | const operand_ty = sema.typeOf(operand); | 4673 | const operand_ty = sema.typeOf(operand); |
| 4707 | 4674 | ||
| 4708 | if (!typeIsDestructurable(operand_ty, zcu)) { | 4675 | if (!operand_ty.destructurable(zcu)) { |
| 4709 | return sema.failWithOwnedErrorMsg(block, msg: { | 4676 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 4710 | const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)}); | 4677 | const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)}); |
| 4711 | errdefer msg.destroy(sema.gpa); | 4678 | errdefer msg.destroy(sema.gpa); |
| 4712 | try sema.errNote(destructure_src, msg, "result destructured here", .{}); | 4679 | try sema.errNote(destructure_src, msg, "result destructured here", .{}); |
| 4713 | if (operand_ty.zigTypeTag(pt.zcu) == .error_union) { | 4680 | if (operand_ty.zigTypeTag(pt.zcu) == .error_union) { |
| 4714 | const base_op_ty = operand_ty.errorUnionPayload(zcu); | 4681 | const base_op_ty = operand_ty.errorUnionPayload(zcu); |
| 4715 | if (typeIsDestructurable(base_op_ty, zcu)) | 4682 | if (base_op_ty.destructurable(zcu)) |
| 4716 | try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); | 4683 | try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 4717 | } | 4684 | } |
| 4718 | break :msg msg; | 4685 | break :msg msg; |
| ... | @@ -8247,8 +8214,15 @@ fn zirOptionalPayload( | ... | @@ -8247,8 +8214,15 @@ fn zirOptionalPayload( |
| 8247 | else => return sema.failWithExpectedOptionalType(block, src, operand_ty), | 8214 | else => return sema.failWithExpectedOptionalType(block, src, operand_ty), |
| 8248 | }; | 8215 | }; |
| 8249 | 8216 | ||
| 8250 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { | 8217 | ct: { |
| 8251 | if (val.optionalValue(zcu)) |payload| return Air.internedToRef(payload.toIntern()); | 8218 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8219 | if (val.optionalValue(zcu)) |payload| return .fromValue(payload); // comptime-known payload | ||
| 8220 | } else if (try sema.resolveIsNullFromType(block, src, operand_ty)) |is_null| { | ||
| 8221 | if (!is_null) break :ct; // fully runtime-known | ||
| 8222 | } else { | ||
| 8223 | break :ct; // fully runtime-known | ||
| 8224 | } | ||
| 8225 | // Comptime-known to be `null`. | ||
| 8252 | if (block.isComptime()) return sema.fail(block, src, "unable to unwrap null", .{}); | 8226 | if (block.isComptime()) return sema.fail(block, src, "unable to unwrap null", .{}); |
| 8253 | if (safety_check and block.wantSafety()) { | 8227 | if (safety_check and block.wantSafety()) { |
| 8254 | try sema.safetyPanic(block, src, .unwrap_null); | 8228 | try sema.safetyPanic(block, src, .unwrap_null); |
| ... | @@ -21085,7 +21059,8 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -21085,7 +21059,8 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 21085 | continue :check ip.funcIesResolvedUnordered(func_index); | 21059 | continue :check ip.funcIesResolvedUnordered(func_index); |
| 21086 | }, | 21060 | }, |
| 21087 | .error_set_type => |dest| { | 21061 | .error_set_type => |dest| { |
| 21088 | if (operand_err_ty.isAnyError(zcu)) break :check .superset; | 21062 | if (dest.names.len == 0) break :check .disjoint; // dest is 'error{}' |
| 21063 | if (operand_err_ty.isAnyError(zcu)) break :check .overlap; // anyerror -> error{...} (non-empty) | ||
| 21089 | var dest_has_all = true; | 21064 | var dest_has_all = true; |
| 21090 | var dest_has_any = false; | 21065 | var dest_has_any = false; |
| 21091 | for (operand_err_ty.errorSetNames(zcu).get(ip)) |operand_err_name| { | 21066 | for (operand_err_ty.errorSetNames(zcu).get(ip)) |operand_err_name| { |
| ... | @@ -24741,15 +24716,30 @@ fn zirBuiltinExtern( | ... | @@ -24741,15 +24716,30 @@ fn zirBuiltinExtern( |
| 24741 | const ty_src = block.builtinCallArgSrc(extra.node, 0); | 24716 | const ty_src = block.builtinCallArgSrc(extra.node, 0); |
| 24742 | const options_src = block.builtinCallArgSrc(extra.node, 1); | 24717 | const options_src = block.builtinCallArgSrc(extra.node, 1); |
| 24743 | 24718 | ||
| 24744 | var ty = try sema.resolveType(block, ty_src, extra.lhs); | 24719 | const ptr_ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 24745 | if (!ty.isPtrAtRuntime(zcu)) { | 24720 | if (!ptr_ty.isPtrAtRuntime(zcu)) { |
| 24746 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); | 24721 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); |
| 24747 | } | 24722 | } |
| 24748 | if (!ty.validateExtern(.other, zcu)) { | 24723 | |
| 24724 | const ptr_info = ptr_ty.ptrInfo(zcu); | ||
| 24725 | |||
| 24726 | const elem_ty: Type = .fromInterned(ptr_info.child); | ||
| 24727 | try sema.ensureLayoutResolved(elem_ty, src, .@"extern"); | ||
| 24728 | |||
| 24729 | if (!elem_ty.validateExtern(.other, zcu)) { | ||
| 24749 | return sema.failWithOwnedErrorMsg(block, msg: { | 24730 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 24750 | const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)}); | 24731 | const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ptr_ty.fmt(pt)}); |
| 24751 | errdefer msg.destroy(sema.gpa); | 24732 | errdefer msg.destroy(sema.gpa); |
| 24752 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other); | 24733 | try sema.errNote(ty_src, msg, "pointer element type '{f}' is not extern compatible", .{elem_ty.fmt(pt)}); |
| 24734 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, elem_ty, .other); | ||
| 24735 | break :msg msg; | ||
| 24736 | }); | ||
| 24737 | } | ||
| 24738 | if (elem_ty.zigTypeTag(zcu) == .@"fn" and !ptr_info.flags.is_const) { | ||
| 24739 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 24740 | const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ptr_ty.fmt(pt)}); | ||
| 24741 | errdefer msg.destroy(sema.gpa); | ||
| 24742 | try sema.errNote(ty_src, msg, "pointer to extern function must be 'const'", .{}); | ||
| 24753 | break :msg msg; | 24743 | break :msg msg; |
| 24754 | }); | 24744 | }); |
| 24755 | } | 24745 | } |
| ... | @@ -24769,14 +24759,9 @@ fn zirBuiltinExtern( | ... | @@ -24769,14 +24759,9 @@ fn zirBuiltinExtern( |
| 24769 | 24759 | ||
| 24770 | // TODO: error for threadlocal functions, non-const functions, etc | 24760 | // TODO: error for threadlocal functions, non-const functions, etc |
| 24771 | 24761 | ||
| 24772 | if (options.linkage == .weak and !ty.ptrAllowsZero(zcu)) { | ||
| 24773 | ty = try pt.optionalType(ty.toIntern()); | ||
| 24774 | } | ||
| 24775 | const ptr_info = ty.ptrInfo(zcu); | ||
| 24776 | |||
| 24777 | const extern_val = try pt.getExtern(.{ | 24762 | const extern_val = try pt.getExtern(.{ |
| 24778 | .name = options.name, | 24763 | .name = options.name, |
| 24779 | .ty = ptr_info.child, | 24764 | .ty = elem_ty.toIntern(), |
| 24780 | .lib_name = options.library_name, | 24765 | .lib_name = options.library_name, |
| 24781 | .linkage = options.linkage, | 24766 | .linkage = options.linkage, |
| 24782 | .visibility = options.visibility, | 24767 | .visibility = options.visibility, |
| ... | @@ -24807,13 +24792,17 @@ fn zirBuiltinExtern( | ... | @@ -24807,13 +24792,17 @@ fn zirBuiltinExtern( |
| 24807 | .source = .builtin, | 24792 | .source = .builtin, |
| 24808 | }); | 24793 | }); |
| 24809 | 24794 | ||
| 24795 | // For a weak symbol where the given type is not nullable, make the pointer optional. | ||
| 24796 | const result_ptr_ty: Type = if (options.linkage == .weak and !ptr_ty.ptrAllowsZero(zcu)) ty: { | ||
| 24797 | break :ty try pt.optionalType(ptr_ty.toIntern()); | ||
| 24798 | } else ptr_ty; | ||
| 24799 | |||
| 24810 | const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav); | 24800 | const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav); |
| 24811 | // We want to cast to `ty`, but that isn't necessarily an allowed coercion. | ||
| 24812 | if (sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| { | 24801 | if (sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| { |
| 24813 | const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, ty); | 24802 | const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, result_ptr_ty); |
| 24814 | return Air.internedToRef(casted_ptr_val.toIntern()); | 24803 | return Air.internedToRef(casted_ptr_val.toIntern()); |
| 24815 | } else { | 24804 | } else { |
| 24816 | return block.addBitCast(ty, uncasted_ptr); | 24805 | return block.addBitCast(result_ptr_ty, uncasted_ptr); |
| 24817 | } | 24806 | } |
| 24818 | } | 24807 | } |
| 24819 | 24808 | ||
| ... | @@ -25258,6 +25247,7 @@ pub fn explainWhyTypeIsUnpackable( | ... | @@ -25258,6 +25247,7 @@ pub fn explainWhyTypeIsUnpackable( |
| 25258 | try sema.errNote(src, msg, "non-packed unions do not have a bit-packed representation", .{}); | 25247 | try sema.errNote(src, msg, "non-packed unions do not have a bit-packed representation", .{}); |
| 25259 | try sema.addDeclaredHereNote(msg, union_ty); | 25248 | try sema.addDeclaredHereNote(msg, union_ty); |
| 25260 | }, | 25249 | }, |
| 25250 | .slice => try sema.errNote(src, msg, "slices do not have a bit-packed representation", .{}), | ||
| 25261 | .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}), | 25251 | .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}), |
| 25262 | } | 25252 | } |
| 25263 | } | 25253 | } |
| ... | @@ -25501,7 +25491,10 @@ fn addSafetyCheckSentinelMismatch( | ... | @@ -25501,7 +25491,10 @@ fn addSafetyCheckSentinelMismatch( |
| 25501 | }; | 25491 | }; |
| 25502 | assert(sema.typeOf(actual_sentinel).toIntern() == sentinel_ty.toIntern()); | 25492 | assert(sema.typeOf(actual_sentinel).toIntern() == sentinel_ty.toIntern()); |
| 25503 | assert(sentinel_ty.isSelfComparable(zcu, true)); | 25493 | assert(sentinel_ty.isSelfComparable(zcu, true)); |
| 25504 | const ok = try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); | 25494 | const ok: Air.Inst.Ref = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: { |
| 25495 | const elementwise = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); | ||
| 25496 | break :ok try parent_block.addReduce(elementwise, .And); | ||
| 25497 | } else try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); | ||
| 25505 | 25498 | ||
| 25506 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{ | 25499 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{ |
| 25507 | expected_sentinel, actual_sentinel, | 25500 | expected_sentinel, actual_sentinel, |
| ... | @@ -26574,8 +26567,13 @@ fn unionFieldVal( | ... | @@ -26574,8 +26567,13 @@ fn unionFieldVal( |
| 26574 | const active_tag_val = union_val.unionTag(zcu).?; | 26567 | const active_tag_val = union_val.unionTag(zcu).?; |
| 26575 | const active_index = enum_tag_ty.enumTagFieldIndex(active_tag_val, zcu).?; | 26568 | const active_index = enum_tag_ty.enumTagFieldIndex(active_tag_val, zcu).?; |
| 26576 | if (active_index == field_index) return .fromValue(union_val.unionPayload(zcu)); | 26569 | if (active_index == field_index) return .fromValue(union_val.unionPayload(zcu)); |
| 26577 | return sema.fail(block, src, "access of union field '{f}' while field '{f}' is active", .{ | 26570 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 26578 | field_name.fmt(ip), enum_tag_ty.enumFieldName(active_index, zcu).fmt(ip), | 26571 | const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ |
| 26572 | field_name.fmt(ip), enum_tag_ty.enumFieldName(active_index, zcu).fmt(ip), | ||
| 26573 | }); | ||
| 26574 | errdefer msg.destroy(zcu.comp.gpa); | ||
| 26575 | try sema.addDeclaredHereNote(msg, union_ty); | ||
| 26576 | break :msg msg; | ||
| 26579 | }); | 26577 | }); |
| 26580 | }, | 26578 | }, |
| 26581 | .@"extern" => if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| { | 26579 | .@"extern" => if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| { |
| ... | @@ -26745,9 +26743,17 @@ fn elemVal( | ... | @@ -26745,9 +26743,17 @@ fn elemVal( |
| 26745 | return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), indexable_src); | 26743 | return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), indexable_src); |
| 26746 | } | 26744 | } |
| 26747 | 26745 | ||
| 26748 | if (try child_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | 26746 | try sema.validateRuntimeElemAccess(block, elem_index_src, child_ty, indexable_ty, src); |
| 26747 | switch (child_ty.classify(zcu)) { | ||
| 26748 | .runtime => {}, | ||
| 26749 | .one_possible_value => return .fromValue((try child_ty.onePossibleValue(pt)).?), | ||
| 26750 | .no_possible_value => switch (child_ty.zigTypeTag(zcu)) { | ||
| 26751 | .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{child_ty.fmt(pt)}), | ||
| 26752 | else => return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{child_ty.fmt(pt)}), | ||
| 26753 | }, | ||
| 26754 | .partially_comptime, .fully_comptime => unreachable, // caught by `validateRuntimeElemAccess` | ||
| 26755 | } | ||
| 26749 | 26756 | ||
| 26750 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | ||
| 26751 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); | 26757 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); |
| 26752 | }, | 26758 | }, |
| 26753 | .one => { | 26759 | .one => { |
| ... | @@ -29082,31 +29088,6 @@ fn storePtr2( | ... | @@ -29082,31 +29088,6 @@ fn storePtr2( |
| 29082 | 29088 | ||
| 29083 | const elem_ty = ptr_ty.childType(zcu); | 29089 | const elem_ty = ptr_ty.childType(zcu); |
| 29084 | 29090 | ||
| 29085 | // To generate better code for tuples, we detect a tuple operand here, and | ||
| 29086 | // analyze field loads and stores directly. This avoids an extra allocation + memcpy | ||
| 29087 | // which would occur if we used `coerce`. | ||
| 29088 | // However, we avoid this mechanism if the destination element type is a tuple, | ||
| 29089 | // because the regular store will be better for this case. | ||
| 29090 | // If the destination type is a struct we don't want this mechanism to trigger, because | ||
| 29091 | // this code does not handle tuple-to-struct coercion which requires dealing with missing | ||
| 29092 | // fields. | ||
| 29093 | const operand_ty = sema.typeOf(uncasted_operand); | ||
| 29094 | if (operand_ty.isTuple(zcu) and elem_ty.zigTypeTag(zcu) == .array) { | ||
| 29095 | const field_count = operand_ty.structFieldCount(zcu); | ||
| 29096 | var i: u32 = 0; | ||
| 29097 | while (i < field_count) : (i += 1) { | ||
| 29098 | const elem_src = operand_src; // TODO better source location | ||
| 29099 | const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i); | ||
| 29100 | const elem_index = try pt.intRef(.usize, i); | ||
| 29101 | const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, true); | ||
| 29102 | try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); | ||
| 29103 | } | ||
| 29104 | return; | ||
| 29105 | } | ||
| 29106 | |||
| 29107 | // TODO do the same thing for anon structs as for tuples above. | ||
| 29108 | // However, beware of the need to handle missing/extra fields. | ||
| 29109 | |||
| 29110 | const is_ret = air_tag == .ret_ptr; | 29091 | const is_ret = air_tag == .ret_ptr; |
| 29111 | 29092 | ||
| 29112 | const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { | 29093 | const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { |
| ... | @@ -29129,16 +29110,13 @@ fn storePtr2( | ... | @@ -29129,16 +29110,13 @@ fn storePtr2( |
| 29129 | return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); | 29110 | return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); |
| 29130 | }; | 29111 | }; |
| 29131 | 29112 | ||
| 29132 | // We're performing the store at runtime; as such, we need to make sure the pointee type | 29113 | // We're performing the store at runtime, so the pointee type must not be comptime-only. |
| 29133 | // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer. | 29114 | if (comptime_only) return sema.failWithOwnedErrorMsg(block, msg: { |
| 29134 | if (comptime_only) { | 29115 | const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)}); |
| 29135 | return sema.failWithOwnedErrorMsg(block, msg: { | 29116 | errdefer msg.destroy(sema.gpa); |
| 29136 | const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)}); | 29117 | try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{}); |
| 29137 | errdefer msg.destroy(sema.gpa); | 29118 | break :msg msg; |
| 29138 | try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{}); | 29119 | }); |
| 29139 | break :msg msg; | ||
| 29140 | }); | ||
| 29141 | } | ||
| 29142 | 29120 | ||
| 29143 | try sema.requireRuntimeBlock(block, src, runtime_src); | 29121 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 29144 | 29122 | ||
| ... | @@ -29556,7 +29534,10 @@ fn coerceEnumToUnion( | ... | @@ -29556,7 +29534,10 @@ fn coerceEnumToUnion( |
| 29556 | return sema.failWithOwnedErrorMsg(block, msg); | 29534 | return sema.failWithOwnedErrorMsg(block, msg); |
| 29557 | } | 29535 | } |
| 29558 | 29536 | ||
| 29559 | if (union_ty.unionHasAllZeroBitFieldTypes(zcu)) { | 29537 | for (union_obj.field_types.get(ip)) |field_ty_ip| { |
| 29538 | if (Type.fromInterned(field_ty_ip).classify(zcu) != .one_possible_value) break; | ||
| 29539 | } else { | ||
| 29540 | // All fields are OPV, so the coercion is okay. | ||
| 29560 | if (try union_ty.onePossibleValue(pt)) |opv| { | 29541 | if (try union_ty.onePossibleValue(pt)) |opv| { |
| 29561 | // The tag had redundant bits, but we've omitted the tag from the union's runtime layout, so the union is OPV and hence runtime-known. | 29542 | // The tag had redundant bits, but we've omitted the tag from the union's runtime layout, so the union is OPV and hence runtime-known. |
| 29562 | return .fromValue(opv); | 29543 | return .fromValue(opv); |
| ... | @@ -29566,6 +29547,8 @@ fn coerceEnumToUnion( | ... | @@ -29566,6 +29547,8 @@ fn coerceEnumToUnion( |
| 29566 | } | 29547 | } |
| 29567 | } | 29548 | } |
| 29568 | 29549 | ||
| 29550 | // The coercion is invalid because one or more fields is not OPV. | ||
| 29551 | |||
| 29569 | const msg = msg: { | 29552 | const msg = msg: { |
| 29570 | const msg = try sema.errMsg( | 29553 | const msg = try sema.errMsg( |
| 29571 | inst_src, | 29554 | inst_src, |
| ... | @@ -30186,12 +30169,18 @@ fn analyzeLoad( | ... | @@ -30186,12 +30169,18 @@ fn analyzeLoad( |
| 30186 | .pointer => ptr_ty.childType(zcu), | 30169 | .pointer => ptr_ty.childType(zcu), |
| 30187 | else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}), | 30170 | else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}), |
| 30188 | }; | 30171 | }; |
| 30189 | if (elem_ty.zigTypeTag(zcu) == .@"opaque") { | ||
| 30190 | return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}); | ||
| 30191 | } | ||
| 30192 | 30172 | ||
| 30193 | try sema.ensureLayoutResolved(elem_ty, src, .ptr_access); | 30173 | try sema.ensureLayoutResolved(elem_ty, src, .ptr_access); |
| 30194 | if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | 30174 | |
| 30175 | const comptime_only = switch (elem_ty.classify(zcu)) { | ||
| 30176 | .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) { | ||
| 30177 | .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}), | ||
| 30178 | else => return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(pt)}), | ||
| 30179 | }, | ||
| 30180 | .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?), | ||
| 30181 | .runtime => false, | ||
| 30182 | .partially_comptime, .fully_comptime => true, | ||
| 30183 | }; | ||
| 30195 | 30184 | ||
| 30196 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { | 30185 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 30197 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { | 30186 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { |
| ... | @@ -30199,7 +30188,7 @@ fn analyzeLoad( | ... | @@ -30199,7 +30188,7 @@ fn analyzeLoad( |
| 30199 | } | 30188 | } |
| 30200 | } | 30189 | } |
| 30201 | 30190 | ||
| 30202 | if (elem_ty.comptimeOnly(zcu)) return sema.failWithOwnedErrorMsg(block, msg: { | 30191 | if (comptime_only) return sema.failWithOwnedErrorMsg(block, msg: { |
| 30203 | const msg = try sema.errMsg(src, "cannot load comptime-only type '{f}'", .{elem_ty.fmt(pt)}); | 30192 | const msg = try sema.errMsg(src, "cannot load comptime-only type '{f}'", .{elem_ty.fmt(pt)}); |
| 30204 | errdefer msg.destroy(zcu.gpa); | 30193 | errdefer msg.destroy(zcu.gpa); |
| 30205 | try sema.errNote(ptr_src, msg, "pointer of type '{f}' is runtime-known", .{ptr_ty.fmt(pt)}); | 30194 | try sema.errNote(ptr_src, msg, "pointer of type '{f}' is runtime-known", .{ptr_ty.fmt(pt)}); |
src/Sema/arith.zig+3| ... | @@ -20,6 +20,9 @@ pub fn incrementDefinedInt( | ... | @@ -20,6 +20,9 @@ pub fn incrementDefinedInt( |
| 20 | const zcu = pt.zcu; | 20 | const zcu = pt.zcu; |
| 21 | assert(prev_val.typeOf(zcu).toIntern() == ty.toIntern()); | 21 | assert(prev_val.typeOf(zcu).toIntern() == ty.toIntern()); |
| 22 | assert(!prev_val.isUndef(zcu)); | 22 | assert(!prev_val.isUndef(zcu)); |
| 23 | if (ty.intInfo(zcu).bits == 0) { | ||
| 24 | return .{ .overflow = true, .val = try comptimeIntAdd(sema, prev_val, .one_comptime_int) }; | ||
| 25 | } | ||
| 23 | const res = try intAdd(sema, prev_val, try pt.intValue(ty, 1), ty); | 26 | const res = try intAdd(sema, prev_val, try pt.intValue(ty, 1), ty); |
| 24 | return .{ .overflow = res.overflow, .val = res.val }; | 27 | return .{ .overflow = res.overflow, .val = res.val }; |
| 25 | } | 28 | } |
src/Sema/type_resolution.zig+30-16| ... | @@ -33,6 +33,7 @@ pub const LayoutResolveReason = enum { | ... | @@ -33,6 +33,7 @@ pub const LayoutResolveReason = enum { |
| 33 | align_check, | 33 | align_check, |
| 34 | bit_ptr_child, | 34 | bit_ptr_child, |
| 35 | @"export", | 35 | @"export", |
| 36 | @"extern", | ||
| 36 | builtin_type, | 37 | builtin_type, |
| 37 | 38 | ||
| 38 | /// Written after string: "while resolving type 'T' " | 39 | /// Written after string: "while resolving type 'T' " |
| ... | @@ -58,6 +59,7 @@ pub const LayoutResolveReason = enum { | ... | @@ -58,6 +59,7 @@ pub const LayoutResolveReason = enum { |
| 58 | .align_check => "for alignment check here", | 59 | .align_check => "for alignment check here", |
| 59 | .bit_ptr_child => "for bit size check here", | 60 | .bit_ptr_child => "for bit size check here", |
| 60 | .@"export" => "for export here", | 61 | .@"export" => "for export here", |
| 62 | .@"extern" => "for extern declaration here", | ||
| 61 | .builtin_type => "from 'std.builtin'", | 63 | .builtin_type => "from 'std.builtin'", |
| 62 | // zig fmt: on | 64 | // zig fmt: on |
| 63 | }; | 65 | }; |
| ... | @@ -198,7 +200,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -198,7 +200,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 198 | const name = struct_obj.field_names.get(ip)[field_index]; | 200 | const name = struct_obj.field_names.get(ip)[field_index]; |
| 199 | if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| { | 201 | if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| { |
| 200 | return sema.failWithOwnedErrorMsg(&block, msg: { | 202 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 201 | const src = block.nodeOffset(.zero); | 203 | const src = block.builtinCallArgSrc(.zero, 2); |
| 202 | const msg = try sema.errMsg(src, "duplicate struct field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); | 204 | const msg = try sema.errMsg(src, "duplicate struct field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); |
| 203 | errdefer msg.destroy(gpa); | 205 | errdefer msg.destroy(gpa); |
| 204 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); | 206 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); |
| ... | @@ -494,20 +496,22 @@ fn resolvePackedStructLayout( | ... | @@ -494,20 +496,22 @@ fn resolvePackedStructLayout( |
| 494 | 496 | ||
| 495 | // Finally, either validate or infer the backing int type. | 497 | // Finally, either validate or infer the backing int type. |
| 496 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { | 498 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { |
| 497 | // We only need to validate the type. | 499 | if (backing_ty.zigTypeTag(zcu) != .int) return sema.fail( |
| 498 | if (backing_ty.zigTypeTag(zcu) != .int) return sema.failWithOwnedErrorMsg(block, msg: { | 500 | block, |
| 499 | const src = struct_ty.srcLoc(zcu); | 501 | block.src(.container_arg), |
| 500 | const msg = try sema.errMsg(src, "expected backing integer type, found '{f}'", .{backing_ty.fmt(pt)}); | 502 | "expected backing integer type, found '{f}'", |
| 501 | errdefer msg.destroy(gpa); | 503 | .{backing_ty.fmt(pt)}, |
| 502 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | 504 | ); |
| 503 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | ||
| 504 | break :msg msg; | ||
| 505 | }); | ||
| 506 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { | 505 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { |
| 507 | const src = struct_ty.srcLoc(zcu); | 506 | const src = struct_ty.srcLoc(zcu); |
| 508 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); | 507 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); |
| 509 | errdefer msg.destroy(gpa); | 508 | errdefer msg.destroy(gpa); |
| 510 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | 509 | try sema.errNote( |
| 510 | block.src(.container_arg), | ||
| 511 | msg, | ||
| 512 | "backing integer '{f}' has bit width '{d}'", | ||
| 513 | .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }, | ||
| 514 | ); | ||
| 511 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | 515 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); |
| 512 | break :msg msg; | 516 | break :msg msg; |
| 513 | }); | 517 | }); |
| ... | @@ -1033,7 +1037,6 @@ fn resolvePackedUnionLayout( | ... | @@ -1033,7 +1037,6 @@ fn resolvePackedUnionLayout( |
| 1033 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 1037 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 1034 | errdefer msg.destroy(gpa); | 1038 | errdefer msg.destroy(gpa); |
| 1035 | try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason); | 1039 | try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason); |
| 1036 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 1037 | break :msg msg; | 1040 | break :msg msg; |
| 1038 | }); | 1041 | }); |
| 1039 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | 1042 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only |
| ... | @@ -1062,6 +1065,12 @@ fn resolvePackedUnionLayout( | ... | @@ -1062,6 +1065,12 @@ fn resolvePackedUnionLayout( |
| 1062 | 1065 | ||
| 1063 | // Finally, either validate or infer the backing int type. | 1066 | // Finally, either validate or infer the backing int type. |
| 1064 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { | 1067 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { |
| 1068 | if (backing_ty.zigTypeTag(zcu) != .int) return sema.fail( | ||
| 1069 | block, | ||
| 1070 | block.src(.container_arg), | ||
| 1071 | "expected backing integer type, found '{f}'", | ||
| 1072 | .{backing_ty.fmt(pt)}, | ||
| 1073 | ); | ||
| 1065 | const backing_int_bits = backing_ty.intInfo(zcu).bits; | 1074 | const backing_int_bits = backing_ty.intInfo(zcu).bits; |
| 1066 | for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| { | 1075 | for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| { |
| 1067 | const field_type: Type = .fromInterned(field_type_ip); | 1076 | const field_type: Type = .fromInterned(field_type_ip); |
| ... | @@ -1071,7 +1080,12 @@ fn resolvePackedUnionLayout( | ... | @@ -1071,7 +1080,12 @@ fn resolvePackedUnionLayout( |
| 1071 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{}); | 1080 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{}); |
| 1072 | errdefer msg.destroy(gpa); | 1081 | errdefer msg.destroy(gpa); |
| 1073 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | 1082 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); |
| 1074 | try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_int_bits }); | 1083 | try sema.errNote( |
| 1084 | block.src(.container_arg), | ||
| 1085 | msg, | ||
| 1086 | "backing integer '{f}' has bit width '{d}'", | ||
| 1087 | .{ backing_ty.fmt(pt), backing_int_bits }, | ||
| 1088 | ); | ||
| 1075 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | 1089 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); |
| 1076 | break :msg msg; | 1090 | break :msg msg; |
| 1077 | }); | 1091 | }); |
| ... | @@ -1157,7 +1171,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -1157,7 +1171,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { |
| 1157 | const name = enum_obj.field_names.get(ip)[field_index]; | 1171 | const name = enum_obj.field_names.get(ip)[field_index]; |
| 1158 | if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| { | 1172 | if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| { |
| 1159 | return sema.failWithOwnedErrorMsg(&block, msg: { | 1173 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 1160 | const src = block.nodeOffset(.zero); | 1174 | const src = block.builtinCallArgSrc(.zero, 2); |
| 1161 | const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); | 1175 | const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); |
| 1162 | errdefer msg.destroy(gpa); | 1176 | errdefer msg.destroy(gpa); |
| 1163 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); | 1177 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); |
| ... | @@ -1183,8 +1197,8 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -1183,8 +1197,8 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { |
| 1183 | const name = enum_obj.field_names.get(ip)[field_index]; | 1197 | const name = enum_obj.field_names.get(ip)[field_index]; |
| 1184 | if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| { | 1198 | if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| { |
| 1185 | return sema.failWithOwnedErrorMsg(&block, msg: { | 1199 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 1186 | const src = block.nodeOffset(.zero); | 1200 | const src = block.builtinCallArgSrc(.zero, 2); |
| 1187 | const msg = try sema.errMsg(src, "duplicate enum field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); | 1201 | const msg = try sema.errMsg(src, "duplicate enum field '{f}' at index '{d}'", .{ name.fmt(ip), field_index }); |
| 1188 | errdefer msg.destroy(gpa); | 1202 | errdefer msg.destroy(gpa); |
| 1189 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); | 1203 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); |
| 1190 | break :msg msg; | 1204 | break :msg msg; |
src/Type.zig+13-1| ... | @@ -2985,12 +2985,21 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina | ... | @@ -2985,12 +2985,21 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina |
| 2985 | }; | 2985 | }; |
| 2986 | } | 2986 | } |
| 2987 | 2987 | ||
| 2988 | pub fn destructurable(ty: Type, zcu: *const Zcu) bool { | ||
| 2989 | return switch (ty.zigTypeTag(zcu)) { | ||
| 2990 | .array, .vector => true, | ||
| 2991 | .@"struct" => ty.isTuple(zcu), | ||
| 2992 | else => false, | ||
| 2993 | }; | ||
| 2994 | } | ||
| 2995 | |||
| 2988 | pub const UnpackableReason = union(enum) { | 2996 | pub const UnpackableReason = union(enum) { |
| 2989 | comptime_only, | 2997 | comptime_only, |
| 2990 | pointer, | 2998 | pointer, |
| 2991 | enum_inferred_int_tag: Type, | 2999 | enum_inferred_int_tag: Type, |
| 2992 | non_packed_struct: Type, | 3000 | non_packed_struct: Type, |
| 2993 | non_packed_union: Type, | 3001 | non_packed_union: Type, |
| 3002 | slice, | ||
| 2994 | other, | 3003 | other, |
| 2995 | }; | 3004 | }; |
| 2996 | 3005 | ||
| ... | @@ -3027,7 +3036,10 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { | ... | @@ -3027,7 +3036,10 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { |
| 3027 | else | 3036 | else |
| 3028 | .other, | 3037 | .other, |
| 3029 | 3038 | ||
| 3030 | .pointer => .pointer, | 3039 | .pointer => switch (ty.ptrSize(zcu)) { |
| 3040 | .slice => .slice, | ||
| 3041 | .one, .many, .c => .pointer, | ||
| 3042 | }, | ||
| 3031 | 3043 | ||
| 3032 | .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) { | 3044 | .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) { |
| 3033 | .explicit => null, | 3045 | .explicit => null, |
src/Value.zig+11-3| ... | @@ -2014,7 +2014,11 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op | ... | @@ -2014,7 +2014,11 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op |
| 2014 | }, | 2014 | }, |
| 2015 | .field => |field| base: { | 2015 | .field => |field| base: { |
| 2016 | const base_ptr = Value.fromInterned(field.base); | 2016 | const base_ptr = Value.fromInterned(field.base); |
| 2017 | const base_ptr_ty = base_ptr.typeOf(zcu); | 2017 | const base_ptr_ty = try pt.ptrType(info: { |
| 2018 | var info = base_ptr.typeOf(zcu).ptrInfo(zcu); | ||
| 2019 | info.flags.size = .one; | ||
| 2020 | break :info info; | ||
| 2021 | }); | ||
| 2018 | const parent_step = try arena.create(PointerDeriveStep); | 2022 | const parent_step = try arena.create(PointerDeriveStep); |
| 2019 | parent_step.* = try pointerDerivation(base_ptr, arena, pt, opt_sema); | 2023 | parent_step.* = try pointerDerivation(base_ptr, arena, pt, opt_sema); |
| 2020 | break :base .{ .field_ptr = .{ | 2024 | break :base .{ .field_ptr = .{ |
| ... | @@ -2155,13 +2159,17 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op | ... | @@ -2155,13 +2159,17 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op |
| 2155 | const start_off = cur_ty.structFieldOffset(field_idx, zcu); | 2159 | const start_off = cur_ty.structFieldOffset(field_idx, zcu); |
| 2156 | const end_off = start_off + field_ty.abiSize(zcu); | 2160 | const end_off = start_off + field_ty.abiSize(zcu); |
| 2157 | if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) { | 2161 | if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) { |
| 2158 | const old_ptr_ty = try cur_derive.ptrType(pt); | 2162 | const base_ptr_ty = try pt.ptrType(info: { |
| 2163 | var info = (try cur_derive.ptrType(pt)).ptrInfo(zcu); | ||
| 2164 | info.flags.size = .one; | ||
| 2165 | break :info info; | ||
| 2166 | }); | ||
| 2159 | const parent = try arena.create(PointerDeriveStep); | 2167 | const parent = try arena.create(PointerDeriveStep); |
| 2160 | parent.* = cur_derive; | 2168 | parent.* = cur_derive; |
| 2161 | cur_derive = .{ .field_ptr = .{ | 2169 | cur_derive = .{ .field_ptr = .{ |
| 2162 | .parent = parent, | 2170 | .parent = parent, |
| 2163 | .field_idx = @intCast(field_idx), | 2171 | .field_idx = @intCast(field_idx), |
| 2164 | .result_ptr_ty = try old_ptr_ty.fieldPtrType(@intCast(field_idx), pt), | 2172 | .result_ptr_ty = try base_ptr_ty.fieldPtrType(@intCast(field_idx), pt), |
| 2165 | } }; | 2173 | } }; |
| 2166 | cur_offset -= start_off; | 2174 | cur_offset -= start_off; |
| 2167 | break; | 2175 | break; |
src/Zcu.zig+40-4| ... | @@ -2028,9 +2028,15 @@ pub const SrcLoc = struct { | ... | @@ -2028,9 +2028,15 @@ pub const SrcLoc = struct { |
| 2028 | const tree = try src_loc.file_scope.getTree(zcu); | 2028 | const tree = try src_loc.file_scope.getTree(zcu); |
| 2029 | const node = src_loc.base_node; | 2029 | const node = src_loc.base_node; |
| 2030 | var buf: [2]Ast.Node.Index = undefined; | 2030 | var buf: [2]Ast.Node.Index = undefined; |
| 2031 | const container_decl = tree.fullContainerDecl(&buf, node) orelse return tree.nodeToSpan(node); | 2031 | if (tree.fullContainerDecl(&buf, node)) |container_decl| { |
| 2032 | const arg_node = container_decl.ast.arg.unwrap() orelse return tree.nodeToSpan(node); | 2032 | const arg_node = container_decl.ast.arg.unwrap() orelse return tree.nodeToSpan(node); |
| 2033 | return tree.nodeToSpan(arg_node); | 2033 | return tree.nodeToSpan(arg_node); |
| 2034 | } else if (tree.builtinCallParams(&buf, node)) |args| { | ||
| 2035 | // Builtin calls (`@Enum` etc) should use the first argument. | ||
| 2036 | return tree.nodeToSpan(if (args.len > 0) args[0] else node); | ||
| 2037 | } else { | ||
| 2038 | return tree.nodeToSpan(node); | ||
| 2039 | } | ||
| 2034 | }, | 2040 | }, |
| 2035 | .container_field_name, | 2041 | .container_field_name, |
| 2036 | .container_field_value, | 2042 | .container_field_value, |
| ... | @@ -2040,8 +2046,38 @@ pub const SrcLoc = struct { | ... | @@ -2040,8 +2046,38 @@ pub const SrcLoc = struct { |
| 2040 | const tree = try src_loc.file_scope.getTree(zcu); | 2046 | const tree = try src_loc.file_scope.getTree(zcu); |
| 2041 | const node = src_loc.base_node; | 2047 | const node = src_loc.base_node; |
| 2042 | var buf: [2]Ast.Node.Index = undefined; | 2048 | var buf: [2]Ast.Node.Index = undefined; |
| 2043 | const container_decl = tree.fullContainerDecl(&buf, node) orelse | 2049 | const container_decl = tree.fullContainerDecl(&buf, node) orelse { |
| 2050 | // This could be a reification builtin. These are the args we care about: | ||
| 2051 | // * `@Enum(_, _, names, values)` | ||
| 2052 | // * `@Struct(_, _, names, types, values_and_aligns)` | ||
| 2053 | // * `@Union(_, _, names, types, aligns)` | ||
| 2054 | if (tree.builtinCallParams(&buf, node)) |args| { | ||
| 2055 | const builtin_name = tree.tokenSlice(tree.firstToken(node)); | ||
| 2056 | const arg_index: ?u3 = if (std.mem.eql(u8, builtin_name, "@Enum")) switch (src_loc.lazy) { | ||
| 2057 | .container_field_name => 2, | ||
| 2058 | .container_field_value => 3, | ||
| 2059 | .container_field_type => null, | ||
| 2060 | .container_field_align => null, | ||
| 2061 | else => unreachable, | ||
| 2062 | } else if (std.mem.eql(u8, builtin_name, "@Struct")) switch (src_loc.lazy) { | ||
| 2063 | .container_field_name => 2, | ||
| 2064 | .container_field_value => 4, | ||
| 2065 | .container_field_type => 3, | ||
| 2066 | .container_field_align => 4, | ||
| 2067 | else => unreachable, | ||
| 2068 | } else if (std.mem.eql(u8, builtin_name, "@Union")) switch (src_loc.lazy) { | ||
| 2069 | .container_field_name => 2, | ||
| 2070 | .container_field_value => 4, | ||
| 2071 | .container_field_type => 3, | ||
| 2072 | .container_field_align => null, | ||
| 2073 | else => unreachable, | ||
| 2074 | } else null; | ||
| 2075 | if (arg_index) |i| { | ||
| 2076 | if (args.len >= i) return tree.nodeToSpan(args[i]); | ||
| 2077 | } | ||
| 2078 | } | ||
| 2044 | return tree.nodeToSpan(node); | 2079 | return tree.nodeToSpan(node); |
| 2080 | }; | ||
| 2045 | 2081 | ||
| 2046 | var cur_field_idx: usize = 0; | 2082 | var cur_field_idx: usize = 0; |
| 2047 | for (container_decl.ast.members) |member_node| { | 2083 | for (container_decl.ast.members) |member_node| { |
src/Zcu/PerThread.zig+59-38| ... | @@ -2176,6 +2176,9 @@ fn analyzeNavType( | ... | @@ -2176,6 +2176,9 @@ fn analyzeNavType( |
| 2176 | return .{ .type_changed = true }; | 2176 | return .{ .type_changed = true }; |
| 2177 | } | 2177 | } |
| 2178 | 2178 | ||
| 2179 | /// If `func_index` is not a runtime function (e.g. it has a comptime-only parameter type) then it | ||
| 2180 | /// is still valid to call this function and use its `func_body` unit in general---analysis of the | ||
| 2181 | /// runtime function body will simply fail. | ||
| 2179 | pub fn ensureFuncBodyUpToDate( | 2182 | pub fn ensureFuncBodyUpToDate( |
| 2180 | pt: Zcu.PerThread, | 2183 | pt: Zcu.PerThread, |
| 2181 | func_index: InternPool.Index, | 2184 | func_index: InternPool.Index, |
| ... | @@ -2278,29 +2281,6 @@ fn analyzeFuncBody( | ... | @@ -2278,29 +2281,6 @@ fn analyzeFuncBody( |
| 2278 | const func = zcu.funcInfo(func_index); | 2281 | const func = zcu.funcInfo(func_index); |
| 2279 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); | 2282 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); |
| 2280 | 2283 | ||
| 2281 | // Make sure that this function is still owned by the same `Nav`. Otherwise, analyzing | ||
| 2282 | // it would be a waste of time in the best case, and could cause codegen to give bogus | ||
| 2283 | // results in the worst case. | ||
| 2284 | |||
| 2285 | if (func.generic_owner == .none) { | ||
| 2286 | // Among another things, this ensures that the function's `zir_body_inst` is correct. | ||
| 2287 | try pt.ensureNavValUpToDate(func.owner_nav, reason); | ||
| 2288 | if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) { | ||
| 2289 | // This function is no longer referenced! There's no point in re-analyzing it. | ||
| 2290 | // Just mark a transitive failure and move on. | ||
| 2291 | return error.AnalysisFail; | ||
| 2292 | } | ||
| 2293 | } else { | ||
| 2294 | const go_nav = zcu.funcInfo(func.generic_owner).owner_nav; | ||
| 2295 | // Among another things, this ensures that the function's `zir_body_inst` is correct. | ||
| 2296 | try pt.ensureNavValUpToDate(go_nav, reason); | ||
| 2297 | if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) { | ||
| 2298 | // The generic owner is no longer referenced, so this function is also unreferenced. | ||
| 2299 | // There's no point in re-analyzing it. Just mark a transitive failure and move on. | ||
| 2300 | return error.AnalysisFail; | ||
| 2301 | } | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | // We'll want to remember what the IES used to be before the update for | 2284 | // We'll want to remember what the IES used to be before the update for |
| 2305 | // dependency invalidation purposes. | 2285 | // dependency invalidation purposes. |
| 2306 | const old_resolved_ies = if (func.analysisUnordered(ip).inferred_error_set) | 2286 | const old_resolved_ies = if (func.analysisUnordered(ip).inferred_error_set) |
| ... | @@ -3263,29 +3243,25 @@ fn analyzeFuncBodyInner( | ... | @@ -3263,29 +3243,25 @@ fn analyzeFuncBodyInner( |
| 3263 | 3243 | ||
| 3264 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); | 3244 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); |
| 3265 | const func = zcu.funcInfo(func_index); | 3245 | const func = zcu.funcInfo(func_index); |
| 3266 | const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail; | 3246 | |
| 3267 | const file = zcu.fileByIndex(inst_info.file); | 3247 | // This is the `Nav` corresponding to the `declaration` instruction which the function or its generic owner originates from. |
| 3248 | const decl_analysis = if (func.generic_owner == .none) | ||
| 3249 | ip.getNav(func.owner_nav).analysis.? | ||
| 3250 | else | ||
| 3251 | ip.getNav(zcu.funcInfo(func.generic_owner).owner_nav).analysis.?; | ||
| 3252 | |||
| 3253 | const file = zcu.fileByIndex(decl_analysis.zir_index.resolveFile(ip)); | ||
| 3268 | const zir = file.zir.?; | 3254 | const zir = file.zir.?; |
| 3269 | 3255 | ||
| 3270 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason); | 3256 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason); |
| 3271 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); | 3257 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); |
| 3272 | 3258 | ||
| 3273 | if (func.analysisUnordered(ip).inferred_error_set) { | ||
| 3274 | func.setResolvedErrorSet(ip, io, .none); | ||
| 3275 | } | ||
| 3276 | |||
| 3277 | if (zcu.comp.time_report) |*tr| { | 3259 | if (zcu.comp.time_report) |*tr| { |
| 3278 | if (func.generic_owner != .none) { | 3260 | if (func.generic_owner != .none) { |
| 3279 | tr.stats.n_generic_instances += 1; | 3261 | tr.stats.n_generic_instances += 1; |
| 3280 | } | 3262 | } |
| 3281 | } | 3263 | } |
| 3282 | 3264 | ||
| 3283 | // This is the `Nau` corresponding to the `declaration` instruction which the function or its generic owner originates from. | ||
| 3284 | const decl_nav = ip.getNav(if (func.generic_owner == .none) | ||
| 3285 | func.owner_nav | ||
| 3286 | else | ||
| 3287 | zcu.funcInfo(func.generic_owner).owner_nav); | ||
| 3288 | |||
| 3289 | const func_nav = ip.getNav(func.owner_nav); | 3265 | const func_nav = ip.getNav(func.owner_nav); |
| 3290 | 3266 | ||
| 3291 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | 3267 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| ... | @@ -3319,9 +3295,30 @@ fn analyzeFuncBodyInner( | ... | @@ -3319,9 +3295,30 @@ fn analyzeFuncBodyInner( |
| 3319 | 3295 | ||
| 3320 | // Every runtime function has a dependency on the source of the Decl it originates from. | 3296 | // Every runtime function has a dependency on the source of the Decl it originates from. |
| 3321 | // It also depends on the value of its owner Decl. | 3297 | // It also depends on the value of its owner Decl. |
| 3322 | try sema.declareDependency(.{ .src_hash = decl_nav.analysis.?.zir_index }); | 3298 | try sema.declareDependency(.{ .src_hash = decl_analysis.zir_index }); |
| 3323 | try sema.declareDependency(.{ .nav_val = func.owner_nav }); | 3299 | try sema.declareDependency(.{ .nav_val = func.owner_nav }); |
| 3324 | 3300 | ||
| 3301 | // Make sure that the declaration `Nav` still refers to this function (or its generic owner). | ||
| 3302 | // This will not be the case if the incremental update has changed a function type or turned a | ||
| 3303 | // `fn` decl into some other declaration. In that case, we must not run analysis: this function | ||
| 3304 | // will not be referenced this update, and trying to generate it could be problematic since we | ||
| 3305 | // assume the owner NAV actually, um, owns us. | ||
| 3306 | // | ||
| 3307 | // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary. | ||
| 3308 | |||
| 3309 | if (func.generic_owner == .none) { | ||
| 3310 | try pt.ensureNavValUpToDate(func.owner_nav, reason); | ||
| 3311 | if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) { | ||
| 3312 | return error.AnalysisFail; | ||
| 3313 | } | ||
| 3314 | } else { | ||
| 3315 | const go_nav = zcu.funcInfo(func.generic_owner).owner_nav; | ||
| 3316 | try pt.ensureNavValUpToDate(go_nav, reason); | ||
| 3317 | if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) { | ||
| 3318 | return error.AnalysisFail; | ||
| 3319 | } | ||
| 3320 | } | ||
| 3321 | |||
| 3325 | if (func.analysisUnordered(ip).inferred_error_set) { | 3322 | if (func.analysisUnordered(ip).inferred_error_set) { |
| 3326 | const ies = try analysis_arena.allocator().create(Sema.InferredErrorSet); | 3323 | const ies = try analysis_arena.allocator().create(Sema.InferredErrorSet); |
| 3327 | ies.* = .{ .func = func_index }; | 3324 | ies.* = .{ .func = func_index }; |
| ... | @@ -3339,11 +3336,11 @@ fn analyzeFuncBodyInner( | ... | @@ -3339,11 +3336,11 @@ fn analyzeFuncBodyInner( |
| 3339 | var inner_block: Sema.Block = .{ | 3336 | var inner_block: Sema.Block = .{ |
| 3340 | .parent = null, | 3337 | .parent = null, |
| 3341 | .sema = &sema, | 3338 | .sema = &sema, |
| 3342 | .namespace = decl_nav.analysis.?.namespace, | 3339 | .namespace = decl_analysis.namespace, |
| 3343 | .instructions = .empty, | 3340 | .instructions = .empty, |
| 3344 | .inlining = null, | 3341 | .inlining = null, |
| 3345 | .comptime_reason = null, | 3342 | .comptime_reason = null, |
| 3346 | .src_base_inst = decl_nav.analysis.?.zir_index, | 3343 | .src_base_inst = decl_analysis.zir_index, |
| 3347 | .type_name_ctx = func_nav.fqn, | 3344 | .type_name_ctx = func_nav.fqn, |
| 3348 | }; | 3345 | }; |
| 3349 | defer inner_block.instructions.deinit(gpa); | 3346 | defer inner_block.instructions.deinit(gpa); |
| ... | @@ -3385,6 +3382,13 @@ fn analyzeFuncBodyInner( | ... | @@ -3385,6 +3382,13 @@ fn analyzeFuncBodyInner( |
| 3385 | const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]); | 3382 | const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]); |
| 3386 | runtime_param_index += 1; | 3383 | runtime_param_index += 1; |
| 3387 | 3384 | ||
| 3385 | if (param_ty.isGenericPoison()) { | ||
| 3386 | // We're guaranteed to get a compile error on the `fnHasRuntimeBits` check after this | ||
| 3387 | // loop (the generic poison means this is a generic function). But `continue` here to | ||
| 3388 | // avoid an illegal call to `onePossibleValue` below. | ||
| 3389 | continue; | ||
| 3390 | } | ||
| 3391 | |||
| 3388 | const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) }); | 3392 | const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) }); |
| 3389 | 3393 | ||
| 3390 | try sema.ensureLayoutResolved(param_ty, param_ty_src, .parameter); | 3394 | try sema.ensureLayoutResolved(param_ty, param_ty_src, .parameter); |
| ... | @@ -3406,6 +3410,23 @@ fn analyzeFuncBodyInner( | ... | @@ -3406,6 +3410,23 @@ fn analyzeFuncBodyInner( |
| 3406 | 3410 | ||
| 3407 | try sema.ensureLayoutResolved(sema.fn_ret_ty, inner_block.src(.{ .node_offset_fn_type_ret_ty = .zero }), .return_type); | 3411 | try sema.ensureLayoutResolved(sema.fn_ret_ty, inner_block.src(.{ .node_offset_fn_type_ret_ty = .zero }), .return_type); |
| 3408 | 3412 | ||
| 3413 | // The function type is now resolved, so we're ready to check whether it even makes sense to ask | ||
| 3414 | // for it to be analyzed at runtime. | ||
| 3415 | if (!fn_ty.fnHasRuntimeBits(zcu)) { | ||
| 3416 | const description: []const u8 = switch (fn_ty_info.cc) { | ||
| 3417 | .@"inline" => "inline", | ||
| 3418 | else => "generic", | ||
| 3419 | }; | ||
| 3420 | // This error makes sense because the only reason this analysis would ever be requested is | ||
| 3421 | // for IES resolution. | ||
| 3422 | return sema.fail( | ||
| 3423 | &inner_block, | ||
| 3424 | inner_block.nodeOffset(.zero), | ||
| 3425 | "cannot resolve inferred error set of {s} function type '{f}'", | ||
| 3426 | .{ description, fn_ty.fmt(pt) }, | ||
| 3427 | ); | ||
| 3428 | } | ||
| 3429 | |||
| 3409 | const last_arg_index = inner_block.instructions.items.len; | 3430 | const last_arg_index = inner_block.instructions.items.len; |
| 3410 | 3431 | ||
| 3411 | // Save the error trace as our first action in the function. | 3432 | // Save the error trace as our first action in the function. |
src/codegen/c.zig+11-4| ... | @@ -2112,7 +2112,7 @@ pub fn genTagNameFn( | ... | @@ -2112,7 +2112,7 @@ pub fn genTagNameFn( |
| 2112 | const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); | 2112 | const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); |
| 2113 | assert(loaded_enum.field_names.len > 0); | 2113 | assert(loaded_enum.field_names.len > 0); |
| 2114 | if (Type.fromInterned(loaded_enum.int_tag_type).bitSize(zcu) > 64) { | 2114 | if (Type.fromInterned(loaded_enum.int_tag_type).bitSize(zcu) > 64) { |
| 2115 | @panic("TODO CBE: tagName for enum over 128 bits"); | 2115 | @panic("TODO CBE: tagName for enum over 64 bits"); |
| 2116 | } | 2116 | } |
| 2117 | 2117 | ||
| 2118 | try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{ | 2118 | try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{ |
| ... | @@ -2130,10 +2130,10 @@ pub fn genTagNameFn( | ... | @@ -2130,10 +2130,10 @@ pub fn genTagNameFn( |
| 2130 | try w.writeAll(" switch (tag) {\n"); | 2130 | try w.writeAll(" switch (tag) {\n"); |
| 2131 | const field_values = loaded_enum.field_values.get(ip); | 2131 | const field_values = loaded_enum.field_values.get(ip); |
| 2132 | for (loaded_enum.field_names.get(ip), 0..) |field_name, field_index| { | 2132 | for (loaded_enum.field_names.get(ip), 0..) |field_name, field_index| { |
| 2133 | const field_int: u64 = int: { | 2133 | const field_int: i65 = int: { |
| 2134 | if (field_values.len == 0) break :int field_index; | 2134 | if (field_values.len == 0) break :int field_index; |
| 2135 | const field_val: Value = .fromInterned(field_values[field_index]); | 2135 | const field_val: Value = .fromInterned(field_values[field_index]); |
| 2136 | break :int field_val.toUnsignedInt(zcu); | 2136 | break :int field_val.getUnsignedInt(zcu) orelse field_val.toSignedInt(zcu); |
| 2137 | }; | 2137 | }; |
| 2138 | try w.print(" case {d}: return ({s}){{name{d},{d}}};\n", .{ | 2138 | try w.print(" case {d}: return ({s}){{name{d},{d}}};\n", .{ |
| 2139 | field_int, | 2139 | field_int, |
| ... | @@ -3278,7 +3278,10 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3278,7 +3278,10 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3278 | const operand_ty = f.typeOf(ty_op.operand); | 3278 | const operand_ty = f.typeOf(ty_op.operand); |
| 3279 | const scalar_ty = operand_ty.scalarType(zcu); | 3279 | const scalar_ty = operand_ty.scalarType(zcu); |
| 3280 | 3280 | ||
| 3281 | if (f.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) return f.moveCValue(inst, inst_ty, operand); | 3281 | // `intCastIsNoop` doesn't apply to vectors because every vector lowers to a different C struct. |
| 3282 | if (inst_ty.zigTypeTag(zcu) != .vector and f.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) { | ||
| 3283 | return f.moveCValue(inst, inst_ty, operand); | ||
| 3284 | } | ||
| 3282 | 3285 | ||
| 3283 | const w = &f.code.writer; | 3286 | const w = &f.code.writer; |
| 3284 | const local = try f.allocLocal(inst, inst_ty); | 3287 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -3491,6 +3494,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: | ... | @@ -3491,6 +3494,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3491 | const operand_ty = f.typeOf(bin_op.lhs); | 3494 | const operand_ty = f.typeOf(bin_op.lhs); |
| 3492 | const scalar_ty = operand_ty.scalarType(zcu); | 3495 | const scalar_ty = operand_ty.scalarType(zcu); |
| 3493 | 3496 | ||
| 3497 | const ref_arg = lowersToBigInt(scalar_ty, zcu); | ||
| 3498 | |||
| 3494 | const w = &f.code.writer; | 3499 | const w = &f.code.writer; |
| 3495 | const local = try f.allocLocal(inst, inst_ty); | 3500 | const local = try f.allocLocal(inst, inst_ty); |
| 3496 | const v = try Vectorize.start(f, inst, w, operand_ty); | 3501 | const v = try Vectorize.start(f, inst, w, operand_ty); |
| ... | @@ -3504,9 +3509,11 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: | ... | @@ -3504,9 +3509,11 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3504 | try f.writeCValueMember(w, local, .{ .field = 0 }); | 3509 | try f.writeCValueMember(w, local, .{ .field = 0 }); |
| 3505 | try v.elem(f, w); | 3510 | try v.elem(f, w); |
| 3506 | try w.writeAll(", "); | 3511 | try w.writeAll(", "); |
| 3512 | if (ref_arg) try w.writeByte('&'); | ||
| 3507 | try f.writeCValue(w, lhs, .other); | 3513 | try f.writeCValue(w, lhs, .other); |
| 3508 | try v.elem(f, w); | 3514 | try v.elem(f, w); |
| 3509 | try w.writeAll(", "); | 3515 | try w.writeAll(", "); |
| 3516 | if (ref_arg) try w.writeByte('&'); | ||
| 3510 | try f.writeCValue(w, rhs, .other); | 3517 | try f.writeCValue(w, rhs, .other); |
| 3511 | if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); | 3518 | if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); |
| 3512 | try f.dg.renderBuiltinInfo(w, scalar_ty, info); | 3519 | try f.dg.renderBuiltinInfo(w, scalar_ty, info); |
src/codegen/c/type.zig+12-2| ... | @@ -898,13 +898,23 @@ pub const CType = union(enum) { | ... | @@ -898,13 +898,23 @@ pub const CType = union(enum) { |
| 898 | try w.writeAll("fn_"); // intentional double underscore to start | 898 | try w.writeAll("fn_"); // intentional double underscore to start |
| 899 | for (func_type.param_types.get(ip)) |param_ty_ip| { | 899 | for (func_type.param_types.get(ip)) |param_ty_ip| { |
| 900 | const param_ty: Type = .fromInterned(param_ty_ip); | 900 | const param_ty: Type = .fromInterned(param_ty_ip); |
| 901 | try w.print("_P{f}", .{fmtZigType(param_ty, zcu)}); | 901 | if (param_ty.isGenericPoison()) { |
| 902 | try w.writeAll("_Pgeneric"); | ||
| 903 | } else { | ||
| 904 | try w.print("_P{f}", .{fmtZigType(param_ty, zcu)}); | ||
| 905 | } | ||
| 902 | } | 906 | } |
| 903 | if (func_type.is_var_args) { | 907 | if (func_type.is_var_args) { |
| 904 | try w.writeAll("_VA"); | 908 | try w.writeAll("_VA"); |
| 905 | } | 909 | } |
| 906 | const ret_ty: Type = .fromInterned(func_type.return_type); | 910 | const ret_ty: Type = .fromInterned(func_type.return_type); |
| 907 | try w.print("_R{f}", .{fmtZigType(ret_ty, zcu)}); | 911 | if (ret_ty.isGenericPoison()) { |
| 912 | try w.writeAll("_Rgeneric"); | ||
| 913 | } else if (ret_ty.zigTypeTag(zcu) == .error_union and ret_ty.errorUnionPayload(zcu).isGenericPoison()) { | ||
| 914 | try w.writeAll("_Rgeneric_ies"); | ||
| 915 | } else { | ||
| 916 | try w.print("_R{f}", .{fmtZigType(ret_ty, zcu)}); | ||
| 917 | } | ||
| 908 | }, | 918 | }, |
| 909 | 919 | ||
| 910 | .vector => try w.print("vec_{d}_{f}", .{ | 920 | .vector => try w.print("vec_{d}_{f}", .{ |
src/codegen/llvm.zig+7-25| ... | @@ -3436,9 +3436,9 @@ pub const Object = struct { | ... | @@ -3436,9 +3436,9 @@ pub const Object = struct { |
| 3436 | } | 3436 | } |
| 3437 | 3437 | ||
| 3438 | if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) { | 3438 | if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) { |
| 3439 | const stack_trace_ty = zcu.builtin_decl_values.get(.StackTrace); | 3439 | // First parameter is a pointer to `std.builtin.StackTrace`. |
| 3440 | const ptr_ty = try pt.ptrType(.{ .child = stack_trace_ty }); | 3440 | const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(.generic, target)); |
| 3441 | try llvm_params.append(o.gpa, try o.lowerType(pt, ptr_ty)); | 3441 | try llvm_params.append(o.gpa, llvm_ptr_ty); |
| 3442 | } | 3442 | } |
| 3443 | 3443 | ||
| 3444 | var it = iterateParamTypes(o, pt, fn_info); | 3444 | var it = iterateParamTypes(o, pt, fn_info); |
| ... | @@ -6719,16 +6719,11 @@ pub const FuncGen = struct { | ... | @@ -6719,16 +6719,11 @@ pub const FuncGen = struct { |
| 6719 | const zcu = pt.zcu; | 6719 | const zcu = pt.zcu; |
| 6720 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 6720 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6721 | const ptr_ty = self.typeOf(bin_op.lhs); | 6721 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 6722 | const elem_ty = ptr_ty.childType(zcu); | 6722 | const elem_ty = ptr_ty.indexableElem(zcu); |
| 6723 | const llvm_elem_ty = try o.lowerType(pt, elem_ty); | 6723 | const llvm_elem_ty = try o.lowerType(pt, elem_ty); |
| 6724 | const base_ptr = try self.resolveInst(bin_op.lhs); | 6724 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 6725 | const rhs = try self.resolveInst(bin_op.rhs); | 6725 | const rhs = try self.resolveInst(bin_op.rhs); |
| 6726 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch | 6726 | const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{rhs}, ""); |
| 6727 | const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(zcu)) | ||
| 6728 | // If this is a single-item pointer to an array, we need another index in the GEP. | ||
| 6729 | &.{ try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), rhs } | ||
| 6730 | else | ||
| 6731 | &.{rhs}, ""); | ||
| 6732 | if (isByRef(elem_ty, zcu)) { | 6727 | if (isByRef(elem_ty, zcu)) { |
| 6733 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); | 6728 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| 6734 | const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); | 6729 | const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); |
| ... | @@ -6808,11 +6803,6 @@ pub const FuncGen = struct { | ... | @@ -6808,11 +6803,6 @@ pub const FuncGen = struct { |
| 6808 | const truncated_int = | 6803 | const truncated_int = |
| 6809 | try self.wip.cast(.trunc, shifted_value, same_size_int, ""); | 6804 | try self.wip.cast(.trunc, shifted_value, same_size_int, ""); |
| 6810 | return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, ""); | 6805 | return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, ""); |
| 6811 | } else if (field_ty.isPtrAtRuntime(zcu)) { | ||
| 6812 | const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); | ||
| 6813 | const truncated_int = | ||
| 6814 | try self.wip.cast(.trunc, shifted_value, same_size_int, ""); | ||
| 6815 | return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, ""); | ||
| 6816 | } | 6806 | } |
| 6817 | return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, ""); | 6807 | return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, ""); |
| 6818 | }, | 6808 | }, |
| ... | @@ -6830,11 +6820,6 @@ pub const FuncGen = struct { | ... | @@ -6830,11 +6820,6 @@ pub const FuncGen = struct { |
| 6830 | const truncated_int = | 6820 | const truncated_int = |
| 6831 | try self.wip.cast(.trunc, containing_int, same_size_int, ""); | 6821 | try self.wip.cast(.trunc, containing_int, same_size_int, ""); |
| 6832 | return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, ""); | 6822 | return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, ""); |
| 6833 | } else if (field_ty.isPtrAtRuntime(zcu)) { | ||
| 6834 | const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); | ||
| 6835 | const truncated_int = | ||
| 6836 | try self.wip.cast(.trunc, containing_int, same_size_int, ""); | ||
| 6837 | return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, ""); | ||
| 6838 | } | 6823 | } |
| 6839 | return self.wip.cast(.trunc, containing_int, elem_llvm_ty, ""); | 6824 | return self.wip.cast(.trunc, containing_int, elem_llvm_ty, ""); |
| 6840 | }, | 6825 | }, |
| ... | @@ -10110,7 +10095,7 @@ pub const FuncGen = struct { | ... | @@ -10110,7 +10095,7 @@ pub const FuncGen = struct { |
| 10110 | const ip = &zcu.intern_pool; | 10095 | const ip = &zcu.intern_pool; |
| 10111 | const enum_type = ip.loadEnumType(enum_ty.toIntern()); | 10096 | const enum_type = ip.loadEnumType(enum_ty.toIntern()); |
| 10112 | 10097 | ||
| 10113 | // TODO: detect when the type changes and re-emit this function. | 10098 | // TODO: detect when the type changes (`updateContainerType` will be called) and re-emit this function |
| 10114 | const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern()); | 10099 | const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern()); |
| 10115 | if (gop.found_existing) return gop.value_ptr.*; | 10100 | if (gop.found_existing) return gop.value_ptr.*; |
| 10116 | errdefer assert(o.named_enum_map.remove(enum_ty.toIntern())); | 10101 | errdefer assert(o.named_enum_map.remove(enum_ty.toIntern())); |
| ... | @@ -10728,10 +10713,7 @@ pub const FuncGen = struct { | ... | @@ -10728,10 +10713,7 @@ pub const FuncGen = struct { |
| 10728 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]); | 10713 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]); |
| 10729 | const non_int_val = try self.resolveInst(extra.init); | 10714 | const non_int_val = try self.resolveInst(extra.init); |
| 10730 | const small_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); | 10715 | const small_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); |
| 10731 | const small_int_val = if (field_ty.isPtrAtRuntime(zcu)) | 10716 | const small_int_val = try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); |
| 10732 | try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") | ||
| 10733 | else | ||
| 10734 | try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); | ||
| 10735 | return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, ""); | 10717 | return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, ""); |
| 10736 | } | 10718 | } |
| 10737 | 10719 |
src/link/Dwarf.zig+6| ... | @@ -2252,6 +2252,12 @@ pub const WipNav = struct { | ... | @@ -2252,6 +2252,12 @@ pub const WipNav = struct { |
| 2252 | .generic_decl_const, | 2252 | .generic_decl_const, |
| 2253 | .generic_decl_func, | 2253 | .generic_decl_func, |
| 2254 | => true, | 2254 | => true, |
| 2255 | |||
| 2256 | // This comes from a decl which was previously generated as an incomplete value | ||
| 2257 | // (I think that must mean either a function or an extern which previously had | ||
| 2258 | // incomplete types). | ||
| 2259 | .undefined_comptime_value => false, | ||
| 2260 | |||
| 2255 | else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}), | 2261 | else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}), |
| 2256 | }; | 2262 | }; |
| 2257 | if (parent_type.getCaptures(zcu).len == 0) { | 2263 | if (parent_type.getCaptures(zcu).len == 0) { |
src/print_value.zig+19-4| ... | @@ -113,7 +113,7 @@ pub fn print( | ... | @@ -113,7 +113,7 @@ pub fn print( |
| 113 | if (slice.len == .zero_usize) { | 113 | if (slice.len == .zero_usize) { |
| 114 | return writer.writeAll("&.{}"); | 114 | return writer.writeAll("&.{}"); |
| 115 | } | 115 | } |
| 116 | try print(.fromInterned(slice.ptr), writer, level - 1, pt, opt_sema); | 116 | try print(.fromInterned(slice.ptr), writer, level, pt, opt_sema); |
| 117 | } else { | 117 | } else { |
| 118 | const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) { | 118 | const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) { |
| 119 | .field, .arr_elem, .eu_payload, .opt_payload => unreachable, | 119 | .field, .arr_elem, .eu_payload, .opt_payload => unreachable, |
| ... | @@ -170,6 +170,9 @@ pub fn print( | ... | @@ -170,6 +170,9 @@ pub fn print( |
| 170 | } | 170 | } |
| 171 | }, | 171 | }, |
| 172 | .bitpack => |bitpack| { | 172 | .bitpack => |bitpack| { |
| 173 | if (level == 0) { | ||
| 174 | return writer.writeAll(".{ ... }"); | ||
| 175 | } | ||
| 173 | const ty: Type = .fromInterned(bitpack.ty); | 176 | const ty: Type = .fromInterned(bitpack.ty); |
| 174 | switch (ty.zigTypeTag(zcu)) { | 177 | switch (ty.zigTypeTag(zcu)) { |
| 175 | .@"struct" => { | 178 | .@"struct" => { |
| ... | @@ -464,18 +467,30 @@ pub fn printPtrDerivation( | ... | @@ -464,18 +467,30 @@ pub fn printPtrDerivation( |
| 464 | .uav_ptr => |uav| { | 467 | .uav_ptr => |uav| { |
| 465 | const ty = Value.fromInterned(uav.val).typeOf(zcu); | 468 | const ty = Value.fromInterned(uav.val).typeOf(zcu); |
| 466 | try writer.print("@as({f}, ", .{ty.fmt(pt)}); | 469 | try writer.print("@as({f}, ", .{ty.fmt(pt)}); |
| 467 | try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema); | 470 | if (x.level == 0) { |
| 471 | try writer.writeAll("..."); | ||
| 472 | } else { | ||
| 473 | try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema); | ||
| 474 | } | ||
| 468 | try writer.writeByte(')'); | 475 | try writer.writeByte(')'); |
| 469 | }, | 476 | }, |
| 470 | .comptime_alloc_ptr => |info| { | 477 | .comptime_alloc_ptr => |info| { |
| 471 | try writer.print("@as({f}, ", .{info.val.typeOf(zcu).fmt(pt)}); | 478 | try writer.print("@as({f}, ", .{info.val.typeOf(zcu).fmt(pt)}); |
| 472 | try print(info.val, writer, x.level - 1, pt, x.opt_sema); | 479 | if (x.level == 0) { |
| 480 | try writer.writeAll("..."); | ||
| 481 | } else { | ||
| 482 | try print(info.val, writer, x.level - 1, pt, x.opt_sema); | ||
| 483 | } | ||
| 473 | try writer.writeByte(')'); | 484 | try writer.writeByte(')'); |
| 474 | }, | 485 | }, |
| 475 | .comptime_field_ptr => |val| { | 486 | .comptime_field_ptr => |val| { |
| 476 | const ty = val.typeOf(zcu); | 487 | const ty = val.typeOf(zcu); |
| 477 | try writer.print("@as({f}, ", .{ty.fmt(pt)}); | 488 | try writer.print("@as({f}, ", .{ty.fmt(pt)}); |
| 478 | try print(val, writer, x.level - 1, pt, x.opt_sema); | 489 | if (x.level == 0) { |
| 490 | try writer.writeAll("..."); | ||
| 491 | } else { | ||
| 492 | try print(val, writer, x.level - 1, pt, x.opt_sema); | ||
| 493 | } | ||
| 479 | try writer.writeByte(')'); | 494 | try writer.writeByte(')'); |
| 480 | }, | 495 | }, |
| 481 | else => unreachable, | 496 | else => unreachable, |