authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-28 19:22:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-28 19:22:16-07:00
log157f66ec077ad02f08891bec1a426c0ffef98e09
tree75b207ed6ccbbd2af83a338e09b86bc8de2965c4
parenta7ca40b2817dbf3f2085141f32f20f431707391b

Sema: fix pointer type hash and equality functions

Several issues with pointer types are fixed: Prior to this commit, Zig would not canonicalize a pointer type with an explicit alignment to alignment=0 if it matched the pointee ABI alignment. In order to fix this, `Type.ptr` now takes a Target parameter. I also moved the host_size canonicalization to `Type.ptr` since target is now available. Similarly, is_allowzero in the case of C pointers is now treated as a canonicalization done by the function rather than a precondition. in-memory coercion for pointers now properly checks ABI alignment of pointee types instead of incorrectly treating the 0 value as an alignment. Type equality is completely reworked based on the tag() rather than the zigTypeTag(). It's still semantically based on zigTypeTag() but that knowledge is implied rather than dictating the control flow of the logic. Importantly, this fixes cases for opaques, structs, tuples, enums, and unions, where type equality was incorrectly returning based on whether the tag() values were equal. Additionally, pointer type equality now takes into account alignment. Because we canonicalize non-zero alignment which equals pointee type ABI alignment to alignment=0, this now can be a simple integer comparison. Type hashing is implemented for pointers and floats. Array types now additionally hash their sentinels. This regressed some behavior tests that were passing but only because of bugs regarding type equality. The C backend has a noticeable problem with lowering differently-aligned pointers (particularly slices) as the same type, causing C compilation errors due to duplicate declarations.

7 files changed, 492 insertions(+), 267 deletions(-)

