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...@@ -1432,9 +1432,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1432 const bin_inst = sema.code.instructions.items(.data)[inst].bin;1432 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1433 const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs);1433 const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs);
1434 const ptr = sema.resolveInst(bin_inst.rhs);1434 const ptr = sema.resolveInst(bin_inst.rhs);
1435
1436 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);1435 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
1438 if (Air.refToIndex(ptr)) |ptr_inst| {1440 if (Air.refToIndex(ptr)) |ptr_inst| {
1439 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {1441 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
1440 const air_datas = sema.air_instructions.items(.data);1442 const air_datas = sema.air_instructions.items(.data);
...@@ -2076,7 +2078,8 @@ fn zirRetPtr(...@@ -2076,7 +2078,8 @@ fn zirRetPtr(
2076 try sema.requireFunctionBlock(block, src);2078 try sema.requireFunctionBlock(block, src);
20772079
2078 if (block.is_comptime) {2080 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);
2080 }2083 }
20812084
2082 const ptr_type = try Type.ptr(sema.arena, .{2085 const ptr_type = try Type.ptr(sema.arena, .{
...@@ -2227,7 +2230,7 @@ fn zirAllocExtended(...@@ -2227,7 +2230,7 @@ fn zirAllocExtended(
22272230
2228 if (small.is_comptime) {2231 if (small.is_comptime) {
2229 if (small.has_type) {2232 if (small.has_type) {
2230 return sema.analyzeComptimeAlloc(block, var_ty, alignment);2233 return sema.analyzeComptimeAlloc(block, var_ty, alignment, ty_src);
2231 } else {2234 } else {
2232 return sema.addConstant(2235 return sema.addConstant(
2233 inferred_alloc_ty,2236 inferred_alloc_ty,
...@@ -2273,7 +2276,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -2273,7 +2276,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
2273 const inst_data = sema.code.instructions.items(.data)[inst].un_node;2276 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2274 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };2277 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
2275 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);2278 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);
2277}2280}
22782281
2279fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {2282fn 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...@@ -2295,7 +2298,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
2295 const var_decl_src = inst_data.src();2298 const var_decl_src = inst_data.src();
2296 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);2299 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
2297 if (block.is_comptime) {2300 if (block.is_comptime) {
2298 return sema.analyzeComptimeAlloc(block, var_ty, 0);2301 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
2299 }2302 }
2300 const ptr_type = try Type.ptr(sema.arena, .{2303 const ptr_type = try Type.ptr(sema.arena, .{
2301 .pointee_type = var_ty,2304 .pointee_type = var_ty,
...@@ -2315,7 +2318,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -2315,7 +2318,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2315 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };2318 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
2316 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);2319 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
2317 if (block.is_comptime) {2320 if (block.is_comptime) {
2318 return sema.analyzeComptimeAlloc(block, var_ty, 0);2321 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
2319 }2322 }
2320 try sema.validateVarType(block, ty_src, var_ty, false);2323 try sema.validateVarType(block, ty_src, var_ty, false);
2321 const ptr_type = try Type.ptr(sema.arena, .{2324 const ptr_type = try Type.ptr(sema.arena, .{
...@@ -4261,14 +4264,14 @@ fn analyzeCall(...@@ -4261,14 +4264,14 @@ fn analyzeCall(
4261 const arg_src = call_src; // TODO: better source location4264 const arg_src = call_src; // TODO: better source location
4262 if (i < fn_params_len) {4265 if (i < fn_params_len) {
4263 const param_ty = func_ty.fnParamType(i);4266 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);
4265 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);4268 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
4266 } else {4269 } else {
4267 args[i] = uncasted_arg;4270 args[i] = uncasted_arg;
4268 }4271 }
4269 }4272 }
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
4273 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +4276 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
4274 args.len);4277 args.len);
...@@ -4338,7 +4341,7 @@ fn finishGenericCall(...@@ -4338,7 +4341,7 @@ fn finishGenericCall(
4338 const param_ty = new_fn_ty.fnParamType(runtime_i);4341 const param_ty = new_fn_ty.fnParamType(runtime_i);
4339 const arg_src = call_src; // TODO: better source location4342 const arg_src = call_src; // TODO: better source location
4340 const uncasted_arg = uncasted_args[total_i];4343 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);
4342 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);4345 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
4343 runtime_args[runtime_i] = casted_arg;4346 runtime_args[runtime_i] = casted_arg;
4344 runtime_i += 1;4347 runtime_i += 1;
...@@ -4346,7 +4349,7 @@ fn finishGenericCall(...@@ -4346,7 +4349,7 @@ fn finishGenericCall(
4346 total_i += 1;4349 total_i += 1;
4347 }4350 }
43484351
4349 try sema.resolveTypeLayout(block, call_src, new_fn_ty.fnReturnType());4352 try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType());
4350 }4353 }
4351 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +4354 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
4352 runtime_args_len);4355 runtime_args_len);
...@@ -8751,7 +8754,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -8751,7 +8754,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
8751 .AnyFrame,8754 .AnyFrame,
8752 => operand_ty.abiSize(target),8755 => operand_ty.abiSize(target),
8753 };8756 };
8754 return sema.addIntUnsigned(Type.initTag(.comptime_int), abi_size);8757 return sema.addIntUnsigned(Type.comptime_int, abi_size);
8755}8758}
87568759
8757fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {8760fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -12429,7 +12432,7 @@ fn coerce(...@@ -12429,7 +12432,7 @@ fn coerce(
12429 const arena = sema.arena;12432 const arena = sema.arena;
12430 const target = sema.mod.getTarget();12433 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);
12433 if (in_memory_result == .ok) {12436 if (in_memory_result == .ok) {
12434 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {12437 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
12435 // Keep the comptime Value representation; take the new type.12438 // Keep the comptime Value representation; take the new type.
...@@ -12482,7 +12485,7 @@ fn coerce(...@@ -12482,7 +12485,7 @@ fn coerce(
12482 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;12485 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;
12483 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;12486 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;
12484 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;12487 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)) {
12486 .ok => {},12489 .ok => {},
12487 .no_match => break :single_item,12490 .no_match => break :single_item,
12488 }12491 }
...@@ -12494,14 +12497,16 @@ fn coerce(...@@ -12494,14 +12497,16 @@ fn coerce(
12494 if (!inst_ty.isSinglePointer()) break :src_array_ptr;12497 if (!inst_ty.isSinglePointer()) break :src_array_ptr;
12495 const array_ty = inst_ty.childType();12498 const array_ty = inst_ty.childType();
12496 if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;12499 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());
12498 const dest_is_mut = dest_info.mutable;12503 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;
12500 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :src_array_ptr;12505 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :src_array_ptr;
12501 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;12506 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;
1250212507
12503 const dst_elem_type = dest_info.pointee_type;12508 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)) {
12505 .ok => {},12510 .ok => {},
12506 .no_match => break :src_array_ptr,12511 .no_match => break :src_array_ptr,
12507 }12512 }
...@@ -12540,7 +12545,7 @@ fn coerce(...@@ -12540,7 +12545,7 @@ fn coerce(
12540 const src_elem_ty = inst_ty.childType();12545 const src_elem_ty = inst_ty.childType();
12541 const dest_is_mut = dest_info.mutable;12546 const dest_is_mut = dest_info.mutable;
12542 const dst_elem_type = dest_info.pointee_type;12547 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)) {
12544 .ok => {},12549 .ok => {},
12545 .no_match => break :src_c_ptr,12550 .no_match => break :src_c_ptr,
12546 }12551 }
...@@ -12738,10 +12743,13 @@ const InMemoryCoercionResult = enum {...@@ -12738,10 +12743,13 @@ const InMemoryCoercionResult = enum {
12738/// look at the function types_match_const_cast_only12743/// look at the function types_match_const_cast_only
12739fn coerceInMemoryAllowed(12744fn coerceInMemoryAllowed(
12740 sema: *Sema,12745 sema: *Sema,
12746 block: *Block,
12741 dest_ty: Type,12747 dest_ty: Type,
12742 src_ty: Type,12748 src_ty: Type,
12743 dest_is_mut: bool,12749 dest_is_mut: bool,
12744 target: std.Target,12750 target: std.Target,
12751 dest_src: LazySrcLoc,
12752 src_src: LazySrcLoc,
12745) CompileError!InMemoryCoercionResult {12753) CompileError!InMemoryCoercionResult {
12746 if (dest_ty.eql(src_ty))12754 if (dest_ty.eql(src_ty))
12747 return .ok;12755 return .ok;
...@@ -12749,15 +12757,15 @@ fn coerceInMemoryAllowed(...@@ -12749,15 +12757,15 @@ fn coerceInMemoryAllowed(
12749 // Pointers / Pointer-like Optionals12757 // Pointers / Pointer-like Optionals
12750 var dest_buf: Type.Payload.ElemType = undefined;12758 var dest_buf: Type.Payload.ElemType = undefined;
12751 var src_buf: Type.Payload.ElemType = undefined;12759 var src_buf: Type.Payload.ElemType = undefined;
12752 if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {12760 if (try sema.typePtrOrOptionalPtrTy(block, dest_ty, &dest_buf, dest_src)) |dest_ptr_ty| {
12753 if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {12761 if (try sema.typePtrOrOptionalPtrTy(block, src_ty, &src_buf, src_src)) |src_ptr_ty| {
12754 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);12762 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
12755 }12763 }
12756 }12764 }
1275712765
12758 // Slices12766 // Slices
12759 if (dest_ty.isSlice() and src_ty.isSlice()) {12767 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);
12761 }12769 }
1276212770
12763 const dest_tag = dest_ty.zigTypeTag();12771 const dest_tag = dest_ty.zigTypeTag();
...@@ -12765,16 +12773,16 @@ fn coerceInMemoryAllowed(...@@ -12765,16 +12773,16 @@ fn coerceInMemoryAllowed(
1276512773
12766 // Functions12774 // Functions
12767 if (dest_tag == .Fn and src_tag == .Fn) {12775 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);
12769 }12777 }
1277012778
12771 // Error Unions12779 // Error Unions
12772 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {12780 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);
12774 if (child == .no_match) {12782 if (child == .no_match) {
12775 return child;12783 return child;
12776 }12784 }
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);
12778 }12786 }
1277912787
12780 // Error Sets12788 // Error Sets
...@@ -12884,9 +12892,12 @@ fn coerceInMemoryAllowedErrorSets(...@@ -12884,9 +12892,12 @@ fn coerceInMemoryAllowedErrorSets(
1288412892
12885fn coerceInMemoryAllowedFns(12893fn coerceInMemoryAllowedFns(
12886 sema: *Sema,12894 sema: *Sema,
12895 block: *Block,
12887 dest_ty: Type,12896 dest_ty: Type,
12888 src_ty: Type,12897 src_ty: Type,
12889 target: std.Target,12898 target: std.Target,
12899 dest_src: LazySrcLoc,
12900 src_src: LazySrcLoc,
12890) !InMemoryCoercionResult {12901) !InMemoryCoercionResult {
12891 const dest_info = dest_ty.fnInfo();12902 const dest_info = dest_ty.fnInfo();
12892 const src_info = src_ty.fnInfo();12903 const src_info = src_ty.fnInfo();
...@@ -12900,7 +12911,7 @@ fn coerceInMemoryAllowedFns(...@@ -12900,7 +12911,7 @@ fn coerceInMemoryAllowedFns(
12900 }12911 }
1290112912
12902 if (!src_info.return_type.isNoReturn()) {12913 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);
12904 if (rt == .no_match) {12915 if (rt == .no_match) {
12905 return rt;12916 return rt;
12906 }12917 }
...@@ -12920,7 +12931,7 @@ fn coerceInMemoryAllowedFns(...@@ -12920,7 +12931,7 @@ fn coerceInMemoryAllowedFns(
12920 // TODO: nolias12931 // TODO: nolias
1292112932
12922 // Note: Cast direction is reversed here.12933 // 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);
12924 if (param == .no_match) {12935 if (param == .no_match) {
12925 return param;12936 return param;
12926 }12937 }
...@@ -12935,17 +12946,20 @@ fn coerceInMemoryAllowedFns(...@@ -12935,17 +12946,20 @@ fn coerceInMemoryAllowedFns(
1293512946
12936fn coerceInMemoryAllowedPtrs(12947fn coerceInMemoryAllowedPtrs(
12937 sema: *Sema,12948 sema: *Sema,
12949 block: *Block,
12938 dest_ty: Type,12950 dest_ty: Type,
12939 src_ty: Type,12951 src_ty: Type,
12940 dest_ptr_ty: Type,12952 dest_ptr_ty: Type,
12941 src_ptr_ty: Type,12953 src_ptr_ty: Type,
12942 dest_is_mut: bool,12954 dest_is_mut: bool,
12943 target: std.Target,12955 target: std.Target,
12956 dest_src: LazySrcLoc,
12957 src_src: LazySrcLoc,
12944) !InMemoryCoercionResult {12958) !InMemoryCoercionResult {
12945 const dest_info = dest_ptr_ty.ptrInfo().data;12959 const dest_info = dest_ptr_ty.ptrInfo().data;
12946 const src_info = src_ptr_ty.ptrInfo().data;12960 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);
12949 if (child == .no_match) {12963 if (child == .no_match) {
12950 return child;12964 return child;
12951 }12965 }
...@@ -13592,7 +13606,7 @@ fn coerceVectorInMemory(...@@ -13592,7 +13606,7 @@ fn coerceVectorInMemory(
13592 const target = sema.mod.getTarget();13606 const target = sema.mod.getTarget();
13593 const dest_elem_ty = dest_ty.childType();13607 const dest_elem_ty = dest_ty.childType();
13594 const inst_elem_ty = inst_ty.childType();13608 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);
13596 if (in_memory_result != .ok) {13610 if (in_memory_result != .ok) {
13597 // TODO recursive error notes for coerceInMemoryAllowed failure13611 // TODO recursive error notes for coerceInMemoryAllowed failure
13598 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });13612 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
...@@ -14351,12 +14365,12 @@ fn resolvePeerTypes(...@@ -14351,12 +14365,12 @@ fn resolvePeerTypes(
14351 .Optional => {14365 .Optional => {
14352 var opt_child_buf: Type.Payload.ElemType = undefined;14366 var opt_child_buf: Type.Payload.ElemType = undefined;
14353 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);14367 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) {
14355 chosen = candidate;14369 chosen = candidate;
14356 chosen_i = candidate_i + 1;14370 chosen_i = candidate_i + 1;
14357 continue;14371 continue;
14358 }14372 }
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) {
14360 any_are_null = true;14374 any_are_null = true;
14361 continue;14375 continue;
14362 }14376 }
...@@ -14379,10 +14393,10 @@ fn resolvePeerTypes(...@@ -14379,10 +14393,10 @@ fn resolvePeerTypes(
14379 .Optional => {14393 .Optional => {
14380 var opt_child_buf: Type.Payload.ElemType = undefined;14394 var opt_child_buf: Type.Payload.ElemType = undefined;
14381 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);14395 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) {
14383 continue;14397 continue;
14384 }14398 }
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) {
14386 any_are_null = true;14400 any_are_null = true;
14387 chosen = candidate;14401 chosen = candidate;
14388 chosen_i = candidate_i + 1;14402 chosen_i = candidate_i + 1;
...@@ -14439,38 +14453,8 @@ pub fn resolveTypeLayout(...@@ -14439,38 +14453,8 @@ pub fn resolveTypeLayout(
14439 ty: Type,14453 ty: Type,
14440) CompileError!void {14454) CompileError!void {
14441 switch (ty.zigTypeTag()) {14455 switch (ty.zigTypeTag()) {
14442 .Struct => {14456 .Struct => return sema.resolveStructLayout(block, src, ty),
14443 const resolved_ty = try sema.resolveTypeFields(block, src, ty);14457 .Union => return sema.resolveUnionLayout(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 },
14474 .Array => {14458 .Array => {
14475 const elem_ty = ty.childType();14459 const elem_ty = ty.childType();
14476 return sema.resolveTypeLayout(block, src, elem_ty);14460 return sema.resolveTypeLayout(block, src, elem_ty);
...@@ -14488,6 +14472,73 @@ pub fn resolveTypeLayout(...@@ -14488,6 +14472,73 @@ pub fn resolveTypeLayout(
14488 }14472 }
14489}14473}
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
14491fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {14542fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
14492 switch (ty.tag()) {14543 switch (ty.tag()) {
14493 .@"struct" => {14544 .@"struct" => {
...@@ -15215,11 +15266,20 @@ fn typeHasOnePossibleValue(...@@ -15215,11 +15266,20 @@ fn typeHasOnePossibleValue(
15215 return null;15266 return null;
15216 }15267 }
15217 },15268 },
15218 .@"union" => {15269 .@"union", .union_tagged => {
15219 return null; // TODO15270 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15220 },15271 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
15221 .union_tagged => {15272 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
15222 return null; // TODO15273 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 });
15223 },15283 },
1522415284
15225 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),15285 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
...@@ -15453,7 +15513,11 @@ fn analyzeComptimeAlloc(...@@ -15453,7 +15513,11 @@ fn analyzeComptimeAlloc(
15453 block: *Block,15513 block: *Block,
15454 var_type: Type,15514 var_type: Type,
15455 alignment: u32,15515 alignment: u32,
15516 src: LazySrcLoc,
15456) CompileError!Air.Inst.Ref {15517) 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
15457 const ptr_type = try Type.ptr(sema.arena, .{15521 const ptr_type = try Type.ptr(sema.arena, .{
15458 .pointee_type = var_type,15522 .pointee_type = var_type,
15459 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),15523 .@"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...@@ -15551,8 +15615,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
15551 // We have a Value that lines up in virtual memory exactly with what we want to load.15615 // We have a Value that lines up in virtual memory exactly with what we want to load.
15552 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.15616 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.
15553 const coerce_in_mem_ok =15617 const coerce_in_mem_ok =
15554 (try sema.coerceInMemoryAllowed(load_ty, parent.ty, false, target)) == .ok or15618 (try sema.coerceInMemoryAllowed(block, load_ty, parent.ty, false, target, src, src)) == .ok or
15555 (try sema.coerceInMemoryAllowed(parent.ty, load_ty, false, target)) == .ok;15619 (try sema.coerceInMemoryAllowed(block, parent.ty, load_ty, false, target, src, src)) == .ok;
15556 if (coerce_in_mem_ok) {15620 if (coerce_in_mem_ok) {
15557 if (parent.is_mutable) {15621 if (parent.is_mutable) {
15558 // The decl whose value we are obtaining here may be overwritten with15622 // 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...@@ -15588,3 +15652,64 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
15588 error.Overflow => return sema.fail(block, src, "expression produces integer value {d} which is too big for this compiler implementation to handle", .{int}),15652 error.Overflow => return sema.fail(block, src, "expression produces integer value {d} which is too big for this compiler implementation to handle", .{int}),
15589 };15653 };
15590}15654}
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 {...@@ -1518,8 +1518,6 @@ pub const Type = extern union {
1518 }1518 }
1519 }1519 }
15201520
1521 /// For structs and unions, if the type does not have their fields resolved
1522 /// this will return `false`.
1523 pub fn hasCodeGenBits(self: Type) bool {1521 pub fn hasCodeGenBits(self: Type) bool {
1524 return switch (self.tag()) {1522 return switch (self.tag()) {
1525 .u1,1523 .u1,
...@@ -1601,6 +1599,7 @@ pub const Type = extern union {...@@ -1601,6 +1599,7 @@ pub const Type = extern union {
1601 if (struct_obj.known_has_bits) {1599 if (struct_obj.known_has_bits) {
1602 return true;1600 return true;
1603 }1601 }
1602 assert(struct_obj.haveFieldTypes());
1604 for (struct_obj.fields.values()) |value| {1603 for (struct_obj.fields.values()) |value| {
1605 if (value.ty.hasCodeGenBits())1604 if (value.ty.hasCodeGenBits())
1606 return true;1605 return true;
...@@ -1623,6 +1622,7 @@ pub const Type = extern union {...@@ -1623,6 +1622,7 @@ pub const Type = extern union {
1623 },1622 },
1624 .@"union" => {1623 .@"union" => {
1625 const union_obj = self.castTag(.@"union").?.data;1624 const union_obj = self.castTag(.@"union").?.data;
1625 assert(union_obj.haveFieldTypes());
1626 for (union_obj.fields.values()) |value| {1626 for (union_obj.fields.values()) |value| {
1627 if (value.ty.hasCodeGenBits())1627 if (value.ty.hasCodeGenBits())
1628 return true;1628 return true;
...@@ -1635,6 +1635,7 @@ pub const Type = extern union {...@@ -1635,6 +1635,7 @@ pub const Type = extern union {
1635 if (union_obj.tag_ty.hasCodeGenBits()) {1635 if (union_obj.tag_ty.hasCodeGenBits()) {
1636 return true;1636 return true;
1637 }1637 }
1638 assert(union_obj.haveFieldTypes());
1638 for (union_obj.fields.values()) |value| {1639 for (union_obj.fields.values()) |value| {
1639 if (value.ty.hasCodeGenBits())1640 if (value.ty.hasCodeGenBits())
1640 return true;1641 return true;
...@@ -2032,11 +2033,6 @@ pub const Type = extern union {...@@ -2032,11 +2033,6 @@ pub const Type = extern union {
2032 .c_const_pointer,2033 .c_const_pointer,
2033 .c_mut_pointer,2034 .c_mut_pointer,
2034 .pointer,2035 .pointer,
2035 => {
2036 if (!self.elemType().hasCodeGenBits()) return 0;
2037 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
2038 },
2039
2040 .manyptr_u8,2036 .manyptr_u8,
2041 .manyptr_const_u8,2037 .manyptr_const_u8,
2042 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),2038 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
...@@ -2524,37 +2520,6 @@ pub const Type = extern union {...@@ -2524,37 +2520,6 @@ pub const Type = extern union {
2524 return ty.ptrInfo().data.@"allowzero";2520 return ty.ptrInfo().data.@"allowzero";
2525 }2521 }
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
2558 /// Returns true if the type is optional and would be lowered to a single pointer2523 /// Returns true if the type is optional and would be lowered to a single pointer
2559 /// address value, using 0 for null. Note that this returns true for C pointers.2524 /// address value, using 0 for null. Note that this returns true for C pointers.
2560 pub fn isPtrLikeOptional(self: Type) bool {2525 pub fn isPtrLikeOptional(self: Type) bool {
...@@ -3393,11 +3358,14 @@ pub const Type = extern union {...@@ -3393,11 +3358,14 @@ pub const Type = extern union {
3393 return null;3358 return null;
3394 }3359 }
3395 },3360 },
3396 .@"union" => {3361 .@"union", .union_tagged => {
3397 return null; // TODO3362 const union_obj = ty.cast(Payload.Union).?.data;
3398 },3363 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
3399 .union_tagged => {3364 const only_field = union_obj.fields.values()[0];
3400 return null; // TODO3365 const val_val = only_field.ty.onePossibleValue() orelse return null;
3366 _ = tag_val;
3367 _ = val_val;
3368 return Value.initTag(.empty_struct_value);
3401 },3369 },
34023370
3403 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),3371 .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" {...@@ -8,5 +8,12 @@ test "bug 2006" {
8 var a: S = undefined;8 var a: S = undefined;
9 a = S{ .p = undefined };9 a = S{ .p = undefined };
10 try expect(@sizeOf(S) != 0);10 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 }
12}19}
test/behavior/bugs/6850.zig+6
...@@ -8,5 +8,11 @@ test "lazy sizeof comparison with zero" {...@@ -8,5 +8,11 @@ test "lazy sizeof comparison with zero" {
8}8}
99
10fn hasNoBits(comptime T: type) bool {10fn 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 }
11 return @sizeOf(T) == 0;17 return @sizeOf(T) == 0;
12}18}
test/behavior/struct_llvm.zig+49
...@@ -77,3 +77,52 @@ const EmptyStruct = struct {...@@ -77,3 +77,52 @@ const EmptyStruct = struct {
77 return 1234;77 return 1234;
78 }78 }
79};79};
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;...@@ -6,11 +6,6 @@ const expectEqual = std.testing.expectEqual;
6const expectEqualSlices = std.testing.expectEqualSlices;6const expectEqualSlices = std.testing.expectEqualSlices;
7const maxInt = std.math.maxInt;7const maxInt = std.math.maxInt;
88
9const EmptyStruct2 = struct {};
10fn testReturnEmptyStructFromFn() EmptyStruct2 {
11 return EmptyStruct2{};
12}
13
14const APackedStruct = packed struct {9const APackedStruct = packed struct {
15 x: u8,10 x: u8,
16 y: u8,11 y: u8,
...@@ -245,20 +240,6 @@ test "native bit field understands endianness" {...@@ -245,20 +240,6 @@ test "native bit field understands endianness" {
245 try expect(bitfields.f7 == 0x77);240 try expect(bitfields.f7 == 0x77);
246}241}
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
262test "implicit cast packed struct field to const ptr" {243test "implicit cast packed struct field to const ptr" {
263 const LevelUpMove = packed struct {244 const LevelUpMove = packed struct {
264 move_id: u9,245 move_id: u9,
...@@ -668,38 +649,3 @@ test "packed struct with undefined initializers" {...@@ -668,38 +649,3 @@ test "packed struct with undefined initializers" {
668 try S.doTheTest();649 try S.doTheTest();
669 comptime try S.doTheTest();650 comptime try S.doTheTest();
670}651}
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}