diff options
| -rw-r--r-- | lib/std/zig/tokenizer.zig | 11 | ||||
| -rw-r--r-- | src/AstGen.zig | 25 | ||||
| -rw-r--r-- | src/Sema.zig | 25 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 18 | ||||
| -rw-r--r-- | test/behavior/packed-struct.zig | 26 | ||||
| -rw-r--r-- | test/behavior/pointers.zig | 10 | ||||
| -rw-r--r-- | test/behavior/switch.zig | 14 | ||||
| -rw-r--r-- | test/behavior/type_info.zig | 13 | ||||
| -rw-r--r-- | test/c_abi/main.zig | 1 | ||||
| -rw-r--r-- | test/cases/compile_errors/invalid_store_to_comptime_field.zig | 19 | ||||
| -rw-r--r-- | test/cases/f32_passed_to_variadic_fn.zig | 15 |
11 files changed, 150 insertions, 27 deletions
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index cd6e85e1fa..ba99fe3d2c 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -1151,7 +1151,13 @@ pub const Tokenizer = struct { }, }, .line_comment => switch (c) { - 0 => break, + 0 => { + if (self.index != self.buffer.len) { + result.tag = .invalid; + self.index += 1; + } + break; + }, '\n' => { state = .start; result.loc.start = self.index + 1; @@ -1865,6 +1871,9 @@ test "null byte before eof" { try testTokenize("//\x00", &.{.invalid}); try testTokenize("\\\\\x00", &.{ .multiline_string_literal_line, .invalid }); try testTokenize("\x00", &.{.invalid}); + try testTokenize("// NUL\x00\n", &.{.invalid}); + try testTokenize("///\x00\n", &.{ .doc_comment, .invalid }); + try testTokenize("/// NUL\x00\n", &.{ .doc_comment, .invalid }); } fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void { diff --git a/src/AstGen.zig b/src/AstGen.zig index 894acdd8f2..15b3611a1e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3341,6 +3341,9 @@ fn ptrType( return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{}); } + const source_offset = gz.astgen.source_offset; + const source_line = gz.astgen.source_line; + const source_column = gz.astgen.source_column; const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); var sentinel_ref: Zir.Inst.Ref = .none; @@ -3351,17 +3354,31 @@ fn ptrType( var trailing_count: u32 = 0; if (ptr_info.ast.sentinel != 0) { + // These attributes can appear in any order and they all come before the + // element type so we need to reset the source cursor before generating them. + gz.astgen.source_offset = source_offset; + gz.astgen.source_line = source_line; + gz.astgen.source_column = source_column; + sentinel_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, ptr_info.ast.sentinel); trailing_count += 1; } - if (ptr_info.ast.align_node != 0) { - align_ref = try expr(gz, scope, coerced_align_ri, ptr_info.ast.align_node); - trailing_count += 1; - } if (ptr_info.ast.addrspace_node != 0) { + gz.astgen.source_offset = source_offset; + gz.astgen.source_line = source_line; + gz.astgen.source_column = source_column; + addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node); trailing_count += 1; } + if (ptr_info.ast.align_node != 0) { + gz.astgen.source_offset = source_offset; + gz.astgen.source_line = source_line; + gz.astgen.source_column = source_column; + + align_ref = try expr(gz, scope, coerced_align_ri, ptr_info.ast.align_node); + trailing_count += 1; + } if (ptr_info.ast.bit_range_start != 0) { assert(ptr_info.ast.bit_range_end != 0); bit_start_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_start); diff --git a/src/Sema.zig b/src/Sema.zig index fcf25ab9bf..dcc38e4c0a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11288,6 +11288,7 @@ fn resolveSwitchItemVal( // Only if we know for sure we need to report a compile error do we resolve the // full source locations. if (sema.resolveConstValue(block, .unneeded, item, "")) |val| { + try sema.resolveLazyValue(val); return TypedValue{ .ty = item_ty, .val = val }; } else |err| switch (err) { error.NeededSourceLocation => { @@ -16258,6 +16259,7 @@ fn typeInfoNamespaceDecls( for (decls) |decl_index| { const decl = sema.mod.declPtr(decl_index); if (decl.kind == .@"usingnamespace") { + if (decl.analysis == .in_progress) continue; try sema.mod.ensureDeclAnalyzed(decl_index); var buf: Value.ToTypeBuffer = undefined; const new_ns = decl.val.toType(&buf).getNamespace().?; @@ -24820,8 +24822,13 @@ fn coerceExtra( // empty tuple to zero-length slice // note that this allows coercing to a mutable slice. if (inst_child_ty.structFieldCount() == 0) { + // Optional slice is represented with a null pointer so + // we use a dummy pointer value with the required alignment. const slice_val = try Value.Tag.slice.create(sema.arena, .{ - .ptr = Value.undef, + .ptr = if (dest_info.@"align" != 0) + try Value.Tag.int_u64.create(sema.arena, dest_info.@"align") + else + try inst_child_ty.lazyAbiAlignment(target, sema.arena), .len = Value.zero, }); return sema.addConstant(dest_ty, slice_val); @@ -26065,7 +26072,8 @@ fn coerceVarArgParam( ) !Air.Inst.Ref { if (block.is_typeof) return inst; - const coerced = switch (sema.typeOf(inst).zigTypeTag()) { + const uncasted_ty = sema.typeOf(inst); + const coerced = switch (uncasted_ty.zigTypeTag()) { // TODO consider casting to c_int/f64 if they fit .ComptimeInt, .ComptimeFloat => return sema.fail( block, @@ -26079,6 +26087,17 @@ fn coerceVarArgParam( break :blk try sema.analyzeDeclRef(fn_decl); }, .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), + .Float => float: { + const target = sema.mod.getTarget(); + const double_bits = @import("type.zig").CType.sizeInBits(.double, target); + const inst_bits = uncasted_ty.floatBits(sema.mod.getTarget()); + if (inst_bits >= double_bits) break :float inst; + switch (double_bits) { + 32 => break :float try sema.coerce(block, Type.f32, inst, inst_src), + 64 => break :float try sema.coerce(block, Type.f64, inst, inst_src), + else => unreachable, + } + }, else => inst, }; @@ -27316,7 +27335,7 @@ fn coerceCompatiblePtrs( return sema.addConstant(dest_ty, val); } try sema.requireRuntimeBlock(block, inst_src, null); - const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true; + const inst_allows_zero = inst_ty.zigTypeTag() != .Pointer or inst_ty.ptrAllowsZero(); if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and try sema.typeHasRuntimeBits(dest_ty.elemType2())) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b7e1466a2b..abcb9b4060 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3370,7 +3370,7 @@ pub const DeclGen = struct { return llvm_int.constIntToPtr(try dg.lowerType(tv.ty)); }, .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { - return dg.lowerParentPtr(tv.val); + return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo().data.bit_offset % 8 == 0); }, .null_value, .zero => { const llvm_type = try dg.lowerType(tv.ty); @@ -3378,7 +3378,7 @@ pub const DeclGen = struct { }, .opt_payload => { const payload = tv.val.castTag(.opt_payload).?.data; - return dg.lowerParentPtr(payload); + return dg.lowerParentPtr(payload, tv.ty.ptrInfo().data.bit_offset % 8 == 0); }, else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ tv.ty.fmtDebug(), tag, @@ -3967,7 +3967,7 @@ pub const DeclGen = struct { return try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index); } - fn lowerParentPtr(dg: *DeclGen, ptr_val: Value) Error!*llvm.Value { + fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value { const target = dg.module.getTarget(); switch (ptr_val.tag()) { .decl_ref_mut => { @@ -3996,7 +3996,7 @@ pub const DeclGen = struct { }, .field_ptr => { const field_ptr = ptr_val.castTag(.field_ptr).?.data; - const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr); + const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, byte_aligned); const parent_ty = field_ptr.container_ty; const field_index = @intCast(u32, field_ptr.field_index); @@ -4026,6 +4026,7 @@ pub const DeclGen = struct { }, .Struct => { if (parent_ty.containerLayout() == .Packed) { + if (!byte_aligned) return parent_llvm_ptr; const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); // count bits of fields before this one @@ -4072,7 +4073,7 @@ pub const DeclGen = struct { }, .elem_ptr => { const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; - const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr); + const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, true); const llvm_usize = try dg.lowerType(Type.usize); const indices: [1]*llvm.Value = .{ @@ -4083,7 +4084,7 @@ pub const DeclGen = struct { }, .opt_payload_ptr => { const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; - const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr); + const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr, true); var buf: Type.Payload.ElemType = undefined; const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf); @@ -4105,7 +4106,7 @@ pub const DeclGen = struct { }, .eu_payload_ptr => { const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; - const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr); + const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, true); const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload(); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { @@ -10667,8 +10668,7 @@ const ParamTypeIterator = struct { .memory => { it.zig_index += 1; it.llvm_index += 1; - it.byval_attr = true; - return .byref; + return .byref_mut; }, .sse => { it.zig_index += 1; diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 3baaaee3d8..e1237a578b 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -599,3 +599,29 @@ test "packed struct initialized in bitcast" { const t = @bitCast(u8, T{ .val = val }); try expect(t == val); } + +test "pointer to container level packed struct field" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + const S = packed struct(u32) { + test_bit: bool, + someother_data: u12, + other_test_bit: bool, + someother_more_different_data: u12, + other_bits: packed struct(u6) { + enable_1: bool, + enable_2: bool, + enable_3: bool, + enable_4: bool, + enable_5: bool, + enable_6: bool, + }, + var arr = [_]u32{0} ** 2; + }; + @ptrCast(*S, &S.arr[0]).other_bits.enable_3 = true; + try expect(S.arr[0] == 0x10000000); +} diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index e718169731..c8879453ad 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -522,3 +522,13 @@ test "ptrToInt on a generic function" { }; try S.doTheTest(&S.generic); } + +test "pointer alignment and element type include call expression" { + const S = struct { + fn T() type { + return struct { _: i32 }; + } + const P = *align(@alignOf(T())) [@sizeOf(T())]u8; + }; + try expect(@alignOf(S.P) > 0); +} diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 3bb9c35a4e..b8c367eb44 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -686,3 +686,17 @@ test "enum value without tag name used as switch item" { _ => return error.TestFailed, } } + +test "switch item sizeof" { + const S = struct { + fn doTheTest() !void { + var a: usize = 0; + switch (a) { + @sizeOf(struct {}) => {}, + else => return error.TestFailed, + } + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index ef8c89bd23..419a2f231c 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -590,3 +590,16 @@ test "@typeInfo decls and usingnamespace" { try expectEqualStrings(decls[1].name, "y"); try expectEqualStrings(decls[2].name, "z"); } + +test "@typeInfo decls ignore dependency loops" { + const S = struct { + fn Def(comptime T: type) type { + std.debug.assert(@typeInfo(T).Struct.decls.len == 1); + return struct { + const foo = u32; + }; + } + usingnamespace Def(@This()); + }; + _ = S.foo; +} diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 426651aa9e..b0d7a822d2 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -1032,7 +1032,6 @@ extern fn c_modify_by_ref_param(ByRef) ByRef; test "C function modifies by ref param" { if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.mode != .Debug) return error.SkipZigTest; const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined }); try expect(res.val == 42); diff --git a/test/cases/compile_errors/invalid_store_to_comptime_field.zig b/test/cases/compile_errors/invalid_store_to_comptime_field.zig index 89deda92d4..0f444ba78c 100644 --- a/test/cases/compile_errors/invalid_store_to_comptime_field.zig +++ b/test/cases/compile_errors/invalid_store_to_comptime_field.zig @@ -44,15 +44,15 @@ pub export fn entry5() void { comptime var y = .{ 1, 2 }; y = .{ 3, 4 }; } -// pub export fn entry5() void { -// var x: u32 = 15; -// const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x }); -// const S = struct { -// fn foo(_: T) void {} -// }; -// _ = S.foo(.{ -1234, 5679, x }); -// } pub export fn entry6() void { + var x: u32 = 15; + const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x }); + const S = struct { + fn foo(_: T) void {} + }; + _ = S.foo(.{ -1234, 5679, x }); +} +pub export fn entry7() void { const State = struct { comptime id: bool = true, fn init(comptime id: bool) @This() { @@ -61,7 +61,7 @@ pub export fn entry6() void { }; _ = State.init(false); } -pub export fn entry7() void { +pub export fn entry8() void { const list1 = .{ "sss", 1, 2, 3 }; const list2 = @TypeOf(list1){ .@"0" = "xxx", .@"1" = 4, .@"2" = 5, .@"3" = 6 }; _ = list2; @@ -73,6 +73,7 @@ pub export fn entry7() void { // // :6:19: error: value stored in comptime field does not match the default value of the field // :14:19: error: value stored in comptime field does not match the default value of the field +// :53:16: error: value stored in comptime field does not match the default value of the field // :19:38: error: value stored in comptime field does not match the default value of the field // :31:19: error: value stored in comptime field does not match the default value of the field // :25:29: note: default value set here diff --git a/test/cases/f32_passed_to_variadic_fn.zig b/test/cases/f32_passed_to_variadic_fn.zig new file mode 100644 index 0000000000..c029b4b69f --- /dev/null +++ b/test/cases/f32_passed_to_variadic_fn.zig @@ -0,0 +1,15 @@ +extern fn printf(format: [*:0]const u8, ...) c_int; +pub fn main() void { + var a: f64 = 2.0; + var b: f32 = 10.0; + _ = printf("f64: %f\n", a); + _ = printf("f32: %f\n", b); +} + +// run +// backend=llvm +// target=x86_64-linux-gnu +// +// f64: 2.000000 +// f32: 10.000000 +//
\ No newline at end of file |
