| author | |
| committer | |
| log | 8eea73fb922c1c7fab4b8bf1717588464691a66e |
| tree | 6b80dd1b1d2e1993e05e6d3c19cbc5ba4d424c5e |
| parent | 4cea15f12bdaf1603d60cf80e767dd8f2bb48b26 |
14 files changed, 260 insertions(+), 30 deletions(-)
lib/std/zig/parse.zig+1-1| ... | @@ -884,7 +884,7 @@ const Parser = struct { | ... | @@ -884,7 +884,7 @@ const Parser = struct { |
| 884 | 884 | ||
| 885 | var align_expr: Node.Index = 0; | 885 | var align_expr: Node.Index = 0; |
| 886 | var type_expr: Node.Index = 0; | 886 | var type_expr: Node.Index = 0; |
| 887 | if (p.eatToken(.colon) != null or tuple_like) |_| { | 887 | if (p.eatToken(.colon) != null or tuple_like) { |
| 888 | type_expr = try p.expectTypeExpr(); | 888 | type_expr = try p.expectTypeExpr(); |
| 889 | align_expr = try p.parseByteAlign(); | 889 | align_expr = try p.parseByteAlign(); |
| 890 | } | 890 | } |
lib/std/zig/render.zig+19| ... | @@ -1189,6 +1189,16 @@ fn renderContainerField( | ... | @@ -1189,6 +1189,16 @@ fn renderContainerField( |
| 1189 | try renderToken(ais, tree, t, .space); // comptime | 1189 | try renderToken(ais, tree, t, .space); // comptime |
| 1190 | } | 1190 | } |
| 1191 | if (field.ast.type_expr == 0 and field.ast.value_expr == 0) { | 1191 | if (field.ast.type_expr == 0 and field.ast.value_expr == 0) { |
| 1192 | if (field.ast.align_expr != 0) { | ||
| 1193 | try renderIdentifier(ais, tree, field.ast.main_token, .space, .eagerly_unquote); // name | ||
| 1194 | const lparen_token = tree.firstToken(field.ast.align_expr) - 1; | ||
| 1195 | const align_kw = lparen_token - 1; | ||
| 1196 | const rparen_token = tree.lastToken(field.ast.align_expr) + 1; | ||
| 1197 | try renderToken(ais, tree, align_kw, .none); // align | ||
| 1198 | try renderToken(ais, tree, lparen_token, .none); // ( | ||
| 1199 | try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment | ||
| 1200 | return renderToken(ais, tree, rparen_token, .space); // ) | ||
| 1201 | } | ||
| 1192 | return renderIdentifierComma(ais, tree, field.ast.main_token, space, .eagerly_unquote); // name | 1202 | return renderIdentifierComma(ais, tree, field.ast.main_token, space, .eagerly_unquote); // name |
| 1193 | } | 1203 | } |
| 1194 | if (field.ast.type_expr != 0 and field.ast.value_expr == 0) { | 1204 | if (field.ast.type_expr != 0 and field.ast.value_expr == 0) { |
| ... | @@ -1211,6 +1221,15 @@ fn renderContainerField( | ... | @@ -1211,6 +1221,15 @@ fn renderContainerField( |
| 1211 | } | 1221 | } |
| 1212 | if (field.ast.type_expr == 0 and field.ast.value_expr != 0) { | 1222 | if (field.ast.type_expr == 0 and field.ast.value_expr != 0) { |
| 1213 | try renderIdentifier(ais, tree, field.ast.main_token, .space, .eagerly_unquote); // name | 1223 | try renderIdentifier(ais, tree, field.ast.main_token, .space, .eagerly_unquote); // name |
| 1224 | if (field.ast.align_expr != 0) { | ||
| 1225 | const lparen_token = tree.firstToken(field.ast.align_expr) - 1; | ||
| 1226 | const align_kw = lparen_token - 1; | ||
| 1227 | const rparen_token = tree.lastToken(field.ast.align_expr) + 1; | ||
| 1228 | try renderToken(ais, tree, align_kw, .none); // align | ||
| 1229 | try renderToken(ais, tree, lparen_token, .none); // ( | ||
| 1230 | try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment | ||
| 1231 | try renderToken(ais, tree, rparen_token, .space); // ) | ||
| 1232 | } | ||
| 1214 | try renderToken(ais, tree, field.ast.main_token + 1, .space); // = | 1233 | try renderToken(ais, tree, field.ast.main_token + 1, .space); // = |
| 1215 | return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value | 1234 | return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value |
| 1216 | } | 1235 | } |
src/AstGen.zig+3-2| ... | @@ -4854,8 +4854,9 @@ fn containerDecl( | ... | @@ -4854,8 +4854,9 @@ fn containerDecl( |
| 4854 | }, | 4854 | }, |
| 4855 | ); | 4855 | ); |
| 4856 | } | 4856 | } |
| 4857 | // Alignment expressions in enums are caught by the parser. | 4857 | if (member.ast.align_expr != 0) { |
| 4858 | assert(member.ast.align_expr == 0); | 4858 | return astgen.failNode(member.ast.align_expr, "enum fields cannot be aligned", .{}); |
| 4859 | } | ||
| 4859 | 4860 | ||
| 4860 | const name_token = member.ast.main_token; | 4861 | const name_token = member.ast.main_token; |
| 4861 | if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { | 4862 | if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { |
src/Sema.zig+41-8| ... | @@ -11834,6 +11834,12 @@ fn analyzeTupleCat( | ... | @@ -11834,6 +11834,12 @@ fn analyzeTupleCat( |
| 11834 | if (dest_fields == 0) { | 11834 | if (dest_fields == 0) { |
| 11835 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); | 11835 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); |
| 11836 | } | 11836 | } |
| 11837 | if (lhs_len == 0) { | ||
| 11838 | return rhs; | ||
| 11839 | } | ||
| 11840 | if (rhs_len == 0) { | ||
| 11841 | return lhs; | ||
| 11842 | } | ||
| 11837 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); | 11843 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); |
| 11838 | 11844 | ||
| 11839 | const types = try sema.arena.alloc(Type, final_len); | 11845 | const types = try sema.arena.alloc(Type, final_len); |
| ... | @@ -11880,13 +11886,13 @@ fn analyzeTupleCat( | ... | @@ -11880,13 +11886,13 @@ fn analyzeTupleCat( |
| 11880 | var i: u32 = 0; | 11886 | var i: u32 = 0; |
| 11881 | while (i < lhs_len) : (i += 1) { | 11887 | while (i < lhs_len) : (i += 1) { |
| 11882 | const operand_src = lhs_src; // TODO better source location | 11888 | const operand_src = lhs_src; // TODO better source location |
| 11883 | element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty); | 11889 | element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, i, lhs_ty); |
| 11884 | } | 11890 | } |
| 11885 | i = 0; | 11891 | i = 0; |
| 11886 | while (i < rhs_len) : (i += 1) { | 11892 | while (i < rhs_len) : (i += 1) { |
| 11887 | const operand_src = rhs_src; // TODO better source location | 11893 | const operand_src = rhs_src; // TODO better source location |
| 11888 | element_refs[i + lhs_len] = | 11894 | element_refs[i + lhs_len] = |
| 11889 | try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty); | 11895 | try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); |
| 11890 | } | 11896 | } |
| 11891 | 11897 | ||
| 11892 | return block.addAggregateInit(tuple_ty, element_refs); | 11898 | return block.addAggregateInit(tuple_ty, element_refs); |
| ... | @@ -18502,8 +18508,12 @@ fn reifyStruct( | ... | @@ -18502,8 +18508,12 @@ fn reifyStruct( |
| 18502 | } | 18508 | } |
| 18503 | const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?); | 18509 | const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?); |
| 18504 | 18510 | ||
| 18505 | if (layout == .Packed and abi_align != 0) { | 18511 | if (layout == .Packed) { |
| 18506 | return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); | 18512 | if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); |
| 18513 | if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}); | ||
| 18514 | } | ||
| 18515 | if (layout == .Extern and is_comptime_val.toBool()) { | ||
| 18516 | return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}); | ||
| 18507 | } | 18517 | } |
| 18508 | 18518 | ||
| 18509 | const field_name = try name_val.toAllocatedBytes( | 18519 | const field_name = try name_val.toAllocatedBytes( |
| ... | @@ -18512,6 +18522,25 @@ fn reifyStruct( | ... | @@ -18512,6 +18522,25 @@ fn reifyStruct( |
| 18512 | mod, | 18522 | mod, |
| 18513 | ); | 18523 | ); |
| 18514 | 18524 | ||
| 18525 | if (is_tuple) { | ||
| 18526 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch { | ||
| 18527 | return sema.fail( | ||
| 18528 | block, | ||
| 18529 | src, | ||
| 18530 | "tuple cannot have non-numeric field '{s}'", | ||
| 18531 | .{field_name}, | ||
| 18532 | ); | ||
| 18533 | }; | ||
| 18534 | |||
| 18535 | if (field_index >= fields_len) { | ||
| 18536 | return sema.fail( | ||
| 18537 | block, | ||
| 18538 | src, | ||
| 18539 | "tuple field {} exceeds tuple field count", | ||
| 18540 | .{field_index}, | ||
| 18541 | ); | ||
| 18542 | } | ||
| 18543 | } | ||
| 18515 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | 18544 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); |
| 18516 | if (gop.found_existing) { | 18545 | if (gop.found_existing) { |
| 18517 | // TODO: better source location | 18546 | // TODO: better source location |
| ... | @@ -18525,6 +18554,9 @@ fn reifyStruct( | ... | @@ -18525,6 +18554,9 @@ fn reifyStruct( |
| 18525 | opt_val; | 18554 | opt_val; |
| 18526 | break :blk try payload_val.copy(new_decl_arena_allocator); | 18555 | break :blk try payload_val.copy(new_decl_arena_allocator); |
| 18527 | } else Value.initTag(.unreachable_value); | 18556 | } else Value.initTag(.unreachable_value); |
| 18557 | if (is_comptime_val.toBool() and default_val.tag() == .unreachable_value) { | ||
| 18558 | return sema.fail(block, src, "comptime field without default initialization value", .{}); | ||
| 18559 | } | ||
| 18528 | 18560 | ||
| 18529 | var buffer: Value.ToTypeBuffer = undefined; | 18561 | var buffer: Value.ToTypeBuffer = undefined; |
| 18530 | gop.value_ptr.* = .{ | 18562 | gop.value_ptr.* = .{ |
| ... | @@ -27094,7 +27126,7 @@ fn coerceTupleToStruct( | ... | @@ -27094,7 +27126,7 @@ fn coerceTupleToStruct( |
| 27094 | 27126 | ||
| 27095 | const inst_ty = sema.typeOf(inst); | 27127 | const inst_ty = sema.typeOf(inst); |
| 27096 | var runtime_src: ?LazySrcLoc = null; | 27128 | var runtime_src: ?LazySrcLoc = null; |
| 27097 | const field_count = struct_ty.structFieldCount(); | 27129 | const field_count = inst_ty.structFieldCount(); |
| 27098 | var field_i: u32 = 0; | 27130 | var field_i: u32 = 0; |
| 27099 | while (field_i < field_count) : (field_i += 1) { | 27131 | while (field_i < field_count) : (field_i += 1) { |
| 27100 | const field_src = inst_src; // TODO better source location | 27132 | const field_src = inst_src; // TODO better source location |
| ... | @@ -27176,15 +27208,16 @@ fn coerceTupleToTuple( | ... | @@ -27176,15 +27208,16 @@ fn coerceTupleToTuple( |
| 27176 | inst: Air.Inst.Ref, | 27208 | inst: Air.Inst.Ref, |
| 27177 | inst_src: LazySrcLoc, | 27209 | inst_src: LazySrcLoc, |
| 27178 | ) !Air.Inst.Ref { | 27210 | ) !Air.Inst.Ref { |
| 27179 | const field_count = tuple_ty.structFieldCount(); | 27211 | const dest_field_count = tuple_ty.structFieldCount(); |
| 27180 | const field_vals = try sema.arena.alloc(Value, field_count); | 27212 | const field_vals = try sema.arena.alloc(Value, dest_field_count); |
| 27181 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); | 27213 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 27182 | mem.set(Air.Inst.Ref, field_refs, .none); | 27214 | mem.set(Air.Inst.Ref, field_refs, .none); |
| 27183 | 27215 | ||
| 27184 | const inst_ty = sema.typeOf(inst); | 27216 | const inst_ty = sema.typeOf(inst); |
| 27217 | const inst_field_count = inst_ty.structFieldCount(); | ||
| 27185 | var runtime_src: ?LazySrcLoc = null; | 27218 | var runtime_src: ?LazySrcLoc = null; |
| 27186 | var field_i: u32 = 0; | 27219 | var field_i: u32 = 0; |
| 27187 | while (field_i < field_count) : (field_i += 1) { | 27220 | while (field_i < inst_field_count) : (field_i += 1) { |
| 27188 | const field_src = inst_src; // TODO better source location | 27221 | const field_src = inst_src; // TODO better source location |
| 27189 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | 27222 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| |
| 27190 | payload.data.names[field_i] | 27223 | payload.data.names[field_i] |
src/arch/x86_64/abi.zig+1| ... | @@ -552,6 +552,7 @@ test "C_C_D" { | ... | @@ -552,6 +552,7 @@ test "C_C_D" { |
| 552 | .layout = .Extern, | 552 | .layout = .Extern, |
| 553 | .status = .fully_resolved, | 553 | .status = .fully_resolved, |
| 554 | .known_non_opv = true, | 554 | .known_non_opv = true, |
| 555 | .is_tuple = false, | ||
| 555 | }; | 556 | }; |
| 556 | var C_C_D = Type.Payload.Struct{ .data = &C_C_D_struct }; | 557 | var C_C_D = Type.Payload.Struct{ .data = &C_C_D_struct }; |
| 557 | 558 |
src/type.zig+6-2| ... | @@ -804,7 +804,7 @@ pub const Type = extern union { | ... | @@ -804,7 +804,7 @@ pub const Type = extern union { |
| 804 | return a_struct_obj == b_struct_obj; | 804 | return a_struct_obj == b_struct_obj; |
| 805 | }, | 805 | }, |
| 806 | .tuple, .empty_struct_literal => { | 806 | .tuple, .empty_struct_literal => { |
| 807 | if (!b.isTuple()) return false; | 807 | if (!b.isSimpleTuple()) return false; |
| 808 | 808 | ||
| 809 | const a_tuple = a.tupleFields(); | 809 | const a_tuple = a.tupleFields(); |
| 810 | const b_tuple = b.tupleFields(); | 810 | const b_tuple = b.tupleFields(); |
| ... | @@ -5572,7 +5572,11 @@ pub const Type = extern union { | ... | @@ -5572,7 +5572,11 @@ pub const Type = extern union { |
| 5572 | 5572 | ||
| 5573 | pub fn structFieldCount(ty: Type) usize { | 5573 | pub fn structFieldCount(ty: Type) usize { |
| 5574 | switch (ty.tag()) { | 5574 | switch (ty.tag()) { |
| 5575 | .@"struct" => return ty.castTag(.@"struct").?.data.fields.count(), | 5575 | .@"struct" => { |
| 5576 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 5577 | assert(struct_obj.haveFieldTypes()); | ||
| 5578 | return struct_obj.fields.count(); | ||
| 5579 | }, | ||
| 5576 | .empty_struct, .empty_struct_literal => return 0, | 5580 | .empty_struct, .empty_struct_literal => return 0, |
| 5577 | .tuple => return ty.castTag(.tuple).?.data.types.len, | 5581 | .tuple => return ty.castTag(.tuple).?.data.types.len, |
| 5578 | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, | 5582 | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, |
test/behavior.zig+1| ... | @@ -200,6 +200,7 @@ test { | ... | @@ -200,6 +200,7 @@ test { |
| 200 | _ = @import("behavior/packed_struct_explicit_backing_int.zig"); | 200 | _ = @import("behavior/packed_struct_explicit_backing_int.zig"); |
| 201 | _ = @import("behavior/empty_union.zig"); | 201 | _ = @import("behavior/empty_union.zig"); |
| 202 | _ = @import("behavior/inline_switch.zig"); | 202 | _ = @import("behavior/inline_switch.zig"); |
| 203 | _ = @import("behavior/tuple_declarations.zig"); | ||
| 203 | _ = @import("behavior/bugs/12723.zig"); | 204 | _ = @import("behavior/bugs/12723.zig"); |
| 204 | _ = @import("behavior/bugs/12776.zig"); | 205 | _ = @import("behavior/bugs/12776.zig"); |
| 205 | } | 206 | } |
test/behavior/tuple_declarations.zig created+79| ... | @@ -0,0 +1,79 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const testing = std.testing; | ||
| 4 | const expect = testing.expect; | ||
| 5 | const expectEqualStrings = testing.expectEqualStrings; | ||
| 6 | |||
| 7 | test "tuple declaration type info" { | ||
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 10 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 11 | |||
| 12 | { | ||
| 13 | const T = struct { comptime u32 align(2) = 1, []const u8 }; | ||
| 14 | const info = @typeInfo(T).Struct; | ||
| 15 | |||
| 16 | try expect(info.layout == .Auto); | ||
| 17 | try expect(info.backing_integer == null); | ||
| 18 | try expect(info.fields.len == 2); | ||
| 19 | try expect(info.decls.len == 0); | ||
| 20 | try expect(info.is_tuple); | ||
| 21 | |||
| 22 | try expectEqualStrings(info.fields[0].name, "0"); | ||
| 23 | try expect(info.fields[0].field_type == u32); | ||
| 24 | try expect(@ptrCast(*const u32, @alignCast(@alignOf(u32), info.fields[0].default_value)).* == 1); | ||
| 25 | try expect(info.fields[0].is_comptime); | ||
| 26 | try expect(info.fields[0].alignment == 2); | ||
| 27 | |||
| 28 | try expectEqualStrings(info.fields[1].name, "1"); | ||
| 29 | try expect(info.fields[1].field_type == []const u8); | ||
| 30 | try expect(info.fields[1].default_value == null); | ||
| 31 | try expect(!info.fields[1].is_comptime); | ||
| 32 | try expect(info.fields[1].alignment == @alignOf([]const u8)); | ||
| 33 | } | ||
| 34 | { | ||
| 35 | const T = packed struct(u32) { u1, u30, u1 }; | ||
| 36 | const info = @typeInfo(T).Struct; | ||
| 37 | |||
| 38 | try expect(std.mem.endsWith(u8, @typeName(T), "test.tuple declaration type info.T")); | ||
| 39 | |||
| 40 | try expect(info.layout == .Packed); | ||
| 41 | try expect(info.backing_integer == u32); | ||
| 42 | try expect(info.fields.len == 3); | ||
| 43 | try expect(info.decls.len == 0); | ||
| 44 | try expect(info.is_tuple); | ||
| 45 | |||
| 46 | try expectEqualStrings(info.fields[0].name, "0"); | ||
| 47 | try expect(info.fields[0].field_type == u1); | ||
| 48 | |||
| 49 | try expectEqualStrings(info.fields[1].name, "1"); | ||
| 50 | try expect(info.fields[1].field_type == u30); | ||
| 51 | |||
| 52 | try expectEqualStrings(info.fields[2].name, "2"); | ||
| 53 | try expect(info.fields[2].field_type == u1); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | test "Tuple declaration usage" { | ||
| 58 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 59 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 60 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 61 | |||
| 62 | const T = struct { u32, []const u8 }; | ||
| 63 | var t: T = .{ 1, "foo" }; | ||
| 64 | try expect(t[0] == 1); | ||
| 65 | try expectEqualStrings(t[1], "foo"); | ||
| 66 | |||
| 67 | var mul = t ** 3; | ||
| 68 | try expect(@TypeOf(mul) != T); | ||
| 69 | try expect(mul.len == 6); | ||
| 70 | try expect(mul[2] == 1); | ||
| 71 | try expectEqualStrings(mul[3], "foo"); | ||
| 72 | |||
| 73 | var t2: T = .{ 2, "bar" }; | ||
| 74 | var cat = t ++ t2; | ||
| 75 | try expect(@TypeOf(cat) != T); | ||
| 76 | try expect(cat.len == 4); | ||
| 77 | try expect(cat[2] == 2); | ||
| 78 | try expectEqualStrings(cat[3], "bar"); | ||
| 79 | } | ||
test/cases/compile_errors/alignment_of_enum_field_specified.zig+1-1| ... | @@ -11,4 +11,4 @@ export fn entry1() void { | ... | @@ -11,4 +11,4 @@ export fn entry1() void { |
| 11 | // backend=stage2 | 11 | // backend=stage2 |
| 12 | // target=native | 12 | // target=native |
| 13 | // | 13 | // |
| 14 | // :3:7: error: expected ',' after field | 14 | // :3:13: error: enum fields cannot be aligned |
test/cases/compile_errors/reify_struct.zig created+80| ... | @@ -0,0 +1,80 @@ | ||
| 1 | comptime { | ||
| 2 | @Type(.{ .Struct = .{ | ||
| 3 | .layout = .Auto, | ||
| 4 | .fields = &.{.{ | ||
| 5 | .name = "foo", | ||
| 6 | .field_type = u32, | ||
| 7 | .default_value = null, | ||
| 8 | .is_comptime = false, | ||
| 9 | .alignment = 4, | ||
| 10 | }}, | ||
| 11 | .decls = &.{}, | ||
| 12 | .is_tuple = true, | ||
| 13 | } }); | ||
| 14 | } | ||
| 15 | comptime { | ||
| 16 | @Type(.{ .Struct = .{ | ||
| 17 | .layout = .Auto, | ||
| 18 | .fields = &.{.{ | ||
| 19 | .name = "3", | ||
| 20 | .field_type = u32, | ||
| 21 | .default_value = null, | ||
| 22 | .is_comptime = false, | ||
| 23 | .alignment = 4, | ||
| 24 | }}, | ||
| 25 | .decls = &.{}, | ||
| 26 | .is_tuple = true, | ||
| 27 | } }); | ||
| 28 | } | ||
| 29 | comptime { | ||
| 30 | @Type(.{ .Struct = .{ | ||
| 31 | .layout = .Auto, | ||
| 32 | .fields = &.{.{ | ||
| 33 | .name = "0", | ||
| 34 | .field_type = u32, | ||
| 35 | .default_value = null, | ||
| 36 | .is_comptime = true, | ||
| 37 | .alignment = 4, | ||
| 38 | }}, | ||
| 39 | .decls = &.{}, | ||
| 40 | .is_tuple = true, | ||
| 41 | } }); | ||
| 42 | } | ||
| 43 | comptime { | ||
| 44 | @Type(.{ .Struct = .{ | ||
| 45 | .layout = .Extern, | ||
| 46 | .fields = &.{.{ | ||
| 47 | .name = "0", | ||
| 48 | .field_type = u32, | ||
| 49 | .default_value = null, | ||
| 50 | .is_comptime = true, | ||
| 51 | .alignment = 4, | ||
| 52 | }}, | ||
| 53 | .decls = &.{}, | ||
| 54 | .is_tuple = true, | ||
| 55 | } }); | ||
| 56 | } | ||
| 57 | comptime { | ||
| 58 | @Type(.{ .Struct = .{ | ||
| 59 | .layout = .Packed, | ||
| 60 | .fields = &.{.{ | ||
| 61 | .name = "0", | ||
| 62 | .field_type = u32, | ||
| 63 | .default_value = null, | ||
| 64 | .is_comptime = true, | ||
| 65 | .alignment = 4, | ||
| 66 | }}, | ||
| 67 | .decls = &.{}, | ||
| 68 | .is_tuple = true, | ||
| 69 | } }); | ||
| 70 | } | ||
| 71 | |||
| 72 | // error | ||
| 73 | // backend=stage2 | ||
| 74 | // target=native | ||
| 75 | // | ||
| 76 | // :2:5: error: tuple cannot have non-numeric field 'foo' | ||
| 77 | // :16:5: error: tuple field 3 exceeds tuple field count | ||
| 78 | // :30:5: error: comptime field without default initialization value | ||
| 79 | // :44:5: error: extern struct fields cannot be marked comptime | ||
| 80 | // :58:5: error: alignment in a packed struct field must be set to 0 | ||
test/cases/compile_errors/struct_field_missing_type.zig deleted-13| ... | @@ -1,13 +0,0 @@ | ||
| 1 | const Letter = struct { | ||
| 2 | A, | ||
| 3 | }; | ||
| 4 | export fn entry() void { | ||
| 5 | var a = Letter { .A = {} }; | ||
| 6 | _ = a; | ||
| 7 | } | ||
| 8 | |||
| 9 | // error | ||
| 10 | // backend=stage2 | ||
| 11 | // target=native | ||
| 12 | // | ||
| 13 | // :2:5: error: struct field missing type | ||
test/cases/compile_errors/tuple_declarations.zig created+25| ... | @@ -0,0 +1,25 @@ | ||
| 1 | const E = enum { | ||
| 2 | *u32, | ||
| 3 | }; | ||
| 4 | const U = union { | ||
| 5 | *u32, | ||
| 6 | }; | ||
| 7 | const S = struct { | ||
| 8 | a: u32, | ||
| 9 | *u32, | ||
| 10 | }; | ||
| 11 | const T = struct { | ||
| 12 | u32, | ||
| 13 | []const u8, | ||
| 14 | |||
| 15 | const a = 1; | ||
| 16 | }; | ||
| 17 | |||
| 18 | // error | ||
| 19 | // backend=stage2 | ||
| 20 | // target=native | ||
| 21 | // | ||
| 22 | // :2:5: error: enum field missing name | ||
| 23 | // :5:5: error: union field missing name | ||
| 24 | // :8:5: error: tuple field has a name | ||
| 25 | // :15:5: error: tuple declarations cannot contain declarations | ||
test/compile_errors.zig+2-2| ... | @@ -213,7 +213,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -213,7 +213,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 213 | case.backend = .stage2; | 213 | case.backend = .stage2; |
| 214 | 214 | ||
| 215 | case.addSourceFile("b.zig", | 215 | case.addSourceFile("b.zig", |
| 216 | \\bad | 216 | \\+ |
| 217 | ); | 217 | ); |
| 218 | 218 | ||
| 219 | case.addError( | 219 | case.addError( |
| ... | @@ -221,7 +221,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -221,7 +221,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 221 | \\ _ = (@sizeOf(@import("b.zig"))); | 221 | \\ _ = (@sizeOf(@import("b.zig"))); |
| 222 | \\} | 222 | \\} |
| 223 | , &[_][]const u8{ | 223 | , &[_][]const u8{ |
| 224 | ":1:1: error: struct field missing type", | 224 | ":1:1: error: expected type expression, found '+'", |
| 225 | }); | 225 | }); |
| 226 | } | 226 | } |
| 227 | 227 |
test/stage2/cbe.zig+1-1| ... | @@ -670,7 +670,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -670,7 +670,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 670 | \\ _ = E1.a; | 670 | \\ _ = E1.a; |
| 671 | \\} | 671 | \\} |
| 672 | , &.{ | 672 | , &.{ |
| 673 | ":3:7: error: expected ',' after field", | 673 | ":3:13: error: enum fields cannot be aligned", |
| 674 | }); | 674 | }); |
| 675 | 675 | ||
| 676 | // Redundant non-exhaustive enum mark. | 676 | // Redundant non-exhaustive enum mark. |