From 03a0dfbeca4b31d235097c66c9891d825cf73c15 Mon Sep 17 00:00:00 2001 From: scurest Date: Mon, 23 Oct 2017 15:40:49 -0500 Subject: [PATCH 01/13] Print better floats --- std/fmt/errol/index.zig | 12 ++++++------ std/fmt/index.zig | 38 +++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig index ac9f6b0c64216aa73a56fbc15bd1544085ff71cf..8cf13bca2e74ed365f3a0f87a190924c6991d231 100644 --- a/std/fmt/errol/index.zig +++ b/std/fmt/errol/index.zig @@ -38,7 +38,7 @@ fn errol3u(val: f64, buffer: []u8) -> FloatDecimal { return errolFixed(val, buffer); } - + // normalize the midpoint const e = math.frexp(val).exponent; @@ -138,7 +138,7 @@ fn tableLowerBound(k: u64) -> usize { while (j < enum3.len) { if (enum3[j] < k) { - j = 2 * k + 2; + j = 2 * j + 2; } else { i = j; j = 2 * j + 1; @@ -217,7 +217,7 @@ fn hpMul10(hp: &HP) { hp.val *= 10.0; hp.off *= 10.0; - + var off = hp.val; off -= val * 8.0; off -= val * 2.0; @@ -241,7 +241,7 @@ fn errolInt(val: f64, buffer: []u8) -> FloatDecimal { var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0); var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0); - if (@bitCast(u64, val) & 0x1 != 0) { + if (@bitCast(u64, val) & 0x1 != 0) { high -= 1; } else { low -= 1; @@ -347,11 +347,11 @@ fn errolFixed(val: f64, buffer: []u8) -> FloatDecimal { } fn fpnext(val: f64) -> f64 { - return @bitCast(f64, @bitCast(u64, val) + 1); + return @bitCast(f64, @bitCast(u64, val) +% 1); } fn fpprev(val: f64) -> f64 { - return @bitCast(f64, @bitCast(u64, val) - 1); + return @bitCast(f64, @bitCast(u64, val) -% 1); } pub const c_digits_lut = []u8 { diff --git a/std/fmt/index.zig b/std/fmt/index.zig index b378afa1b03f4cbbc739e5f25bd9ff24a7689918..85688b361db9b430b72a0d1805d9687fc6a855fd 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -244,30 +244,46 @@ pub fn formatBuf(buf: []const u8, width: usize, } pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool { - var buffer: [20]u8 = undefined; - const float_decimal = errol3(f64(value), buffer[0..]); - if (float_decimal.exp != 0) { - if (!output(context, float_decimal.digits[0..1])) - return false; - } else { - if (!output(context, "0")) + var x = f64(value); + + // Errol doesn't handle these special cases. + if (math.isNan(x)) { + return output(context, "NaN"); + } + if (math.isPositiveInf(x)) { + return output(context, "Infinity"); + } + if (math.isNegativeInf(x)) { + return output(context, "-Infinity"); + } + if (x == 0.0) { + return output(context, "0.0"); + } + if (x < 0.0) { + if (!output(context, "-")) return false; + x = -x; } + + var buffer: [32]u8 = undefined; + const float_decimal = errol3(x, buffer[0..]); + if (!output(context, float_decimal.digits[0..1])) + return false; if (!output(context, ".")) return false; if (float_decimal.digits.len > 1) { - const start = if (float_decimal.exp == 0) usize(0) else usize(1); - if (!output(context, float_decimal.digits[start .. math.min(usize(7), float_decimal.digits.len)])) + const num_digits = if (@typeOf(value) == f32) { usize(8) } else { usize(17) }; + if (!output(context, float_decimal.digits[1 .. math.min(num_digits, float_decimal.digits.len)])) return false; } else { if (!output(context, "0")) return false; } - if (float_decimal.exp != 1 and float_decimal.exp != 0) { + if (float_decimal.exp != 1) { if (!output(context, "e")) return false; - if (!formatInt(float_decimal.exp, 10, false, 0, context, output)) + if (!formatInt(float_decimal.exp - 1, 10, false, 0, context, output)) return false; } return true; -- 2.54.0 From 643ab90ace52d6d752a12ece9d6a8655ca2ca596 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 23 Oct 2017 22:33:00 -0400 Subject: [PATCH 02/13] add maximum value for @setAlignStack --- src/ir.cpp | 5 +++++ test/cases/align.zig | 2 +- test/compile_errors.zig | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 0879942b3e107c6aeab71d6d8df96bb00cb0331e..787d58442e158fe893513d651fbdf81d90798734 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15312,6 +15312,11 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes)) return ira->codegen->builtin_types.entry_invalid; + if (align_bytes > 256) { + ir_add_error(ira, &instruction->base, buf_sprintf("attempt to @setAlignStack(%" PRIu32 "); maximum is 256", align_bytes)); + return ira->codegen->builtin_types.entry_invalid; + } + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); if (fn_entry == nullptr) { ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack outside function")); diff --git a/test/cases/align.zig b/test/cases/align.zig index cd806a5dc65ddcb66a5e157a51eebd2134dd207b..3bf0d9c9afba0dc7bc32b2e3aca8c00e311377cc 100644 --- a/test/cases/align.zig +++ b/test/cases/align.zig @@ -188,6 +188,6 @@ test "alignstack" { } fn fnWithAlignedStack() -> i32 { - @setAlignStack(1024); + @setAlignStack(256); return 1234; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index dd25886d2b8066274730228df6fe131c180baa03..efab136d7ea78e3979b82f2b114e413ae73f24af 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2187,6 +2187,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:3:5: error: alignstack set twice", ".tmp_source.zig:2:5: note: first set here"); + cases.add("@setAlignStack too big", + \\export fn entry() { + \\ @setAlignStack(511 + 1); + \\} + , + ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256"); + cases.add("storing runtime value in compile time variable then using it", \\const Mode = @import("builtin").Mode; \\ -- 2.54.0 From d7e28f991d431ee6347f316f03a6f35a5692e095 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 23 Oct 2017 22:37:59 -0400 Subject: [PATCH 03/13] remove CXX ABI workaround the actual solution is you must compile zig with the same compiler that compiled llvm, lld, and clang. reverts 8d60ffe314306e5295fb76338c6391e5fe986dea --- src/config.h.in | 1 - src/zig_llvm.cpp | 11 ++--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/config.h.in b/src/config.h.in index 36bd66098b8d0c8ffd40906a458dc173cdac79d2..a596213a3d82e861c195790a48d4a812cf7edf2f 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -20,7 +20,6 @@ #define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@" #cmakedefine ZIG_EACH_LIB_RPATH -#cmakedefine ZIG_LLVM_OLD_CXX_ABI // Only used for running tests before installing. #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index f82b1d5423a9f3452eaf6294d8e9bbb7a50c5f8e..0e1a067bc6e8833e260e22295fa75c8a501c8504 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -5,15 +5,6 @@ * See http://opensource.org/licenses/MIT */ -// This must go before all includes. -#include "config.h" -#if defined(ZIG_LLVM_OLD_CXX_ABI) -#define _GLIBCXX_USE_CXX11_ABI 0 -#endif - - -#include "zig_llvm.hpp" - /* * The point of this file is to contain all the LLVM C++ API interaction so that: @@ -22,6 +13,8 @@ * 3. Prevent C++ from infecting the rest of the project. */ +#include "zig_llvm.hpp" + #include #include #include -- 2.54.0 From 262b7428cfad88de9d328773cc4bae6151b8a030 Mon Sep 17 00:00:00 2001 From: scurest Date: Tue, 24 Oct 2017 14:18:50 -0500 Subject: [PATCH 04/13] More corrections to float printing Testing suggests all f32s are now printed accurately. --- std/fmt/errol/index.zig | 10 +++------- std/fmt/index.zig | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig index 8cf13bca2e74ed365f3a0f87a190924c6991d231..0a1ea7deef4e1a9d1f3cfb1d638bd3b307065919 100644 --- a/std/fmt/errol/index.zig +++ b/std/fmt/errol/index.zig @@ -32,7 +32,7 @@ pub fn errol3(value: f64, buffer: []u8) -> FloatDecimal { fn errol3u(val: f64, buffer: []u8) -> FloatDecimal { // check if in integer or fixed range - if (val >= 9.007199254740992e15 and val < 3.40282366920938e+38) { + if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) { return errolInt(val, buffer); } else if (val >= 16.0 and val < 9.007199254740992e15) { return errolFixed(val, buffer); @@ -235,7 +235,7 @@ fn hpMul10(hp: &HP) { fn errolInt(val: f64, buffer: []u8) -> FloatDecimal { const pow19 = u128(1e19); - assert((val >= 9.007199254740992e15) and val < (3.40282366920938e38)); + assert((val > 9.007199254740992e15) and val < (3.40282366920938e38)); var mid = u128(val); var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0); @@ -510,10 +510,6 @@ fn u64toa(value_param: u64, buffer: []u8) -> usize { buf_index += 1; buffer[buf_index] = c_digits_lut[d8]; buf_index += 1; - buffer[buf_index] = c_digits_lut[d8]; - buf_index += 1; - buffer[buf_index] = c_digits_lut[d8]; - buf_index += 1; buffer[buf_index] = c_digits_lut[d8 + 1]; buf_index += 1; } else { @@ -613,7 +609,7 @@ fn fpeint(from: f64) -> u128 { const bits = @bitCast(u64, from); assert((bits & ((1 << 52) - 1)) == 0); - return u64(1) << u6(((bits >> 52) - 1023)); + return u128(1) << @truncate(u7, (bits >> 52) -% 1023); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 85688b361db9b430b72a0d1805d9687fc6a855fd..0fece54b4ce4eaf05e7c09a33fcdb9b659a0f5a6 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -250,20 +250,17 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons if (math.isNan(x)) { return output(context, "NaN"); } + if (math.signbit(x)) { + if (!output(context, "-")) + return false; + x = -x; + } if (math.isPositiveInf(x)) { return output(context, "Infinity"); } - if (math.isNegativeInf(x)) { - return output(context, "-Infinity"); - } if (x == 0.0) { return output(context, "0.0"); } - if (x < 0.0) { - if (!output(context, "-")) - return false; - x = -x; - } var buffer: [32]u8 = undefined; const float_decimal = errol3(x, buffer[0..]); @@ -272,8 +269,12 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons if (!output(context, ".")) return false; if (float_decimal.digits.len > 1) { - const num_digits = if (@typeOf(value) == f32) { usize(8) } else { usize(17) }; - if (!output(context, float_decimal.digits[1 .. math.min(num_digits, float_decimal.digits.len)])) + const num_digits = if (@typeOf(value) == f32) { + math.min(usize(9), float_decimal.digits.len) + } else { + float_decimal.digits.len + }; + if (!output(context, float_decimal.digits[1 .. num_digits])) return false; } else { if (!output(context, "0")) -- 2.54.0 From 1828f8eb8e1514578ed2da8d58536903f94b7ed0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 24 Oct 2017 21:28:56 -0400 Subject: [PATCH 05/13] fix missing compiler_rt in release modes the optimizer was deleting compiler_rt symbols, so I changed the linkage type from LinkOnce to Weak also changed LinkOnce to mean linkonce_odr in llvm and Weak to mean weak_odr in llvm. See #563 --- src/codegen.cpp | 4 ++-- src/link.cpp | 1 + std/special/compiler_rt/comparetf2.zig | 2 +- std/special/compiler_rt/fixunsdfdi.zig | 2 +- std/special/compiler_rt/fixunsdfsi.zig | 2 +- std/special/compiler_rt/fixunsdfti.zig | 2 +- std/special/compiler_rt/fixunssfdi.zig | 2 +- std/special/compiler_rt/fixunssfsi.zig | 2 +- std/special/compiler_rt/fixunssfti.zig | 2 +- std/special/compiler_rt/fixunstfdi.zig | 2 +- std/special/compiler_rt/fixunstfsi.zig | 2 +- std/special/compiler_rt/fixunstfti.zig | 2 +- std/special/compiler_rt/index.zig | 6 +----- std/special/compiler_rt/udivmoddi4.zig | 2 +- std/special/compiler_rt/udivmodti4.zig | 2 +- std/special/compiler_rt/udivti3.zig | 2 +- std/special/compiler_rt/umodti3.zig | 2 +- 17 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 8c5d7622ccf704b20e0ad75ac859bec9913245f2..6fb8d4b8efaf04d0e3570cf302d5b7a960f834f0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -456,10 +456,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage); break; case GlobalLinkageIdWeak: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakAnyLinkage); + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage); break; case GlobalLinkageIdLinkOnce: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceAnyLinkage); + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage); break; } diff --git a/src/link.cpp b/src/link.cpp index f2f21fd74606ee4db6950372af507861116d9e2e..316c7bc76120d4ab87f675b85058b248fc1822d2 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -38,6 +38,7 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) child_gen->want_h_file = false; child_gen->verbose_link = parent_gen->verbose_link; + child_gen->verbose_ir = parent_gen->verbose_ir; codegen_set_cache_dir(child_gen, parent_gen->cache_dir); diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig index 45c7cb50376adeeb07c7cb87ff703f90adeee8d7..f1552ca61ff71fabd3a6f5c3bb1b7a37c1132ee7 100644 --- a/std/special/compiler_rt/comparetf2.zig +++ b/std/special/compiler_rt/comparetf2.zig @@ -20,7 +20,7 @@ const infRep = exponentMask; const builtin = @import("builtin"); const is_test = builtin.is_test; -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __letf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); diff --git a/std/special/compiler_rt/fixunsdfdi.zig b/std/special/compiler_rt/fixunsdfdi.zig index 0290ad3975d73ba382db593796c451b18f8c39d4..5f730bbc850a6667903a0a598d923ee1b181a5f5 100644 --- a/std/special/compiler_rt/fixunsdfdi.zig +++ b/std/special/compiler_rt/fixunsdfdi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunsdfdi(a: f64) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunsdfsi.zig b/std/special/compiler_rt/fixunsdfsi.zig index 1dbc2525f2c5d53875c4d05f7e5b5dddbcebd8dc..784d5fde4f15c1abc15d9d1f9915484292642808 100644 --- a/std/special/compiler_rt/fixunsdfsi.zig +++ b/std/special/compiler_rt/fixunsdfsi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunsdfsi(a: f64) -> u32 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunsdfti.zig b/std/special/compiler_rt/fixunsdfti.zig index 33b0e7c274c1247f3a43b33a7ab927aeb614c0e8..579455c2f98d135be3a4a54722b23155248d07aa 100644 --- a/std/special/compiler_rt/fixunsdfti.zig +++ b/std/special/compiler_rt/fixunsdfti.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunsdfti(a: f64) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunssfdi.zig b/std/special/compiler_rt/fixunssfdi.zig index c183f17c62a984cc523382befd8d2aaca54e9683..eab553d8c9f3e2a461e716cf4eb5909ca802e3f5 100644 --- a/std/special/compiler_rt/fixunssfdi.zig +++ b/std/special/compiler_rt/fixunssfdi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunssfdi(a: f32) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunssfsi.zig b/std/special/compiler_rt/fixunssfsi.zig index 51ceef65d3039c139a278d60c2ecce2522f22b62..18c0e666777a2c7984ddcc668a9bad10a6cac2c5 100644 --- a/std/special/compiler_rt/fixunssfsi.zig +++ b/std/special/compiler_rt/fixunssfsi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunssfsi(a: f32) -> u32 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunssfti.zig b/std/special/compiler_rt/fixunssfti.zig index 69e1c82a9dfd744879ea93748674627d76bbb04e..f513604247bb7c1cb6bccc3b7da6fd6c05704ca0 100644 --- a/std/special/compiler_rt/fixunssfti.zig +++ b/std/special/compiler_rt/fixunssfti.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunssfti(a: f32) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunstfdi.zig b/std/special/compiler_rt/fixunstfdi.zig index a5dbe0f52e5c6f2b7188d6e4ce3fff0f5b1cb264..85212e2176af9b17cf54cff4606965b501796dad 100644 --- a/std/special/compiler_rt/fixunstfdi.zig +++ b/std/special/compiler_rt/fixunstfdi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunstfdi(a: f128) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunstfsi.zig b/std/special/compiler_rt/fixunstfsi.zig index d488f4c6027bf146d2f896dfb9d10ecada4c50ee..33c85c92247229e0faae4410197bc21fc5e6589e 100644 --- a/std/special/compiler_rt/fixunstfsi.zig +++ b/std/special/compiler_rt/fixunstfsi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunstfsi(a: f128) -> u32 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunstfti.zig b/std/special/compiler_rt/fixunstfti.zig index fc5c645d72e42ed0400d8d1b7359431b1bb5c6f8..1bf7fbab4bf96a138c4cc1caff275ca79ecc8199 100644 --- a/std/special/compiler_rt/fixunstfti.zig +++ b/std/special/compiler_rt/fixunstfti.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunstfti(a: f128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 4a4d71fde959210291f6128d811b9a11c5b64e1c..bea06a0b4107388359d607875b1059058611a9a3 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -26,7 +26,7 @@ const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch. const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64; const win32_nocrt = win32 and !builtin.link_libc; const win64_nocrt = win64 and !builtin.link_libc; -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; @@ -152,10 +152,6 @@ export nakedcc fn _chkstk() align(4) { @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); } -// TODO The implementation from compiler-rt causes crashes and -// the implementation from disassembled ntdll seems to depend on -// thread local storage. So we have given up this safety check -// and simply have `ret`. export nakedcc fn __chkstk() align(4) { @setDebugSafety(this, false); diff --git a/std/special/compiler_rt/udivmoddi4.zig b/std/special/compiler_rt/udivmoddi4.zig index 2e167bc64af78786b511eb789a5adbedabab6899..8005538d9a57b6610a3424a5aadb5cd2243dcf53 100644 --- a/std/special/compiler_rt/udivmoddi4.zig +++ b/std/special/compiler_rt/udivmoddi4.zig @@ -1,6 +1,6 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/udivmodti4.zig b/std/special/compiler_rt/udivmodti4.zig index d7507e95216aa429450e12675f3ca2594ba79d5f..2ee2fdb57f2b89350cc1a02a6a58b55029ed92ee 100644 --- a/std/special/compiler_rt/udivmodti4.zig +++ b/std/special/compiler_rt/udivmodti4.zig @@ -1,6 +1,6 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/udivti3.zig b/std/special/compiler_rt/udivti3.zig index 67ea15eb96fb8e89d210d1e958d18816360de0e3..3764449758e156d127395466e8ab3c68c8f2f5f2 100644 --- a/std/special/compiler_rt/udivti3.zig +++ b/std/special/compiler_rt/udivti3.zig @@ -1,6 +1,6 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __udivti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig index e4a4e7a7ee41ee0c7c35788c5af432042e2fbacb..0ad9e127b3d17d57d2cc86c001a6d7b9108225cd 100644 --- a/std/special/compiler_rt/umodti3.zig +++ b/std/special/compiler_rt/umodti3.zig @@ -1,6 +1,6 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __umodti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); -- 2.54.0 From 73fe5f63c6acc1b2e6fec51da545178ffd12180e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 24 Oct 2017 21:45:00 -0400 Subject: [PATCH 06/13] add some sanity tests for float printing --- std/fmt/index.zig | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 0fece54b4ce4eaf05e7c09a33fcdb9b659a0f5a6..56b9a2e9602a1c4d0b8db03b915f8601961e054f 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -531,6 +531,38 @@ test "fmt.format" { const result = bufPrint(buf1[0..], "u3: {}\n", value); assert(mem.eql(u8, result, "u3: 5\n")); } + + // TODO get these tests passing in release modes + // https://github.com/zig-lang/zig/issues/564 + if (builtin.mode == builtin.Mode.Debug) { + { + var buf1: [32]u8 = undefined; + const value: f32 = 12.34; + const result = bufPrint(buf1[0..], "f32: {}\n", value); + assert(mem.eql(u8, result, "f32: 1.23400001e1\n")); + } + { + var buf1: [32]u8 = undefined; + const value: f64 = -12.34e10; + const result = bufPrint(buf1[0..], "f64: {}\n", value); + assert(mem.eql(u8, result, "f64: -1.234e11\n")); + } + { + var buf1: [32]u8 = undefined; + const result = bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); + assert(mem.eql(u8, result, "f64: NaN\n")); + } + { + var buf1: [32]u8 = undefined; + const result = bufPrint(buf1[0..], "f64: {}\n", math.inf_f64); + assert(mem.eql(u8, result, "f64: Infinity\n")); + } + { + var buf1: [32]u8 = undefined; + const result = bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); + assert(mem.eql(u8, result, "f64: -Infinity\n")); + } + } } pub fn trim(buf: []const u8) -> []const u8 { -- 2.54.0 From 5f28a9d23851d94edc2b24e549b7c5abbbf23f68 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 25 Oct 2017 23:10:41 -0400 Subject: [PATCH 07/13] cleaner verbose flags and zig build prints failed command --- src/all_types.hpp | 5 +- src/analyze.cpp | 10 +-- src/codegen.cpp | 18 +---- src/codegen.hpp | 1 - src/ir.cpp | 6 +- src/link.cpp | 21 ++---- src/main.cpp | 142 +++++++++++++++++++++-------------- src/parsec.cpp | 2 +- std/build.zig | 39 ++++++++-- std/special/build_runner.zig | 39 ++++++++-- 10 files changed, 171 insertions(+), 112 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 894deca930c9fef522682ccfd3e395840c1ec2fe..b8966e764a7643374b4b902c8b907441dda90e82 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1515,9 +1515,12 @@ struct CodeGen { size_t version_major; size_t version_minor; size_t version_patch; - bool verbose; + bool verbose_tokenize; + bool verbose_ast; bool verbose_link; bool verbose_ir; + bool verbose_llvm_ir; + bool verbose_cimport; ErrColor err_color; ImportTableEntry *root_import; ImportTableEntry *bootstrap_import; diff --git a/src/analyze.cpp b/src/analyze.cpp index 292943a6e6154c05428d3c2ea1c2b097a87cd17b..45efa205e33625e7e6b6c73d1d57620d79922743 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2982,7 +2982,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ return; } - if (g->verbose) { + if (g->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4); fprintf(stderr, "}\n"); @@ -3015,7 +3015,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { fn_table_entry->anal_state = FnAnalStateInvalid; return; } - if (g->verbose) { + if (g->verbose_ir) { fprintf(stderr, "\n"); ast_render(g, stderr, fn_table_entry->body_node, 4); fprintf(stderr, "\n{ // (IR)\n"); @@ -3115,7 +3115,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) { } ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code) { - if (g->verbose) { + if (g->verbose_tokenize) { fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(abs_full_path)); fprintf(stderr, "----------------\n"); fprintf(stderr, "%s\n", buf_ptr(source_code)); @@ -3135,7 +3135,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a exit(1); } - if (g->verbose) { + if (g->verbose_tokenize) { print_tokens(source_code, tokenization.tokens); fprintf(stderr, "\nAST:\n"); @@ -3150,7 +3150,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color); assert(import_entry->root); - if (g->verbose) { + if (g->verbose_ast) { ast_print(stderr, import_entry->root, 0); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 6fb8d4b8efaf04d0e3570cf302d5b7a960f834f0..68fd4159bd7b571a350680aaaad6bec27db666ef 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -196,10 +196,6 @@ void codegen_set_is_static(CodeGen *g, bool is_static) { g->is_static = is_static; } -void codegen_set_verbose(CodeGen *g, bool verbose) { - g->verbose = verbose; -} - void codegen_set_each_lib_rpath(CodeGen *g, bool each_lib_rpath) { g->each_lib_rpath = each_lib_rpath; } @@ -4163,10 +4159,6 @@ static void validate_inline_fns(CodeGen *g) { } static void do_code_gen(CodeGen *g) { - if (g->verbose) { - fprintf(stderr, "\nCode Generation:\n"); - fprintf(stderr, "------------------\n"); - } assert(!g->errors.length); codegen_add_time_event(g, "Code Generation"); @@ -4443,7 +4435,8 @@ static void do_code_gen(CodeGen *g) { ZigLLVMDIBuilderFinalize(g->dbuilder); - if (g->verbose || g->verbose_ir) { + if (g->verbose_llvm_ir) { + fflush(stderr); LLVMDumpModule(g->module); } @@ -5273,10 +5266,6 @@ static void gen_root_source(CodeGen *g) { resolve_top_level_decl(g, panic_tld, false, nullptr); } - if (g->verbose) { - fprintf(stderr, "\nIR Generation and Semantic Analysis:\n"); - fprintf(stderr, "--------------------------------------\n"); - } if (!g->error_during_imports) { semantic_analyze(g); } @@ -5290,9 +5279,6 @@ static void gen_root_source(CodeGen *g) { } report_errors_and_maybe_exit(g); - if (g->verbose) { - fprintf(stderr, "OK\n"); - } } diff --git a/src/codegen.hpp b/src/codegen.hpp index f4c7f6a8c71a54a772a522eedbbd32a950fcae7f..cc7721e9f8490e3a2be613415ebb45304e9b4112 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -25,7 +25,6 @@ void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath); void codegen_set_is_static(CodeGen *codegen, bool is_static); void codegen_set_strip(CodeGen *codegen, bool strip); -void codegen_set_verbose(CodeGen *codegen, bool verbose); void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); void codegen_set_out_name(CodeGen *codegen, Buf *out_name); void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir); diff --git a/src/ir.cpp b/src/ir.cpp index 787d58442e158fe893513d651fbdf81d90798734..6c6ce676f63de16a5e8c7e28d7fac1afc1d82d07 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7849,7 +7849,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node if (ir_executable.invalid) return codegen->invalid_instruction; - if (codegen->verbose) { + if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); ast_render(codegen, stderr, node, 4); fprintf(stderr, "\n{ // (IR)\n"); @@ -7870,7 +7870,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node if (type_is_invalid(result_type)) return codegen->invalid_instruction; - if (codegen->verbose) { + if (codegen->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); ir_print(codegen, stderr, &analyzed_executable, 4); fprintf(stderr, "}\n"); @@ -13514,7 +13514,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_invalid; } - if (ira->codegen->verbose) { + if (ira->codegen->verbose_cimport) { fprintf(stderr, "\nC imports:\n"); fprintf(stderr, "-----------\n"); ast_render(ira->codegen, stderr, child_import->root, 4); diff --git a/src/link.cpp b/src/link.cpp index 316c7bc76120d4ab87f675b85058b248fc1822d2..a4e5b2dd254274c380237bbef776fc0ca8c26068 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -37,8 +37,12 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) parent_gen->zig_lib_dir); child_gen->want_h_file = false; + child_gen->verbose_tokenize = parent_gen->verbose_tokenize; + child_gen->verbose_ast = parent_gen->verbose_ast; child_gen->verbose_link = parent_gen->verbose_link; child_gen->verbose_ir = parent_gen->verbose_ir; + child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir; + child_gen->verbose_cimport = parent_gen->verbose_cimport; codegen_set_cache_dir(child_gen, parent_gen->cache_dir); @@ -47,7 +51,6 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) codegen_set_out_name(child_gen, buf_create_from_str(oname)); - codegen_set_verbose(child_gen, parent_gen->verbose); codegen_set_errmsg_color(child_gen, parent_gen->err_color); codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); @@ -859,15 +862,12 @@ void codegen_link(CodeGen *g, const char *out_file) { buf_resize(&lj.out_file, 0); } - if (g->verbose || g->verbose_ir) { + if (g->verbose_llvm_ir) { fprintf(stderr, "\nOptimization:\n"); fprintf(stderr, "---------------\n"); + fflush(stderr); LLVMDumpModule(g->module); } - if (g->verbose || g->verbose_link) { - fprintf(stderr, "\nLink:\n"); - fprintf(stderr, "-------\n"); - } bool override_out_file = (buf_len(&lj.out_file) != 0); if (!override_out_file) { @@ -888,9 +888,6 @@ void codegen_link(CodeGen *g, const char *out_file) { zig_panic("unable to rename object file into final output: %s", err_str(err)); } } - if (g->verbose || g->verbose_link) { - fprintf(stderr, "OK\n"); - } return; } @@ -908,7 +905,7 @@ void codegen_link(CodeGen *g, const char *out_file) { construct_linker_job(&lj); - if (g->verbose || g->verbose_link) { + if (g->verbose_link) { for (size_t i = 0; i < lj.args.length; i += 1) { const char *space = (i != 0) ? " " : ""; fprintf(stderr, "%s%s", space, lj.args.at(i)); @@ -925,8 +922,4 @@ void codegen_link(CodeGen *g, const char *out_file) { } codegen_add_time_event(g, "Done"); - - if (g->verbose || g->verbose_link) { - fprintf(stderr, "OK\n"); - } } diff --git a/src/main.cpp b/src/main.cpp index a9a1d5a8da1de5093bedce3fce8e109e62b87d02..bee021c6a5c30509ee1e5ac07bd829640af1ff35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,67 +20,70 @@ static int usage(const char *arg0) { fprintf(stderr, "Usage: %s [command] [options]\n" "Commands:\n" " build build project from build.zig\n" - " build-exe [source] create executable from source or object files\n" - " build-lib [source] create library from source or object files\n" - " build-obj [source] create object from source or assembly\n" - " parsec [source] convert c code to zig code\n" + " build-exe $source create executable from source or object files\n" + " build-lib $source create library from source or object files\n" + " build-obj $source create object from source or assembly\n" + " parsec $source convert c code to zig code\n" " targets list available compilation targets\n" - " test [source] create and run a test build\n" + " test $source create and run a test build\n" " version print version number and exit\n" " zen print zen of zig and exit\n" "Compile Options:\n" - " --assembly [source] add assembly file to build\n" - " --cache-dir [path] override the cache directory\n" - " --color [auto|off|on] enable or disable colored error messages\n" + " --assembly $source add assembly file to build\n" + " --cache-dir $path override the cache directory\n" + " --color $auto|off|on enable or disable colored error messages\n" " --enable-timing-info print timing diagnostics\n" - " --libc-include-dir [path] directory where libc stdlib.h resides\n" - " --name [name] override output name\n" - " --output [file] override destination path\n" - " --output-h [file] override generated header file path\n" - " --pkg-begin [name] [path] make package available to import and push current pkg\n" + " --libc-include-dir $path directory where libc stdlib.h resides\n" + " --name $name override output name\n" + " --output $file override destination path\n" + " --output-h $file override generated header file path\n" + " --pkg-begin $name $path make package available to import and push current pkg\n" " --pkg-end pop current pkg\n" " --release-fast build with optimizations on and safety off\n" " --release-safe build with optimizations on and safety on\n" " --static output will be statically linked\n" " --strip exclude debug symbols\n" - " --target-arch [name] specify target architecture\n" - " --target-environ [name] specify target environment\n" - " --target-os [name] specify target operating system\n" - " --verbose turn on compiler debug output\n" - " --verbose-link turn on compiler debug output for linking only\n" - " --verbose-ir turn on compiler debug output for IR only\n" - " --zig-install-prefix [path] override directory where zig thinks it is installed\n" - " -dirafter [dir] same as -isystem but do it last\n" - " -isystem [dir] add additional search path for other .h files\n" - " -mllvm [arg] additional arguments to forward to LLVM's option processing\n" + " --target-arch $name specify target architecture\n" + " --target-environ $name specify target environment\n" + " --target-os $name specify target operating system\n" + " --verbose-tokenize turn on compiler debug output for tokenization\n" + " --verbose-ast turn on compiler debug output for parsing into an AST\n" + " --verbose-link turn on compiler debug output for linking\n" + " --verbose-ir turn on compiler debug output for Zig IR\n" + " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n" + " --verbose-cimport turn on compiler debug output for C imports\n" + " --zig-install-prefix $path override directory where zig thinks it is installed\n" + " -dirafter $dir same as -isystem but do it last\n" + " -isystem $dir add additional search path for other .h files\n" + " -mllvm $arg additional arguments to forward to LLVM's option processing\n" "Link Options:\n" - " --ar-path [path] set the path to ar\n" - " --dynamic-linker [path] set the path to ld.so\n" + " --ar-path $path set the path to ar\n" + " --dynamic-linker $path set the path to ld.so\n" " --each-lib-rpath add rpath for each used dynamic library\n" - " --libc-lib-dir [path] directory where libc crt1.o resides\n" - " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n" - " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n" - " --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n" - " --library [lib] link against lib\n" - " --library-path [dir] add a directory to the library search path\n" - " --linker-script [path] use a custom linker script\n" - " --object [obj] add object file to build\n" - " -L[dir] alias for --library-path\n" + " --libc-lib-dir $path directory where libc crt1.o resides\n" + " --libc-static-lib-dir $path directory where libc crtbegin.o resides\n" + " --msvc-lib-dir $path (windows) directory where vcruntime.lib resides\n" + " --kernel32-lib-dir $path (windows) directory where kernel32.lib resides\n" + " --library $lib link against lib\n" + " --library-path $dir add a directory to the library search path\n" + " --linker-script $path use a custom linker script\n" + " --object $obj add object file to build\n" + " -L$dir alias for --library-path\n" " -rdynamic add all symbols to the dynamic symbol table\n" - " -rpath [path] add directory to the runtime library search path\n" + " -rpath $path add directory to the runtime library search path\n" " -mconsole (windows) --subsystem console to the linker\n" " -mwindows (windows) --subsystem windows to the linker\n" " -municode (windows) link with unicode\n" - " -framework [name] (darwin) link against framework\n" - " -mios-version-min [ver] (darwin) set iOS deployment target\n" - " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" - " --ver-major [ver] dynamic library semver major version\n" - " --ver-minor [ver] dynamic library semver minor version\n" - " --ver-patch [ver] dynamic library semver patch version\n" + " -framework $name (darwin) link against framework\n" + " -mios-version-min $ver (darwin) set iOS deployment target\n" + " -mmacosx-version-min $ver (darwin) set Mac OS X deployment target\n" + " --ver-major $ver dynamic library semver major version\n" + " --ver-minor $ver dynamic library semver minor version\n" + " --ver-patch $ver dynamic library semver patch version\n" "Test Options:\n" - " --test-filter [text] skip tests that do not match filter\n" - " --test-name-prefix [text] add prefix to all tests\n" - " --test-cmd [arg] specify test execution command one arg at a time\n" + " --test-filter $text skip tests that do not match filter\n" + " --test-name-prefix $text add prefix to all tests\n" + " --test-cmd $arg specify test execution command one arg at a time\n" " --test-cmd-bin appends test binary path to test cmd args\n" , arg0); return EXIT_FAILURE; @@ -274,9 +277,12 @@ int main(int argc, char **argv) { bool is_static = false; OutType out_type = OutTypeUnknown; const char *out_name = nullptr; - bool verbose = false; + bool verbose_tokenize = false; + bool verbose_ast = false; bool verbose_link = false; bool verbose_ir = false; + bool verbose_llvm_ir = false; + bool verbose_cimport = false; ErrColor color = ErrColorAuto; const char *libc_lib_dir = nullptr; const char *libc_static_lib_dir = nullptr; @@ -328,9 +334,7 @@ int main(int argc, char **argv) { args.append(NULL); // placeholder args.append(NULL); // placeholder for (int i = 2; i < argc; i += 1) { - if (strcmp(argv[i], "--debug-build-verbose") == 0) { - verbose = true; - } else if (strcmp(argv[i], "--help") == 0) { + if (strcmp(argv[i], "--help") == 0) { asked_for_help = true; args.append(argv[i]); } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) { @@ -363,7 +367,6 @@ int main(int argc, char **argv) { CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); codegen_set_out_name(g, buf_create_from_str("build")); - codegen_set_verbose(g, verbose); Buf build_file_abs = BUF_INIT; os_path_resolve(buf_create_from_str("."), buf_create_from_str(build_file), &build_file_abs); @@ -398,14 +401,30 @@ int main(int argc, char **argv) { "\n" "General Options:\n" " --help Print this help and exit\n" - " --build-file [file] Override path to build.zig\n" - " --cache-dir [path] Override path to cache directory\n" + " --build-file $file Override path to build.zig\n" + " --cache-dir $path Override path to cache directory\n" " --verbose Print commands before executing them\n" - " --debug-build-verbose Print verbose debugging information for the build system itself\n" - " --prefix [prefix] Override default install prefix\n" + " --verbose-tokenize Enable compiler debug output for tokenization\n" + " --verbose-ast Enable compiler debug output for parsing into an AST\n" + " --verbose-link Enable compiler debug output for linking\n" + " --verbose-ir Enable compiler debug output for Zig IR\n" + " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n" + " --verbose-cimport Enable compiler debug output for C imports\n" + " --prefix $path Override default install prefix\n" "\n" - "More options become available when the build file is found.\n" + "Project-specific options become available when the build file is found.\n" "Run this command with no options to generate a build.zig template.\n" + "\n" + "Advanced Options:\n" + " --build-file $file Override path to build.zig\n" + " --cache-dir $path Override path to cache directory\n" + " --verbose-tokenize Enable compiler debug output for tokenization\n" + " --verbose-ast Enable compiler debug output for parsing into an AST\n" + " --verbose-link Enable compiler debug output for linking\n" + " --verbose-ir Enable compiler debug output for Zig IR\n" + " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n" + " --verbose-cimport Enable compiler debug output for C imports\n" + "\n" , zig_exe_path); return 0; } @@ -452,12 +471,18 @@ int main(int argc, char **argv) { strip = true; } else if (strcmp(arg, "--static") == 0) { is_static = true; - } else if (strcmp(arg, "--verbose") == 0) { - verbose = true; + } else if (strcmp(arg, "--verbose-tokenize") == 0) { + verbose_tokenize = true; + } else if (strcmp(arg, "--verbose-ast") == 0) { + verbose_ast = true; } else if (strcmp(arg, "--verbose-link") == 0) { verbose_link = true; } else if (strcmp(arg, "--verbose-ir") == 0) { verbose_ir = true; + } else if (strcmp(arg, "--verbose-llvm-ir") == 0) { + verbose_llvm_ir = true; + } else if (strcmp(arg, "--verbose-cimport") == 0) { + verbose_cimport = true; } else if (strcmp(arg, "-mwindows") == 0) { mwindows = true; } else if (strcmp(arg, "-mconsole") == 0) { @@ -742,9 +767,12 @@ int main(int argc, char **argv) { codegen_set_kernel32_lib_dir(g, buf_create_from_str(kernel32_lib_dir)); if (dynamic_linker) codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker)); - codegen_set_verbose(g, verbose); + g->verbose_tokenize = verbose_tokenize; + g->verbose_ast = verbose_ast; g->verbose_link = verbose_link; g->verbose_ir = verbose_ir; + g->verbose_llvm_ir = verbose_llvm_ir; + g->verbose_cimport = verbose_cimport; codegen_set_errmsg_color(g, color); for (size_t i = 0; i < lib_dirs.length; i += 1) { diff --git a/src/parsec.cpp b/src/parsec.cpp index d200c0531d2d04920af2cc52f638c69ac0aebbd7..586e95bc751da677a61fd569a35f31be81373470 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -3167,7 +3167,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch { Context context = {0}; Context *c = &context; - c->warnings_on = codegen->verbose; + c->warnings_on = codegen->verbose_cimport; c->import = import; c->errors = errors; if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { diff --git a/std/build.zig b/std/build.zig index 84eba6d33b91edba29621e07484dc6414d4db907..7cf2ac598771cf33832c94a6db8c1848aaf95723 100644 --- a/std/build.zig +++ b/std/build.zig @@ -33,6 +33,12 @@ pub const Builder = struct { available_options_map: AvailableOptionsMap, available_options_list: ArrayList(AvailableOption), verbose: bool, + verbose_tokenize: bool, + verbose_ast: bool, + verbose_link: bool, + verbose_ir: bool, + verbose_llvm_ir: bool, + verbose_cimport: bool, invalid_user_input: bool, zig_exe: []const u8, default_step: &Step, @@ -88,6 +94,12 @@ pub const Builder = struct { .build_root = build_root, .cache_root = %%os.path.relative(allocator, build_root, cache_root), .verbose = false, + .verbose_tokenize = false, + .verbose_ast = false, + .verbose_link = false, + .verbose_ir = false, + .verbose_llvm_ir = false, + .verbose_cimport = false, .invalid_user_input = false, .allocator = allocator, .lib_paths = ArrayList([]const u8).init(allocator), @@ -536,15 +548,19 @@ pub const Builder = struct { return self.spawnChildEnvMap(null, &self.env_map, argv); } + fn printCmd(cwd: ?[]const u8, argv: []const []const u8) { + if (cwd) |yes_cwd| %%io.stderr.print("cd {} && ", yes_cwd); + for (argv) |arg| { + %%io.stderr.print("{} ", arg); + } + %%io.stderr.printf("\n"); + } + fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) -> %void { if (self.verbose) { - if (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd); - for (argv) |arg| { - %%io.stderr.print("{} ", arg); - } - %%io.stderr.printf("\n"); + printCmd(cwd, argv); } const child = %%os.ChildProcess.init(argv, self.allocator); @@ -561,12 +577,15 @@ pub const Builder = struct { switch (term) { Term.Exited => |code| { if (code != 0) { - %%io.stderr.printf("Process {} exited with error code {}\n", argv[0], code); + %%io.stderr.printf("The following command exited with error code {}:\n", code); + printCmd(cwd, argv); return error.UncleanExit; } }, else => { - %%io.stderr.printf("Process {} terminated unexpectedly\n", argv[0]); + %%io.stderr.printf("The following command terminated unexpectedly:\n"); + printCmd(cwd, argv); + return error.UncleanExit; }, }; @@ -1117,6 +1136,12 @@ pub const LibExeObjStep = struct { if (self.verbose) { %%zig_args.append("--verbose"); } + if (builder.verbose_tokenize) %%zig_args.append("--verbose-tokenize"); + if (builder.verbose_ast) %%zig_args.append("--verbose-ast"); + if (builder.verbose_cimport) %%zig_args.append("--verbose-cimport"); + if (builder.verbose_ir) %%zig_args.append("--verbose-ir"); + if (builder.verbose_llvm_ir) %%zig_args.append("--verbose-llvm-ir"); + if (builder.verbose_link) %%zig_args.append("--verbose-link"); if (self.strip) { %%zig_args.append("--strip"); diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index b1fbfc6c2bf38ab169c2a41890fb9345865143aa..089137c923948d719e470d69028bc73bbbcb46b7 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -69,6 +69,18 @@ pub fn main() -> %void { %%io.stderr.printf("Expected argument after --prefix\n\n"); return usage(&builder, false, &io.stderr); }); + } else if (mem.eql(u8, arg, "--verbose-tokenize")) { + builder.verbose_tokenize = true; + } else if (mem.eql(u8, arg, "--verbose-ast")) { + builder.verbose_ast = true; + } else if (mem.eql(u8, arg, "--verbose-link")) { + builder.verbose_link = true; + } else if (mem.eql(u8, arg, "--verbose-ir")) { + builder.verbose_ir = true; + } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { + builder.verbose_llvm_ir = true; + } else if (mem.eql(u8, arg, "--verbose-cimport")) { + builder.verbose_cimport = true; } else { %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); return usage(&builder, false, &io.stderr); @@ -116,27 +128,40 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) \\ \\General Options: \\ --help Print this help and exit - \\ --build-file [file] Override path to build.zig - \\ --cache-dir [path] Override path to cache directory \\ --verbose Print commands before executing them - \\ --debug-build-verbose Print verbose debugging information for the build system itself - \\ --prefix [prefix] Override default install prefix + \\ --prefix $path Override default install prefix \\ \\Project-Specific Options: \\ ); if (builder.available_options_list.len == 0) { - %%out_stream.printf(" (none)\n"); + %%out_stream.print(" (none)\n"); } else { for (builder.available_options_list.toSliceConst()) |option| { const name = %%fmt.allocPrint(allocator, - " -D{}=({})", option.name, Builder.typeIdName(option.type_id)); + " -D{}=${}", option.name, Builder.typeIdName(option.type_id)); defer allocator.free(name); - %%out_stream.printf("{s24} {}\n", name, option.description); + %%out_stream.print("{s24} {}\n", name, option.description); } } + %%out_stream.write( + \\ + \\Advanced Options: + \\ --build-file $file Override path to build.zig + \\ --cache-dir $path Override path to zig cache directory + \\ --verbose-tokenize Enable compiler debug output for tokenization + \\ --verbose-ast Enable compiler debug output for parsing into an AST + \\ --verbose-link Enable compiler debug output for linking + \\ --verbose-ir Enable compiler debug output for Zig IR + \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR + \\ --verbose-cimport Enable compiler debug output for C imports + \\ + ); + + %%out_stream.flush(); + if (out_stream == &io.stderr) return error.InvalidArgs; } -- 2.54.0 From 300c83d8930d15d4bc4e34fe11e3b6bf3130ecc4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 25 Oct 2017 23:18:18 -0400 Subject: [PATCH 08/13] fix crash on field access of opaque type --- src/analyze.cpp | 2 +- test/compile_errors.zig | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 45efa205e33625e7e6b6c73d1d57620d79922743..b6bd9c8124de1fff7b683b9e76c7ed77c055e1a5 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2804,7 +2804,6 @@ static bool is_container(TypeTableEntry *type_entry) { switch (type_entry->id) { case TypeTableEntryIdInvalid: case TypeTableEntryIdVar: - case TypeTableEntryIdOpaque: zig_unreachable(); case TypeTableEntryIdStruct: case TypeTableEntryIdEnum: @@ -2831,6 +2830,7 @@ static bool is_container(TypeTableEntry *type_entry) { case TypeTableEntryIdBoundFn: case TypeTableEntryIdEnumTag: case TypeTableEntryIdArgTuple: + case TypeTableEntryIdOpaque: return false; } zig_unreachable(); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index efab136d7ea78e3979b82f2b114e413ae73f24af..f3201aea9a0cd9ec52ead43d7e32be57a5d2505f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2238,4 +2238,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} , ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable"); + + cases.add("field access of opaque type", + \\const MyType = @OpaqueType(); + \\ + \\export fn entry() -> bool { + \\ var x: i32 = 1; + \\ return bar(@ptrCast(&MyType, &x)); + \\} + \\ + \\fn bar(x: &MyType) -> bool { + \\ return x.blah; + \\} + , + ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); } -- 2.54.0 From c7053bea204f87fe1c8b28ec97b27003a24dcafc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 26 Oct 2017 00:32:30 -0400 Subject: [PATCH 09/13] better output when @cImport generates invalid zig --- src/analyze.cpp | 31 +++++++++++++++++++++++++------ src/errmsg.cpp | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b6bd9c8124de1fff7b683b9e76c7ed77c055e1a5..e6ccf82dfe852bbbf79e42b90430f50daad27288 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -27,9 +27,17 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - // if this assert fails, then parsec generated code that - // failed semantic analysis, which isn't supposed to happen - assert(!node->owner->c_import_node); + if (node->owner->c_import_node != nullptr) { + // if this happens, then parsec generated code that + // failed semantic analysis, which isn't supposed to happen + ErrorMsg *err = add_node_error(g, node->owner->c_import_node, + buf_sprintf("compiler bug: @cImport generated invalid zig code")); + + add_error_note(g, err, node, msg); + + g->errors.append(err); + return err; + } ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, node->owner->source_code, node->owner->line_offsets, msg); @@ -39,9 +47,20 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { } ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { - // if this assert fails, then parsec generated code that - // failed semantic analysis, which isn't supposed to happen - assert(!node->owner->c_import_node); + if (node->owner->c_import_node != nullptr) { + // if this happens, then parsec generated code that + // failed semantic analysis, which isn't supposed to happen + + Buf *note_path = buf_create_from_str("?.c"); + Buf *note_source = buf_create_from_str("TODO: remember C source location to display here "); + ZigList note_line_offsets = {0}; + note_line_offsets.append(0); + ErrorMsg *note = err_msg_create_with_line(note_path, 0, 0, + note_source, ¬e_line_offsets, msg); + + err_msg_add_note(parent_msg, note); + return note; + } ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, node->owner->source_code, node->owner->line_offsets, msg); diff --git a/src/errmsg.cpp b/src/errmsg.cpp index bef4d7548d23a484faef430f22644b75fe2b0eb8..01c3ee84299dba2f9742a09ee09bb09b5a5484cf 100644 --- a/src/errmsg.cpp +++ b/src/errmsg.cpp @@ -123,6 +123,7 @@ ErrorMsg *err_msg_create_with_line(Buf *path, size_t line, size_t column, size_t end_line = line + 1; size_t line_end_offset = (end_line >= line_offsets->length) ? buf_len(source) : line_offsets->at(line + 1); size_t len = (line_end_offset + 1 > line_start_offset) ? (line_end_offset - line_start_offset - 1) : 0; + if (len == SIZE_MAX) len = 0; buf_init_from_mem(&err_msg->line_buf, buf_ptr(source) + line_start_offset, len); -- 2.54.0 From f4ca3482f1954eb0bdd0c378206d3a7b8e178f55 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 26 Oct 2017 01:11:57 -0400 Subject: [PATCH 10/13] add guard to c_headers for duplicate va_list on darwin --- c_headers/stdarg.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/c_headers/stdarg.h b/c_headers/stdarg.h index f6635105e07d3301d4eae12a904bbc6348f95bf8..d603d353f5fafddfa016bcedfb0f2f786b95123a 100644 --- a/c_headers/stdarg.h +++ b/c_headers/stdarg.h @@ -26,10 +26,14 @@ #ifndef __STDARG_H #define __STDARG_H +/* zig: added because macos _va_list.h was duplicately defining va_list + */ #ifndef _VA_LIST +#ifndef _VA_LIST_T typedef __builtin_va_list va_list; #define _VA_LIST #endif +#endif #define va_start(ap, param) __builtin_va_start(ap, param) #define va_end(ap) __builtin_va_end(ap) #define va_arg(ap, type) __builtin_va_arg(ap, type) -- 2.54.0 From 66636381957f214f1acc22dcea01cb4cd1032649 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Fri, 27 Oct 2017 03:00:23 +1300 Subject: [PATCH 11/13] Improve invalid character error messages (#566) See #544 --- src/tokenizer.cpp | 56 ++++++++++++++++++++++++++++++++++------- test/compile_errors.zig | 23 +++++++++++++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d277fb2502317a6d63e0f1fe98efb91428bc1c41..77d74c52ee2150fb415a7dfc18ebb18533fb5f8c 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -416,6 +416,44 @@ static void handle_string_escape(Tokenize *t, uint8_t c) { } } +static const char* get_escape_shorthand(uint8_t c) { + switch (c) { + case '\0': + return "\\0"; + case '\a': + return "\\a"; + case '\b': + return "\\b"; + case '\t': + return "\\t"; + case '\n': + return "\\n"; + case '\v': + return "\\v"; + case '\f': + return "\\f"; + case '\r': + return "\\r"; + default: + return nullptr; + } +} + +static void invalid_char_error(Tokenize *t, uint8_t c) { + if (c == '\r') { + tokenize_error(t, "invalid carriage return, only '\\n' line endings are supported"); + } else if (isprint(c)) { + tokenize_error(t, "invalid character: '%c'", c); + } else { + const char *sh = get_escape_shorthand(c); + if (sh) { + tokenize_error(t, "invalid character: '%s'", sh); + } else { + tokenize_error(t, "invalid character: '\\x%x'", c); + } + } +} + void tokenize(Buf *buf, Tokenization *out) { Tokenize t = {0}; t.out = out; @@ -580,7 +618,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateSawQuestionMark; break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } break; case TokenizeStateSawQuestionMark: @@ -890,7 +928,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateLineString; break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); break; } break; @@ -919,7 +957,7 @@ void tokenize(Buf *buf, Tokenization *out) { break; case '\\': if (t.cur_tok->data.str_lit.is_c_str) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } t.state = TokenizeStateLineStringContinue; break; @@ -949,7 +987,7 @@ void tokenize(Buf *buf, Tokenization *out) { buf_append_char(&t.cur_tok->data.str_lit.str, '\n'); break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); break; } break; @@ -1073,7 +1111,7 @@ void tokenize(Buf *buf, Tokenization *out) { handle_string_escape(&t, '\"'); break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } break; case TokenizeStateCharCode: @@ -1147,7 +1185,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateStart; break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } break; case TokenizeStateZero: @@ -1189,7 +1227,7 @@ void tokenize(Buf *buf, Tokenization *out) { uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { if (is_symbol_char(c)) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } // not my char t.pos -= 1; @@ -1233,7 +1271,7 @@ void tokenize(Buf *buf, Tokenization *out) { uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { if (is_symbol_char(c)) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } // not my char t.pos -= 1; @@ -1282,7 +1320,7 @@ void tokenize(Buf *buf, Tokenization *out) { uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { if (is_symbol_char(c)) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } // not my char t.pos -= 1; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f3201aea9a0cd9ec52ead43d7e32be57a5d2505f..f8e08d599f3a291cff5b9bb7115f8d07442f59bf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2252,4 +2252,27 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} , ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); + + cases.add("carriage return special case", + "fn test() -> bool {\r\n" ++ + " true\r\n" ++ + "}\r\n" + , + ".tmp_source.zig:1:20: error: invalid carriage return, only '\\n' line endings are supported"); + + cases.add("non-printable invalid character", + "\xff\xfe" ++ + \\fn test() -> bool {\r + \\ true\r + \\} + , + ".tmp_source.zig:1:1: error: invalid character: '\\xff'"); + + cases.add("non-printable invalid character with escape alternative", + "fn test() -> bool {\n" ++ + "\ttrue\n" ++ + "}\n" + , + ".tmp_source.zig:2:1: error: invalid character: '\\t'"); + } -- 2.54.0 From f1072d0d9fba397b3920015fd854414868e6ea17 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 24 Oct 2017 02:14:55 -0400 Subject: [PATCH 12/13] use llvm named structs for const values when possible normally we want to use llvm types for constants. but union constants (which are found inside enums) when they are initialized with the non-most-aligned-member must be unnamed structs. these bubble up to all aggregate types. if a constant of an aggregate type contains, recursively, a union constant with a non-most-aligned-member initialized, the aggregate typed constant must be unnamed too. this fixes some of the asserts that were coming in from llvm master branch. --- src/all_types.hpp | 3 ++ src/analyze.cpp | 7 ++-- src/codegen.cpp | 85 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index b8966e764a7643374b4b902c8b907441dda90e82..9f59ae2aac30706d842e39f35e8f393c5a0bbc1f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1008,6 +1008,9 @@ struct TypeTableEntryEnum { size_t gen_union_index; size_t gen_tag_index; + + uint32_t union_size_bytes; + TypeTableEntry *most_aligned_union_member; }; struct TypeTableEntryEnumTag { diff --git a/src/analyze.cpp b/src/analyze.cpp index e6ccf82dfe852bbbf79e42b90430f50daad27288..89ce5df6b49d5e7ca81cd3dadf0485a387e4b49c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1363,6 +1363,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { // unset temporary flag enum_type->data.enumeration.embedded_in_current = false; enum_type->data.enumeration.complete = true; + enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8; + enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member; if (!enum_type->data.enumeration.is_invalid) { TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); @@ -1384,10 +1386,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { }; union_type_ref = LLVMStructType(union_element_types, 2, false); } else { - LLVMTypeRef union_element_types[] = { - most_aligned_union_member->type_ref, - }; - union_type_ref = LLVMStructType(union_element_types, 1, false); + union_type_ref = most_aligned_union_member->type_ref; } enum_type->data.enumeration.union_type_ref = union_type_ref; diff --git a/src/codegen.cpp b/src/codegen.cpp index 68fd4159bd7b571a350680aaaad6bec27db666ef..0a78ef07409d0a0f0a403e87b07735f7701cb36d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3665,6 +3665,12 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con zig_unreachable(); } +// We have this because union constants can't be represented by the official union type, +// and this property bubbles up in whatever aggregate type contains a union constant +static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef val) { + return LLVMTypeOf(val) != type_entry->type_ref; +} + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeTableEntry *type_entry = const_val->type; assert(!type_entry->zero_bits); @@ -3726,24 +3732,34 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } else { LLVMValueRef child_val; LLVMValueRef maybe_val; + bool make_unnamed_struct; if (const_val->data.x_maybe) { child_val = gen_const_val(g, const_val->data.x_maybe); maybe_val = LLVMConstAllOnes(LLVMInt1Type()); + + make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val); } else { - child_val = LLVMConstNull(child_type->type_ref); + child_val = LLVMGetUndef(child_type->type_ref); maybe_val = LLVMConstNull(LLVMInt1Type()); + + make_unnamed_struct = false; } LLVMValueRef fields[] = { child_val, maybe_val, }; - return LLVMConstStruct(fields, 2, false); + if (make_unnamed_struct) { + return LLVMConstStruct(fields, 2, false); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); + } } } case TypeTableEntryIdStruct: { LLVMValueRef *fields = allocate(type_entry->data.structure.gen_field_count); size_t src_field_count = type_entry->data.structure.src_field_count; + bool make_unnamed_struct = false; if (type_entry->data.structure.layout == ContainerLayoutPacked) { size_t src_field_index = 0; while (src_field_index < src_field_count) { @@ -3761,8 +3777,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } if (src_field_index + 1 == src_field_index_end) { - fields[type_struct_field->gen_index] = - gen_const_val(g, &const_val->data.x_struct.fields[src_field_index]); + ConstExprValue *field_val = &const_val->data.x_struct.fields[src_field_index]; + LLVMValueRef val = gen_const_val(g, field_val); + fields[type_struct_field->gen_index] = val; + make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); } else { LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref, (unsigned)type_struct_field->gen_index); @@ -3790,11 +3808,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { if (type_struct_field->gen_index == SIZE_MAX) { continue; } - fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]); + ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; + LLVMValueRef val = gen_const_val(g, field_val); + fields[type_struct_field->gen_index] = val; + make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); } } - return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count, - type_entry->data.structure.layout == ContainerLayoutPacked); + if (make_unnamed_struct) { + return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count, + type_entry->data.structure.layout == ContainerLayoutPacked); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); + } } case TypeTableEntryIdUnion: { @@ -3808,11 +3833,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } LLVMValueRef *values = allocate(len); + LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref; + bool make_unnamed_struct = false; for (uint64_t i = 0; i < len; i += 1) { ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i]; - values[i] = gen_const_val(g, elem_value); + LLVMValueRef val = gen_const_val(g, elem_value); + values[i] = val; + make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val); + } + if (make_unnamed_struct) { + return LLVMConstStruct(values, len, true); + } else { + return LLVMConstArray(element_type_ref, values, (unsigned)len); } - return LLVMConstArray(LLVMTypeOf(values[0]), values, (unsigned)len); } case TypeTableEntryIdEnum: { @@ -3825,14 +3858,20 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag]; assert(enum_field->value == const_val->data.x_enum.tag); LLVMValueRef union_value; + + bool make_unnamed_struct; + if (type_has_bits(enum_field->type_entry)) { - uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, - union_type_ref); uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, enum_field->type_entry->type_ref); - uint64_t pad_bytes = union_type_bytes - field_type_bytes; + uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes; + + ConstExprValue *payload_value = const_val->data.x_enum.payload; + LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); + + make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || + payload_value->type != type_entry->data.enumeration.most_aligned_union_member; - LLVMValueRef correctly_typed_value = gen_const_val(g, const_val->data.x_enum.payload); if (pad_bytes == 0) { union_value = correctly_typed_value; } else { @@ -3843,12 +3882,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { union_value = LLVMConstStruct(fields, 2, false); } } else { + make_unnamed_struct = false; union_value = LLVMGetUndef(union_type_ref); } LLVMValueRef fields[2]; fields[type_entry->data.enumeration.gen_tag_index] = tag_value; fields[type_entry->data.enumeration.gen_union_index] = union_value; - return LLVMConstStruct(fields, 2, false); + + if (make_unnamed_struct) { + return LLVMConstStruct(fields, 2, false); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); + } } } case TypeTableEntryIdFn: @@ -3932,18 +3977,26 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } else { LLVMValueRef err_tag_value; LLVMValueRef err_payload_value; + bool make_unnamed_struct; if (const_val->data.x_err_union.err) { err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); err_payload_value = LLVMConstNull(child_type->type_ref); + make_unnamed_struct = false; } else { err_tag_value = LLVMConstNull(g->err_tag_type->type_ref); - err_payload_value = gen_const_val(g, const_val->data.x_err_union.payload); + ConstExprValue *payload_val = const_val->data.x_err_union.payload; + err_payload_value = gen_const_val(g, payload_val); + make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value); } LLVMValueRef fields[] = { err_tag_value, err_payload_value, }; - return LLVMConstStruct(fields, 2, false); + if (make_unnamed_struct) { + return LLVMConstStruct(fields, 2, false); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); + } } } case TypeTableEntryIdVoid: -- 2.54.0 From 4c306af4eb79071c966b99e877970f0a4582d891 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 27 Oct 2017 01:22:48 -0400 Subject: [PATCH 13/13] add test case for previous commit --- test/behavior.zig | 1 + test/cases/union.zig | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/cases/union.zig diff --git a/test/behavior.zig b/test/behavior.zig index 54c954be3d27b452319be3e8e64c681709056ec1..952c725e8c4bfcc86c307400696ae6811199cb72 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -40,6 +40,7 @@ comptime { _ = @import("cases/this.zig"); _ = @import("cases/try.zig"); _ = @import("cases/undefined.zig"); + _ = @import("cases/union.zig"); _ = @import("cases/var_args.zig"); _ = @import("cases/void.zig"); _ = @import("cases/while.zig"); diff --git a/test/cases/union.zig b/test/cases/union.zig new file mode 100644 index 0000000000000000000000000000000000000000..4b8ccb72454665ca82a5414f41a1937f9d9f42be --- /dev/null +++ b/test/cases/union.zig @@ -0,0 +1,33 @@ +const assert = @import("std").debug.assert; + +const Value = enum { + Int: u64, + Array: [9]u8, +}; + +const Agg = struct { + val1: Value, + val2: Value, +}; + +const v1 = Value.Int { 1234 }; +const v2 = Value.Array { []u8{3} ** 9 }; + +const err = (%Agg)(Agg { + .val1 = v1, + .val2 = v2, +}); + +const array = []Value { v1, v2, v1, v2}; + + +test "unions embedded in aggregate types" { + switch (array[1]) { + Value.Array => |arr| assert(arr[4] == 3), + else => unreachable, + } + switch((%%err).val1) { + Value.Int => |x| assert(x == 1234), + else => unreachable, + } +} -- 2.54.0