diff options
| -rw-r--r-- | lib/std/mem/Allocator.zig | 2 | ||||
| -rw-r--r-- | src/Compilation.zig | 2 | ||||
| -rw-r--r-- | src/Module.zig | 16 | ||||
| -rw-r--r-- | src/Sema.zig | 25 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 33 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 13 | ||||
| -rw-r--r-- | src/stage1/analyze.cpp | 6 | ||||
| -rw-r--r-- | src/zig_llvm.cpp | 12 | ||||
| -rw-r--r-- | src/zig_llvm.h | 6 | ||||
| -rw-r--r-- | test/behavior/call.zig | 17 | ||||
| -rw-r--r-- | test/behavior/eval.zig | 15 | ||||
| -rw-r--r-- | test/behavior/union.zig | 22 |
12 files changed, 146 insertions, 23 deletions
diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 28ca194c29..92347c0919 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -167,7 +167,7 @@ pub inline fn rawFree(self: Allocator, buf: []u8, buf_align: u29, ret_addr: usiz /// Returns a pointer to undefined memory. /// Call `destroy` with the result to free the memory. pub fn create(self: Allocator, comptime T: type) Error!*T { - if (@sizeOf(T) == 0) return @as(*T, undefined); + if (@sizeOf(T) == 0) return @intToPtr(*T, std.math.maxInt(usize)); const slice = try self.allocAdvancedWithRetAddr(T, null, 1, .exact, @returnAddress()); return &slice[0]; } diff --git a/src/Compilation.zig b/src/Compilation.zig index 35be4e86cf..73db9f5e97 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2361,7 +2361,7 @@ pub fn update(comp: *Compilation) !void { // The `test_functions` decl has been intentionally postponed until now, // at which point we must populate it with the list of test functions that // have been discovered and not filtered out. - try module.populateTestFunctions(); + try module.populateTestFunctions(main_progress_node); } // Process the deletion set. We use a while loop here because the diff --git a/src/Module.zig b/src/Module.zig index 3f061491c1..af29a591cc 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -6431,13 +6431,27 @@ pub fn processExports(mod: *Module) !void { } } -pub fn populateTestFunctions(mod: *Module) !void { +pub fn populateTestFunctions( + mod: *Module, + main_progress_node: *std.Progress.Node, +) !void { const gpa = mod.gpa; const builtin_pkg = mod.main_pkg.table.get("builtin").?; const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); const builtin_namespace = root_decl.src_namespace; const decl_index = builtin_namespace.decls.getKeyAdapted(@as([]const u8, "test_functions"), DeclAdapter{ .mod = mod }).?; + { + // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` + // was not referenced by start code. + mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); + mod.sema_prog_node.activate(); + defer { + mod.sema_prog_node.end(); + mod.sema_prog_node = undefined; + } + try mod.ensureDeclAnalyzed(decl_index); + } const decl = mod.declPtr(decl_index); var buf: Type.SlicePtrFieldTypeBuffer = undefined; const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType(); diff --git a/src/Sema.zig b/src/Sema.zig index 493202982e..64b4bf97db 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6361,6 +6361,7 @@ fn analyzeCall( is_comptime_call, &should_memoize, memoized_call_key, + func_ty_info.param_types, ) catch |err| switch (err) { error.NeededSourceLocation => { _ = sema.inst_map.remove(inst); @@ -6376,6 +6377,7 @@ fn analyzeCall( is_comptime_call, &should_memoize, memoized_call_key, + func_ty_info.param_types, ); return error.AnalysisFail; }, @@ -6612,6 +6614,7 @@ fn analyzeInlineCallArg( is_comptime_call: bool, should_memoize: *bool, memoized_call_key: Module.MemoizedCall.Key, + raw_param_types: []const Type, ) !void { const zir_tags = sema.code.instructions.items(.tag); switch (zir_tags[inst]) { @@ -6622,8 +6625,12 @@ fn analyzeInlineCallArg( const param_src = pl_tok.src(); const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index); const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; - const param_ty_inst = try sema.resolveBody(param_block, param_body, inst); - const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst); + const param_ty = param_ty: { + const raw_param_ty = raw_param_types[arg_i.*]; + if (raw_param_ty.tag() != .generic_poison) break :param_ty raw_param_ty; + const param_ty_inst = try sema.resolveBody(param_block, param_body, inst); + break :param_ty try sema.analyzeAsType(param_block, param_src, param_ty_inst); + }; new_fn_info.param_types[arg_i.*] = param_ty; const uncasted_arg = uncasted_args[arg_i.*]; if (try sema.typeRequiresComptime(param_ty)) { @@ -18754,7 +18761,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const addr = val.toUnsignedInt(target); if (!ptr_ty.isAllowzeroPtr() and addr == 0) return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); - if (addr != 0 and addr % ptr_align != 0) + if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0) return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); const val_payload = try sema.arena.create(Value.Payload.U64); @@ -22469,13 +22476,12 @@ fn fieldVal( ); }, .Union => { - const union_ty = try sema.resolveTypeFields(child_type); - - if (union_ty.getNamespace()) |namespace| { + if (child_type.getNamespace()) |namespace| { if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { return inst; } } + const union_ty = try sema.resolveTypeFields(child_type); if (union_ty.unionTagType()) |enum_ty| { if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| { const field_index = @intCast(u32, field_index_usize); @@ -27397,6 +27403,13 @@ fn analyzeRef( const operand_ty = sema.typeOf(operand); if (try sema.resolveMaybeUndefVal(operand)) |val| { + switch (val.tag()) { + .extern_fn, .function => { + const decl_index = val.pointerDecl().?; + return sema.analyzeDeclRef(decl_index); + }, + else => {}, + } var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); return sema.analyzeDeclRef(try anon_decl.finish( diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index abe4256a30..af9dcacf48 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1507,6 +1507,11 @@ pub const Object = struct { }; const field_index_val = Value.initPayload(&buf_field_index.base); + var buffer: Type.Payload.Bits = undefined; + const int_ty = ty.intTagType(&buffer); + const int_info = ty.intInfo(target); + assert(int_info.bits != 0); + for (field_names) |field_name, i| { const field_name_z = try gpa.dupeZ(u8, field_name); defer gpa.free(field_name_z); @@ -1514,9 +1519,25 @@ pub const Object = struct { buf_field_index.data = @intCast(u32, i); var buf_u64: Value.Payload.U64 = undefined; const field_int_val = field_index_val.enumToInt(ty, &buf_u64); - // See https://github.com/ziglang/zig/issues/645 - const field_int = field_int_val.toSignedInt(); - enumerators[i] = dib.createEnumerator(field_name_z, field_int); + + var bigint_space: Value.BigIntSpace = undefined; + const bigint = field_int_val.toBigInt(&bigint_space, target); + + if (bigint.limbs.len == 1) { + enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned); + continue; + } + if (@sizeOf(usize) == @sizeOf(u64)) { + enumerators[i] = dib.createEnumerator2( + field_name_z, + @intCast(c_uint, bigint.limbs.len), + bigint.limbs.ptr, + int_info.bits, + int_info.signedness == .unsigned, + ); + continue; + } + @panic("TODO implement bigint debug enumerators to llvm int for 32-bit compiler builds"); } const di_file = try o.getDIFile(gpa, owner_decl.src_namespace.file_scope); @@ -1524,8 +1545,6 @@ pub const Object = struct { const name = try ty.nameAlloc(gpa, o.module); defer gpa.free(name); - var buffer: Type.Payload.Bits = undefined; - const int_ty = ty.intTagType(&buffer); const enum_di_ty = dib.createEnumerationType( di_scope, @@ -2118,7 +2137,8 @@ pub const Object = struct { break :blk fwd_decl; }; - if (!ty.hasRuntimeBitsIgnoreComptime()) { + const union_obj = ty.cast(Type.Payload.Union).?.data; + if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime()) { const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); dib.replaceTemporary(fwd_decl, union_di_ty); // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` @@ -2128,7 +2148,6 @@ pub const Object = struct { } const layout = ty.unionGetLayout(target); - const union_obj = ty.cast(Type.Payload.Union).?.data; if (layout.payload_size == 0) { const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index a5b01d6ddf..1b462312cd 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -1662,7 +1662,18 @@ pub const DIBuilder = opaque { extern fn ZigLLVMCreateDebugEnumerator( dib: *DIBuilder, name: [*:0]const u8, - val: i64, + val: u64, + is_unsigned: bool, + ) *DIEnumerator; + + pub const createEnumerator2 = ZigLLVMCreateDebugEnumeratorOfArbitraryPrecision; + extern fn ZigLLVMCreateDebugEnumeratorOfArbitraryPrecision( + dib: *DIBuilder, + name: [*:0]const u8, + num_words: c_uint, + words: [*]const u64, + bits: c_uint, + is_unsigned: bool, ) *DIEnumerator; pub const createEnumerationType = ZigLLVMCreateDebugEnumerationType; diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 59ca43644a..94ed3a2162 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -9117,7 +9117,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu // https://github.com/ziglang/zig/issues/645 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name), - bigint_as_signed(&enum_field->value)); + bigint_as_signed(&enum_field->value), false); } ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type; @@ -9728,10 +9728,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) { entry->llvm_type = get_llvm_type(g, g->err_tag_type); ZigList<ZigLLVMDIEnumerator *> err_enumerators = {}; // reserve index 0 to indicate no error - err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0)); + err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0, false)); for (size_t i = 1; i < g->errors_by_index.length; i += 1) { ErrorTableEntry *error_entry = g->errors_by_index.at(i); - err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(&error_entry->name), i)); + err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(&error_entry->name), i, false)); } // create debug type for error sets diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index b5edb336a5..7134df6a9c 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -594,8 +594,16 @@ ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t return reinterpret_cast<ZigLLVMDIType*>(di_type); } -ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(ZigLLVMDIBuilder *dibuilder, const char *name, int64_t val) { - DIEnumerator *di_enumerator = reinterpret_cast<DIBuilder*>(dibuilder)->createEnumerator(name, val); +ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(ZigLLVMDIBuilder *dibuilder, const char *name, uint64_t val, bool isUnsigned) { + DIEnumerator *di_enumerator = reinterpret_cast<DIBuilder*>(dibuilder)->createEnumerator(name, val, isUnsigned); + return reinterpret_cast<ZigLLVMDIEnumerator*>(di_enumerator); +} + +ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumeratorOfArbitraryPrecision(ZigLLVMDIBuilder *dibuilder, + const char *name, unsigned NumWords, const uint64_t Words[], unsigned int bits, bool isUnsigned) +{ + DIEnumerator *di_enumerator = reinterpret_cast<DIBuilder*>(dibuilder)->createEnumerator(name, + APSInt(APInt(bits, makeArrayRef(Words, NumWords)), isUnsigned)); return reinterpret_cast<ZigLLVMDIEnumerator*>(di_enumerator); } diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 1a4d5481b6..0e210f9545 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -176,7 +176,11 @@ ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugArrayType(struct ZigLLVMDIB int elem_count); ZIG_EXTERN_C struct ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(struct ZigLLVMDIBuilder *dibuilder, - const char *name, int64_t val); + const char *name, uint64_t val, bool isUnsigned); + + +ZIG_EXTERN_C struct ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumeratorOfArbitraryPrecision(struct ZigLLVMDIBuilder *dibuilder, + const char *name, unsigned NumWords, const uint64_t Words[], unsigned int bits, bool isUnsigned); ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugEnumerationType(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number, diff --git a/test/behavior/call.zig b/test/behavior/call.zig index a8d59bddff..0414e1d575 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -327,3 +327,20 @@ test "inline call preserves tail call" { S.foo(); try expect(S.a == std.math.maxInt(u16)); } + +test "inline call doesn't re-evaluate non generic struct" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + const S = struct { + fn foo(f: struct { a: u8, b: u8 }) !void { + try expect(f.a == 123); + try expect(f.b == 45); + } + }; + const ArgTuple = std.meta.ArgsTuple(@TypeOf(S.foo)); + try @call(.{ .modifier = .always_inline }, S.foo, ArgTuple{.{ .a = 123, .b = 45 }}); + comptime try @call(.{ .modifier = .always_inline }, S.foo, ArgTuple{.{ .a = 123, .b = 45 }}); +} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index cd0891990c..145be9dede 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -1507,3 +1507,18 @@ test "inline call in @TypeOf inherits is_inline property" { }; try expect(S.T == void); } + +test "comptime function turns function value to function pointer" { + const S = struct { + fn fnPtr(function: anytype) *const @TypeOf(function) { + return &function; + } + fn Nil() u8 { + return 0; + } + const foo = &[_]*const fn () u8{ + fnPtr(Nil), + }; + }; + comptime try expect(S.foo[0] == &S.Nil); +} diff --git a/test/behavior/union.zig b/test/behavior/union.zig index d473debe1f..37cd72e319 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1388,3 +1388,25 @@ test "packed union in packed struct" { const a: S = .{ .nested = .{ .foo = 123 }, .bar = 5 }; try expect(a.unpack() == 123); } + +test "Namespace-like union" { + const DepType = enum { + git, + http, + const DepType = @This(); + const Version = union(DepType) { + git: Git, + http: void, + const Git = enum { + branch, + tag, + commit, + fn frozen(self: Git) bool { + return self == .tag; + } + }; + }; + }; + var a: DepType.Version.Git = .tag; + try expect(a.frozen()); +} |
