Commit 4ed0cd51c0

Veikka Tuominen <git@vexu.eu>
2022-11-16 11:56:51
Merge pull request #13558 from Vexu/stage2-fixes
Stage2 bug fixes to get third party projects building
1 parent 9e50cb2
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];
 }
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;
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);
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
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
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();
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(
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);
 }
 
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,
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 }});
+}
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);
+}
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());
+}