From 409cf4aeb826d8f7c35f0aa10bb0a8fe45188555 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 29 Sep 2022 15:04:07 +0300 Subject: [PATCH 1/4] Sema: use correct ptr ty to check for attributes of slice field ptr Closes #12870 Closes #13006 --- src/Sema.zig | 12 ++++++++---- test/behavior/slice.zig | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 5e65132510..7ad7491ea1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -21664,14 +21664,17 @@ fn fieldPtr( else object_ptr; + const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty; + if (mem.eql(u8, field_name, "ptr")) { const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); const slice_ptr_ty = inner_ty.slicePtrFieldType(buf); const result_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = slice_ptr_ty, - .mutable = object_ptr_ty.ptrIsMutable(), - .@"addrspace" = object_ptr_ty.ptrAddressSpace(), + .mutable = attr_ptr_ty.ptrIsMutable(), + .@"volatile" = attr_ptr_ty.isVolatilePtr(), + .@"addrspace" = attr_ptr_ty.ptrAddressSpace(), }); if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { @@ -21690,8 +21693,9 @@ fn fieldPtr( } else if (mem.eql(u8, field_name, "len")) { const result_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = Type.usize, - .mutable = object_ptr_ty.ptrIsMutable(), - .@"addrspace" = object_ptr_ty.ptrAddressSpace(), + .mutable = attr_ptr_ty.ptrIsMutable(), + .@"volatile" = attr_ptr_ty.isVolatilePtr(), + .@"addrspace" = attr_ptr_ty.ptrAddressSpace(), }); if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index e5cb8ea408..5aeb6a3414 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -684,3 +684,31 @@ test "slice len modification at comptime" { try expect(items[1] == 1); } } + +test "slice field ptr const" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + + const const_slice: []const u8 = "string"; + + const const_ptr_const_slice = &const_slice; + try expectEqual(*const []const u8, @TypeOf(&const_ptr_const_slice.*)); + try expectEqual(*const [*]const u8, @TypeOf(&const_ptr_const_slice.ptr)); + + var var_ptr_const_slice = &const_slice; + try expectEqual(*const []const u8, @TypeOf(&var_ptr_const_slice.*)); + try expectEqual(*const [*]const u8, @TypeOf(&var_ptr_const_slice.ptr)); +} + +test "slice field ptr var" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + + var var_slice: []const u8 = "string"; + + var var_ptr_var_slice = &var_slice; + try expectEqual(*[]const u8, @TypeOf(&var_ptr_var_slice.*)); + try expectEqual(*[*]const u8, @TypeOf(&var_ptr_var_slice.ptr)); + + const const_ptr_var_slice = &var_slice; + try expectEqual(*[]const u8, @TypeOf(&const_ptr_var_slice.*)); + try expectEqual(*[*]const u8, @TypeOf(&const_ptr_var_slice.ptr)); +} From b3c6d774d292e6e4ddf4cd54455c4ef3c6386d66 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 29 Sep 2022 17:45:27 +0300 Subject: [PATCH 2/4] stage2: improve error message for missing member in file root struct * the root struct decl name is fully qualified this prevents error messages containing 'main.main' * avoid declared here note when file struct is missing a member It always points at the start of the file which might contain another container misleading the user. --- src/Module.zig | 1 + src/Sema.zig | 5 +++++ test/cases/aarch64-macos/hello_world_with_updates.0.zig | 3 +-- test/cases/compile_errors/bogus_compile_var.zig | 3 +-- ...032_compile_diagnostic_string_for_top_level_decl_type.zig | 2 +- test/cases/x86_64-linux/hello_world_with_updates.0.zig | 3 +-- test/cases/x86_64-macos/hello_world_with_updates.0.zig | 3 +-- test/cases/x86_64-windows/hello_world_with_updates.0.zig | 3 +-- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index e756cc3dfd..6056c385e3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4435,6 +4435,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. new_decl.analysis = .in_progress; new_decl.generation = mod.generation; + new_decl.name_fully_qualified = true; if (file.status == .success_zir) { assert(file.zir_loaded); diff --git a/src/Sema.zig b/src/Sema.zig index 7ad7491ea1..aed09d6201 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4353,6 +4353,11 @@ fn failWithBadMemberAccess( .Enum => "enum", else => unreachable, }; + if (sema.mod.declIsRoot(agg_ty.getOwnerDecl())) { + return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{ + agg_ty.fmt(sema.mod), field_name, + }); + } const msg = msg: { const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ kw_name, agg_ty.fmt(sema.mod), field_name, diff --git a/test/cases/aarch64-macos/hello_world_with_updates.0.zig b/test/cases/aarch64-macos/hello_world_with_updates.0.zig index 3c7a494180..9f516ff139 100644 --- a/test/cases/aarch64-macos/hello_world_with_updates.0.zig +++ b/test/cases/aarch64-macos/hello_world_with_updates.0.zig @@ -2,5 +2,4 @@ // output_mode=Exe // target=aarch64-macos // -// :109:9: error: struct 'tmp.tmp' has no member named 'main' -// :7:1: note: struct declared here +// :109:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/cases/compile_errors/bogus_compile_var.zig b/test/cases/compile_errors/bogus_compile_var.zig index b675fd941c..be222e5393 100644 --- a/test/cases/compile_errors/bogus_compile_var.zig +++ b/test/cases/compile_errors/bogus_compile_var.zig @@ -5,5 +5,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(x)); } // backend=stage2 // target=native // -// :1:29: error: struct 'builtin.builtin' has no member named 'bogus' -// :1:1: note: struct declared here +// :1:29: error: root struct of file 'builtin' has no member named 'bogus' diff --git a/test/cases/compile_errors/issue_2032_compile_diagnostic_string_for_top_level_decl_type.zig b/test/cases/compile_errors/issue_2032_compile_diagnostic_string_for_top_level_decl_type.zig index 9ae320650a..d78891bb2b 100644 --- a/test/cases/compile_errors/issue_2032_compile_diagnostic_string_for_top_level_decl_type.zig +++ b/test/cases/compile_errors/issue_2032_compile_diagnostic_string_for_top_level_decl_type.zig @@ -7,5 +7,5 @@ export fn entry() void { // backend=stage2 // target=native // -// :2:27: error: expected type 'u32', found 'tmp.tmp' +// :2:27: error: expected type 'u32', found 'tmp' // :1:1: note: struct declared here diff --git a/test/cases/x86_64-linux/hello_world_with_updates.0.zig b/test/cases/x86_64-linux/hello_world_with_updates.0.zig index c9c94442d0..40abdd6c1f 100644 --- a/test/cases/x86_64-linux/hello_world_with_updates.0.zig +++ b/test/cases/x86_64-linux/hello_world_with_updates.0.zig @@ -2,5 +2,4 @@ // output_mode=Exe // target=x86_64-linux // -// :109:9: error: struct 'tmp.tmp' has no member named 'main' -// :7:1: note: struct declared here +// :109:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/cases/x86_64-macos/hello_world_with_updates.0.zig b/test/cases/x86_64-macos/hello_world_with_updates.0.zig index 5860c9c0f6..e0680c81d7 100644 --- a/test/cases/x86_64-macos/hello_world_with_updates.0.zig +++ b/test/cases/x86_64-macos/hello_world_with_updates.0.zig @@ -2,5 +2,4 @@ // output_mode=Exe // target=x86_64-macos // -// :109:9: error: struct 'tmp.tmp' has no member named 'main' -// :7:1: note: struct declared here +// :109:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/cases/x86_64-windows/hello_world_with_updates.0.zig b/test/cases/x86_64-windows/hello_world_with_updates.0.zig index 142699b9da..04e1d4cfad 100644 --- a/test/cases/x86_64-windows/hello_world_with_updates.0.zig +++ b/test/cases/x86_64-windows/hello_world_with_updates.0.zig @@ -2,5 +2,4 @@ // output_mode=Exe // target=x86_64-windows // -// :130:9: error: struct 'tmp.tmp' has no member named 'main' -// :7:1: note: struct declared here +// :130:9: error: root struct of file 'tmp' has no member named 'main' From 312260124279027a248d669e6096c3ab603fa188 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 29 Sep 2022 18:51:04 +0300 Subject: [PATCH 3/4] AstGen: do not set decl_line for containers Previously AstGen would set decl_line for containers so that declarations inside them would be relative to the start of the container but Sema was not aware of the line offset of the container and would make them relative to the containers parent decl which would then break for generic structs. In the future when working on incremental compilation it will likely be better to communicate the line delta to Sema but for now this is a simpler fix that correctly handles the non-incremental case. Closes #12725 Closes #12818 --- src/AstGen.zig | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index 8e6721d7bc..422827c673 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -4233,13 +4233,10 @@ fn structDeclInner( // are in scope, so that field types, alignments, and default value expressions // can refer to decls within the struct itself. astgen.advanceSourceCursorToNode(node); - // If `node == 0` then this is the root struct and all the declarations should - // be relative to the beginning of the file. - const decl_line = if (node == 0) 0 else astgen.source_line; var block_scope: GenZir = .{ .parent = &namespace.base, .decl_node_index = node, - .decl_line = decl_line, + .decl_line = gz.decl_line, .astgen = astgen, .force_comptime = true, .instructions = gz.instructions, @@ -4439,7 +4436,7 @@ fn unionDeclInner( var block_scope: GenZir = .{ .parent = &namespace.base, .decl_node_index = node, - .decl_line = astgen.source_line, + .decl_line = gz.decl_line, .astgen = astgen, .force_comptime = true, .instructions = gz.instructions, @@ -4722,7 +4719,7 @@ fn containerDecl( var block_scope: GenZir = .{ .parent = &namespace.base, .decl_node_index = node, - .decl_line = astgen.source_line, + .decl_line = gz.decl_line, .astgen = astgen, .force_comptime = true, .instructions = gz.instructions, @@ -4827,7 +4824,7 @@ fn containerDecl( var block_scope: GenZir = .{ .parent = &namespace.base, .decl_node_index = node, - .decl_line = astgen.source_line, + .decl_line = gz.decl_line, .astgen = astgen, .force_comptime = true, .instructions = gz.instructions, From 2a4e89e0c9428b1ca59bc23c7c1d667c8ddb2304 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 29 Sep 2022 19:02:59 +0300 Subject: [PATCH 4/4] Type: correctly handle ABI align strat for optionals and error unions Closes #12984 --- src/type.zig | 20 ++++++++++++++++++-- test/behavior.zig | 1 + test/behavior/bugs/12984.zig | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/behavior/bugs/12984.zig diff --git a/src/type.zig b/src/type.zig index 3e2e395d07..1fef525062 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3458,12 +3458,21 @@ pub const Type = extern union { else => {}, } + const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) { + .scalar => |elem_size| elem_size, + .val => switch (strat) { + .sema_kit => unreachable, + .eager => unreachable, + .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, + }, + }; + // Optional types are represented as a struct with the child type as the first // field and a boolean as the second. Since the child type's abi alignment is // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal // to the child type's ABI alignment. return AbiSizeAdvanced{ - .scalar = child_type.abiAlignment(target) + child_type.abiSize(target), + .scalar = child_type.abiAlignment(target) + payload_size, }; }, @@ -3478,7 +3487,14 @@ pub const Type = extern union { } const code_align = abiAlignment(Type.anyerror, target); const payload_align = abiAlignment(data.payload, target); - const payload_size = abiSize(data.payload, target); + const payload_size = switch (try data.payload.abiSizeAdvanced(target, strat)) { + .scalar => |elem_size| elem_size, + .val => switch (strat) { + .sema_kit => unreachable, + .eager => unreachable, + .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, + }, + }; var size: u64 = 0; if (code_align > payload_align) { diff --git a/test/behavior.zig b/test/behavior.zig index 019d9bbac7..ed7910cfbc 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -98,6 +98,7 @@ test { _ = @import("behavior/bugs/12911.zig"); _ = @import("behavior/bugs/12928.zig"); _ = @import("behavior/bugs/12945.zig"); + _ = @import("behavior/bugs/12984.zig"); _ = @import("behavior/byteswap.zig"); _ = @import("behavior/byval_arg_var.zig"); _ = @import("behavior/call.zig"); diff --git a/test/behavior/bugs/12984.zig b/test/behavior/bugs/12984.zig new file mode 100644 index 0000000000..a538b62e8d --- /dev/null +++ b/test/behavior/bugs/12984.zig @@ -0,0 +1,22 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub fn DeleagateWithContext(comptime Function: type) type { + const ArgArgs = std.meta.ArgsTuple(Function); + return struct { + t: ArgArgs, + }; +} + +pub const OnConfirm = DeleagateWithContext(fn (bool) void); +pub const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void); + +test "simple test" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + var c: CustomDraw = undefined; + _ = c; +}