src/Sema.zig+126-77
......@@ -1555,7 +1555,8 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
15551555 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
15561556 const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs);
15571557 const ptr = sema.resolveInst(bin_inst.rhs);
1558 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
1558 const target = sema.mod.getTarget();
1559 const addr_space = target_util.defaultAddressSpace(target, .local);
15591560
15601561 if (Air.refToIndex(ptr)) |ptr_inst| {
15611562 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
......@@ -1575,7 +1576,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
15751576 try inferred_alloc.stored_inst_list.append(sema.arena, operand);
15761577
15771578 try sema.requireRuntimeBlock(block, src);
1578 const ptr_ty = try Type.ptr(sema.arena, .{
1579 const ptr_ty = try Type.ptr(sema.arena, target, .{
15791580 .pointee_type = pointee_ty,
15801581 .@"align" = inferred_alloc.alignment,
15811582 .@"addrspace" = addr_space,
......@@ -1593,7 +1594,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
15931594 try pointee_ty.copy(anon_decl.arena()),
15941595 Value.undef,
15951596 );
1596 const ptr_ty = try Type.ptr(sema.arena, .{
1597 const ptr_ty = try Type.ptr(sema.arena, target, .{
15971598 .pointee_type = pointee_ty,
15981599 .@"align" = iac.data.alignment,
15991600 .@"addrspace" = addr_space,
......@@ -1642,7 +1643,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
16421643 }
16431644 }
16441645
1645 const ptr_ty = try Type.ptr(sema.arena, .{
1646 const ptr_ty = try Type.ptr(sema.arena, target, .{
16461647 .pointee_type = pointee_ty,
16471648 .@"addrspace" = addr_space,
16481649 });
......@@ -1663,7 +1664,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
16631664 }
16641665 const ty_op = air_datas[trash_inst].ty_op;
16651666 const operand_ty = sema.getTmpAir().typeOf(ty_op.operand);
1666 const ptr_operand_ty = try Type.ptr(sema.arena, .{
1667 const ptr_operand_ty = try Type.ptr(sema.arena, target, .{
16671668 .pointee_type = operand_ty,
16681669 .@"addrspace" = addr_space,
16691670 });
......@@ -2225,9 +2226,10 @@ fn zirRetPtr(
22252226 return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src);
22262227 }
22272228
2228 const ptr_type = try Type.ptr(sema.arena, .{
2229 const target = sema.mod.getTarget();
2230 const ptr_type = try Type.ptr(sema.arena, target, .{
22292231 .pointee_type = sema.fn_ret_ty,
2230 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
2232 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
22312233 });
22322234
22332235 if (block.inlining != null) {
......@@ -2389,10 +2391,11 @@ fn zirAllocExtended(
23892391 if (!small.is_const) {
23902392 try sema.validateVarType(block, ty_src, var_ty, false);
23912393 }
2392 const ptr_type = try Type.ptr(sema.arena, .{
2394 const target = sema.mod.getTarget();
2395 const ptr_type = try Type.ptr(sema.arena, target, .{
23932396 .pointee_type = var_ty,
23942397 .@"align" = alignment,
2395 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
2398 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
23962399 });
23972400 try sema.requireRuntimeBlock(block, src);
23982401 try sema.resolveTypeLayout(block, src, var_ty);
......@@ -2450,9 +2453,10 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
24502453 if (block.is_comptime) {
24512454 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
24522455 }
2453 const ptr_type = try Type.ptr(sema.arena, .{
2456 const target = sema.mod.getTarget();
2457 const ptr_type = try Type.ptr(sema.arena, target, .{
24542458 .pointee_type = var_ty,
2455 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
2459 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
24562460 });
24572461 try sema.requireRuntimeBlock(block, var_decl_src);
24582462 try sema.resolveTypeLayout(block, ty_src, var_ty);
......@@ -2471,9 +2475,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
24712475 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
24722476 }
24732477 try sema.validateVarType(block, ty_src, var_ty, false);
2474 const ptr_type = try Type.ptr(sema.arena, .{
2478 const target = sema.mod.getTarget();
2479 const ptr_type = try Type.ptr(sema.arena, target, .{
24752480 .pointee_type = var_ty,
2476 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
2481 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
24772482 });
24782483 try sema.requireRuntimeBlock(block, var_decl_src);
24792484 try sema.resolveTypeLayout(block, ty_src, var_ty);
......@@ -2542,7 +2547,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
25422547 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
25432548
25442549 const final_elem_ty = try decl.ty.copy(sema.arena);
2545 const final_ptr_ty = try Type.ptr(sema.arena, .{
2550 const final_ptr_ty = try Type.ptr(sema.arena, target, .{
25462551 .pointee_type = final_elem_ty,
25472552 .mutable = var_is_mut,
25482553 .@"align" = iac.data.alignment,
......@@ -2565,7 +2570,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
25652570 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
25662571 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
25672572
2568 const final_ptr_ty = try Type.ptr(sema.arena, .{
2573 const final_ptr_ty = try Type.ptr(sema.arena, target, .{
25692574 .pointee_type = final_elem_ty,
25702575 .mutable = var_is_mut,
25712576 .@"align" = inferred_alloc.data.alignment,
......@@ -3335,10 +3340,11 @@ fn storeToInferredAlloc(
33353340 // for the inferred allocation.
33363341 try inferred_alloc.data.stored_inst_list.append(sema.arena, operand);
33373342 // Create a runtime bitcast instruction with exactly the type the pointer wants.
3338 const ptr_ty = try Type.ptr(sema.arena, .{
3343 const target = sema.mod.getTarget();
3344 const ptr_ty = try Type.ptr(sema.arena, target, .{
33393345 .pointee_type = operand_ty,
33403346 .@"align" = inferred_alloc.data.alignment,
3341 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
3347 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
33423348 });
33433349 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
33443350 return sema.storePtr(block, src, bitcasted_ptr, operand);
......@@ -5444,7 +5450,8 @@ fn analyzeOptionalPayloadPtr(
54445450 }
54455451
54465452 const child_type = try opt_type.optionalChildAlloc(sema.arena);
5447 const child_pointer = try Type.ptr(sema.arena, .{
5453 const target = sema.mod.getTarget();
5454 const child_pointer = try Type.ptr(sema.arena, target, .{
54485455 .pointee_type = child_type,
54495456 .mutable = !optional_ptr_ty.isConstPtr(),
54505457 .@"addrspace" = optional_ptr_ty.ptrAddressSpace(),
......@@ -5509,7 +5516,8 @@ fn zirOptionalPayload(
55095516 return sema.failWithExpectedOptionalType(block, src, operand_ty);
55105517 }
55115518 const ptr_info = operand_ty.ptrInfo().data;
5512 break :t try Type.ptr(sema.arena, .{
5519 const target = sema.mod.getTarget();
5520 break :t try Type.ptr(sema.arena, target, .{
55135521 .pointee_type = try ptr_info.pointee_type.copy(sema.arena),
55145522 .@"align" = ptr_info.@"align",
55155523 .@"addrspace" = ptr_info.@"addrspace",
......@@ -5607,7 +5615,8 @@ fn analyzeErrUnionPayloadPtr(
56075615 return sema.fail(block, src, "expected error union type, found {}", .{operand_ty.elemType()});
56085616
56095617 const payload_ty = operand_ty.elemType().errorUnionPayload();
5610 const operand_pointer_ty = try Type.ptr(sema.arena, .{
5618 const target = sema.mod.getTarget();
5619 const operand_pointer_ty = try Type.ptr(sema.arena, target, .{
56115620 .pointee_type = payload_ty,
56125621 .mutable = !operand_ty.isConstPtr(),
56135622 .@"addrspace" = operand_ty.ptrAddressSpace(),
......@@ -6517,7 +6526,8 @@ fn zirSwitchCapture(
65176526 if (is_ref) {
65186527 assert(operand_is_ref);
65196528
6520 const field_ty_ptr = try Type.ptr(sema.arena, .{
6529 const target = sema.mod.getTarget();
6530 const field_ty_ptr = try Type.ptr(sema.arena, target, .{
65216531 .pointee_type = field.ty,
65226532 .@"addrspace" = .generic,
65236533 .mutable = operand_ptr_ty.ptrIsMutable(),
......@@ -11327,7 +11337,8 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
1132711337
1132811338 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
1132911339 const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type);
11330 const ty = try Type.ptr(sema.arena, .{
11340 const target = sema.mod.getTarget();
11341 const ty = try Type.ptr(sema.arena, target, .{
1133111342 .pointee_type = elem_type,
1133211343 .@"addrspace" = .generic,
1133311344 .mutable = inst_data.is_mutable,
......@@ -11343,6 +11354,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1134311354 defer tracy.end();
1134411355
1134511356 const src: LazySrcLoc = .unneeded;
11357 const elem_ty_src: LazySrcLoc = .unneeded;
1134611358 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
1134711359 const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
1134811360
......@@ -11366,41 +11378,40 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1136611378 break :blk try sema.analyzeAddrspace(block, .unneeded, ref, .pointer);
1136711379 } else .generic;
1136811380
11369 const bit_start = if (inst_data.flags.has_bit_range) blk: {
11381 const bit_offset = if (inst_data.flags.has_bit_range) blk: {
1137011382 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
1137111383 extra_i += 1;
1137211384 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
1137311385 } else 0;
1137411386
11375 var host_size: u16 = if (inst_data.flags.has_bit_range) blk: {
11387 const host_size: u16 = if (inst_data.flags.has_bit_range) blk: {
1137611388 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
1137711389 extra_i += 1;
1137811390 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
1137911391 } else 0;
1138011392
11381 const elem_type = try sema.resolveType(block, .unneeded, extra.data.elem_type);
11382
11383 if (host_size != 0) {
11384 if (bit_start >= host_size * 8) {
11385 return sema.fail(block, src, "bit offset starts after end of host integer", .{});
11386 }
11387 const target = sema.mod.getTarget();
11388 const elem_type_bits = elem_type.bitSize(target);
11389 if (host_size * 8 == elem_type_bits) {
11390 assert(bit_start == 0);
11391 host_size = 0;
11392 }
11393 if (host_size != 0 and bit_offset >= host_size * 8) {
11394 return sema.fail(block, src, "bit offset starts after end of host integer", .{});
1139311395 }
1139411396
11395 const ty = try Type.ptr(sema.arena, .{
11396 .pointee_type = elem_type,
11397 const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type);
11398 const elem_ty = if (abi_align == 0)
11399 unresolved_elem_ty
11400 else t: {
11401 const elem_ty = try sema.resolveTypeFields(block, elem_ty_src, unresolved_elem_ty);
11402 try sema.resolveTypeLayout(block, elem_ty_src, elem_ty);
11403 break :t elem_ty;
11404 };
11405 const target = sema.mod.getTarget();
11406 const ty = try Type.ptr(sema.arena, target, .{
11407 .pointee_type = elem_ty,
1139711408 .sentinel = sentinel,
1139811409 .@"align" = abi_align,
1139911410 .@"addrspace" = address_space,
11400 .bit_offset = bit_start,
11411 .bit_offset = bit_offset,
1140111412 .host_size = host_size,
1140211413 .mutable = inst_data.flags.is_mutable,
11403 .@"allowzero" = inst_data.flags.is_allowzero or inst_data.size == .C,
11414 .@"allowzero" = inst_data.flags.is_allowzero,
1140411415 .@"volatile" = inst_data.flags.is_volatile,
1140511416 .size = inst_data.size,
1140611417 });
......@@ -11721,15 +11732,16 @@ fn zirArrayInit(
1172111732 try sema.resolveTypeLayout(block, src, elem_ty);
1172211733
1172311734 if (is_ref) {
11724 const alloc_ty = try Type.ptr(sema.arena, .{
11735 const target = sema.mod.getTarget();
11736 const alloc_ty = try Type.ptr(sema.arena, target, .{
1172511737 .pointee_type = array_ty,
11726 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
11738 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
1172711739 });
1172811740 const alloc = try block.addTy(.alloc, alloc_ty);
1172911741
11730 const elem_ptr_ty = try Type.ptr(sema.arena, .{
11742 const elem_ptr_ty = try Type.ptr(sema.arena, target, .{
1173111743 .mutable = true,
11732 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
11744 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
1173311745 .pointee_type = elem_ty,
1173411746 });
1173511747 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
......@@ -11788,12 +11800,13 @@ fn zirArrayInitAnon(
1178811800 try sema.requireRuntimeBlock(block, runtime_src);
1178911801
1179011802 if (is_ref) {
11803 const target = sema.mod.getTarget();
1179111804 const alloc = try block.addTy(.alloc, tuple_ty);
1179211805 for (operands) |operand, i_usize| {
1179311806 const i = @intCast(u32, i_usize);
11794 const field_ptr_ty = try Type.ptr(sema.arena, .{
11807 const field_ptr_ty = try Type.ptr(sema.arena, target, .{
1179511808 .mutable = true,
11796 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
11809 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
1179711810 .pointee_type = types[i],
1179811811 });
1179911812 const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
......@@ -12068,6 +12081,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1206812081 const union_val = val.cast(Value.Payload.Union).?.data;
1206912082 const tag_ty = type_info_ty.unionTagType().?;
1207012083 const tag_index = tag_ty.enumTagFieldIndex(union_val.tag).?;
12084 const target = sema.mod.getTarget();
1207112085 switch (@intToEnum(std.builtin.TypeId, tag_index)) {
1207212086 .Type => return Air.Inst.Ref.type_type,
1207312087 .Void => return Air.Inst.Ref.void_type,
......@@ -12146,11 +12160,14 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1214612160 return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
1214712161 }
1214812162 const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data;
12149 const ptr_ty = try Type.ptr(sema.arena, .{ .@"addrspace" = .generic, .pointee_type = child_ty });
12163 const ptr_ty = try Type.ptr(sema.arena, target, .{
12164 .@"addrspace" = .generic,
12165 .pointee_type = child_ty,
12166 });
1215012167 actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
1215112168 }
1215212169
12153 const ty = try Type.ptr(sema.arena, .{
12170 const ty = try Type.ptr(sema.arena, target, .{
1215412171 .size = ptr_size,
1215512172 .mutable = !is_const_val.toBool(),
1215612173 .@"volatile" = is_volatile_val.toBool(),
......@@ -12176,7 +12193,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1217612193 var buffer: Value.ToTypeBuffer = undefined;
1217712194 const child_ty = try child_val.toType(&buffer).copy(sema.arena);
1217812195 const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: {
12179 const ptr_ty = try Type.ptr(sema.arena, .{ .@"addrspace" = .generic, .pointee_type = child_ty });
12196 const ptr_ty = try Type.ptr(sema.arena, target, .{
12197 .@"addrspace" = .generic,
12198 .pointee_type = child_ty,
12199 });
1218012200 break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?;
1218112201 } else null;
1218212202
......@@ -12468,7 +12488,8 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1246812488 // TODO insert safety check that the alignment is correct
1246912489
1247012490 const ptr_info = ptr_ty.ptrInfo().data;
12471 const dest_ty = try Type.ptr(sema.arena, .{
12491 const target = sema.mod.getTarget();
12492 const dest_ty = try Type.ptr(sema.arena, target, .{
1247212493 .pointee_type = ptr_info.pointee_type,
1247312494 .@"align" = dest_align,
1247412495 .@"addrspace" = ptr_info.@"addrspace",
......@@ -13408,11 +13429,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
1340813429 ptr_ty_data.@"align" = @intCast(u32, field.abi_align.toUnsignedInt());
1340913430 }
1341013431
13411 const actual_field_ptr_ty = try Type.ptr(sema.arena, ptr_ty_data);
13432 const target = sema.mod.getTarget();
13433 const actual_field_ptr_ty = try Type.ptr(sema.arena, target, ptr_ty_data);
1341213434 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
1341313435
1341413436 ptr_ty_data.pointee_type = struct_ty;
13415 const result_ptr = try Type.ptr(sema.arena, ptr_ty_data);
13437 const result_ptr = try Type.ptr(sema.arena, target, ptr_ty_data);
1341613438
1341713439 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
1341813440 const payload = field_ptr_val.castTag(.field_ptr).?.data;
......@@ -13509,7 +13531,8 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
1350913531 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);
1351013532 try sema.checkPtrOperand(block, src_src, uncasted_src_ptr_ty);
1351113533 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;
13512 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{
13534 const target = sema.mod.getTarget();
13535 const wanted_src_ptr_ty = try Type.ptr(sema.arena, target, .{
1351313536 .pointee_type = dest_ptr_ty.elemType2(),
1351413537 .@"align" = src_ptr_info.@"align",
1351513538 .@"addrspace" = src_ptr_info.@"addrspace",
......@@ -14149,9 +14172,10 @@ fn panicWithMsg(
1414914172 const panic_fn = try sema.getBuiltin(block, src, "panic");
1415014173 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
1415114174 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
14152 const ptr_stack_trace_ty = try Type.ptr(arena, .{
14175 const target = mod.getTarget();
14176 const ptr_stack_trace_ty = try Type.ptr(arena, target, .{
1415314177 .pointee_type = stack_trace_ty,
14154 .@"addrspace" = target_util.defaultAddressSpace(mod.getTarget(), .global_constant), // TODO might need a place that is more dynamic
14178 .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
1415514179 });
1415614180 const null_stack_trace = try sema.addConstant(
1415714181 try Type.optional(arena, ptr_stack_trace_ty),
......@@ -14405,6 +14429,8 @@ fn fieldPtr(
1440514429 else
1440614430 object_ty;
1440714431
14432 const target = sema.mod.getTarget();
14433
1440814434 switch (inner_ty.zigTypeTag()) {
1440914435 .Array => {
1441014436 if (mem.eql(u8, field_name, "len")) {
......@@ -14444,7 +14470,7 @@ fn fieldPtr(
1444414470 }
1444514471 try sema.requireRuntimeBlock(block, src);
1444614472
14447 const result_ty = try Type.ptr(sema.arena, .{
14473 const result_ty = try Type.ptr(sema.arena, target, .{
1444814474 .pointee_type = slice_ptr_ty,
1444914475 .mutable = object_ptr_ty.ptrIsMutable(),
1445014476 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
......@@ -14463,7 +14489,7 @@ fn fieldPtr(
1446314489 }
1446414490 try sema.requireRuntimeBlock(block, src);
1446514491
14466 const result_ty = try Type.ptr(sema.arena, .{
14492 const result_ty = try Type.ptr(sema.arena, target, .{
1446714493 .pointee_type = Type.usize,
1446814494 .mutable = object_ptr_ty.ptrIsMutable(),
1446914495 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
......@@ -14692,7 +14718,8 @@ fn finishFieldCallBind(
1469214718 object_ptr: Air.Inst.Ref,
1469314719) CompileError!Air.Inst.Ref {
1469414720 const arena = sema.arena;
14695 const ptr_field_ty = try Type.ptr(arena, .{
14721 const target = sema.mod.getTarget();
14722 const ptr_field_ty = try Type.ptr(arena, target, .{
1469614723 .pointee_type = field_ty,
1469714724 .mutable = ptr_ty.ptrIsMutable(),
1469814725 .@"addrspace" = ptr_ty.ptrAddressSpace(),
......@@ -14831,7 +14858,8 @@ fn structFieldPtrByIndex(
1483114858 }
1483214859 }
1483314860
14834 const ptr_field_ty = try Type.ptr(sema.arena, ptr_ty_data);
14861 const target = sema.mod.getTarget();
14862 const ptr_field_ty = try Type.ptr(sema.arena, target, ptr_ty_data);
1483514863
1483614864 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
1483714865 return sema.addConstant(
......@@ -14959,7 +14987,8 @@ fn unionFieldPtr(
1495914987 const field_index = @intCast(u32, field_index_big);
1496014988
1496114989 const field = union_obj.fields.values()[field_index];
14962 const ptr_field_ty = try Type.ptr(arena, .{
14990 const target = sema.mod.getTarget();
14991 const ptr_field_ty = try Type.ptr(arena, target, .{
1496314992 .pointee_type = field.ty,
1496414993 .mutable = union_ptr_ty.ptrIsMutable(),
1496514994 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
......@@ -15033,7 +15062,8 @@ fn elemPtr(
1503315062 .Pointer => {
1503415063 // In all below cases, we have to deref the ptr operand to get the actual array pointer.
1503515064 const array = try sema.analyzeLoad(block, array_ptr_src, array_ptr, array_ptr_src);
15036 const result_ty = try array_ty.elemPtrType(sema.arena);
15065 const target = sema.mod.getTarget();
15066 const result_ty = try array_ty.elemPtrType(sema.arena, target);
1503715067 switch (array_ty.ptrSize()) {
1503815068 .Slice => {
1503915069 const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array);
......@@ -15172,7 +15202,8 @@ fn tupleFieldPtr(
1517215202 }
1517315203
1517415204 const field_ty = tuple_info.types[field_index];
15175 const ptr_field_ty = try Type.ptr(sema.arena, .{
15205 const target = sema.mod.getTarget();
15206 const ptr_field_ty = try Type.ptr(sema.arena, target, .{
1517615207 .pointee_type = field_ty,
1517715208 .mutable = tuple_ptr_ty.ptrIsMutable(),
1517815209 .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(),
......@@ -15264,7 +15295,8 @@ fn elemPtrArray(
1526415295 elem_index_src: LazySrcLoc,
1526515296) CompileError!Air.Inst.Ref {
1526615297 const array_ptr_ty = sema.typeOf(array_ptr);
15267 const result_ty = try array_ptr_ty.elemPtrType(sema.arena);
15298 const target = sema.mod.getTarget();
15299 const result_ty = try array_ptr_ty.elemPtrType(sema.arena, target);
1526815300
1526915301 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
1527015302 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {
......@@ -15957,15 +15989,28 @@ fn coerceInMemoryAllowedPtrs(
1595715989 // In this case, if they share the same child type, no need to resolve
1595815990 // pointee type alignment. Otherwise both pointee types must have their alignment
1595915991 // resolved and we compare the alignment numerically.
15960 if (src_info.@"align" != 0 or dest_info.@"align" != 0 or
15961 !dest_info.pointee_type.eql(src_info.pointee_type))
15962 {
15963 const src_align = src_info.@"align";
15964 const dest_align = dest_info.@"align";
15992 alignment: {
15993 if (src_info.@"align" == 0 and dest_info.@"align" == 0 and
15994 dest_info.pointee_type.eql(src_info.pointee_type))
15995 {
15996 break :alignment;
15997 }
15998
15999 const src_align = if (src_info.@"align" != 0)
16000 src_info.@"align"
16001 else
16002 src_info.pointee_type.abiAlignment(target);
16003
16004 const dest_align = if (dest_info.@"align" != 0)
16005 dest_info.@"align"
16006 else
16007 dest_info.pointee_type.abiAlignment(target);
1596516008
1596616009 if (dest_align > src_align) {
1596716010 return .no_match;
1596816011 }
16012
16013 break :alignment;
1596916014 }
1597016015
1597116016 return .ok;
......@@ -16874,6 +16919,7 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
1687416919 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
1687516920 try sema.ensureDeclAnalyzed(decl);
1687616921
16922 const target = sema.mod.getTarget();
1687716923 const decl_tv = try decl.typedValue();
1687816924 if (decl_tv.val.castTag(.variable)) |payload| {
1687916925 const variable = payload.data;
......@@ -16881,7 +16927,7 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
1688116927 0
1688216928 else
1688316929 @intCast(u32, decl.align_val.toUnsignedInt());
16884 const ty = try Type.ptr(sema.arena, .{
16930 const ty = try Type.ptr(sema.arena, target, .{
1688516931 .pointee_type = decl_tv.ty,
1688616932 .mutable = variable.is_mutable,
1688716933 .@"addrspace" = decl.@"addrspace",
......@@ -16890,7 +16936,7 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
1689016936 return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl));
1689116937 }
1689216938 return sema.addConstant(
16893 try Type.ptr(sema.arena, .{
16939 try Type.ptr(sema.arena, target, .{
1689416940 .pointee_type = decl_tv.ty,
1689516941 .mutable = false,
1689616942 .@"addrspace" = decl.@"addrspace",
......@@ -16918,12 +16964,13 @@ fn analyzeRef(
1691816964
1691916965 try sema.requireRuntimeBlock(block, src);
1692016966 const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
16921 const ptr_type = try Type.ptr(sema.arena, .{
16967 const target = sema.mod.getTarget();
16968 const ptr_type = try Type.ptr(sema.arena, target, .{
1692216969 .pointee_type = operand_ty,
1692316970 .mutable = false,
1692416971 .@"addrspace" = address_space,
1692516972 });
16926 const mut_ptr_type = try Type.ptr(sema.arena, .{
16973 const mut_ptr_type = try Type.ptr(sema.arena, target, .{
1692716974 .pointee_type = operand_ty,
1692816975 .@"addrspace" = address_space,
1692916976 });
......@@ -17174,11 +17221,12 @@ fn analyzeSlice(
1717417221
1717517222 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
1717617223 const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C;
17224 const target = sema.mod.getTarget();
1717717225
1717817226 if (opt_new_len_val) |new_len_val| {
1717917227 const new_len_int = new_len_val.toUnsignedInt();
1718017228
17181 const return_ty = try Type.ptr(sema.arena, .{
17229 const return_ty = try Type.ptr(sema.arena, target, .{
1718217230 .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty),
1718317231 .sentinel = null,
1718417232 .@"align" = new_ptr_ty_info.@"align",
......@@ -17206,7 +17254,7 @@ fn analyzeSlice(
1720617254 return sema.fail(block, ptr_src, "non-zero length slice of undefined pointer", .{});
1720717255 }
1720817256
17209 const return_ty = try Type.ptr(sema.arena, .{
17257 const return_ty = try Type.ptr(sema.arena, target, .{
1721017258 .pointee_type = elem_ty,
1721117259 .sentinel = sentinel,
1721217260 .@"align" = new_ptr_ty_info.@"align",
......@@ -17904,14 +17952,14 @@ fn resolvePeerTypes(
1790417952 else => unreachable,
1790517953 };
1790617954
17907 return Type.ptr(sema.arena, info.data);
17955 return Type.ptr(sema.arena, target, info.data);
1790817956 }
1790917957
1791017958 if (make_the_slice_const) {
1791117959 // turn []T => []const T
1791217960 var info = chosen_ty.ptrInfo();
1791317961 info.data.mutable = false;
17914 return Type.ptr(sema.arena, info.data);
17962 return Type.ptr(sema.arena, target, info.data);
1791517963 }
1791617964
1791717965 return chosen_ty;
......@@ -19121,7 +19169,8 @@ fn analyzeComptimeAlloc(
1912119169 // Needed to make an anon decl with type `var_type` (the `finish()` call below).
1912219170 _ = try sema.typeHasOnePossibleValue(block, src, var_type);
1912319171
19124 const ptr_type = try Type.ptr(sema.arena, .{
19172 const target = sema.mod.getTarget();
19173 const ptr_type = try Type.ptr(sema.arena, target, .{
1912519174 .pointee_type = var_type,
1912619175 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),
1912719176 .@"align" = alignment,
src/codegen.zig+1-1
......@@ -657,7 +657,7 @@ fn lowerDeclRef(
657657 .data = typed_value.val.sliceLen(),
658658 };
659659 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
660 .ty = Type.initTag(.usize),
660 .ty = Type.usize,
661661 .val = Value.initPayload(&slice_len.base),
662662 }, code, debug_output)) {
663663 .appended => {},
src/type.zig+351-184
......@@ -491,94 +491,115 @@ pub const Type = extern union {
491491
492492 pub fn eql(a: Type, b: Type) bool {
493493 // As a shortcut, if the small tags / addresses match, we're done.
494 if (a.tag_if_small_enough == b.tag_if_small_enough)
495 return true;
496 const zig_tag_a = a.zigTypeTag();
497 const zig_tag_b = b.zigTypeTag();
498 if (zig_tag_a != zig_tag_b)
499 return false;
500 switch (zig_tag_a) {
501 .EnumLiteral => return true,
502 .Type => return true,
503 .Void => return true,
504 .Bool => return true,
505 .NoReturn => return true,
506 .ComptimeFloat => return true,
507 .ComptimeInt => return true,
508 .Undefined => return true,
509 .Null => return true,
510 .AnyFrame => {
511 return a.elemType().eql(b.elemType());
512 },
513 .Pointer => {
514 const info_a = a.ptrInfo().data;
515 const info_b = b.ptrInfo().data;
516 if (!info_a.pointee_type.eql(info_b.pointee_type))
517 return false;
518 if (info_a.size != info_b.size)
519 return false;
520 if (info_a.mutable != info_b.mutable)
521 return false;
522 if (info_a.@"volatile" != info_b.@"volatile")
523 return false;
524 if (info_a.@"allowzero" != info_b.@"allowzero")
525 return false;
526 if (info_a.bit_offset != info_b.bit_offset)
527 return false;
528 if (info_a.host_size != info_b.host_size)
529 return false;
530 if (info_a.@"addrspace" != info_b.@"addrspace")
531 return false;
494 if (a.tag_if_small_enough == b.tag_if_small_enough) return true;
532495
533 const sentinel_a = info_a.sentinel;
534 const sentinel_b = info_b.sentinel;
535 if (sentinel_a) |sa| {
536 if (sentinel_b) |sb| {
537 if (!sa.eql(sb, info_a.pointee_type))
538 return false;
539 } else {
540 return false;
541 }
542 } else {
543 if (sentinel_b != null)
544 return false;
545 }
496 switch (a.tag()) {
497 .generic_poison => unreachable,
546498
547 return true;
499 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
500 .usize,
501 .isize,
502 .c_short,
503 .c_ushort,
504 .c_int,
505 .c_uint,
506 .c_long,
507 .c_ulong,
508 .c_longlong,
509 .c_ulonglong,
510
511 .f16,
512 .f32,
513 .f64,
514 .f80,
515 .f128,
516 .c_longdouble,
517
518 .bool,
519 .void,
520 .type,
521 .comptime_int,
522 .comptime_float,
523 .noreturn,
524 .@"null",
525 .@"undefined",
526 .@"anyopaque",
527 .@"anyframe",
528 .enum_literal,
529 => |a_tag| {
530 assert(a_tag != b.tag()); // because of the comparison at the top of the function.
531 return false;
548532 },
549 .Int => {
550 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
551 const a_is_named_int = a.isNamedInt();
552 const b_is_named_int = b.isNamedInt();
553 if (a_is_named_int != b_is_named_int)
554 return false;
555 if (a_is_named_int)
556 return a.tag() == b.tag();
557 // Remaining cases are arbitrary sized integers.
558 // The target will not be branched upon, because we handled target-dependent cases above.
533
534 .u1,
535 .u8,
536 .i8,
537 .u16,
538 .i16,
539 .u32,
540 .i32,
541 .u64,
542 .i64,
543 .u128,
544 .i128,
545 .int_signed,
546 .int_unsigned,
547 => {
548 if (b.zigTypeTag() != .Int) return false;
549 if (b.isNamedInt()) return false;
550
551 // Arbitrary sized integers. The target will not be branched upon,
552 // because we handled target-dependent cases above.
559553 const info_a = a.intInfo(@as(Target, undefined));
560554 const info_b = b.intInfo(@as(Target, undefined));
561555 return info_a.signedness == info_b.signedness and info_a.bits == info_b.bits;
562556 },
563 .Array, .Vector => {
564 if (a.arrayLen() != b.arrayLen())
565 return false;
566 const elem_ty = a.elemType();
567 if (!elem_ty.eql(b.elemType()))
568 return false;
569 const sentinel_a = a.sentinel();
570 const sentinel_b = b.sentinel();
571 if (sentinel_a) |sa| {
572 if (sentinel_b) |sb| {
573 return sa.eql(sb, elem_ty);
574 } else {
575 return false;
576 }
577 } else {
578 return sentinel_b == null;
557
558 .error_set,
559 .error_set_single,
560 .anyerror,
561 .error_set_inferred,
562 .error_set_merged,
563 => {
564 if (b.zigTypeTag() != .ErrorSet) return false;
565
566 // TODO: revisit the language specification for how to evaluate equality
567 // for error set types.
568
569 if (a.tag() == .anyerror and b.tag() == .anyerror) {
570 return true;
571 }
572
573 if (a.tag() == .error_set and b.tag() == .error_set) {
574 return a.castTag(.error_set).?.data.owner_decl == b.castTag(.error_set).?.data.owner_decl;
579575 }
576
577 if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {
578 return a.castTag(.error_set_inferred).?.data == b.castTag(.error_set_inferred).?.data;
579 }
580
581 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {
582 const a_data = a.castTag(.error_set_single).?.data;
583 const b_data = b.castTag(.error_set_single).?.data;
584 return std.mem.eql(u8, a_data, b_data);
585 }
586 return false;
580587 },
581 .Fn => {
588
589 .@"opaque" => {
590 const opaque_obj_a = a.castTag(.@"opaque").?.data;
591 const opaque_obj_b = (b.castTag(.@"opaque") orelse return false).data;
592 return opaque_obj_a == opaque_obj_b;
593 },
594
595 .fn_noreturn_no_args,
596 .fn_void_no_args,
597 .fn_naked_noreturn_no_args,
598 .fn_ccc_void_no_args,
599 .function,
600 => {
601 if (b.zigTypeTag() != .Fn) return false;
602
582603 const a_info = a.fnInfo();
583604 const b_info = b.fnInfo();
584605
......@@ -613,76 +634,105 @@ pub const Type = extern union {
613634
614635 return true;
615636 },
616 .Optional => {
617 var buf_a: Payload.ElemType = undefined;
618 var buf_b: Payload.ElemType = undefined;
619 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
620 },
621 .Struct => {
622 if (a.castTag(.@"struct")) |a_payload| {
623 if (b.castTag(.@"struct")) |b_payload| {
624 return a_payload.data == b_payload.data;
625 }
626 }
627 if (a.castTag(.tuple)) |a_payload| {
628 if (b.castTag(.tuple)) |b_payload| {
629 if (a_payload.data.types.len != b_payload.data.types.len) return false;
630
631 for (a_payload.data.types) |a_ty, i| {
632 const b_ty = b_payload.data.types[i];
633 if (!eql(a_ty, b_ty)) return false;
634 }
635637
636 for (a_payload.data.values) |a_val, i| {
637 const ty = a_payload.data.types[i];
638 const b_val = b_payload.data.values[i];
639 if (a_val.tag() == .unreachable_value) {
640 if (b_val.tag() == .unreachable_value) {
641 continue;
642 } else {
643 return false;
644 }
645 } else {
646 if (b_val.tag() == .unreachable_value) {
647 return false;
648 } else {
649 if (!Value.eql(a_val, b_val, ty)) return false;
650 }
651 }
652 }
638 .array,
639 .array_u8_sentinel_0,
640 .array_u8,
641 .array_sentinel,
642 .vector,
643 => {
644 if (a.zigTypeTag() != b.zigTypeTag()) return false;
653645
654 return true;
646 if (a.arrayLen() != b.arrayLen())
647 return false;
648 const elem_ty = a.elemType();
649 if (!elem_ty.eql(b.elemType()))
650 return false;
651 const sentinel_a = a.sentinel();
652 const sentinel_b = b.sentinel();
653 if (sentinel_a) |sa| {
654 if (sentinel_b) |sb| {
655 return sa.eql(sb, elem_ty);
656 } else {
657 return false;
655658 }
659 } else {
660 return sentinel_b == null;
656661 }
657 return a.tag() == b.tag();
658662 },
659 .Enum => {
660 if (a.cast(Payload.EnumFull)) |a_payload| {
661 if (b.cast(Payload.EnumFull)) |b_payload| {
662 return a_payload.data == b_payload.data;
663 }
664 }
665 if (a.cast(Payload.EnumSimple)) |a_payload| {
666 if (b.cast(Payload.EnumSimple)) |b_payload| {
667 return a_payload.data == b_payload.data;
663
664 .single_const_pointer_to_comptime_int,
665 .const_slice_u8,
666 .const_slice_u8_sentinel_0,
667 .single_const_pointer,
668 .single_mut_pointer,
669 .many_const_pointer,
670 .many_mut_pointer,
671 .c_const_pointer,
672 .c_mut_pointer,
673 .const_slice,
674 .mut_slice,
675 .pointer,
676 .inferred_alloc_const,
677 .inferred_alloc_mut,
678 .manyptr_u8,
679 .manyptr_const_u8,
680 .manyptr_const_u8_sentinel_0,
681 => {
682 if (b.zigTypeTag() != .Pointer) return false;
683
684 const info_a = a.ptrInfo().data;
685 const info_b = b.ptrInfo().data;
686 if (!info_a.pointee_type.eql(info_b.pointee_type))
687 return false;
688 if (info_a.@"align" != info_b.@"align")
689 return false;
690 if (info_a.@"addrspace" != info_b.@"addrspace")
691 return false;
692 if (info_a.bit_offset != info_b.bit_offset)
693 return false;
694 if (info_a.host_size != info_b.host_size)
695 return false;
696 if (info_a.@"allowzero" != info_b.@"allowzero")
697 return false;
698 if (info_a.mutable != info_b.mutable)
699 return false;
700 if (info_a.@"volatile" != info_b.@"volatile")
701 return false;
702 if (info_a.size != info_b.size)
703 return false;
704
705 const sentinel_a = info_a.sentinel;
706 const sentinel_b = info_b.sentinel;
707 if (sentinel_a) |sa| {
708 if (sentinel_b) |sb| {
709 if (!sa.eql(sb, info_a.pointee_type))
710 return false;
711 } else {
712 return false;
668713 }
714 } else {
715 if (sentinel_b != null)
716 return false;
669717 }
670 return a.tag() == b.tag();
671 },
672 .Opaque => {
673 const opaque_obj_a = a.castTag(.@"opaque").?.data;
674 const opaque_obj_b = b.castTag(.@"opaque").?.data;
675 return opaque_obj_a == opaque_obj_b;
718
719 return true;
676720 },
677 .Union => {
678 if (a.cast(Payload.Union)) |a_payload| {
679 if (b.cast(Payload.Union)) |b_payload| {
680 return a_payload.data == b_payload.data;
681 }
682 }
683 return a.tag() == b.tag();
721
722 .optional,
723 .optional_single_const_pointer,
724 .optional_single_mut_pointer,
725 => {
726 if (b.zigTypeTag() != .Optional) return false;
727
728 var buf_a: Payload.ElemType = undefined;
729 var buf_b: Payload.ElemType = undefined;
730 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
684731 },
685 .ErrorUnion => {
732
733 .anyerror_void_error_union, .error_union => {
734 if (b.zigTypeTag() != .ErrorUnion) return false;
735
686736 const a_set = a.errorUnionSet();
687737 const b_set = b.errorUnionSet();
688738 if (!a_set.eql(b_set)) return false;
......@@ -693,34 +743,100 @@ pub const Type = extern union {
693743
694744 return true;
695745 },
696 .ErrorSet => {
697 // TODO: revisit the language specification for how to evaluate equality
698 // for error set types.
699746
700 if (a.tag() == .anyerror and b.tag() == .anyerror) {
701 return true;
702 }
747 .anyframe_T => {
748 if (b.zigTypeTag() != .AnyFrame) return false;
749 return a.childType().eql(b.childType());
750 },
703751
704 if (a.tag() == .error_set and b.tag() == .error_set) {
705 return a.castTag(.error_set).?.data.owner_decl == b.castTag(.error_set).?.data.owner_decl;
706 }
752 .empty_struct => {
753 const a_namespace = a.castTag(.empty_struct).?.data;
754 const b_namespace = (b.castTag(.empty_struct) orelse return false).data;
755 return a_namespace == b_namespace;
756 },
757 .@"struct" => {
758 const a_struct_obj = a.castTag(.@"struct").?.data;
759 const b_struct_obj = (b.castTag(.@"struct") orelse return false).data;
760 return a_struct_obj == b_struct_obj;
761 },
762 .tuple, .empty_struct_literal => {
763 if (!b.isTuple()) return false;
707764
708 if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {
709 return a.castTag(.error_set_inferred).?.data == b.castTag(.error_set_inferred).?.data;
765 const a_tuple = a.tupleFields();
766 const b_tuple = b.tupleFields();
767
768 if (a_tuple.types.len != b_tuple.types.len) return false;
769
770 for (a_tuple.types) |a_ty, i| {
771 const b_ty = b_tuple.types[i];
772 if (!eql(a_ty, b_ty)) return false;
710773 }
711774
712 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {
713 const a_data = a.castTag(.error_set_single).?.data;
714 const b_data = b.castTag(.error_set_single).?.data;
715 return std.mem.eql(u8, a_data, b_data);
775 for (a_tuple.values) |a_val, i| {
776 const ty = a_tuple.types[i];
777 const b_val = b_tuple.values[i];
778 if (a_val.tag() == .unreachable_value) {
779 if (b_val.tag() == .unreachable_value) {
780 continue;
781 } else {
782 return false;
783 }
784 } else {
785 if (b_val.tag() == .unreachable_value) {
786 return false;
787 } else {
788 if (!Value.eql(a_val, b_val, ty)) return false;
789 }
790 }
716791 }
717 return false;
792
793 return true;
718794 },
719 .Float => return a.tag() == b.tag(),
720795
721 .BoundFn,
722 .Frame,
723 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
796 // we can't compare these based on tags because it wouldn't detect if,
797 // for example, a was resolved into .@"struct" but b was one of these tags.
798 .call_options,
799 .prefetch_options,
800 .export_options,
801 .extern_options,
802 => unreachable, // needed to resolve the type before now
803
804 .enum_full, .enum_nonexhaustive => {
805 const a_enum_obj = a.cast(Payload.EnumFull).?.data;
806 const b_enum_obj = (b.cast(Payload.EnumFull) orelse return false).data;
807 return a_enum_obj == b_enum_obj;
808 },
809 .enum_simple => {
810 const a_enum_obj = a.cast(Payload.EnumSimple).?.data;
811 const b_enum_obj = (b.cast(Payload.EnumSimple) orelse return false).data;
812 return a_enum_obj == b_enum_obj;
813 },
814 .enum_numbered => {
815 const a_enum_obj = a.cast(Payload.EnumNumbered).?.data;
816 const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data;
817 return a_enum_obj == b_enum_obj;
818 },
819 // we can't compare these based on tags because it wouldn't detect if,
820 // for example, a was resolved into .enum_simple but b was one of these tags.
821 .atomic_order,
822 .atomic_rmw_op,
823 .calling_convention,
824 .address_space,
825 .float_mode,
826 .reduce_op,
827 => unreachable, // needed to resolve the type before now
828
829 .@"union", .union_tagged => {
830 const a_union_obj = a.cast(Payload.Union).?.data;
831 const b_union_obj = (b.cast(Payload.Union) orelse return false).data;
832 return a_union_obj == b_union_obj;
833 },
834 // we can't compare these based on tags because it wouldn't detect if,
835 // for example, a was resolved into .union_tagged but b was one of these tags.
836 .type_info => unreachable, // needed to resolve the type before now
837
838 .bound_fn => unreachable,
839 .var_args_param => unreachable, // can be any type
724840 }
725841 }
726842
......@@ -730,8 +846,8 @@ pub const Type = extern union {
730846 return hasher.final();
731847 }
732848
733 pub fn hashWithHasher(self: Type, hasher: *std.hash.Wyhash) void {
734 const zig_type_tag = self.zigTypeTag();
849 pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void {
850 const zig_type_tag = ty.zigTypeTag();
735851 std.hash.autoHash(hasher, zig_type_tag);
736852 switch (zig_type_tag) {
737853 .Type,
......@@ -745,41 +861,58 @@ pub const Type = extern union {
745861 => {}, // The zig type tag is all that is needed to distinguish.
746862
747863 .Pointer => {
748 // TODO implement more pointer type hashing
864 const info = ty.ptrInfo().data;
865 hashWithHasher(info.pointee_type, hasher);
866 hashSentinel(info.sentinel, info.pointee_type, hasher);
867 std.hash.autoHash(hasher, info.@"align");
868 std.hash.autoHash(hasher, info.@"addrspace");
869 std.hash.autoHash(hasher, info.bit_offset);
870 std.hash.autoHash(hasher, info.host_size);
871 std.hash.autoHash(hasher, info.@"allowzero");
872 std.hash.autoHash(hasher, info.mutable);
873 std.hash.autoHash(hasher, info.@"volatile");
874 std.hash.autoHash(hasher, info.size);
749875 },
750876 .Int => {
751877 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
752 if (self.isNamedInt()) {
753 std.hash.autoHash(hasher, self.tag());
878 if (ty.isNamedInt()) {
879 std.hash.autoHash(hasher, ty.tag());
754880 } else {
755881 // Remaining cases are arbitrary sized integers.
756882 // The target will not be branched upon, because we handled target-dependent cases above.
757 const info = self.intInfo(@as(Target, undefined));
883 const info = ty.intInfo(@as(Target, undefined));
758884 std.hash.autoHash(hasher, info.signedness);
759885 std.hash.autoHash(hasher, info.bits);
760886 }
761887 },
762888 .Array, .Vector => {
763 std.hash.autoHash(hasher, self.arrayLen());
764 std.hash.autoHash(hasher, self.elemType().hash());
765 // TODO hash array sentinel
889 const elem_ty = ty.elemType();
890 std.hash.autoHash(hasher, ty.arrayLen());
891 hashWithHasher(elem_ty, hasher);
892 hashSentinel(ty.sentinel(), elem_ty, hasher);
766893 },
767894 .Fn => {
768 std.hash.autoHash(hasher, self.fnReturnType().hash());
769 std.hash.autoHash(hasher, self.fnCallingConvention());
770 const params_len = self.fnParamLen();
771 std.hash.autoHash(hasher, params_len);
772 var i: usize = 0;
773 while (i < params_len) : (i += 1) {
774 std.hash.autoHash(hasher, self.fnParamType(i).hash());
895 const fn_info = ty.fnInfo();
896 hashWithHasher(fn_info.return_type, hasher);
897 std.hash.autoHash(hasher, fn_info.alignment);
898 std.hash.autoHash(hasher, fn_info.cc);
899 std.hash.autoHash(hasher, fn_info.is_var_args);
900 std.hash.autoHash(hasher, fn_info.is_generic);
901
902 std.hash.autoHash(hasher, fn_info.param_types.len);
903 for (fn_info.param_types) |param_ty, i| {
904 std.hash.autoHash(hasher, fn_info.paramIsComptime(i));
905 if (param_ty.tag() == .generic_poison) continue;
906 hashWithHasher(param_ty, hasher);
775907 }
776 std.hash.autoHash(hasher, self.fnIsVarArgs());
777908 },
778909 .Optional => {
779910 var buf: Payload.ElemType = undefined;
780 std.hash.autoHash(hasher, self.optionalChild(&buf).hash());
911 hashWithHasher(ty.optionalChild(&buf), hasher);
912 },
913 .Float => {
914 std.hash.autoHash(hasher, ty.tag());
781915 },
782 .Float,
783916 .Struct,
784917 .ErrorUnion,
785918 .ErrorSet,
......@@ -796,6 +929,15 @@ pub const Type = extern union {
796929 }
797930 }
798931
932 fn hashSentinel(opt_val: ?Value, ty: Type, hasher: *std.hash.Wyhash) void {
933 if (opt_val) |s| {
934 std.hash.autoHash(hasher, true);
935 s.hash(ty, hasher);
936 } else {
937 std.hash.autoHash(hasher, false);
938 }
939 }
940
799941 pub const HashContext64 = struct {
800942 pub fn hash(self: @This(), t: Type) u64 {
801943 _ = self;
......@@ -2834,8 +2976,8 @@ pub const Type = extern union {
28342976 /// For [*]T, returns *T
28352977 /// For []T, returns *T
28362978 /// Handles const-ness and address spaces in particular.
2837 pub fn elemPtrType(ptr_ty: Type, arena: Allocator) !Type {
2838 return try Type.ptr(arena, .{
2979 pub fn elemPtrType(ptr_ty: Type, arena: Allocator, target: Target) !Type {
2980 return try Type.ptr(arena, target, .{
28392981 .pointee_type = ptr_ty.elemType2(),
28402982 .mutable = ptr_ty.ptrIsMutable(),
28412983 .@"addrspace" = ptr_ty.ptrAddressSpace(),
......@@ -4635,6 +4777,8 @@ pub const Type = extern union {
46354777 pointee_type: Type,
46364778 sentinel: ?Value = null,
46374779 /// If zero use pointee_type.abiAlignment()
4780 /// When creating pointer types, if alignment is equal to pointee type
4781 /// abi alignment, this value should be set to 0 instead.
46384782 @"align": u32 = 0,
46394783 /// See src/target.zig defaultAddressSpace function for how to obtain
46404784 /// an appropriate value for this field.
......@@ -4643,6 +4787,8 @@ pub const Type = extern union {
46434787 /// If this is non-zero it means the pointer points to a sub-byte
46444788 /// range of data, which is backed by a "host integer" with this
46454789 /// number of bytes.
4790 /// When host_size=pointee_abi_size and bit_offset=0, this must be
4791 /// represented with host_size=0 instead.
46464792 host_size: u16 = 0,
46474793 @"allowzero": bool = false,
46484794 mutable: bool = true, // TODO rename this to const, not mutable
......@@ -4739,10 +4885,30 @@ pub const Type = extern union {
47394885 pub const @"type" = initTag(.type);
47404886 pub const @"anyerror" = initTag(.anyerror);
47414887
4742 pub fn ptr(arena: Allocator, d: Payload.Pointer.Data) !Type {
4743 assert(d.host_size == 0 or d.bit_offset < d.host_size * 8);
4888 pub fn ptr(arena: Allocator, target: Target, data: Payload.Pointer.Data) !Type {
4889 var d = data;
4890
47444891 if (d.size == .C) {
4745 assert(d.@"allowzero"); // All C pointers must set allowzero to true.
4892 d.@"allowzero" = true;
4893 }
4894
4895 // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee
4896 // type, we change it to 0 here. If this causes an assertion trip because the
4897 // pointee type needs to be resolved more, that needs to be done before calling
4898 // this ptr() function.
4899 if (d.@"align" != 0 and d.@"align" == d.pointee_type.abiAlignment(target)) {
4900 d.@"align" = 0;
4901 }
4902
4903 // Canonicalize host_size. If it matches the bit size of the pointee type,
4904 // we change it to 0 here. If this causes an assertion trip, the pointee type
4905 // needs to be resolved before calling this ptr() function.
4906 if (d.host_size != 0) {
4907 assert(d.bit_offset < d.host_size * 8);
4908 if (d.host_size * 8 == d.pointee_type.bitSize(target)) {
4909 assert(d.bit_offset == 0);
4910 d.host_size = 0;
4911 }
47464912 }
47474913
47484914 if (d.@"align" == 0 and d.@"addrspace" == .generic and
......@@ -4789,6 +4955,7 @@ pub const Type = extern union {
47894955 return Type.initPayload(&type_payload.base);
47904956 }
47914957 }
4958
47924959 return Type.Tag.pointer.create(arena, d);
47934960 }
47944961
test/behavior/align.zig+11-3
......@@ -6,6 +6,8 @@ const native_arch = builtin.target.cpu.arch;
66var foo: u8 align(4) = 100;
77
88test "global variable alignment" {
9 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
10
911 comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
1012 comptime try expect(@TypeOf(&foo) == *align(4) u8);
1113 {
......@@ -84,6 +86,8 @@ test "size of extern struct with 128-bit field" {
8486}
8587
8688test "@ptrCast preserves alignment of bigger source" {
89 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
90
8791 var x: u32 align(16) = 1234;
8892 const ptr = @ptrCast(*u8, &x);
8993 try expect(@TypeOf(ptr) == *align(16) u8);
......@@ -99,6 +103,7 @@ fn fnWithAlignedStack() i32 {
99103}
100104
101105test "implicitly decreasing slice alignment" {
106 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
102107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
104109
......@@ -111,6 +116,7 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
111116}
112117
113118test "specifying alignment allows pointer cast" {
119 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
114120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116122
......@@ -123,6 +129,7 @@ fn testBytesAlign(b: u8) !void {
123129}
124130
125131test "@alignCast slices" {
132 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
126133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127134 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
128135
......@@ -260,9 +267,10 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
260267}
261268
262269test "runtime known array index has best alignment possible" {
263 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
264 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
270 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
266274
267275 // take full advantage of over-alignment
268276 var array align(4) = [_]u8{ 1, 2, 3, 4 };
test/behavior/array.zig+1
......@@ -6,6 +6,7 @@ const expect = testing.expect;
66const expectEqual = testing.expectEqual;
77
88test "array to slice" {
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
910 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1112
test/behavior/ptrcast.zig+2
......@@ -63,6 +63,8 @@ const Bytes = struct {
6363};
6464
6565test "comptime ptrcast keeps larger alignment" {
66 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
67
6668 comptime {
6769 const a: u32 = 1234;
6870 const p = @ptrCast([*]const u8, &a);
test/behavior/union.zig-2
......@@ -876,8 +876,6 @@ test "union no tag with struct member" {
876876}
877877
878878test "union with comptime_int tag" {
879 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
880
881879 const Union = union(enum(comptime_int)) {
882880 X: u32,
883881 Y: u16,