| author | |
| committer | |
| log | f5a67dba08b81c7109c52f6ad957aefdd646b56e |
| tree | fa89431ab0e1c1149ff86cde8ab6c4aff1c79dcb |
| parent | 33fbd8c1d333922efa696b5b9384859a2664f8de |
we now have successful exit codes from main linking
against libc4 files changed, 110 insertions(+), 2 deletions(-)
src-self-hosted/ir.zig+38-1| ... | ... | @@ -139,7 +139,15 @@ pub const Inst = struct { |
| 139 | 139 | } |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | fn copyVal(base: *Inst, comp: *Compilation) !*Value { | |
| 143 | if (base.parent.?.ref_count == 0) { | |
| 144 | return base.val.KnownValue.derefAndCopy(comp); | |
| 145 | } | |
| 146 | return base.val.KnownValue.copy(comp); | |
| 147 | } | |
| 148 | ||
| 142 | 149 | fn getAsParam(param: *Inst) !*Inst { |
| 150 | param.ref_count -= 1; | |
| 143 | 151 | const child = param.child orelse return error.SemanticAnalysisFailed; |
| 144 | 152 | switch (child.val) { |
| 145 | 153 | IrVal.Unknown => return error.SemanticAnalysisFailed, |
| ... | ... | @@ -1715,8 +1723,37 @@ const Analyze = struct { |
| 1715 | 1723 | // } |
| 1716 | 1724 | //} |
| 1717 | 1725 | |
| 1726 | // cast from comptime-known integer to another integer where the value fits | |
| 1727 | if (target.isCompTime() and (from_type.id == Type.Id.Int or from_type.id == Type.Id.ComptimeInt)) cast: { | |
| 1728 | const target_val = target.val.KnownValue; | |
| 1729 | const from_int = &target_val.cast(Value.Int).?.big_int; | |
| 1730 | const fits = fits: { | |
| 1731 | if (dest_type.cast(Type.ComptimeInt)) |ctint| { | |
| 1732 | break :fits true; | |
| 1733 | } | |
| 1734 | if (dest_type.cast(Type.Int)) |int| { | |
| 1735 | break :fits (from_int.positive or from_int.eqZero() or int.key.is_signed) and | |
| 1736 | int.key.bit_count >= from_int.bitcount(); | |
| 1737 | } | |
| 1738 | break :cast; | |
| 1739 | }; | |
| 1740 | if (!fits) { | |
| 1741 | try ira.addCompileError( | |
| 1742 | source_instr.span, | |
| 1743 | "integer value '{}' cannot be stored in type '{}'", | |
| 1744 | from_int, | |
| 1745 | dest_type.name, | |
| 1746 | ); | |
| 1747 | return error.SemanticAnalysisFailed; | |
| 1748 | } | |
| 1749 | ||
| 1750 | const new_val = try target.copyVal(ira.irb.comp); | |
| 1751 | new_val.setType(dest_type, ira.irb.comp); | |
| 1752 | return ira.irb.buildConstValue(source_instr.scope, source_instr.span, new_val); | |
| 1753 | } | |
| 1754 | ||
| 1718 | 1755 | // cast from number literal to another type |
| 1719 | //// cast from number literal to *const integer | |
| 1756 | // cast from number literal to *const integer | |
| 1720 | 1757 | //if (actual_type->id == TypeTableEntryIdComptimeFloat || |
| 1721 | 1758 | // actual_type->id == TypeTableEntryIdComptimeInt) |
| 1722 | 1759 | //{ |
src-self-hosted/value.zig+49| ... | ... | @@ -5,6 +5,7 @@ const Compilation = @import("compilation.zig").Compilation; |
| 5 | 5 | const ObjectFile = @import("codegen.zig").ObjectFile; |
| 6 | 6 | const llvm = @import("llvm.zig"); |
| 7 | 7 | const Buffer = std.Buffer; |
| 8 | const assert = std.debug.assert; | |
| 8 | 9 | |
| 9 | 10 | /// Values are ref-counted, heap-allocated, and copy-on-write |
| 10 | 11 | /// If there is only 1 ref then write need not copy |
| ... | ... | @@ -34,6 +35,12 @@ pub const Value = struct { |
| 34 | 35 | } |
| 35 | 36 | } |
| 36 | 37 | |
| 38 | pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void { | |
| 39 | base.typeof.base.deref(comp); | |
| 40 | new_type.base.ref(); | |
| 41 | base.typeof = new_type; | |
| 42 | } | |
| 43 | ||
| 37 | 44 | pub fn getRef(base: *Value) *Value { |
| 38 | 45 | base.ref(); |
| 39 | 46 | return base; |
| ... | ... | @@ -60,6 +67,28 @@ pub const Value = struct { |
| 60 | 67 | } |
| 61 | 68 | } |
| 62 | 69 | |
| 70 | pub fn derefAndCopy(self: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) { | |
| 71 | if (self.ref_count.get() == 1) { | |
| 72 | // ( ͡° ͜ʖ ͡°) | |
| 73 | return self; | |
| 74 | } | |
| 75 | ||
| 76 | assert(self.ref_count.decr() != 1); | |
| 77 | return self.copy(comp); | |
| 78 | } | |
| 79 | ||
| 80 | pub fn copy(base: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) { | |
| 81 | switch (base.id) { | |
| 82 | Id.Type => unreachable, | |
| 83 | Id.Fn => unreachable, | |
| 84 | Id.Void => unreachable, | |
| 85 | Id.Bool => unreachable, | |
| 86 | Id.NoReturn => unreachable, | |
| 87 | Id.Ptr => unreachable, | |
| 88 | Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base, | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 63 | 92 | pub const Id = enum { |
| 64 | 93 | Type, |
| 65 | 94 | Fn, |
| ... | ... | @@ -256,6 +285,26 @@ pub const Value = struct { |
| 256 | 285 | } |
| 257 | 286 | } |
| 258 | 287 | |
| 288 | pub fn copy(old: *Int, comp: *Compilation) !*Int { | |
| 289 | old.base.typeof.base.ref(); | |
| 290 | errdefer old.base.typeof.base.deref(comp); | |
| 291 | ||
| 292 | const new = try comp.gpa().create(Value.Int{ | |
| 293 | .base = Value{ | |
| 294 | .id = Value.Id.Int, | |
| 295 | .typeof = old.base.typeof, | |
| 296 | .ref_count = std.atomic.Int(usize).init(1), | |
| 297 | }, | |
| 298 | .big_int = undefined, | |
| 299 | }); | |
| 300 | errdefer comp.gpa().destroy(new); | |
| 301 | ||
| 302 | new.big_int = try old.big_int.clone(); | |
| 303 | errdefer new.big_int.deinit(); | |
| 304 | ||
| 305 | return new; | |
| 306 | } | |
| 307 | ||
| 259 | 308 | pub fn destroy(self: *Int, comp: *Compilation) void { |
| 260 | 309 | self.big_int.deinit(); |
| 261 | 310 | comp.gpa().destroy(self); |
std/math/big/int.zig+17-1| ... | ... | @@ -118,7 +118,7 @@ pub const Int = struct { |
| 118 | 118 | |
| 119 | 119 | fn bitcount(self: Int) usize { |
| 120 | 120 | const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1])); |
| 121 | return usize(@boolToInt(!self.positive)) + u_bit_count; | |
| 121 | return @boolToInt(!self.positive) + u_bit_count; | |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | pub fn sizeInBase(self: Int, base: usize) usize { |
| ... | ... | @@ -275,6 +275,7 @@ pub const Int = struct { |
| 275 | 275 | self.positive = positive; |
| 276 | 276 | } |
| 277 | 277 | |
| 278 | /// TODO make this call format instead of the other way around | |
| 278 | 279 | pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 { |
| 279 | 280 | if (base < 2 or base > 16) { |
| 280 | 281 | return error.InvalidBase; |
| ... | ... | @@ -357,6 +358,21 @@ pub const Int = struct { |
| 357 | 358 | return s; |
| 358 | 359 | } |
| 359 | 360 | |
| 361 | /// for the std lib format function | |
| 362 | /// TODO make this non-allocating | |
| 363 | pub fn format( | |
| 364 | self: Int, | |
| 365 | comptime fmt: []const u8, | |
| 366 | context: var, | |
| 367 | comptime FmtError: type, | |
| 368 | output: fn (@typeOf(context), []const u8) FmtError!void, | |
| 369 | ) FmtError!void { | |
| 370 | // TODO look at fmt and support other bases | |
| 371 | const str = self.toString(self.allocator, 10) catch @panic("TODO make this non allocating"); | |
| 372 | defer self.allocator.free(str); | |
| 373 | return output(context, str); | |
| 374 | } | |
| 375 | ||
| 360 | 376 | // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. |
| 361 | 377 | pub fn cmpAbs(a: Int, b: Int) i8 { |
| 362 | 378 | if (a.len < b.len) { |
test/stage2/compile_errors.zig+6| ... | ... | @@ -21,4 +21,10 @@ pub fn addCases(ctx: *TestContext) !void { |
| 21 | 21 | \\ defer return; |
| 22 | 22 | \\} |
| 23 | 23 | , "1.zig", 2, 11, "cannot return from defer expression"); |
| 24 | ||
| 25 | try ctx.testCompileError( | |
| 26 | \\export fn entry() c_int { | |
| 27 | \\ return 36893488147419103232; | |
| 28 | \\} | |
| 29 | , "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); | |
| 24 | 30 | } |