| author | |
| committer | |
| log | a4316d5505d3af1e868a3506787f31a9ae90085a |
| tree | 197b3e2b3da083de2494c85a29fbf938f314fba9 |
| parent | 1f34c03ac14ac352ec03267ca8592dadfbd5e4bc |
| parent | 4e9894cfc4c8e2e1d3e01aa2e3400b295b0ee2df |
7 files changed, 174 insertions(+), 16 deletions(-)
CMakeLists.txt+6-1| ... | ... | @@ -87,10 +87,15 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) |
| 87 | 87 | set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for") |
| 88 | 88 | set(ZIG_TARGET_MCPU "baseline" CACHE STRING "-mcpu parameter to output binaries for") |
| 89 | 89 | set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary") |
| 90 | set(ZIG_PREFER_LLVM_CONFIG off CACHE BOOL "(when cross compiling) use llvm-config to find target llvm dependencies if needed") | |
| 91 | 90 | set(ZIG_SINGLE_THREADED off CACHE BOOL "limit the zig compiler to use only 1 thread") |
| 92 | 91 | set(ZIG_OMIT_STAGE2 off CACHE BOOL "omit the stage2 backend from stage1") |
| 93 | 92 | |
| 93 | if("${ZIG_TARGET_TRIPLE}" STREQUAL "native") | |
| 94 | set(ZIG_USE_LLVM_CONFIG ON CACHE BOOL "use llvm-config to find LLVM libraries") | |
| 95 | else() | |
| 96 | set(ZIG_USE_LLVM_CONFIG OFF CACHE BOOL "use llvm-config to find LLVM libraries") | |
| 97 | endif() | |
| 98 | ||
| 94 | 99 | find_package(llvm) |
| 95 | 100 | find_package(clang) |
| 96 | 101 | find_package(lld) |
cmake/Findllvm.cmake+1-1| ... | ... | @@ -63,7 +63,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB) |
| 63 | 63 | if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 13) |
| 64 | 64 | message(FATAL_ERROR "expected LLVM 12.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") |
| 65 | 65 | endif() |
| 66 | elseif(("${ZIG_TARGET_TRIPLE}" STREQUAL "native") OR ZIG_PREFER_LLVM_CONFIG) | |
| 66 | elseif(ZIG_USE_LLVM_CONFIG) | |
| 67 | 67 | find_program(LLVM_CONFIG_EXE |
| 68 | 68 | NAMES llvm-config-12 llvm-config-12.0 llvm-config120 llvm-config12 llvm-config |
| 69 | 69 | PATHS |
doc/langref.html.in+12-13| ... | ... | @@ -684,7 +684,7 @@ pub fn main() void { |
| 684 | 684 | {#header_close#} |
| 685 | 685 | {#header_open|String Literals and Unicode Code Point Literals#} |
| 686 | 686 | <p> |
| 687 | String literals are single-item constant {#link|Pointers#} to null-terminated byte arrays. | |
| 687 | String literals are constant single-item {#link|Pointers#} to null-terminated byte arrays. | |
| 688 | 688 | The type of string literals encodes both the length, and the fact that they are null-terminated, |
| 689 | 689 | and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and |
| 690 | 690 | {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}. |
| ... | ... | @@ -1783,7 +1783,7 @@ comptime { |
| 1783 | 1783 | expect(message.len == 5); |
| 1784 | 1784 | } |
| 1785 | 1785 | |
| 1786 | // A string literal is a pointer to an array literal. | |
| 1786 | // A string literal is a single-item pointer to an array literal. | |
| 1787 | 1787 | const same_message = "hello"; |
| 1788 | 1788 | |
| 1789 | 1789 | comptime { |
| ... | ... | @@ -1989,15 +1989,15 @@ test "null terminated array" { |
| 1989 | 1989 | |
| 1990 | 1990 | {#header_open|Pointers#} |
| 1991 | 1991 | <p> |
| 1992 | Zig has two kinds of pointers: | |
| 1992 | Zig has two kinds of pointers: single-item and many-item. | |
| 1993 | 1993 | </p> |
| 1994 | 1994 | <ul> |
| 1995 | <li>{#syntax#}*T{#endsyntax#} - pointer to exactly one item. | |
| 1995 | <li>{#syntax#}*T{#endsyntax#} - single-item pointer to exactly one item. | |
| 1996 | 1996 | <ul> |
| 1997 | 1997 | <li>Supports deref syntax: {#syntax#}ptr.*{#endsyntax#}</li> |
| 1998 | 1998 | </ul> |
| 1999 | 1999 | </li> |
| 2000 | <li>{#syntax#}[*]T{#endsyntax#} - pointer to unknown number of items. | |
| 2000 | <li>{#syntax#}[*]T{#endsyntax#} - many-item pointer to unknown number of items. | |
| 2001 | 2001 | <ul> |
| 2002 | 2002 | <li>Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}</li> |
| 2003 | 2003 | <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li> |
| ... | ... | @@ -2009,7 +2009,7 @@ test "null terminated array" { |
| 2009 | 2009 | </ul> |
| 2010 | 2010 | <p>These types are closely related to {#link|Arrays#} and {#link|Slices#}:</p> |
| 2011 | 2011 | <ul> |
| 2012 | <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to array. | |
| 2012 | <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to an array. | |
| 2013 | 2013 | <ul> |
| 2014 | 2014 | <li>Supports index syntax: {#syntax#}array_ptr[i]{#endsyntax#}</li> |
| 2015 | 2015 | <li>Supports slice syntax: {#syntax#}array_ptr[start..end]{#endsyntax#}</li> |
| ... | ... | @@ -2038,7 +2038,7 @@ test "address of syntax" { |
| 2038 | 2038 | // Dereference a pointer: |
| 2039 | 2039 | expect(x_ptr.* == 1234); |
| 2040 | 2040 | |
| 2041 | // When you get the address of a const variable, you get a const pointer to a single item. | |
| 2041 | // When you get the address of a const variable, you get a const single-item pointer. | |
| 2042 | 2042 | expect(@TypeOf(x_ptr) == *const i32); |
| 2043 | 2043 | |
| 2044 | 2044 | // If you want to mutate the value, you'd need an address of a mutable variable: |
| ... | ... | @@ -2051,7 +2051,7 @@ test "address of syntax" { |
| 2051 | 2051 | |
| 2052 | 2052 | test "pointer array access" { |
| 2053 | 2053 | // Taking an address of an individual element gives a |
| 2054 | // pointer to a single item. This kind of pointer | |
| 2054 | // single-item pointer. This kind of pointer | |
| 2055 | 2055 | // does not support pointer arithmetic. |
| 2056 | 2056 | var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; |
| 2057 | 2057 | const ptr = &array[2]; |
| ... | ... | @@ -2320,8 +2320,8 @@ test "basic slices" { |
| 2320 | 2320 | expect(&slice[0] == &array[0]); |
| 2321 | 2321 | expect(slice.len == array.len); |
| 2322 | 2322 | |
| 2323 | // Using the address-of operator on a slice gives a pointer to a single | |
| 2324 | // item, while using the `ptr` field gives an unknown length pointer. | |
| 2323 | // Using the address-of operator on a slice gives a single-item pointer, | |
| 2324 | // while using the `ptr` field gives a many-item pointer. | |
| 2325 | 2325 | expect(@TypeOf(slice.ptr) == [*]i32); |
| 2326 | 2326 | expect(@TypeOf(&slice[0]) == *i32); |
| 2327 | 2327 | expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0])); |
| ... | ... | @@ -5244,8 +5244,7 @@ test "*[N]T to []T" { |
| 5244 | 5244 | expect(std.mem.eql(f32, x2, &[2]f32{ 1.2, 3.4 })); |
| 5245 | 5245 | } |
| 5246 | 5246 | |
| 5247 | // Single-item pointers to arrays can be coerced to | |
| 5248 | // unknown length pointers. | |
| 5247 | // Single-item pointers to arrays can be coerced to many-item pointers. | |
| 5249 | 5248 | test "*[N]T to [*]T" { |
| 5250 | 5249 | var buf: [5]u8 = "hello".*; |
| 5251 | 5250 | const x: [*]u8 = &buf; |
| ... | ... | @@ -9853,7 +9852,7 @@ const c = @cImport({ |
| 9853 | 9852 | </p> |
| 9854 | 9853 | <p> |
| 9855 | 9854 | When importing C header files, it is ambiguous whether pointers should be translated as |
| 9856 | single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}). | |
| 9855 | single-item pointers ({#syntax#}*T{#endsyntax#}) or many-item pointers ({#syntax#}[*]T{#endsyntax#}). | |
| 9857 | 9856 | C pointers are a compromise so that Zig code can utilize translated header files directly. |
| 9858 | 9857 | </p> |
| 9859 | 9858 | <p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p> |
src/link/MachO.zig+4-1| ... | ... | @@ -835,7 +835,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 835 | 835 | std.process.exit(1); |
| 836 | 836 | } |
| 837 | 837 | }, |
| 838 | else => std.process.abort(), | |
| 838 | else => { | |
| 839 | log.err("{s} terminated", .{ argv.items[0] }); | |
| 840 | return error.LLDCrashed; | |
| 841 | }, | |
| 839 | 842 | } |
| 840 | 843 | } else { |
| 841 | 844 | child.stdin_behavior = .Ignore; |
src/stage1/codegen.cpp+47| ... | ... | @@ -487,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 487 | 487 | addLLVMFnAttr(llvm_fn, "noreturn"); |
| 488 | 488 | } |
| 489 | 489 | |
| 490 | if (!calling_convention_allows_zig_types(cc)) { | |
| 491 | // A simplistic and desperate attempt at making the compiler respect the | |
| 492 | // target ABI for return types. | |
| 493 | // This is just enough to avoid miscompiling the test suite, it will be | |
| 494 | // better in stage2. | |
| 495 | ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type : | |
| 496 | return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type : | |
| 497 | nullptr; | |
| 498 | ||
| 499 | if (int_type != nullptr) { | |
| 500 | const bool is_signed = int_type->data.integral.is_signed; | |
| 501 | const uint32_t bit_width = int_type->data.integral.bit_count; | |
| 502 | bool should_extend = false; | |
| 503 | ||
| 504 | // Rough equivalent of Clang's isPromotableIntegerType. | |
| 505 | switch (bit_width) { | |
| 506 | case 1: // bool | |
| 507 | case 8: // {un,}signed char | |
| 508 | case 16: // {un,}signed short | |
| 509 | should_extend = true; | |
| 510 | break; | |
| 511 | default: | |
| 512 | break; | |
| 513 | } | |
| 514 | ||
| 515 | switch (g->zig_target->arch) { | |
| 516 | case ZigLLVM_sparcv9: | |
| 517 | case ZigLLVM_riscv64: | |
| 518 | case ZigLLVM_ppc64: | |
| 519 | case ZigLLVM_ppc64le: | |
| 520 | // Always extend to the register width. | |
| 521 | should_extend = bit_width < 64; | |
| 522 | break; | |
| 523 | default: | |
| 524 | break; | |
| 525 | } | |
| 526 | ||
| 527 | // {zero,sign}-extend the result. | |
| 528 | if (should_extend) { | |
| 529 | if (is_signed) | |
| 530 | addLLVMAttr(llvm_fn, 0, "signext"); | |
| 531 | else | |
| 532 | addLLVMAttr(llvm_fn, 0, "zeroext"); | |
| 533 | } | |
| 534 | } | |
| 535 | } | |
| 536 | ||
| 490 | 537 | if (fn->body_node != nullptr) { |
| 491 | 538 | maybe_export_dll(g, llvm_fn, linkage); |
| 492 | 539 |
test/stage1/c_abi/cfuncs.c+52| ... | ... | @@ -24,6 +24,16 @@ void zig_f32(float); |
| 24 | 24 | void zig_f64(double); |
| 25 | 25 | void zig_five_floats(float, float, float, float, float); |
| 26 | 26 | |
| 27 | bool zig_ret_bool(); | |
| 28 | uint8_t zig_ret_u8(); | |
| 29 | uint16_t zig_ret_u16(); | |
| 30 | uint32_t zig_ret_u32(); | |
| 31 | uint64_t zig_ret_u64(); | |
| 32 | int8_t zig_ret_i8(); | |
| 33 | int16_t zig_ret_i16(); | |
| 34 | int32_t zig_ret_i32(); | |
| 35 | int64_t zig_ret_i64(); | |
| 36 | ||
| 27 | 37 | void zig_ptr(void *); |
| 28 | 38 | |
| 29 | 39 | void zig_bool(bool); |
| ... | ... | @@ -119,6 +129,20 @@ void run_c_tests(void) { |
| 119 | 129 | assert_or_panic(res.d == 23); |
| 120 | 130 | assert_or_panic(res.e == 24); |
| 121 | 131 | } |
| 132 | ||
| 133 | { | |
| 134 | assert_or_panic(zig_ret_bool() == 1); | |
| 135 | ||
| 136 | assert_or_panic(zig_ret_u8() == 0xff); | |
| 137 | assert_or_panic(zig_ret_u16() == 0xffff); | |
| 138 | assert_or_panic(zig_ret_u32() == 0xffffffff); | |
| 139 | assert_or_panic(zig_ret_u64() == 0xffffffffffffffff); | |
| 140 | ||
| 141 | assert_or_panic(zig_ret_i8() == -1); | |
| 142 | assert_or_panic(zig_ret_i16() == -1); | |
| 143 | assert_or_panic(zig_ret_i32() == -1); | |
| 144 | assert_or_panic(zig_ret_i64() == -1); | |
| 145 | } | |
| 122 | 146 | } |
| 123 | 147 | |
| 124 | 148 | void c_u8(uint8_t x) { |
| ... | ... | @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { |
| 236 | 260 | assert_or_panic(vec.w == 69); |
| 237 | 261 | assert_or_panic(vec.q == 55); |
| 238 | 262 | } |
| 263 | ||
| 264 | bool c_ret_bool() { | |
| 265 | return 1; | |
| 266 | } | |
| 267 | uint8_t c_ret_u8() { | |
| 268 | return 0xff; | |
| 269 | } | |
| 270 | uint16_t c_ret_u16() { | |
| 271 | return 0xffff; | |
| 272 | } | |
| 273 | uint32_t c_ret_u32() { | |
| 274 | return 0xffffffff; | |
| 275 | } | |
| 276 | uint64_t c_ret_u64() { | |
| 277 | return 0xffffffffffffffff; | |
| 278 | } | |
| 279 | int8_t c_ret_i8() { | |
| 280 | return -1; | |
| 281 | } | |
| 282 | int16_t c_ret_i16() { | |
| 283 | return -1; | |
| 284 | } | |
| 285 | int32_t c_ret_i32() { | |
| 286 | return -1; | |
| 287 | } | |
| 288 | int64_t c_ret_i64() { | |
| 289 | return -1; | |
| 290 | } |
test/stage1/c_abi/main.zig+52| ... | ... | @@ -284,3 +284,55 @@ test "C ABI structs of floats as parameter" { |
| 284 | 284 | }; |
| 285 | 285 | c_big_struct_floats(v5); |
| 286 | 286 | } |
| 287 | ||
| 288 | export fn zig_ret_bool() bool { | |
| 289 | return true; | |
| 290 | } | |
| 291 | export fn zig_ret_u8() u8 { | |
| 292 | return 0xff; | |
| 293 | } | |
| 294 | export fn zig_ret_u16() u16 { | |
| 295 | return 0xffff; | |
| 296 | } | |
| 297 | export fn zig_ret_u32() u32 { | |
| 298 | return 0xffffffff; | |
| 299 | } | |
| 300 | export fn zig_ret_u64() u64 { | |
| 301 | return 0xffffffffffffffff; | |
| 302 | } | |
| 303 | export fn zig_ret_i8() i8 { | |
| 304 | return -1; | |
| 305 | } | |
| 306 | export fn zig_ret_i16() i16 { | |
| 307 | return -1; | |
| 308 | } | |
| 309 | export fn zig_ret_i32() i32 { | |
| 310 | return -1; | |
| 311 | } | |
| 312 | export fn zig_ret_i64() i64 { | |
| 313 | return -1; | |
| 314 | } | |
| 315 | ||
| 316 | extern fn c_ret_bool() bool; | |
| 317 | extern fn c_ret_u8() u8; | |
| 318 | extern fn c_ret_u16() u16; | |
| 319 | extern fn c_ret_u32() u32; | |
| 320 | extern fn c_ret_u64() u64; | |
| 321 | extern fn c_ret_i8() i8; | |
| 322 | extern fn c_ret_i16() i16; | |
| 323 | extern fn c_ret_i32() i32; | |
| 324 | extern fn c_ret_i64() i64; | |
| 325 | ||
| 326 | test "C ABI integer return types" { | |
| 327 | expect(c_ret_bool() == true); | |
| 328 | ||
| 329 | expect(c_ret_u8() == 0xff); | |
| 330 | expect(c_ret_u16() == 0xffff); | |
| 331 | expect(c_ret_u32() == 0xffffffff); | |
| 332 | expect(c_ret_u64() == 0xffffffffffffffff); | |
| 333 | ||
| 334 | expect(c_ret_i8() == -1); | |
| 335 | expect(c_ret_i16() == -1); | |
| 336 | expect(c_ret_i32() == -1); | |
| 337 | expect(c_ret_i64() == -1); | |
| 338 | } |