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 | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig index ac9f6b0c64..8cf13bca2e 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 b378afa1b0..85688b361d 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")) - return false; + 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; 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 0879942b3e..787d58442e 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 cd806a5dc6..3bf0d9c9af 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 dd25886d2b..efab136d7e 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; \\ 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 36bd66098b..a596213a3d 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 f82b1d5423..0e1a067bc6 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 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 | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig index 8cf13bca2e..0a1ea7deef 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 85688b361d..0fece54b4c 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.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 (math.signbit(x)) { if (!output(context, "-")) return false; x = -x; } + if (math.isPositiveInf(x)) { + return output(context, "Infinity"); + } + if (x == 0.0) { + return output(context, "0.0"); + } 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")) 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 8c5d7622cc..6fb8d4b8ef 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 f2f21fd746..316c7bc761 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 45c7cb5037..f1552ca61f 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 0290ad3975..5f730bbc85 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 1dbc2525f2..784d5fde4f 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 33b0e7c274..579455c2f9 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 c183f17c62..eab553d8c9 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 51ceef65d3..18c0e66677 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 69e1c82a9d..f513604247 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 a5dbe0f52e..85212e2176 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 d488f4c602..33c85c9224 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 fc5c645d72..1bf7fbab4b 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 4a4d71fde9..bea06a0b41 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 2e167bc64a..8005538d9a 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 d7507e9521..2ee2fdb57f 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 67ea15eb96..3764449758 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 e4a4e7a7ee..0ad9e127b3 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); 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 0fece54b4c..56b9a2e960 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 { 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 894deca930..b8966e764a 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 292943a6e6..45efa205e3 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 6fb8d4b8ef..68fd4159bd 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 f4c7f6a8c7..cc7721e9f8 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 787d58442e..6c6ce676f6 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 316c7bc761..a4e5b2dd25 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 a9a1d5a8da..bee021c6a5 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 d200c0531d..586e95bc75 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 84eba6d33b..7cf2ac5987 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 b1fbfc6c2b..089137c923 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; } 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 45efa205e3..b6bd9c8124 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 efab136d7e..f3201aea9a 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"); } 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 b6bd9c8124..e6ccf82dfe 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 bef4d7548d..01c3ee8429 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); 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 f6635105e0..d603d353f5 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) 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 d277fb2502..77d74c52ee 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 f3201aea9a..f8e08d599f 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'"); + } 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 b8966e764a..9f59ae2aac 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 e6ccf82dfe..89ce5df6b4 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 68fd4159bd..0a78ef0740 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: 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 54c954be3d..952c725e8c 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 0000000000..4b8ccb7245 --- /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, + } +}