authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-22 20:22:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-22 20:29:26-07:00
logcc937369fb8fed44e8e1b653f1f22805c84a3507
tree70a851043cc1a3ca4c5ff93512f988388ed63e43
parente061d75cdf6a7994dd50f2d28c9f1ed3ed5ec205

stage2: `Type.hasCodeGenBits` asserts structs and unions have fields

Previously, this function would return an incorrect result for structs and unions which did not have their fields resolved yet. This required introducing more logic in Sema to resolve types before doing certain things such as creating an anonmyous Decl and emitting function call AIR. As a result a couple more struct tests pass. Oh, and I implemented the language change to make sizeOf for pointers always return pointer size bytes even if the element type is 0 bits.

6 files changed, 270 insertions(+), 169 deletions(-)

src/Sema.zig+196-71
......@@ -1432,9 +1432,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
14321432 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
14331433 const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs);
14341434 const ptr = sema.resolveInst(bin_inst.rhs);
1435
14361435 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
14371436
1437 // Needed for the call to `anon_decl.finish()` below which checks `ty.hasCodeGenBits()`.
1438 _ = try sema.typeHasOnePossibleValue(block, src, pointee_ty);
1439
14381440 if (Air.refToIndex(ptr)) |ptr_inst| {
14391441 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
14401442 const air_datas = sema.air_instructions.items(.data);
......@@ -2076,7 +2078,8 @@ fn zirRetPtr(
20762078 try sema.requireFunctionBlock(block, src);
20772079
20782080 if (block.is_comptime) {
2079 return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, 0);
2081 const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty);
2082 return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src);
20802083 }
20812084
20822085 const ptr_type = try Type.ptr(sema.arena, .{
......@@ -2227,7 +2230,7 @@ fn zirAllocExtended(
22272230
22282231 if (small.is_comptime) {
22292232 if (small.has_type) {
2230 return sema.analyzeComptimeAlloc(block, var_ty, alignment);
2233 return sema.analyzeComptimeAlloc(block, var_ty, alignment, ty_src);
22312234 } else {
22322235 return sema.addConstant(
22332236 inferred_alloc_ty,
......@@ -2273,7 +2276,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
22732276 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
22742277 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
22752278 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
2276 return sema.analyzeComptimeAlloc(block, var_ty, 0);
2279 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
22772280}
22782281
22792282fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -2295,7 +2298,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
22952298 const var_decl_src = inst_data.src();
22962299 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
22972300 if (block.is_comptime) {
2298 return sema.analyzeComptimeAlloc(block, var_ty, 0);
2301 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
22992302 }
23002303 const ptr_type = try Type.ptr(sema.arena, .{
23012304 .pointee_type = var_ty,
......@@ -2315,7 +2318,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
23152318 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
23162319 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
23172320 if (block.is_comptime) {
2318 return sema.analyzeComptimeAlloc(block, var_ty, 0);
2321 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
23192322 }
23202323 try sema.validateVarType(block, ty_src, var_ty, false);
23212324 const ptr_type = try Type.ptr(sema.arena, .{
......@@ -4261,14 +4264,14 @@ fn analyzeCall(
42614264 const arg_src = call_src; // TODO: better source location
42624265 if (i < fn_params_len) {
42634266 const param_ty = func_ty.fnParamType(i);
4264 try sema.resolveTypeLayout(block, arg_src, param_ty);
4267 try sema.resolveTypeForCodegen(block, arg_src, param_ty);
42654268 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
42664269 } else {
42674270 args[i] = uncasted_arg;
42684271 }
42694272 }
42704273
4271 try sema.resolveTypeLayout(block, call_src, func_ty_info.return_type);
4274 try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type);
42724275
42734276 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
42744277 args.len);
......@@ -4338,7 +4341,7 @@ fn finishGenericCall(
43384341 const param_ty = new_fn_ty.fnParamType(runtime_i);
43394342 const arg_src = call_src; // TODO: better source location
43404343 const uncasted_arg = uncasted_args[total_i];
4341 try sema.resolveTypeLayout(block, arg_src, param_ty);
4344 try sema.resolveTypeForCodegen(block, arg_src, param_ty);
43424345 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
43434346 runtime_args[runtime_i] = casted_arg;
43444347 runtime_i += 1;
......@@ -4346,7 +4349,7 @@ fn finishGenericCall(
43464349 total_i += 1;
43474350 }
43484351
4349 try sema.resolveTypeLayout(block, call_src, new_fn_ty.fnReturnType());
4352 try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType());
43504353 }
43514354 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
43524355 runtime_args_len);
......@@ -8751,7 +8754,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
87518754 .AnyFrame,
87528755 => operand_ty.abiSize(target),
87538756 };
8754 return sema.addIntUnsigned(Type.initTag(.comptime_int), abi_size);
8757 return sema.addIntUnsigned(Type.comptime_int, abi_size);
87558758}
87568759
87578760fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -12429,7 +12432,7 @@ fn coerce(
1242912432 const arena = sema.arena;
1243012433 const target = sema.mod.getTarget();
1243112434
12432 const in_memory_result = try sema.coerceInMemoryAllowed(dest_ty, inst_ty, false, target);
12435 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
1243312436 if (in_memory_result == .ok) {
1243412437 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
1243512438 // Keep the comptime Value representation; take the new type.
......@@ -12482,7 +12485,7 @@ fn coerce(
1248212485 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;
1248312486 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;
1248412487 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
12485 switch (try sema.coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) {
12488 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
1248612489 .ok => {},
1248712490 .no_match => break :single_item,
1248812491 }
......@@ -12494,14 +12497,16 @@ fn coerce(
1249412497 if (!inst_ty.isSinglePointer()) break :src_array_ptr;
1249512498 const array_ty = inst_ty.childType();
1249612499 if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;
12497 const array_elem_type = array_ty.childType();
12500 const len0 = array_ty.arrayLen() == 0;
12501 // We resolve here so that the backend has the layout of the elem type.
12502 const array_elem_type = try sema.resolveTypeFields(block, inst_src, array_ty.childType());
1249812503 const dest_is_mut = dest_info.mutable;
12499 if (inst_ty.isConstPtr() and dest_is_mut) break :src_array_ptr;
12504 if (inst_ty.isConstPtr() and dest_is_mut and !len0) break :src_array_ptr;
1250012505 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :src_array_ptr;
1250112506 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;
1250212507
1250312508 const dst_elem_type = dest_info.pointee_type;
12504 switch (try sema.coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) {
12509 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {
1250512510 .ok => {},
1250612511 .no_match => break :src_array_ptr,
1250712512 }
......@@ -12540,7 +12545,7 @@ fn coerce(
1254012545 const src_elem_ty = inst_ty.childType();
1254112546 const dest_is_mut = dest_info.mutable;
1254212547 const dst_elem_type = dest_info.pointee_type;
12543 switch (try sema.coerceInMemoryAllowed(dst_elem_type, src_elem_ty, dest_is_mut, target)) {
12548 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
1254412549 .ok => {},
1254512550 .no_match => break :src_c_ptr,
1254612551 }
......@@ -12738,10 +12743,13 @@ const InMemoryCoercionResult = enum {
1273812743/// look at the function types_match_const_cast_only
1273912744fn coerceInMemoryAllowed(
1274012745 sema: *Sema,
12746 block: *Block,
1274112747 dest_ty: Type,
1274212748 src_ty: Type,
1274312749 dest_is_mut: bool,
1274412750 target: std.Target,
12751 dest_src: LazySrcLoc,
12752 src_src: LazySrcLoc,
1274512753) CompileError!InMemoryCoercionResult {
1274612754 if (dest_ty.eql(src_ty))
1274712755 return .ok;
......@@ -12749,15 +12757,15 @@ fn coerceInMemoryAllowed(
1274912757 // Pointers / Pointer-like Optionals
1275012758 var dest_buf: Type.Payload.ElemType = undefined;
1275112759 var src_buf: Type.Payload.ElemType = undefined;
12752 if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {
12753 if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {
12754 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);
12760 if (try sema.typePtrOrOptionalPtrTy(block, dest_ty, &dest_buf, dest_src)) |dest_ptr_ty| {
12761 if (try sema.typePtrOrOptionalPtrTy(block, src_ty, &src_buf, src_src)) |src_ptr_ty| {
12762 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
1275512763 }
1275612764 }
1275712765
1275812766 // Slices
1275912767 if (dest_ty.isSlice() and src_ty.isSlice()) {
12760 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
12768 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
1276112769 }
1276212770
1276312771 const dest_tag = dest_ty.zigTypeTag();
......@@ -12765,16 +12773,16 @@ fn coerceInMemoryAllowed(
1276512773
1276612774 // Functions
1276712775 if (dest_tag == .Fn and src_tag == .Fn) {
12768 return try sema.coerceInMemoryAllowedFns(dest_ty, src_ty, target);
12776 return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src);
1276912777 }
1277012778
1277112779 // Error Unions
1277212780 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
12773 const child = try sema.coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target);
12781 const child = try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target, dest_src, src_src);
1277412782 if (child == .no_match) {
1277512783 return child;
1277612784 }
12777 return try sema.coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);
12785 return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src);
1277812786 }
1277912787
1278012788 // Error Sets
......@@ -12884,9 +12892,12 @@ fn coerceInMemoryAllowedErrorSets(
1288412892
1288512893fn coerceInMemoryAllowedFns(
1288612894 sema: *Sema,
12895 block: *Block,
1288712896 dest_ty: Type,
1288812897 src_ty: Type,
1288912898 target: std.Target,
12899 dest_src: LazySrcLoc,
12900 src_src: LazySrcLoc,
1289012901) !InMemoryCoercionResult {
1289112902 const dest_info = dest_ty.fnInfo();
1289212903 const src_info = src_ty.fnInfo();
......@@ -12900,7 +12911,7 @@ fn coerceInMemoryAllowedFns(
1290012911 }
1290112912
1290212913 if (!src_info.return_type.isNoReturn()) {
12903 const rt = try sema.coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);
12914 const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src);
1290412915 if (rt == .no_match) {
1290512916 return rt;
1290612917 }
......@@ -12920,7 +12931,7 @@ fn coerceInMemoryAllowedFns(
1292012931 // TODO: nolias
1292112932
1292212933 // Note: Cast direction is reversed here.
12923 const param = try sema.coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);
12934 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
1292412935 if (param == .no_match) {
1292512936 return param;
1292612937 }
......@@ -12935,17 +12946,20 @@ fn coerceInMemoryAllowedFns(
1293512946
1293612947fn coerceInMemoryAllowedPtrs(
1293712948 sema: *Sema,
12949 block: *Block,
1293812950 dest_ty: Type,
1293912951 src_ty: Type,
1294012952 dest_ptr_ty: Type,
1294112953 src_ptr_ty: Type,
1294212954 dest_is_mut: bool,
1294312955 target: std.Target,
12956 dest_src: LazySrcLoc,
12957 src_src: LazySrcLoc,
1294412958) !InMemoryCoercionResult {
1294512959 const dest_info = dest_ptr_ty.ptrInfo().data;
1294612960 const src_info = src_ptr_ty.ptrInfo().data;
1294712961
12948 const child = try sema.coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);
12962 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
1294912963 if (child == .no_match) {
1295012964 return child;
1295112965 }
......@@ -13592,7 +13606,7 @@ fn coerceVectorInMemory(
1359213606 const target = sema.mod.getTarget();
1359313607 const dest_elem_ty = dest_ty.childType();
1359413608 const inst_elem_ty = inst_ty.childType();
13595 const in_memory_result = try sema.coerceInMemoryAllowed(dest_elem_ty, inst_elem_ty, false, target);
13609 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src);
1359613610 if (in_memory_result != .ok) {
1359713611 // TODO recursive error notes for coerceInMemoryAllowed failure
1359813612 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
......@@ -14351,12 +14365,12 @@ fn resolvePeerTypes(
1435114365 .Optional => {
1435214366 var opt_child_buf: Type.Payload.ElemType = undefined;
1435314367 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
14354 if ((try sema.coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target)) == .ok) {
14368 if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, chosen_ty, false, target, src, src)) == .ok) {
1435514369 chosen = candidate;
1435614370 chosen_i = candidate_i + 1;
1435714371 continue;
1435814372 }
14359 if ((try sema.coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target)) == .ok) {
14373 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) {
1436014374 any_are_null = true;
1436114375 continue;
1436214376 }
......@@ -14379,10 +14393,10 @@ fn resolvePeerTypes(
1437914393 .Optional => {
1438014394 var opt_child_buf: Type.Payload.ElemType = undefined;
1438114395 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
14382 if ((try sema.coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target)) == .ok) {
14396 if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) {
1438314397 continue;
1438414398 }
14385 if ((try sema.coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target)) == .ok) {
14399 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, opt_child_ty, false, target, src, src)) == .ok) {
1438614400 any_are_null = true;
1438714401 chosen = candidate;
1438814402 chosen_i = candidate_i + 1;
......@@ -14439,38 +14453,8 @@ pub fn resolveTypeLayout(
1443914453 ty: Type,
1444014454) CompileError!void {
1444114455 switch (ty.zigTypeTag()) {
14442 .Struct => {
14443 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
14444 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
14445 switch (struct_obj.status) {
14446 .none, .have_field_types => {},
14447 .field_types_wip, .layout_wip => {
14448 return sema.fail(block, src, "struct {} depends on itself", .{ty});
14449 },
14450 .have_layout => return,
14451 }
14452 struct_obj.status = .layout_wip;
14453 for (struct_obj.fields.values()) |field| {
14454 try sema.resolveTypeLayout(block, src, field.ty);
14455 }
14456 struct_obj.status = .have_layout;
14457 },
14458 .Union => {
14459 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
14460 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
14461 switch (union_obj.status) {
14462 .none, .have_field_types => {},
14463 .field_types_wip, .layout_wip => {
14464 return sema.fail(block, src, "union {} depends on itself", .{ty});
14465 },
14466 .have_layout => return,
14467 }
14468 union_obj.status = .layout_wip;
14469 for (union_obj.fields.values()) |field| {
14470 try sema.resolveTypeLayout(block, src, field.ty);
14471 }
14472 union_obj.status = .have_layout;
14473 },
14456 .Struct => return sema.resolveStructLayout(block, src, ty),
14457 .Union => return sema.resolveUnionLayout(block, src, ty),
1447414458 .Array => {
1447514459 const elem_ty = ty.childType();
1447614460 return sema.resolveTypeLayout(block, src, elem_ty);
......@@ -14488,6 +14472,73 @@ pub fn resolveTypeLayout(
1448814472 }
1448914473}
1449014474
14475fn resolveStructLayout(
14476 sema: *Sema,
14477 block: *Block,
14478 src: LazySrcLoc,
14479 ty: Type,
14480) CompileError!void {
14481 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
14482 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
14483 switch (struct_obj.status) {
14484 .none, .have_field_types => {},
14485 .field_types_wip, .layout_wip => {
14486 return sema.fail(block, src, "struct {} depends on itself", .{ty});
14487 },
14488 .have_layout => return,
14489 }
14490 struct_obj.status = .layout_wip;
14491 for (struct_obj.fields.values()) |field| {
14492 try sema.resolveTypeLayout(block, src, field.ty);
14493 }
14494 struct_obj.status = .have_layout;
14495}
14496
14497fn resolveUnionLayout(
14498 sema: *Sema,
14499 block: *Block,
14500 src: LazySrcLoc,
14501 ty: Type,
14502) CompileError!void {
14503 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
14504 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
14505 switch (union_obj.status) {
14506 .none, .have_field_types => {},
14507 .field_types_wip, .layout_wip => {
14508 return sema.fail(block, src, "union {} depends on itself", .{ty});
14509 },
14510 .have_layout => return,
14511 }
14512 union_obj.status = .layout_wip;
14513 for (union_obj.fields.values()) |field| {
14514 try sema.resolveTypeLayout(block, src, field.ty);
14515 }
14516 union_obj.status = .have_layout;
14517}
14518
14519fn resolveTypeForCodegen(
14520 sema: *Sema,
14521 block: *Block,
14522 src: LazySrcLoc,
14523 ty: Type,
14524) CompileError!void {
14525 switch (ty.zigTypeTag()) {
14526 .Pointer => {
14527 const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
14528 return resolveTypeForCodegen(sema, block, src, child_ty);
14529 },
14530 .Struct => return resolveStructLayout(sema, block, src, ty),
14531 .Union => return resolveUnionLayout(sema, block, src, ty),
14532 .Array => return resolveTypeForCodegen(sema, block, src, ty.childType()),
14533 .Optional => {
14534 var buf: Type.Payload.ElemType = undefined;
14535 return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf));
14536 },
14537 .ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()),
14538 else => {},
14539 }
14540}
14541
1449114542fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
1449214543 switch (ty.tag()) {
1449314544 .@"struct" => {
......@@ -15215,11 +15266,20 @@ fn typeHasOnePossibleValue(
1521515266 return null;
1521615267 }
1521715268 },
15218 .@"union" => {
15219 return null; // TODO
15220 },
15221 .union_tagged => {
15222 return null; // TODO
15269 .@"union", .union_tagged => {
15270 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15271 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
15272 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
15273 return null;
15274 const only_field = union_obj.fields.values()[0];
15275 const val_val = (try sema.typeHasOnePossibleValue(block, src, only_field.ty)) orelse
15276 return null;
15277 // TODO make this not allocate. The function in `Type.onePossibleValue`
15278 // currently returns `empty_struct_value` and we should do that here too.
15279 return try Value.Tag.@"union".create(sema.arena, .{
15280 .tag = tag_val,
15281 .val = val_val,
15282 });
1522315283 },
1522415284
1522515285 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
......@@ -15453,7 +15513,11 @@ fn analyzeComptimeAlloc(
1545315513 block: *Block,
1545415514 var_type: Type,
1545515515 alignment: u32,
15516 src: LazySrcLoc,
1545615517) CompileError!Air.Inst.Ref {
15518 // Needed to make an anon decl with type `var_type` (the `finish()` call below).
15519 _ = try sema.typeHasOnePossibleValue(block, src, var_type);
15520
1545715521 const ptr_type = try Type.ptr(sema.arena, .{
1545815522 .pointee_type = var_type,
1545915523 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),
......@@ -15551,8 +15615,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
1555115615 // We have a Value that lines up in virtual memory exactly with what we want to load.
1555215616 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.
1555315617 const coerce_in_mem_ok =
15554 (try sema.coerceInMemoryAllowed(load_ty, parent.ty, false, target)) == .ok or
15555 (try sema.coerceInMemoryAllowed(parent.ty, load_ty, false, target)) == .ok;
15618 (try sema.coerceInMemoryAllowed(block, load_ty, parent.ty, false, target, src, src)) == .ok or
15619 (try sema.coerceInMemoryAllowed(block, parent.ty, load_ty, false, target, src, src)) == .ok;
1555615620 if (coerce_in_mem_ok) {
1555715621 if (parent.is_mutable) {
1555815622 // The decl whose value we are obtaining here may be overwritten with
......@@ -15588,3 +15652,64 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
1558815652 error.Overflow => return sema.fail(block, src, "expression produces integer value {d} which is too big for this compiler implementation to handle", .{int}),
1558915653 };
1559015654}
15655
15656/// For pointer-like optionals, it returns the pointer type. For pointers,
15657/// the type is returned unmodified.
15658/// This can return `error.AnalysisFail` because it sometimes requires resolving whether
15659/// a type has zero bits, which can cause a "foo depends on itself" compile error.
15660/// This logic must be kept in sync with `Type.isPtrLikeOptional`.
15661fn typePtrOrOptionalPtrTy(
15662 sema: *Sema,
15663 block: *Block,
15664 ty: Type,
15665 buf: *Type.Payload.ElemType,
15666 src: LazySrcLoc,
15667) !?Type {
15668 switch (ty.tag()) {
15669 .optional_single_const_pointer,
15670 .optional_single_mut_pointer,
15671 .c_const_pointer,
15672 .c_mut_pointer,
15673 => return ty.optionalChild(buf),
15674
15675 .single_const_pointer_to_comptime_int,
15676 .single_const_pointer,
15677 .single_mut_pointer,
15678 .many_const_pointer,
15679 .many_mut_pointer,
15680 .manyptr_u8,
15681 .manyptr_const_u8,
15682 => return ty,
15683
15684 .pointer => switch (ty.ptrSize()) {
15685 .Slice => return null,
15686 .C => return ty.optionalChild(buf),
15687 else => return ty,
15688 },
15689
15690 .inferred_alloc_const => unreachable,
15691 .inferred_alloc_mut => unreachable,
15692
15693 .optional => {
15694 const child_type = ty.optionalChild(buf);
15695 if (child_type.zigTypeTag() != .Pointer) return null;
15696
15697 const info = child_type.ptrInfo().data;
15698 switch (info.size) {
15699 .Slice, .C => return null,
15700 .Many, .One => {
15701 if (info.@"allowzero") return null;
15702
15703 // optionals of zero sized types behave like bools, not pointers
15704 if ((try sema.typeHasOnePossibleValue(block, src, child_type)) != null) {
15705 return null;
15706 }
15707
15708 return child_type;
15709 },
15710 }
15711 },
15712
15713 else => return null,
15714 }
15715}
src/type.zig+11-43
......@@ -1518,8 +1518,6 @@ pub const Type = extern union {
15181518 }
15191519 }
15201520
1521 /// For structs and unions, if the type does not have their fields resolved
1522 /// this will return `false`.
15231521 pub fn hasCodeGenBits(self: Type) bool {
15241522 return switch (self.tag()) {
15251523 .u1,
......@@ -1601,6 +1599,7 @@ pub const Type = extern union {
16011599 if (struct_obj.known_has_bits) {
16021600 return true;
16031601 }
1602 assert(struct_obj.haveFieldTypes());
16041603 for (struct_obj.fields.values()) |value| {
16051604 if (value.ty.hasCodeGenBits())
16061605 return true;
......@@ -1623,6 +1622,7 @@ pub const Type = extern union {
16231622 },
16241623 .@"union" => {
16251624 const union_obj = self.castTag(.@"union").?.data;
1625 assert(union_obj.haveFieldTypes());
16261626 for (union_obj.fields.values()) |value| {
16271627 if (value.ty.hasCodeGenBits())
16281628 return true;
......@@ -1635,6 +1635,7 @@ pub const Type = extern union {
16351635 if (union_obj.tag_ty.hasCodeGenBits()) {
16361636 return true;
16371637 }
1638 assert(union_obj.haveFieldTypes());
16381639 for (union_obj.fields.values()) |value| {
16391640 if (value.ty.hasCodeGenBits())
16401641 return true;
......@@ -2032,11 +2033,6 @@ pub const Type = extern union {
20322033 .c_const_pointer,
20332034 .c_mut_pointer,
20342035 .pointer,
2035 => {
2036 if (!self.elemType().hasCodeGenBits()) return 0;
2037 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
2038 },
2039
20402036 .manyptr_u8,
20412037 .manyptr_const_u8,
20422038 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
......@@ -2524,37 +2520,6 @@ pub const Type = extern union {
25242520 return ty.ptrInfo().data.@"allowzero";
25252521 }
25262522
2527 /// For pointer-like optionals, it returns the pointer type. For pointers,
2528 /// the type is returned unmodified.
2529 pub fn ptrOrOptionalPtrTy(ty: Type, buf: *Payload.ElemType) ?Type {
2530 if (isPtrLikeOptional(ty)) return ty.optionalChild(buf);
2531 switch (ty.tag()) {
2532 .c_const_pointer,
2533 .c_mut_pointer,
2534 .single_const_pointer_to_comptime_int,
2535 .single_const_pointer,
2536 .single_mut_pointer,
2537 .many_const_pointer,
2538 .many_mut_pointer,
2539 .manyptr_u8,
2540 .manyptr_const_u8,
2541 => return ty,
2542
2543 .pointer => {
2544 if (ty.ptrSize() == .Slice) {
2545 return null;
2546 } else {
2547 return ty;
2548 }
2549 },
2550
2551 .inferred_alloc_const => unreachable,
2552 .inferred_alloc_mut => unreachable,
2553
2554 else => return null,
2555 }
2556 }
2557
25582523 /// Returns true if the type is optional and would be lowered to a single pointer
25592524 /// address value, using 0 for null. Note that this returns true for C pointers.
25602525 pub fn isPtrLikeOptional(self: Type) bool {
......@@ -3393,11 +3358,14 @@ pub const Type = extern union {
33933358 return null;
33943359 }
33953360 },
3396 .@"union" => {
3397 return null; // TODO
3398 },
3399 .union_tagged => {
3400 return null; // TODO
3361 .@"union", .union_tagged => {
3362 const union_obj = ty.cast(Payload.Union).?.data;
3363 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
3364 const only_field = union_obj.fields.values()[0];
3365 const val_val = only_field.ty.onePossibleValue() orelse return null;
3366 _ = tag_val;
3367 _ = val_val;
3368 return Value.initTag(.empty_struct_value);
34013369 },
34023370
34033371 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
test/behavior/bugs/2006.zig+8-1
......@@ -8,5 +8,12 @@ test "bug 2006" {
88 var a: S = undefined;
99 a = S{ .p = undefined };
1010 try expect(@sizeOf(S) != 0);
11 try expect(@sizeOf(*void) == 0);
11 if (@import("builtin").zig_is_stage2) {
12 // It is an accepted proposal to make `@sizeOf` for pointers independent
13 // of whether the element type is zero bits.
14 // This language change has not been implemented in stage1.
15 try expect(@sizeOf(*void) == @sizeOf(*i32));
16 } else {
17 try expect(@sizeOf(*void) == 0);
18 }
1219}
test/behavior/bugs/6850.zig+6
......@@ -8,5 +8,11 @@ test "lazy sizeof comparison with zero" {
88}
99
1010fn hasNoBits(comptime T: type) bool {
11 if (@import("builtin").zig_is_stage2) {
12 // It is an accepted proposal to make `@sizeOf` for pointers independent
13 // of whether the element type is zero bits.
14 // This language change has not been implemented in stage1.
15 return @sizeOf(T) == @sizeOf(*i32);
16 }
1117 return @sizeOf(T) == 0;
1218}
test/behavior/struct_llvm.zig+49
......@@ -77,3 +77,52 @@ const EmptyStruct = struct {
7777 return 1234;
7878 }
7979};
80
81test "align 1 field before self referential align 8 field as slice return type" {
82 const result = alloc(Expr);
83 try expect(result.len == 0);
84}
85
86const Expr = union(enum) {
87 Literal: u8,
88 Question: *Expr,
89};
90
91fn alloc(comptime T: type) []T {
92 return &[_]T{};
93}
94
95test "for loop over pointers to struct, getting field from struct pointer" {
96 const S = struct {
97 const Foo = struct {
98 name: []const u8,
99 };
100
101 var ok = true;
102
103 fn eql(a: []const u8) bool {
104 _ = a;
105 return true;
106 }
107
108 const ArrayList = struct {
109 fn toSlice(self: *ArrayList) []*Foo {
110 _ = self;
111 return @as([*]*Foo, undefined)[0..0];
112 }
113 };
114
115 fn doTheTest() !void {
116 var objects: ArrayList = undefined;
117
118 for (objects.toSlice()) |obj| {
119 if (eql(obj.name)) {
120 ok = false;
121 }
122 }
123
124 try expect(ok);
125 }
126 };
127 try S.doTheTest();
128}
test/behavior/struct_stage1.zig-54
......@@ -6,11 +6,6 @@ const expectEqual = std.testing.expectEqual;
66const expectEqualSlices = std.testing.expectEqualSlices;
77const maxInt = std.math.maxInt;
88
9const EmptyStruct2 = struct {};
10fn testReturnEmptyStructFromFn() EmptyStruct2 {
11 return EmptyStruct2{};
12}
13
149const APackedStruct = packed struct {
1510 x: u8,
1611 y: u8,
......@@ -245,20 +240,6 @@ test "native bit field understands endianness" {
245240 try expect(bitfields.f7 == 0x77);
246241}
247242
248test "align 1 field before self referential align 8 field as slice return type" {
249 const result = alloc(Expr);
250 try expect(result.len == 0);
251}
252
253const Expr = union(enum) {
254 Literal: u8,
255 Question: *Expr,
256};
257
258fn alloc(comptime T: type) []T {
259 return &[_]T{};
260}
261
262243test "implicit cast packed struct field to const ptr" {
263244 const LevelUpMove = packed struct {
264245 move_id: u9,
......@@ -668,38 +649,3 @@ test "packed struct with undefined initializers" {
668649 try S.doTheTest();
669650 comptime try S.doTheTest();
670651}
671
672test "for loop over pointers to struct, getting field from struct pointer" {
673 const S = struct {
674 const Foo = struct {
675 name: []const u8,
676 };
677
678 var ok = true;
679
680 fn eql(a: []const u8) bool {
681 _ = a;
682 return true;
683 }
684
685 const ArrayList = struct {
686 fn toSlice(self: *ArrayList) []*Foo {
687 _ = self;
688 return @as([*]*Foo, undefined)[0..0];
689 }
690 };
691
692 fn doTheTest() !void {
693 var objects: ArrayList = undefined;
694
695 for (objects.toSlice()) |obj| {
696 if (eql(obj.name)) {
697 ok = false;
698 }
699 }
700
701 try expect(ok);
702 }
703 };
704 try S.doTheTest();
705}