diff options
| author | hryx <codroid@gmail.com> | 2019-05-12 02:00:49 -0700 |
|---|---|---|
| committer | hryx <codroid@gmail.com> | 2019-05-12 02:00:49 -0700 |
| commit | 3787f3428625e830fd852a8f5a40c7d8a2d429f6 (patch) | |
| tree | 23fb493b9d2f07c7abe57955874682959936319a | |
| parent | 16aee1f58a80295f7599a8290d764a5c7040c373 (diff) | |
| parent | edcc7c72d1a684a8a16ca23ad26689f2cce4e803 (diff) | |
| download | zig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.tar.gz zig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.zip | |
Merge branch 'master' into rebased
220 files changed, 17655 insertions, 6432 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index cbd1317bdb..ea367c00a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) set(ZIG_VERSION_MAJOR 0) -set(ZIG_VERSION_MINOR 3) +set(ZIG_VERSION_MINOR 4) set(ZIG_VERSION_PATCH 0) set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}") @@ -50,10 +50,6 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead find_package(llvm) find_package(clang) -if(MINGW) - find_package(z3) -endif() - if(APPLE AND ZIG_STATIC) list(REMOVE_ITEM LLVM_LIBRARIES "-lz") find_library(ZLIB NAMES z zlib libz) @@ -62,6 +58,16 @@ endif() set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp") +# Handle multi-config builds and place each into a common lib. The VS generator +# for example will append a Debug folder by default if not explicitly specified. +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${ZIG_CPP_LIB_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${ZIG_CPP_LIB_DIR}) +foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${CONFIG_TYPE} CONFIG_TYPE) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${ZIG_CPP_LIB_DIR}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${ZIG_CPP_LIB_DIR}) +endforeach(CONFIG_TYPE CMAKE_CONFIGURATION_TYPES) + if(ZIG_FORCE_EXTERNAL_LLD) find_package(lld) include_directories(${LLVM_INCLUDE_DIRS}) @@ -196,7 +202,7 @@ else() if(MSVC) set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w") else() - set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment") + set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Wno-comment") if(MINGW) set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO -Wno-pedantic-ms-format") endif() @@ -257,7 +263,6 @@ else() embedded_lld_wasm embedded_lld_lib ) - install(TARGETS embedded_lld_elf embedded_lld_coff embedded_lld_mingw embedded_lld_wasm embedded_lld_lib DESTINATION "${ZIG_CPP_LIB_DIR}") endif() # No patches have been applied to SoftFloat-3e @@ -407,6 +412,12 @@ set(SOFTFLOAT_LIBRARIES embedded_softfloat) find_package(Threads) +# CMake doesn't let us create an empty executable, so we hang on to this one separately. +set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp") + +# This is our shim which will be replaced by libuserland written in Zig. +set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp") + set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/analyze.cpp" "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" @@ -423,7 +434,6 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp" "${CMAKE_SOURCE_DIR}/src/link.cpp" - "${CMAKE_SOURCE_DIR}/src/main.cpp" "${CMAKE_SOURCE_DIR}/src/os.cpp" "${CMAKE_SOURCE_DIR}/src/parser.cpp" "${CMAKE_SOURCE_DIR}/src/range_set.cpp" @@ -477,6 +487,7 @@ set(ZIG_STD_FILES "crypto/x25519.zig" "cstr.zig" "debug.zig" + "debug/leb128.zig" "debug/failing_allocator.zig" "dwarf.zig" "dynamic_library.zig" @@ -507,6 +518,7 @@ set(ZIG_STD_FILES "heap.zig" "io.zig" "io/seekable_stream.zig" + "io/c_out_stream.zig" "json.zig" "lazy_init.zig" "linked_list.zig" @@ -521,6 +533,7 @@ set(ZIG_STD_FILES "math/atanh.zig" "math/big.zig" "math/big/int.zig" + "math/big/rational.zig" "math/cbrt.zig" "math/ceil.zig" "math/complex.zig" @@ -599,6 +612,7 @@ set(ZIG_STD_FILES "os/linux.zig" "os/linux/arm64.zig" "os/linux/errno.zig" + "os/linux/tls.zig" "os/linux/vdso.zig" "os/linux/x86_64.zig" "os/netbsd.zig" @@ -606,6 +620,8 @@ set(ZIG_STD_FILES "os/path.zig" "os/time.zig" "os/uefi.zig" + "os/wasi.zig" + "os/wasi/core.zig" "os/windows.zig" "os/windows/advapi32.zig" "os/windows/error.zig" @@ -615,6 +631,7 @@ set(ZIG_STD_FILES "os/windows/shell32.zig" "os/windows/util.zig" "os/zen.zig" + "packed_int_array.zig" "pdb.zig" "priority_queue.zig" "rand.zig" @@ -628,10 +645,15 @@ set(ZIG_STD_FILES "special/build_runner.zig" "special/builtin.zig" "special/compiler_rt.zig" + "special/compiler_rt/stack_probe.zig" + "special/compiler_rt/arm/aeabi_fcmp.zig" + "special/compiler_rt/arm/aeabi_dcmp.zig" "special/compiler_rt/addXf3.zig" "special/compiler_rt/aulldiv.zig" "special/compiler_rt/aullrem.zig" "special/compiler_rt/comparetf2.zig" + "special/compiler_rt/comparedf2.zig" + "special/compiler_rt/comparesf2.zig" "special/compiler_rt/divsf3.zig" "special/compiler_rt/divdf3.zig" "special/compiler_rt/divti3.zig" @@ -656,9 +678,13 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" + "special/compiler_rt/floatdidf.zig" + "special/compiler_rt/floatsiXf.zig" + "special/compiler_rt/floatunsidf.zig" "special/compiler_rt/floattidf.zig" "special/compiler_rt/floattisf.zig" "special/compiler_rt/floattitf.zig" + "special/compiler_rt/floatundidf.zig" "special/compiler_rt/floatunditf.zig" "special/compiler_rt/floatunsitf.zig" "special/compiler_rt/floatuntidf.zig" @@ -667,7 +693,11 @@ set(ZIG_STD_FILES "special/compiler_rt/modti3.zig" "special/compiler_rt/mulXf3.zig" "special/compiler_rt/muloti4.zig" + "special/compiler_rt/mulodi4.zig" "special/compiler_rt/multi3.zig" + "special/compiler_rt/ashlti3.zig" + "special/compiler_rt/ashrti3.zig" + "special/compiler_rt/lshrti3.zig" "special/compiler_rt/negXf2.zig" "special/compiler_rt/popcountdi2.zig" "special/compiler_rt/truncXfYf2.zig" @@ -676,7 +706,6 @@ set(ZIG_STD_FILES "special/compiler_rt/udivmodti4.zig" "special/compiler_rt/udivti3.zig" "special/compiler_rt/umodti3.zig" - "special/fmt_runner.zig" "special/init-exe/build.zig" "special/init-exe/src/main.zig" "special/init-lib/build.zig" @@ -6604,7 +6633,7 @@ endif() if(MSVC) set(EXE_CFLAGS "${EXE_CFLAGS}") else() - set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fno-exceptions -fno-rtti -Werror=strict-prototypes -Werror=old-style-definition -Werror=type-limits -Wno-missing-braces") + set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=strict-prototypes -Werror=old-style-definition -Werror=type-limits -Wno-missing-braces") if(MINGW) set(EXE_CFLAGS "${EXE_CFLAGS} -D__USE_MINGW_ANSI_STDIO -Wno-pedantic-ms-format") endif() @@ -6639,13 +6668,12 @@ set_target_properties(opt_c_util PROPERTIES COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}" ) -add_executable(zig ${ZIG_SOURCES}) -set_target_properties(zig PROPERTIES +add_library(compiler STATIC ${ZIG_SOURCES}) +set_target_properties(compiler PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) - -target_link_libraries(zig LINK_PUBLIC +target_link_libraries(compiler LINK_PUBLIC zig_cpp opt_c_util ${SOFTFLOAT_LIBRARIES} @@ -6654,24 +6682,63 @@ target_link_libraries(zig LINK_PUBLIC ${LLVM_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) - if(NOT MSVC) - target_link_libraries(zig LINK_PUBLIC ${LIBXML2}) + target_link_libraries(compiler LINK_PUBLIC ${LIBXML2}) endif() if(MINGW) - target_link_libraries(zig LINK_PUBLIC ${Z3_LIBRARIES}) + find_library(Z3_LIBRARIES NAMES z3 z3.dll) + target_link_libraries(compiler LINK_PUBLIC ${Z3_LIBRARIES}) endif() if(ZIG_DIA_GUIDS_LIB) - target_link_libraries(zig LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) + target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) endif() if(MSVC OR MINGW) - target_link_libraries(zig LINK_PUBLIC version) + target_link_libraries(compiler LINK_PUBLIC version) endif() + +add_executable(zig0 "${ZIG_MAIN_SRC}" "${ZIG0_SHIM_SRC}") +set_target_properties(zig0 PROPERTIES + COMPILE_FLAGS ${EXE_CFLAGS} + LINK_FLAGS ${EXE_LDFLAGS} +) +target_link_libraries(zig0 compiler) + +if(WIN32) + set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib") +elseif(APPLE) + set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.o") +else() + set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a") +endif() +add_custom_command( + OUTPUT "${LIBUSERLAND}" + COMMAND zig0 ARGS build + --override-std-dir std + --override-lib-dir "${CMAKE_SOURCE_DIR}" + libuserland + "-Doutput-dir=${CMAKE_BINARY_DIR}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + DEPENDS + "${CMAKE_SOURCE_DIR}/src-self-hosted/stage1.zig" + "${CMAKE_SOURCE_DIR}/src-self-hosted/translate_c.zig" + "${CMAKE_SOURCE_DIR}/build.zig" +) +add_custom_target(userland_target DEPENDS "${LIBUSERLAND}") +add_executable(zig "${ZIG_MAIN_SRC}") +if(MINGW) + set(EXE_LDFLAGS "${EXE_LDFLAGS} -fstack-protector") +endif() +set_target_properties(zig PROPERTIES + COMPILE_FLAGS ${EXE_CFLAGS} + LINK_FLAGS ${EXE_LDFLAGS} +) +target_link_libraries(zig compiler "${LIBUSERLAND}") +add_dependencies(zig userland_target) install(TARGETS zig DESTINATION bin) -install(TARGETS zig_cpp DESTINATION "${ZIG_CPP_LIB_DIR}") + foreach(file ${ZIG_C_HEADER_FILES}) get_filename_component(file_dir "${C_HEADERS_DEST}/${file}" DIRECTORY) @@ -6697,7 +6764,3 @@ foreach(file ${ZIG_LIBCXX_FILES}) get_filename_component(file_dir "${LIBCXX_FILES_DEST}/${file}" DIRECTORY) install(FILES "${CMAKE_SOURCE_DIR}/libcxx/${file}" DESTINATION "${file_dir}") endforeach() - -install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/") -install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/") -install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/") @@ -1,140 +1,15 @@  -A programming language designed for robustness, optimality, and -clarity. - -[Download & Documentation](https://ziglang.org/download/) - -## Feature Highlights - - * Small, simple language. Focus on debugging your application rather than - debugging knowledge of your programming language. - * Ships with a build system that obviates the need for a configure script - or a makefile. In fact, existing C and C++ projects may choose to depend on - Zig instead of e.g. cmake. - * A fresh take on error handling which makes writing correct code easier than - writing buggy code. - * Debug mode optimizes for fast compilation time and crashing with a stack trace - when undefined behavior *would* happen. - * ReleaseFast mode produces heavily optimized code. What other projects call - "Link Time Optimization" Zig does automatically. - * Compatible with C libraries with no wrapper necessary. Directly include - C .h files and get access to the functions and symbols therein. - * Provides standard library which competes with the C standard library and is - always compiled against statically in source form. Zig binaries do not - depend on libc unless explicitly linked. - * Optional type instead of null pointers. - * Safe unions, tagged unions, and C ABI compatible unions. - * Generics so that one can write efficient data structures that work for any - data type. - * No header files required. Top level declarations are entirely - order-independent. - * Compile-time code execution. Compile-time reflection. - * Partial compile-time function evaluation which eliminates the need for - a preprocessor or macros. - * The binaries produced by Zig have complete debugging information so you can, - for example, use GDB, MSVC, or LLDB to debug your software. - * Built-in unit tests with `zig test`. - * Friendly toward package maintainers. Reproducible build, bootstrapping - process carefully documented. Issues filed by package maintainers are - considered especially important. - * Cross-compiling is a primary use case. - * In addition to creating executables, creating a C library is a primary use - case. You can export an auto-generated .h file. - -### Supported Targets - -#### Tier 1 Support - - * Not only can Zig generate machine code for these targets, but the standard - library cross-platform abstractions have implementations for these targets. - Thus it is practical to write a pure Zig application with no dependency on - libc. - * The CI server automatically tests these targets on every commit to master - branch, and updates ziglang.org/download with links to pre-built binaries. - * These targets have debug info capabilities and therefore produce stack - traces on failed assertions. - * ([coming soon](https://github.com/ziglang/zig/issues/514)) libc is available - for this target even when cross compiling. - -#### Tier 2 Support - - * There may be some standard library implementations, but many abstractions - will give an "Unsupported OS" compile error. One can link with libc or other - libraries to fill in the gaps in the standard library. - * These targets are known to work, but are not automatically tested, so there - are occasional regressions. - * Some tests may be disabled for these targets as we work toward Tier 1 - support. - -#### Tier 3 Support - - * The standard library has little to no knowledge of the existence of this - target. - * Because Zig is based on LLVM, it has the capability to build for these - targets, and LLVM has the target enabled by default. - * These targets are not frequently tested; one will likely need to contribute - to Zig in order to build for these targets. - * The Zig compiler might need to be updated with a few things such as - - what sizes are the C integer types - - C ABI calling convention for this target - - bootstrap code and default panic handler - * `zig targets` is guaranteed to include this target. - -#### Tier 4 Support - - * Support for these targets is entirely experimental. - * LLVM may have the target as an experimental target, which means that you - need to use Zig-provided binaries for the target to be available, or - build LLVM from source with special configure flags. `zig targets` will - display the target if it is available. - * This target may be considered deprecated by an official party, - [such as macosx/i386](https://support.apple.com/en-us/HT208436) in which - case this target will remain forever stuck in Tier 4. - * This target may only support `--emit asm` and cannot emit object files. - -#### Support Table - -| | freestanding | linux | macosx | windows | freebsd | netbsd | UEFI | other | -|-------------|--------------|--------|--------|---------|---------|------- | -------|--------| -|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | -|i386 | Tier 2 | Tier 2 | Tier 4 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | -|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | -|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | -|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 | -|wasm32 | Tier 3 | N/A | N/A | N/A | N/A | N/A | N/A | N/A | -|wasm64 | Tier 3 | N/A | N/A | N/A | N/A | N/A | N/A | N/A | -|avr | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | Tier 4 | -|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | Tier 4 | -|xcore | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|nvptx | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|msp430 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|r600 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|arc | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|tce | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|le | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|amdil | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|hsail | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|spir | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|kalimba | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|shave | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | -|renderscript | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 | - -## Community - - * IRC: `#zig` on Freenode ([Channel Logs](https://irclog.whitequark.org/zig/)). - * Reddit: [/r/zig](https://www.reddit.com/r/zig) - * Email list: [~andrewrk/ziglang@lists.sr.ht](https://lists.sr.ht/%7Eandrewrk/ziglang) - -## Building +Zig is an open-source programming language designed for **robustness**, +**optimality**, and **maintainability**. + +## Resources + + * [Introduction](https://ziglang.org/#Introduction) + * [Download & Documentation](https://ziglang.org/download) + * [Community](https://github.com/ziglang/zig/wiki/Community) + +## Building from Source [](https://dev.azure.com/ziglang/zig/_build/latest?definitionId=1&branchName=master) @@ -150,12 +25,14 @@ Note that you can * cmake >= 2.8.5 * gcc >= 5.0.0 or clang >= 3.6.0 * LLVM, Clang, LLD development libraries == 8.x, compiled with the same gcc or clang version above + - Use the system package manager, or [build from source](https://github.com/ziglang/zig/wiki/How-to-build-LLVM,-libclang,-and-liblld-from-source#posix). ##### Windows * cmake >= 2.8.5 * Microsoft Visual Studio 2017 (version 15.8) * LLVM, Clang, LLD development libraries == 8.x, compiled with the same MSVC version above + - Use the [pre-built binaries](https://github.com/ziglang/zig/wiki/How-to-build-LLVM,-libclang,-and-liblld-from-source#pre-built-binaries) or [build from source](https://github.com/ziglang/zig/wiki/How-to-build-LLVM,-libclang,-and-liblld-from-source#windows). #### Instructions @@ -165,9 +42,7 @@ Note that you can mkdir build cd build cmake .. -make make install -bin/zig build --build-file ../build.zig test ``` ##### MacOS @@ -179,7 +54,6 @@ mkdir build cd build cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0 make install -bin/zig build --build-file ../build.zig test ``` ##### Windows @@ -222,3 +96,95 @@ use stage 1. ``` ./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast ``` + +## Contributing + +### Start a Project Using Zig + +One of the best ways you can contribute to Zig is to start using it for a +personal project. Here are some great examples: + + * [Oxid](https://github.com/dbandstra/oxid) - arcade style game + * [TM35-Metronome](https://github.com/TM35-Metronome) - tools for modifying and randomizing Pokémon games + * [trOS](https://github.com/sjdh02/trOS) - tiny aarch64 baremetal OS thingy + +Without fail, these projects lead to discovering bugs and helping flesh out use +cases, which lead to further design iterations of Zig. Importantly, each issue +found this way comes with real world motivations, so it is easy to explain +your reasoning behind proposals and feature requests. + +Ideally, such a project will help you to learn new skills and add something +to your personal portfolio at the same time. + +### Spread the Word + +Another way to contribute is to write about Zig, or speak about Zig at a +conference, or do either of those things for your project which uses Zig. +Here are some examples: + + * [Iterative Replacement of C with Zig](http://tiehuis.github.io/blog/zig1.html) + * [The Right Tool for the Right Job: Redis Modules & Zig](https://www.youtube.com/watch?v=eCHM8-_poZY) + +Zig is a brand new language, with no advertising budget. Word of mouth is the +only way people find out about the project, and the more people hear about it, +the more people will use it, and the better chance we have to take over the +world. + +### Finding Contributor Friendly Issues + +Please note that issues labeled +[Proposal](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3Aproposal) +but do not also have the +[Accepted](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3Aaccepted) +label are still under consideration, and efforts to implement such a proposal +have a high risk of being wasted. If you are interested in a proposal which is +still under consideration, please express your interest in the issue tracker, +providing extra insights and considerations that others have not yet expressed. +The most highly regarded argument in such a discussion is a real world use case. + +The issue label +[Contributor Friendly](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributor+friendly%22) +exists to help contributors find issues that are "limited in scope and/or +knowledge of Zig internals." + +### Editing Source Code + +First, build the Stage 1 compiler as described in [the Building section](#building). + +When making changes to the standard library, be sure to edit the files in the +`std` directory and not the installed copy in the build directory. If you add a +new file to the standard library, you must also add the file path in +CMakeLists.txt. + +To test changes, do the following from the build directory: + +1. Run `make install` (on POSIX) or + `msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows). +2. `bin/zig build --build-file ../build.zig test` (on POSIX) or + `bin\zig.exe build --build-file ..\build.zig test` (on Windows). + +That runs the whole test suite, which does a lot of extra testing that you +likely won't always need, and can take upwards of 2 hours. This is what the +CI server runs when you make a pull request. + +To save time, you can add the `--help` option to the `zig build` command and +see what options are available. One of the most helpful ones is +`-Dskip-release`. Adding this option to the command in step 2 above will take +the time down from around 2 hours to about 6 minutes, and this is a good +enough amount of testing before making a pull request. + +Another example is choosing a different set of things to test. For example, +`test-std` instead of `test` will only run the standard library tests, and +not the other ones. Combining this suggestion with the previous one, you could +do this: + +`bin/zig build --build-file ../build.zig test-std -Dskip-release` (on POSIX) or +`bin\zig.exe build --build-file ..\build.zig test-std -Dskip-release` (on Windows). + +This will run only the standard library tests, in debug mode only, for all +targets (it will cross-compile the tests for non-native targets but not run +them). + +When making changes to the compiler source code, the most helpful test step to +run is `test-behavior`. When editing documentation it is `docs`. You can find +this information and more in the `--help` menu. @@ -65,6 +65,8 @@ pub fn build(b: *Builder) !void { b.default_step.dependOn(&exe.step); + addLibUserlandStep(b); + const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release; @@ -380,3 +382,28 @@ const Context = struct { dia_guids_lib: []const u8, llvm: LibraryDep, }; + +fn addLibUserlandStep(b: *Builder) void { + // Sadly macOS requires hacks to work around the buggy MACH-O linker code. + const artifact = if (builtin.os == .macosx) + b.addObject("userland", "src-self-hosted/stage1.zig") + else + b.addStaticLibrary("userland", "src-self-hosted/stage1.zig"); + artifact.disable_gen_h = true; + if (builtin.os == .macosx) { + artifact.disable_stack_probing = true; + } else { + artifact.bundle_compiler_rt = true; + } + artifact.setTarget(builtin.arch, builtin.os, builtin.abi); + artifact.linkSystemLibrary("c"); + const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1"); + libuserland_step.dependOn(&artifact.step); + + const output_dir = b.option( + []const u8, + "output-dir", + "For libuserland step, where to put the output", + ) orelse return; + artifact.setOutputDir(output_dir); +} diff --git a/ci/azure/windows_upload b/ci/azure/windows_upload index 088294a180..8478be0e0b 100755 --- a/ci/azure/windows_upload +++ b/ci/azure/windows_upload @@ -6,7 +6,7 @@ set -e if [ "${BUILD_REASON}" != "PullRequest" ]; then cd "$ZIGBUILDDIR" - rm release/*.lib + rm release/*.exe mv ../LICENSE release/ mv ../zig-cache/langref.html release/ mv release/bin/zig.exe release/ diff --git a/cmake/Findclang.cmake b/cmake/Findclang.cmake index 6747e489b4..5555485d89 100644 --- a/cmake/Findclang.cmake +++ b/cmake/Findclang.cmake @@ -44,7 +44,7 @@ else() /usr/local/llvm80/include /mingw64/include) - macro(FIND_AND_ADD_CLANG_LIB _libname_) + macro(FIND_AND_ADD_CLANG_LIB _libname_) string(TOUPPER ${_libname_} _prettylibname_) find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_} PATHS diff --git a/deps/lld/wasm/OutputSections.cpp b/deps/lld/wasm/OutputSections.cpp index 4123d63b74..6b7b18d4ca 100644 --- a/deps/lld/wasm/OutputSections.cpp +++ b/deps/lld/wasm/OutputSections.cpp @@ -111,8 +111,8 @@ void CodeSection::writeTo(uint8_t *Buf) { memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size()); // Write code section bodies - parallelForEach(Functions, - [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); }); + for (const InputChunk *Chunk : Functions) + Chunk->writeTo(Buf); } uint32_t CodeSection::numRelocations() const { @@ -176,7 +176,7 @@ void DataSection::writeTo(uint8_t *Buf) { // Write data section headers memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size()); - parallelForEach(Segments, [&](const OutputSegment *Segment) { + for (const OutputSegment *Segment : Segments) { // Write data segment header uint8_t *SegStart = Buf + Segment->SectionOffset; memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); @@ -184,7 +184,7 @@ void DataSection::writeTo(uint8_t *Buf) { // Write segment data payload for (const InputChunk *Chunk : Segment->InputSegments) Chunk->writeTo(Buf); - }); + } } uint32_t DataSection::numRelocations() const { @@ -232,8 +232,8 @@ void CustomSection::writeTo(uint8_t *Buf) { Buf += NameData.size(); // Write custom sections payload - parallelForEach(InputSections, - [&](const InputSection *Section) { Section->writeTo(Buf); }); + for (const InputSection *Section : InputSections) + Section->writeTo(Buf); } uint32_t CustomSection::numRelocations() const { diff --git a/doc/docgen.zig b/doc/docgen.zig index 0c859e4a15..75c80cc528 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -265,6 +265,7 @@ const SeeAlsoItem = struct { const ExpectedOutcome = enum { Succeed, Fail, + BuildFail, }; const Code = struct { @@ -468,6 +469,8 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Succeed }; } else if (mem.eql(u8, code_kind_str, "exe_err")) { code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Fail }; + } else if (mem.eql(u8, code_kind_str, "exe_build_err")) { + code_kind_id = Code.Id{ .Exe = ExpectedOutcome.BuildFail }; } else if (mem.eql(u8, code_kind_str, "test")) { code_kind_id = Code.Id.Test; } else if (mem.eql(u8, code_kind_str, "test_err")) { @@ -509,6 +512,10 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { target_str = "x86_64-windows"; } else if (mem.eql(u8, end_tag_name, "target_linux_x86_64")) { target_str = "x86_64-linux"; + } else if (mem.eql(u8, end_tag_name, "target_wasm")) { + target_str = "wasm32-freestanding"; + } else if (mem.eql(u8, end_tag_name, "target_wasi")) { + target_str = "wasm32-wasi"; } else if (mem.eql(u8, end_tag_name, "link_libc")) { link_libc = true; } else if (mem.eql(u8, end_tag_name, "code_end")) { @@ -1025,6 +1032,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var tmp_dir_name, "--name", code.name, + "--color", + "on", }); try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", code.name); switch (code.mode) { @@ -1059,14 +1068,52 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } if (code.target_str) |triple| { try build_args.appendSlice([][]const u8{ "-target", triple }); + if (!code.is_inline) { + try out.print(" -target {}", triple); + } + } + if (expected_outcome == .BuildFail) { + const result = try os.ChildProcess.exec( + allocator, + build_args.toSliceConst(), + null, + &env_map, + max_doc_file_size, + ); + switch (result.term) { + os.ChildProcess.Term.Exited => |exit_code| { + if (exit_code == 0) { + warn("{}\nThe following command incorrectly succeeded:\n", result.stderr); + for (build_args.toSliceConst()) |arg| + warn("{} ", arg) + else + warn("\n"); + return parseError(tokenizer, code.source_token, "example incorrectly compiled"); + } + }, + else => { + warn("{}\nThe following command crashed:\n", result.stderr); + for (build_args.toSliceConst()) |arg| + warn("{} ", arg) + else + warn("\n"); + return parseError(tokenizer, code.source_token, "example compile crashed"); + }, + } + const escaped_stderr = try escapeHtml(allocator, result.stderr); + const colored_stderr = try termColor(allocator, escaped_stderr); + try out.print("\n{}</code></pre>\n", colored_stderr); + break :code_block; } _ = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile"); if (code.target_str) |triple| { - if (mem.startsWith(u8, triple, "x86_64-linux") and + if (mem.startsWith(u8, triple, "wasm32") or + mem.startsWith(u8, triple, "x86_64-linux") and (builtin.os != builtin.Os.linux or builtin.arch != builtin.Arch.x86_64)) { // skip execution + try out.print("</code></pre>\n"); break :code_block; } } @@ -1130,6 +1177,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } if (code.target_str) |triple| { try test_args.appendSlice([][]const u8{ "-target", triple }); + try out.print(" -target {}", triple); } const result = exec(allocator, &env_map, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed"); const escaped_stderr = try escapeHtml(allocator, result.stderr); @@ -1310,6 +1358,11 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var }, } + if (code.target_str) |triple| { + try build_args.appendSlice([][]const u8{ "-target", triple }); + try out.print(" -target {}", triple); + } + if (maybe_error_match) |error_match| { const result = try os.ChildProcess.exec(allocator, build_args.toSliceConst(), null, &env_map, max_doc_file_size); switch (result.term) { diff --git a/doc/langref.html.in b/doc/langref.html.in index bb2a67c562..807fe7d6db 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4,11 +4,12 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> <title>Documentation - The Zig Programming Language</title> + <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNSAxMCIgZmlsbD0iI2Y3YTQxZCI+PHBhdGggZD0iTTAsMSBIMy41IFYzIEgyIFY3IEgzLjY4MiBMMS44ODEsOSBIMCBaIE0xNSw5IEgxMS41IFY3IEgxMyBWMyBIMTEuMzE4IEwxMy4xMTksMSBIMTUgWiBNNCwxIEg5LjkxMiBMMTMuMzI4LDAuMDIxIEw3LjA0NSw3IEgxMSBWOSBINS4wODggTDEuNjcyLDkuOTc5IEw3Ljk1NSwzIEg0IFoiLz48L3N2Zz4="/> <style type="text/css"> body{ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; } - a { + a:not(:hover) { text-decoration: none; } table, th, td { @@ -158,13 +159,15 @@ <div id="contents"> {#header_open|Introduction#} <p> - Zig is an open-source programming language designed for <strong>robustness</strong>, - <strong>optimality</strong>, and <strong>clarity</strong>. + Zig is a general-purpose programming language designed for <strong>robustness</strong>, + <strong>optimality</strong>, and <strong>maintainability</strong>. </p> <ul> <li><strong>Robust</strong> - behavior is correct even for edge cases such as out of memory.</li> <li><strong>Optimal</strong> - write programs the best way they can behave and perform.</li> - <li><strong>Clear</strong> - precisely communicate your intent to the compiler and other programmers. The language imposes a low overhead to reading code.</li> + <li><strong>Maintainable</strong> - precisely communicate intent to the compiler and other programmers. + The language imposes a low overhead to reading code and is resilient to changing requirements + and environments.</li> </ul> <p> Often the most efficient way to learn something new is to see examples, so @@ -3125,7 +3128,7 @@ test "while null capture" { while (eventuallyNullSequence()) |value| { sum2 += value; } else { - assert(sum1 == 3); + assert(sum2 == 3); } } @@ -7180,14 +7183,6 @@ pub const FloatMode = enum { {#see_also|Floating Point Operations#} {#header_close#} - {#header_open|@setGlobalLinkage#} - <pre>{#syntax#}@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage){#endsyntax#}</pre> - <p> - {#syntax#}GlobalLinkage{#endsyntax#} can be found with {#syntax#}@import("builtin").GlobalLinkage{#endsyntax#}. - </p> - {#see_also|Compile Variables#} - {#header_close#} - {#header_open|@setRuntimeSafety#} <pre>{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}</pre> <p> @@ -7217,6 +7212,8 @@ test "@setRuntimeSafety" { } } {#code_end#} + <p>Note: it is <a href="https://github.com/ziglang/zig/issues/978">planned</a> to replace + {#syntax#}@setRuntimeSafety{#endsyntax#} with <code>@optimizeFor</code></p> {#header_close#} @@ -7272,6 +7269,10 @@ test "@setRuntimeSafety" { consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or {#syntax#}@typeInfo(T).Int.bits{#endsyntax#}. </p> + <p> + This function measures the size at runtime. For types that are disallowed at runtime, such as + {#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}. + </p> {#see_also|@typeInfo#} {#header_close#} @@ -7360,20 +7361,30 @@ fn List(comptime T: type) type { <pre>{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}</pre> <p> This function truncates bits from an integer type, resulting in a smaller - integer type. + or same-sized integer type. </p> <p> - The following produces a crash in {#link|Debug#} mode and {#link|Undefined Behavior#} in - {#link|ReleaseFast#} mode: + The following produces safety-checked {#link|Undefined Behavior#}: </p> - <pre>{#syntax#}const a: u16 = 0xabcd; -const b: u8 = u8(a);{#endsyntax#}</pre> + {#code_begin|test_err|cast truncated bits#} +test "integer cast panic" { + var a: u16 = 0xabcd; + var b: u8 = @intCast(u8, a); +} + {#code_end#} <p> However this is well defined and working code: </p> - <pre>{#syntax#}const a: u16 = 0xabcd; -const b: u8 = @truncate(u8, a); -// b is now 0xcd{#endsyntax#}</pre> + {#code_begin|test|truncate#} +const std = @import("std"); +const assert = std.debug.assert; + +test "integer truncation" { + var a: u16 = 0xabcd; + var b: u8 = @truncate(u8, a); + assert(b == 0xcd); +} + {#code_end#} <p> This function always truncates the significant bits of the integer, regardless of endianness on the target platform. @@ -8840,20 +8851,21 @@ export fn add(a: i32, b: i32) i32 { return a + b; } {#code_end#} - <p>To make a shared library:</p> + <p>To make a static library:</p> <pre><code class="shell">$ zig build-lib mathtest.zig </code></pre> - <p>To make a static library:</p> - <pre><code class="shell">$ zig build-lib mathtest.zig --static + <p>To make a shared library:</p> + <pre><code class="shell">$ zig build-lib mathtest.zig -dynamic </code></pre> <p>Here is an example with the {#link|Zig Build System#}:</p> <p class="file">test.c</p> <pre><code class="cpp">// This header is generated by zig from mathtest.zig #include "mathtest.h" -#include <assert.h> +#include <stdio.h> int main(int argc, char **argv) { - assert(add(42, 1337) == 1379); + int32_t result = add(42, 1337); + printf("%d\n", result); return 0; }</code></pre> <p class="file">build.zig</p> @@ -8863,10 +8875,10 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); - const exe = b.addCExecutable("test"); - exe.addCompileFlags([][]const u8{"-std=c99"}); - exe.addSourceFile("test.c"); + const exe = b.addExecutable("test", null); + exe.addCSourceFile("test.c", [][]const u8{"-std=c99"}); exe.linkLibrary(lib); + exe.linkSystemLibrary("c"); b.default_step.dependOn(&exe.step); @@ -8877,10 +8889,9 @@ pub fn build(b: *Builder) void { } {#code_end#} <p class="file">terminal</p> - <pre><code class="shell">$ zig build -$ ./test -$ echo $? -0</code></pre> + <pre><code class="shell">$ zig build test +1379 +</code></pre> {#see_also|export#} {#header_close#} {#header_open|Mixing Object Files#} @@ -8947,6 +8958,33 @@ all your base are belong to us</code></pre> {#see_also|Targets|Zig Build System#} {#header_close#} {#header_close#} + {#header_open|WebAssembly#} + {#header_open|Freestanding#} + {#code_begin|exe|wasm#} + {#target_wasm#} +extern fn print(i32) void; + +export fn add(a: i32, b: i32) void { + print(a + b); +} + {#code_end#} + {#header_close#} + {#header_open|WASI#} + {#code_begin|exe|wasi#} + {#target_wasi#} +const std = @import("std"); + +pub fn main() !void { + const args = try std.os.argsAlloc(std.heap.wasm_allocator); + defer std.os.argsFree(std.heap.wasm_allocator, args); + + for (args) |arg, i| { + std.debug.warn("{}: {}\n", i, arg); + } +} + {#code_end#} + {#header_close#} + {#header_close#} {#header_open|Targets#} <p> Zig supports generating code for all targets that LLVM supports. Here is @@ -9430,8 +9468,6 @@ PrimaryExpr IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? -LabeledExpr <- BlockLabel? (Block / LoopExpr) - Block <- LBRACE Statement* RBRACE LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) @@ -9440,6 +9476,8 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? +CurlySuffixExpr <- TypeExpr InitList? + InitList <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE / LBRACE Expr (COMMA Expr)* COMMA? RBRACE @@ -9457,6 +9495,7 @@ PrimaryTypeExpr <- BUILTINIDENTIFIER FnCallArguments / CHAR_LITERAL / ContainerDecl + / DOT IDENTIFIER / ErrorSetDecl / FLOAT / FnProto diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig new file mode 100644 index 0000000000..92fe7b7cd3 --- /dev/null +++ b/src-self-hosted/clang.zig @@ -0,0 +1,866 @@ +pub const struct_ZigClangAPValue = @OpaqueType(); +pub const struct_ZigClangAPSInt = @OpaqueType(); +pub const struct_ZigClangASTContext = @OpaqueType(); +pub const struct_ZigClangASTUnit = @OpaqueType(); +pub const struct_ZigClangArraySubscriptExpr = @OpaqueType(); +pub const struct_ZigClangArrayType = @OpaqueType(); +pub const struct_ZigClangAttributedType = @OpaqueType(); +pub const struct_ZigClangBinaryOperator = @OpaqueType(); +pub const struct_ZigClangBreakStmt = @OpaqueType(); +pub const struct_ZigClangBuiltinType = @OpaqueType(); +pub const struct_ZigClangCStyleCastExpr = @OpaqueType(); +pub const struct_ZigClangCallExpr = @OpaqueType(); +pub const struct_ZigClangCaseStmt = @OpaqueType(); +pub const struct_ZigClangCompoundAssignOperator = @OpaqueType(); +pub const ZigClangCompoundStmt = @OpaqueType(); +pub const struct_ZigClangConditionalOperator = @OpaqueType(); +pub const struct_ZigClangConstantArrayType = @OpaqueType(); +pub const struct_ZigClangContinueStmt = @OpaqueType(); +pub const struct_ZigClangDecayedType = @OpaqueType(); +pub const struct_ZigClangDecl = @OpaqueType(); +pub const struct_ZigClangDeclRefExpr = @OpaqueType(); +pub const struct_ZigClangDeclStmt = @OpaqueType(); +pub const struct_ZigClangDefaultStmt = @OpaqueType(); +pub const struct_ZigClangDiagnosticOptions = @OpaqueType(); +pub const struct_ZigClangDiagnosticsEngine = @OpaqueType(); +pub const struct_ZigClangDoStmt = @OpaqueType(); +pub const struct_ZigClangElaboratedType = @OpaqueType(); +pub const struct_ZigClangEnumConstantDecl = @OpaqueType(); +pub const struct_ZigClangEnumDecl = @OpaqueType(); +pub const struct_ZigClangEnumType = @OpaqueType(); +pub const struct_ZigClangExpr = @OpaqueType(); +pub const struct_ZigClangFieldDecl = @OpaqueType(); +pub const struct_ZigClangFileID = @OpaqueType(); +pub const struct_ZigClangForStmt = @OpaqueType(); +pub const struct_ZigClangFullSourceLoc = @OpaqueType(); +pub const ZigClangFunctionDecl = @OpaqueType(); +pub const struct_ZigClangFunctionProtoType = @OpaqueType(); +pub const struct_ZigClangIfStmt = @OpaqueType(); +pub const struct_ZigClangImplicitCastExpr = @OpaqueType(); +pub const struct_ZigClangIncompleteArrayType = @OpaqueType(); +pub const struct_ZigClangIntegerLiteral = @OpaqueType(); +pub const struct_ZigClangMacroDefinitionRecord = @OpaqueType(); +pub const struct_ZigClangMemberExpr = @OpaqueType(); +pub const struct_ZigClangNamedDecl = @OpaqueType(); +pub const struct_ZigClangNone = @OpaqueType(); +pub const struct_ZigClangPCHContainerOperations = @OpaqueType(); +pub const struct_ZigClangParenExpr = @OpaqueType(); +pub const struct_ZigClangParenType = @OpaqueType(); +pub const struct_ZigClangParmVarDecl = @OpaqueType(); +pub const struct_ZigClangPointerType = @OpaqueType(); +pub const struct_ZigClangPreprocessedEntity = @OpaqueType(); +pub const struct_ZigClangRecordDecl = @OpaqueType(); +pub const struct_ZigClangRecordType = @OpaqueType(); +pub const struct_ZigClangReturnStmt = @OpaqueType(); +pub const struct_ZigClangSkipFunctionBodiesScope = @OpaqueType(); +pub const struct_ZigClangSourceManager = @OpaqueType(); +pub const struct_ZigClangSourceRange = @OpaqueType(); +pub const struct_ZigClangStmt = @OpaqueType(); +pub const struct_ZigClangStringLiteral = @OpaqueType(); +pub const struct_ZigClangStringRef = @OpaqueType(); +pub const struct_ZigClangSwitchStmt = @OpaqueType(); +pub const struct_ZigClangTagDecl = @OpaqueType(); +pub const struct_ZigClangType = @OpaqueType(); +pub const struct_ZigClangTypedefNameDecl = @OpaqueType(); +pub const struct_ZigClangTypedefType = @OpaqueType(); +pub const struct_ZigClangUnaryExprOrTypeTraitExpr = @OpaqueType(); +pub const struct_ZigClangUnaryOperator = @OpaqueType(); +pub const struct_ZigClangValueDecl = @OpaqueType(); +pub const struct_ZigClangVarDecl = @OpaqueType(); +pub const struct_ZigClangWhileStmt = @OpaqueType(); +pub const ZigClangFunctionType = @OpaqueType(); + +pub const ZigClangBO = extern enum { + PtrMemD, + PtrMemI, + Mul, + Div, + Rem, + Add, + Sub, + Shl, + Shr, + Cmp, + LT, + GT, + LE, + GE, + EQ, + NE, + And, + Xor, + Or, + LAnd, + LOr, + Assign, + MulAssign, + DivAssign, + RemAssign, + AddAssign, + SubAssign, + ShlAssign, + ShrAssign, + AndAssign, + XorAssign, + OrAssign, + Comma, +}; + +pub const ZigClangUO = extern enum { + PostInc, + PostDec, + PreInc, + PreDec, + AddrOf, + Deref, + Plus, + Minus, + Not, + LNot, + Real, + Imag, + Extension, + Coawait, +}; + +pub const ZigClangTypeClass = extern enum { + Builtin, + Complex, + Pointer, + BlockPointer, + LValueReference, + RValueReference, + MemberPointer, + ConstantArray, + IncompleteArray, + VariableArray, + DependentSizedArray, + DependentSizedExtVector, + DependentAddressSpace, + Vector, + DependentVector, + ExtVector, + FunctionProto, + FunctionNoProto, + UnresolvedUsing, + Paren, + Typedef, + Adjusted, + Decayed, + TypeOfExpr, + TypeOf, + Decltype, + UnaryTransform, + Record, + Enum, + Elaborated, + Attributed, + TemplateTypeParm, + SubstTemplateTypeParm, + SubstTemplateTypeParmPack, + TemplateSpecialization, + Auto, + DeducedTemplateSpecialization, + InjectedClassName, + DependentName, + DependentTemplateSpecialization, + PackExpansion, + ObjCTypeParam, + ObjCObject, + ObjCInterface, + ObjCObjectPointer, + Pipe, + Atomic, +}; + +pub const ZigClangStmtClass = extern enum { + NoStmtClass = 0, + GCCAsmStmtClass = 1, + MSAsmStmtClass = 2, + AttributedStmtClass = 3, + BreakStmtClass = 4, + CXXCatchStmtClass = 5, + CXXForRangeStmtClass = 6, + CXXTryStmtClass = 7, + CapturedStmtClass = 8, + CompoundStmtClass = 9, + ContinueStmtClass = 10, + CoreturnStmtClass = 11, + CoroutineBodyStmtClass = 12, + DeclStmtClass = 13, + DoStmtClass = 14, + BinaryConditionalOperatorClass = 15, + ConditionalOperatorClass = 16, + AddrLabelExprClass = 17, + ArrayInitIndexExprClass = 18, + ArrayInitLoopExprClass = 19, + ArraySubscriptExprClass = 20, + ArrayTypeTraitExprClass = 21, + AsTypeExprClass = 22, + AtomicExprClass = 23, + BinaryOperatorClass = 24, + CompoundAssignOperatorClass = 25, + BlockExprClass = 26, + CXXBindTemporaryExprClass = 27, + CXXBoolLiteralExprClass = 28, + CXXConstructExprClass = 29, + CXXTemporaryObjectExprClass = 30, + CXXDefaultArgExprClass = 31, + CXXDefaultInitExprClass = 32, + CXXDeleteExprClass = 33, + CXXDependentScopeMemberExprClass = 34, + CXXFoldExprClass = 35, + CXXInheritedCtorInitExprClass = 36, + CXXNewExprClass = 37, + CXXNoexceptExprClass = 38, + CXXNullPtrLiteralExprClass = 39, + CXXPseudoDestructorExprClass = 40, + CXXScalarValueInitExprClass = 41, + CXXStdInitializerListExprClass = 42, + CXXThisExprClass = 43, + CXXThrowExprClass = 44, + CXXTypeidExprClass = 45, + CXXUnresolvedConstructExprClass = 46, + CXXUuidofExprClass = 47, + CallExprClass = 48, + CUDAKernelCallExprClass = 49, + CXXMemberCallExprClass = 50, + CXXOperatorCallExprClass = 51, + UserDefinedLiteralClass = 52, + CStyleCastExprClass = 53, + CXXFunctionalCastExprClass = 54, + CXXConstCastExprClass = 55, + CXXDynamicCastExprClass = 56, + CXXReinterpretCastExprClass = 57, + CXXStaticCastExprClass = 58, + ObjCBridgedCastExprClass = 59, + ImplicitCastExprClass = 60, + CharacterLiteralClass = 61, + ChooseExprClass = 62, + CompoundLiteralExprClass = 63, + ConvertVectorExprClass = 64, + CoawaitExprClass = 65, + CoyieldExprClass = 66, + DeclRefExprClass = 67, + DependentCoawaitExprClass = 68, + DependentScopeDeclRefExprClass = 69, + DesignatedInitExprClass = 70, + DesignatedInitUpdateExprClass = 71, + ExpressionTraitExprClass = 72, + ExtVectorElementExprClass = 73, + FixedPointLiteralClass = 74, + FloatingLiteralClass = 75, + ConstantExprClass = 76, + ExprWithCleanupsClass = 77, + FunctionParmPackExprClass = 78, + GNUNullExprClass = 79, + GenericSelectionExprClass = 80, + ImaginaryLiteralClass = 81, + ImplicitValueInitExprClass = 82, + InitListExprClass = 83, + IntegerLiteralClass = 84, + LambdaExprClass = 85, + MSPropertyRefExprClass = 86, + MSPropertySubscriptExprClass = 87, + MaterializeTemporaryExprClass = 88, + MemberExprClass = 89, + NoInitExprClass = 90, + OMPArraySectionExprClass = 91, + ObjCArrayLiteralClass = 92, + ObjCAvailabilityCheckExprClass = 93, + ObjCBoolLiteralExprClass = 94, + ObjCBoxedExprClass = 95, + ObjCDictionaryLiteralClass = 96, + ObjCEncodeExprClass = 97, + ObjCIndirectCopyRestoreExprClass = 98, + ObjCIsaExprClass = 99, + ObjCIvarRefExprClass = 100, + ObjCMessageExprClass = 101, + ObjCPropertyRefExprClass = 102, + ObjCProtocolExprClass = 103, + ObjCSelectorExprClass = 104, + ObjCStringLiteralClass = 105, + ObjCSubscriptRefExprClass = 106, + OffsetOfExprClass = 107, + OpaqueValueExprClass = 108, + UnresolvedLookupExprClass = 109, + UnresolvedMemberExprClass = 110, + PackExpansionExprClass = 111, + ParenExprClass = 112, + ParenListExprClass = 113, + PredefinedExprClass = 114, + PseudoObjectExprClass = 115, + ShuffleVectorExprClass = 116, + SizeOfPackExprClass = 117, + StmtExprClass = 118, + StringLiteralClass = 119, + SubstNonTypeTemplateParmExprClass = 120, + SubstNonTypeTemplateParmPackExprClass = 121, + TypeTraitExprClass = 122, + TypoExprClass = 123, + UnaryExprOrTypeTraitExprClass = 124, + UnaryOperatorClass = 125, + VAArgExprClass = 126, + ForStmtClass = 127, + GotoStmtClass = 128, + IfStmtClass = 129, + IndirectGotoStmtClass = 130, + LabelStmtClass = 131, + MSDependentExistsStmtClass = 132, + NullStmtClass = 133, + OMPAtomicDirectiveClass = 134, + OMPBarrierDirectiveClass = 135, + OMPCancelDirectiveClass = 136, + OMPCancellationPointDirectiveClass = 137, + OMPCriticalDirectiveClass = 138, + OMPFlushDirectiveClass = 139, + OMPDistributeDirectiveClass = 140, + OMPDistributeParallelForDirectiveClass = 141, + OMPDistributeParallelForSimdDirectiveClass = 142, + OMPDistributeSimdDirectiveClass = 143, + OMPForDirectiveClass = 144, + OMPForSimdDirectiveClass = 145, + OMPParallelForDirectiveClass = 146, + OMPParallelForSimdDirectiveClass = 147, + OMPSimdDirectiveClass = 148, + OMPTargetParallelForSimdDirectiveClass = 149, + OMPTargetSimdDirectiveClass = 150, + OMPTargetTeamsDistributeDirectiveClass = 151, + OMPTargetTeamsDistributeParallelForDirectiveClass = 152, + OMPTargetTeamsDistributeParallelForSimdDirectiveClass = 153, + OMPTargetTeamsDistributeSimdDirectiveClass = 154, + OMPTaskLoopDirectiveClass = 155, + OMPTaskLoopSimdDirectiveClass = 156, + OMPTeamsDistributeDirectiveClass = 157, + OMPTeamsDistributeParallelForDirectiveClass = 158, + OMPTeamsDistributeParallelForSimdDirectiveClass = 159, + OMPTeamsDistributeSimdDirectiveClass = 160, + OMPMasterDirectiveClass = 161, + OMPOrderedDirectiveClass = 162, + OMPParallelDirectiveClass = 163, + OMPParallelSectionsDirectiveClass = 164, + OMPSectionDirectiveClass = 165, + OMPSectionsDirectiveClass = 166, + OMPSingleDirectiveClass = 167, + OMPTargetDataDirectiveClass = 168, + OMPTargetDirectiveClass = 169, + OMPTargetEnterDataDirectiveClass = 170, + OMPTargetExitDataDirectiveClass = 171, + OMPTargetParallelDirectiveClass = 172, + OMPTargetParallelForDirectiveClass = 173, + OMPTargetTeamsDirectiveClass = 174, + OMPTargetUpdateDirectiveClass = 175, + OMPTaskDirectiveClass = 176, + OMPTaskgroupDirectiveClass = 177, + OMPTaskwaitDirectiveClass = 178, + OMPTaskyieldDirectiveClass = 179, + OMPTeamsDirectiveClass = 180, + ObjCAtCatchStmtClass = 181, + ObjCAtFinallyStmtClass = 182, + ObjCAtSynchronizedStmtClass = 183, + ObjCAtThrowStmtClass = 184, + ObjCAtTryStmtClass = 185, + ObjCAutoreleasePoolStmtClass = 186, + ObjCForCollectionStmtClass = 187, + ReturnStmtClass = 188, + SEHExceptStmtClass = 189, + SEHFinallyStmtClass = 190, + SEHLeaveStmtClass = 191, + SEHTryStmtClass = 192, + CaseStmtClass = 193, + DefaultStmtClass = 194, + SwitchStmtClass = 195, + WhileStmtClass = 196, +}; + +pub const ZigClangCK = extern enum { + Dependent, + BitCast, + LValueBitCast, + LValueToRValue, + NoOp, + BaseToDerived, + DerivedToBase, + UncheckedDerivedToBase, + Dynamic, + ToUnion, + ArrayToPointerDecay, + FunctionToPointerDecay, + NullToPointer, + NullToMemberPointer, + BaseToDerivedMemberPointer, + DerivedToBaseMemberPointer, + MemberPointerToBoolean, + ReinterpretMemberPointer, + UserDefinedConversion, + ConstructorConversion, + IntegralToPointer, + PointerToIntegral, + PointerToBoolean, + ToVoid, + VectorSplat, + IntegralCast, + IntegralToBoolean, + IntegralToFloating, + FixedPointCast, + FixedPointToBoolean, + FloatingToIntegral, + FloatingToBoolean, + BooleanToSignedIntegral, + FloatingCast, + CPointerToObjCPointerCast, + BlockPointerToObjCPointerCast, + AnyPointerToBlockPointerCast, + ObjCObjectLValueCast, + FloatingRealToComplex, + FloatingComplexToReal, + FloatingComplexToBoolean, + FloatingComplexCast, + FloatingComplexToIntegralComplex, + IntegralRealToComplex, + IntegralComplexToReal, + IntegralComplexToBoolean, + IntegralComplexCast, + IntegralComplexToFloatingComplex, + ARCProduceObject, + ARCConsumeObject, + ARCReclaimReturnedObject, + ARCExtendBlockObject, + AtomicToNonAtomic, + NonAtomicToAtomic, + CopyAndAutoreleaseBlockObject, + BuiltinFnToFnPtr, + ZeroToOCLOpaqueType, + AddressSpaceConversion, + IntToOCLSampler, +}; + +pub const ZigClangAPValueKind = extern enum { + Uninitialized, + Int, + Float, + ComplexInt, + ComplexFloat, + LValue, + Vector, + Array, + Struct, + Union, + MemberPointer, + AddrLabelDiff, +}; + +pub extern fn ZigClangSourceManager_getSpellingLoc(arg0: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; +pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*]const u8; +pub extern fn ZigClangSourceManager_getSpellingLineNumber(arg0: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; +pub extern fn ZigClangSourceManager_getSpellingColumnNumber(arg0: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; +pub extern fn ZigClangSourceManager_getCharacterData(arg0: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*c]const u8; +pub extern fn ZigClangASTContext_getPointerType(arg0: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType; +pub extern fn ZigClangASTUnit_getASTContext(arg0: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext; +pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; +pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool; +pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) ?*const struct_ZigClangRecordDecl; +pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl; +pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; +pub extern fn ZigClangEnumDecl_getCanonicalDecl(arg0: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; +pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(arg0: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl; +pub extern fn ZigClangRecordDecl_getDefinition(arg0: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl; +pub extern fn ZigClangEnumDecl_getDefinition(arg0: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl; +pub extern fn ZigClangRecordDecl_getLocation(arg0: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation; +pub extern fn ZigClangEnumDecl_getLocation(arg0: ?*const struct_ZigClangEnumDecl) struct_ZigClangSourceLocation; +pub extern fn ZigClangTypedefNameDecl_getLocation(arg0: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangSourceLocation; +pub extern fn ZigClangDecl_getLocation(self: *const ZigClangDecl) ZigClangSourceLocation; +pub extern fn ZigClangRecordDecl_isUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool; +pub extern fn ZigClangRecordDecl_isStruct(record_decl: ?*const struct_ZigClangRecordDecl) bool; +pub extern fn ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool; +pub extern fn ZigClangEnumDecl_getIntegerType(arg0: ?*const struct_ZigClangEnumDecl) struct_ZigClangQualType; +pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8; +pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool; +pub extern fn ZigClangTypedefType_getDecl(arg0: ?*const struct_ZigClangTypedefType) ?*const struct_ZigClangTypedefNameDecl; +pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(arg0: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType; +pub extern fn ZigClangQualType_getCanonicalType(arg0: struct_ZigClangQualType) struct_ZigClangQualType; +pub extern fn ZigClangQualType_getTypePtr(self: struct_ZigClangQualType) *const struct_ZigClangType; +pub extern fn ZigClangQualType_addConst(arg0: [*c]struct_ZigClangQualType) void; +pub extern fn ZigClangQualType_eq(arg0: struct_ZigClangQualType, arg1: struct_ZigClangQualType) bool; +pub extern fn ZigClangQualType_isConstQualified(arg0: struct_ZigClangQualType) bool; +pub extern fn ZigClangQualType_isVolatileQualified(arg0: struct_ZigClangQualType) bool; +pub extern fn ZigClangQualType_isRestrictQualified(arg0: struct_ZigClangQualType) bool; +pub extern fn ZigClangType_getTypeClass(self: ?*const struct_ZigClangType) ZigClangTypeClass; +pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool; +pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*]const u8; +pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; +pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass; +pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool; +pub extern fn ZigClangExpr_getStmtClass(self: ?*const struct_ZigClangExpr) ZigClangStmtClass; +pub extern fn ZigClangExpr_getType(self: ?*const struct_ZigClangExpr) struct_ZigClangQualType; +pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation; +pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind; +pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) ?*const struct_ZigClangAPSInt; +pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint; +pub extern fn ZigClangAPValue_getArrayInitializedElt(self: ?*const struct_ZigClangAPValue, i: c_uint) ?*const struct_ZigClangAPValue; +pub extern fn ZigClangAPValue_getArrayFiller(self: ?*const struct_ZigClangAPValue) ?*const struct_ZigClangAPValue; +pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint; +pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase; +pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool; +pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool; +pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt; +pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void; +pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*c]const u64; +pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint; +pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr; +pub extern fn ZigClangASTUnit_delete(arg0: ?*struct_ZigClangASTUnit) void; + +pub extern fn ZigClangFunctionDecl_getType(self: *const ZigClangFunctionDecl) struct_ZigClangQualType; +pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl) struct_ZigClangSourceLocation; +pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool; +pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass; +pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl; +pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt; + +pub extern fn ZigClangBuiltinType_getKind(self: *const struct_ZigClangBuiltinType) ZigClangBuiltinTypeKind; + +pub extern fn ZigClangFunctionType_getNoReturnAttr(self: *const ZigClangFunctionType) bool; +pub extern fn ZigClangFunctionType_getCallConv(self: *const ZigClangFunctionType) ZigClangCallingConv; +pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionType) ZigClangQualType; + +pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool; +pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint; +pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType; + +pub const ZigClangSourceLocation = struct_ZigClangSourceLocation; +pub const ZigClangQualType = struct_ZigClangQualType; +pub const ZigClangAPValueLValueBase = struct_ZigClangAPValueLValueBase; +pub const ZigClangAPValue = struct_ZigClangAPValue; +pub const ZigClangAPSInt = struct_ZigClangAPSInt; +pub const ZigClangASTContext = struct_ZigClangASTContext; +pub const ZigClangASTUnit = struct_ZigClangASTUnit; +pub const ZigClangArraySubscriptExpr = struct_ZigClangArraySubscriptExpr; +pub const ZigClangArrayType = struct_ZigClangArrayType; +pub const ZigClangAttributedType = struct_ZigClangAttributedType; +pub const ZigClangBinaryOperator = struct_ZigClangBinaryOperator; +pub const ZigClangBreakStmt = struct_ZigClangBreakStmt; +pub const ZigClangBuiltinType = struct_ZigClangBuiltinType; +pub const ZigClangCStyleCastExpr = struct_ZigClangCStyleCastExpr; +pub const ZigClangCallExpr = struct_ZigClangCallExpr; +pub const ZigClangCaseStmt = struct_ZigClangCaseStmt; +pub const ZigClangCompoundAssignOperator = struct_ZigClangCompoundAssignOperator; +pub const ZigClangConditionalOperator = struct_ZigClangConditionalOperator; +pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType; +pub const ZigClangContinueStmt = struct_ZigClangContinueStmt; +pub const ZigClangDecayedType = struct_ZigClangDecayedType; +pub const ZigClangDecl = struct_ZigClangDecl; +pub const ZigClangDeclRefExpr = struct_ZigClangDeclRefExpr; +pub const ZigClangDeclStmt = struct_ZigClangDeclStmt; +pub const ZigClangDefaultStmt = struct_ZigClangDefaultStmt; +pub const ZigClangDiagnosticOptions = struct_ZigClangDiagnosticOptions; +pub const ZigClangDiagnosticsEngine = struct_ZigClangDiagnosticsEngine; +pub const ZigClangDoStmt = struct_ZigClangDoStmt; +pub const ZigClangElaboratedType = struct_ZigClangElaboratedType; +pub const ZigClangEnumConstantDecl = struct_ZigClangEnumConstantDecl; +pub const ZigClangEnumDecl = struct_ZigClangEnumDecl; +pub const ZigClangEnumType = struct_ZigClangEnumType; +pub const ZigClangExpr = struct_ZigClangExpr; +pub const ZigClangFieldDecl = struct_ZigClangFieldDecl; +pub const ZigClangFileID = struct_ZigClangFileID; +pub const ZigClangForStmt = struct_ZigClangForStmt; +pub const ZigClangFullSourceLoc = struct_ZigClangFullSourceLoc; +pub const ZigClangFunctionProtoType = struct_ZigClangFunctionProtoType; +pub const ZigClangIfStmt = struct_ZigClangIfStmt; +pub const ZigClangImplicitCastExpr = struct_ZigClangImplicitCastExpr; +pub const ZigClangIncompleteArrayType = struct_ZigClangIncompleteArrayType; +pub const ZigClangIntegerLiteral = struct_ZigClangIntegerLiteral; +pub const ZigClangMacroDefinitionRecord = struct_ZigClangMacroDefinitionRecord; +pub const ZigClangMemberExpr = struct_ZigClangMemberExpr; +pub const ZigClangNamedDecl = struct_ZigClangNamedDecl; +pub const ZigClangNone = struct_ZigClangNone; +pub const ZigClangPCHContainerOperations = struct_ZigClangPCHContainerOperations; +pub const ZigClangParenExpr = struct_ZigClangParenExpr; +pub const ZigClangParenType = struct_ZigClangParenType; +pub const ZigClangParmVarDecl = struct_ZigClangParmVarDecl; +pub const ZigClangPointerType = struct_ZigClangPointerType; +pub const ZigClangPreprocessedEntity = struct_ZigClangPreprocessedEntity; +pub const ZigClangRecordDecl = struct_ZigClangRecordDecl; +pub const ZigClangRecordType = struct_ZigClangRecordType; +pub const ZigClangReturnStmt = struct_ZigClangReturnStmt; +pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope; +pub const ZigClangSourceManager = struct_ZigClangSourceManager; +pub const ZigClangSourceRange = struct_ZigClangSourceRange; +pub const ZigClangStmt = struct_ZigClangStmt; +pub const ZigClangStringLiteral = struct_ZigClangStringLiteral; +pub const ZigClangStringRef = struct_ZigClangStringRef; +pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt; +pub const ZigClangTagDecl = struct_ZigClangTagDecl; +pub const ZigClangType = struct_ZigClangType; +pub const ZigClangTypedefNameDecl = struct_ZigClangTypedefNameDecl; +pub const ZigClangTypedefType = struct_ZigClangTypedefType; +pub const ZigClangUnaryExprOrTypeTraitExpr = struct_ZigClangUnaryExprOrTypeTraitExpr; +pub const ZigClangUnaryOperator = struct_ZigClangUnaryOperator; +pub const ZigClangValueDecl = struct_ZigClangValueDecl; +pub const ZigClangVarDecl = struct_ZigClangVarDecl; +pub const ZigClangWhileStmt = struct_ZigClangWhileStmt; + +pub const struct_ZigClangSourceLocation = extern struct { + ID: c_uint, +}; + +pub const Stage2ErrorMsg = extern struct { + filename_ptr: ?[*]const u8, + filename_len: usize, + msg_ptr: [*]const u8, + msg_len: usize, + // valid until the ASTUnit is freed + source: ?[*]const u8, + // 0 based + line: c_uint, + // 0 based + column: c_uint, + // byte offset into source + offset: c_uint, +}; +pub extern fn ZigClangErrorMsg_delete(ptr: [*c]Stage2ErrorMsg, len: usize) void; + +pub extern fn ZigClangLoadFromCommandLine( + args_begin: [*]?[*]const u8, + args_end: [*]?[*]const u8, + errors_ptr: *[*]Stage2ErrorMsg, + errors_len: *usize, + resources_path: [*c]const u8, +) ?*ZigClangASTUnit; + +pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind; +pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*]const u8; + +pub const ZigClangDeclKind = extern enum { + AccessSpec, + Block, + Captured, + ClassScopeFunctionSpecialization, + Empty, + Export, + ExternCContext, + FileScopeAsm, + Friend, + FriendTemplate, + Import, + LinkageSpec, + Label, + Namespace, + NamespaceAlias, + ObjCCompatibleAlias, + ObjCCategory, + ObjCCategoryImpl, + ObjCImplementation, + ObjCInterface, + ObjCProtocol, + ObjCMethod, + ObjCProperty, + BuiltinTemplate, + ClassTemplate, + FunctionTemplate, + TypeAliasTemplate, + VarTemplate, + TemplateTemplateParm, + Enum, + Record, + CXXRecord, + ClassTemplateSpecialization, + ClassTemplatePartialSpecialization, + TemplateTypeParm, + ObjCTypeParam, + TypeAlias, + Typedef, + UnresolvedUsingTypename, + Using, + UsingDirective, + UsingPack, + UsingShadow, + ConstructorUsingShadow, + Binding, + Field, + ObjCAtDefsField, + ObjCIvar, + Function, + CXXDeductionGuide, + CXXMethod, + CXXConstructor, + CXXConversion, + CXXDestructor, + MSProperty, + NonTypeTemplateParm, + Var, + Decomposition, + ImplicitParam, + OMPCapturedExpr, + ParmVar, + VarTemplateSpecialization, + VarTemplatePartialSpecialization, + EnumConstant, + IndirectField, + OMPDeclareReduction, + UnresolvedUsingValue, + OMPRequires, + OMPThreadPrivate, + ObjCPropertyImpl, + PragmaComment, + PragmaDetectMismatch, + StaticAssert, + TranslationUnit, +}; + +pub const struct_ZigClangQualType = extern struct { + ptr: ?*c_void, +}; + +pub const ZigClangBuiltinTypeKind = extern enum { + OCLImage1dRO, + OCLImage1dArrayRO, + OCLImage1dBufferRO, + OCLImage2dRO, + OCLImage2dArrayRO, + OCLImage2dDepthRO, + OCLImage2dArrayDepthRO, + OCLImage2dMSAARO, + OCLImage2dArrayMSAARO, + OCLImage2dMSAADepthRO, + OCLImage2dArrayMSAADepthRO, + OCLImage3dRO, + OCLImage1dWO, + OCLImage1dArrayWO, + OCLImage1dBufferWO, + OCLImage2dWO, + OCLImage2dArrayWO, + OCLImage2dDepthWO, + OCLImage2dArrayDepthWO, + OCLImage2dMSAAWO, + OCLImage2dArrayMSAAWO, + OCLImage2dMSAADepthWO, + OCLImage2dArrayMSAADepthWO, + OCLImage3dWO, + OCLImage1dRW, + OCLImage1dArrayRW, + OCLImage1dBufferRW, + OCLImage2dRW, + OCLImage2dArrayRW, + OCLImage2dDepthRW, + OCLImage2dArrayDepthRW, + OCLImage2dMSAARW, + OCLImage2dArrayMSAARW, + OCLImage2dMSAADepthRW, + OCLImage2dArrayMSAADepthRW, + OCLImage3dRW, + OCLIntelSubgroupAVCMcePayload, + OCLIntelSubgroupAVCImePayload, + OCLIntelSubgroupAVCRefPayload, + OCLIntelSubgroupAVCSicPayload, + OCLIntelSubgroupAVCMceResult, + OCLIntelSubgroupAVCImeResult, + OCLIntelSubgroupAVCRefResult, + OCLIntelSubgroupAVCSicResult, + OCLIntelSubgroupAVCImeResultSingleRefStreamout, + OCLIntelSubgroupAVCImeResultDualRefStreamout, + OCLIntelSubgroupAVCImeSingleRefStreamin, + OCLIntelSubgroupAVCImeDualRefStreamin, + Void, + Bool, + Char_U, + UChar, + WChar_U, + Char8, + Char16, + Char32, + UShort, + UInt, + ULong, + ULongLong, + UInt128, + Char_S, + SChar, + WChar_S, + Short, + Int, + Long, + LongLong, + Int128, + ShortAccum, + Accum, + LongAccum, + UShortAccum, + UAccum, + ULongAccum, + ShortFract, + Fract, + LongFract, + UShortFract, + UFract, + ULongFract, + SatShortAccum, + SatAccum, + SatLongAccum, + SatUShortAccum, + SatUAccum, + SatULongAccum, + SatShortFract, + SatFract, + SatLongFract, + SatUShortFract, + SatUFract, + SatULongFract, + Half, + Float, + Double, + LongDouble, + Float16, + Float128, + NullPtr, + ObjCId, + ObjCClass, + ObjCSel, + OCLSampler, + OCLEvent, + OCLClkEvent, + OCLQueue, + OCLReserveID, + Dependent, + Overload, + BoundMember, + PseudoObject, + UnknownAny, + BuiltinFn, + ARCUnbridgedCast, + OMPArraySection, +}; + +pub const ZigClangCallingConv = extern enum { + C, + X86StdCall, + X86FastCall, + X86ThisCall, + X86VectorCall, + X86Pascal, + Win64, + X86_64SysV, + X86RegCall, + AAPCS, + AAPCS_VFP, + IntelOclBicc, + SpirFunction, + OpenCLKernel, + Swift, + PreserveMost, + PreserveAll, + AArch64VectorCall, +}; + +pub const ZigClangStorageClass = extern enum { + None, + Extern, + Static, + PrivateExtern, + Auto, + Register, +}; + +pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangStmt; + +pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; +pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 478edce020..7a30bbad98 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -569,9 +569,9 @@ pub const Compilation = struct { 'i', 'u' => blk: { for (name[1..]) |byte| switch (byte) { - '0'...'9' => {}, - else => break :blk, - }; + '0'...'9' => {}, + else => break :blk, + }; const is_signed = name[0] == 'i'; const bit_count = std.fmt.parseUnsigned(u32, name[1..], 10) catch |err| switch (err) { error.Overflow => return error.Overflow, @@ -841,11 +841,9 @@ pub const Compilation = struct { }; errdefer self.gpa().free(source_code); - const tree = try self.gpa().create(ast.Tree); - tree.* = try std.zig.parse(self.gpa(), source_code); + const tree = try std.zig.parse(self.gpa(), source_code); errdefer { tree.deinit(); - self.gpa().destroy(tree); } break :blk try Scope.AstTree.create(self, tree, root_scope); diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 4c3edf6d5d..cbbf73f3f5 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -625,7 +625,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size); defer allocator.free(source_code); - var tree = std.zig.parse(allocator, source_code) catch |err| { + const tree = std.zig.parse(allocator, source_code) catch |err| { try stderr.print("error parsing stdin: {}\n", err); os.exit(1); }; @@ -633,7 +633,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { var error_it = tree.errors.iterator(0); while (error_it.next()) |parse_error| { - const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>"); + const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>"); defer msg.destroy(); try msg.printToFile(stderr_file, color); @@ -642,12 +642,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { os.exit(1); } if (flags.present("check")) { - const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree); + const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree); const code = if (anything_changed) u8(1) else u8(0); os.exit(code); } - _ = try std.zig.render(allocator, stdout, &tree); + _ = try std.zig.render(allocator, stdout, tree); return; } @@ -768,7 +768,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro }; defer fmt.loop.allocator.free(source_code); - var tree = std.zig.parse(fmt.loop.allocator, source_code) catch |err| { + const tree = std.zig.parse(fmt.loop.allocator, source_code) catch |err| { try stderr.print("error parsing file '{}': {}\n", file_path, err); fmt.any_error = true; return; @@ -777,7 +777,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro var error_it = tree.errors.iterator(0); while (error_it.next()) |parse_error| { - const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path); + const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, tree, file_path); defer fmt.loop.allocator.destroy(msg); try msg.printToFile(stderr_file, fmt.color); @@ -788,7 +788,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro } if (check_mode) { - const anything_changed = try std.zig.render(fmt.loop.allocator, io.null_out_stream, &tree); + const anything_changed = try std.zig.render(fmt.loop.allocator, io.null_out_stream, tree); if (anything_changed) { try stderr.print("{}\n", file_path); fmt.any_error = true; @@ -798,7 +798,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro const baf = try io.BufferedAtomicFile.create(fmt.loop.allocator, file_path); defer baf.destroy(); - const anything_changed = try std.zig.render(fmt.loop.allocator, baf.stream(), &tree); + const anything_changed = try std.zig.render(fmt.loop.allocator, baf.stream(), tree); if (anything_changed) { try stderr.print("{}\n", file_path); try baf.finish(); @@ -858,7 +858,7 @@ fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { try stdout.write(usage); } -const info_zen = +pub const info_zen = \\ \\ * Communicate intent precisely. \\ * Edge cases matter. diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig index 9a84ad256e..4ff3e303a2 100644 --- a/src-self-hosted/scope.zig +++ b/src-self-hosted/scope.zig @@ -163,7 +163,6 @@ pub const Scope = struct { pub fn destroy(self: *AstTree, comp: *Compilation) void { comp.gpa().free(self.tree.source); self.tree.deinit(); - comp.gpa().destroy(self.tree); comp.gpa().destroy(self); } diff --git a/std/special/fmt_runner.zig b/src-self-hosted/stage1.zig index f0ed6704ed..da2dcb414c 100644 --- a/std/special/fmt_runner.zig +++ b/src-self-hosted/stage1.zig @@ -1,32 +1,148 @@ +// This is Zig code that is used by both stage1 and stage2. +// The prototypes in src/userland.h must match these definitions. + const std = @import("std"); const builtin = @import("builtin"); -const os = std.os; -const io = std.io; -const mem = std.mem; -const Allocator = mem.Allocator; -const ArrayList = std.ArrayList; -const Buffer = std.Buffer; +// ABI warning +export fn stage2_zen(ptr: *[*]const u8, len: *usize) void { + const info_zen = @import("main.zig").info_zen; + ptr.* = &info_zen; + len.* = info_zen.len; +} + +// ABI warning +export fn stage2_panic(ptr: [*]const u8, len: usize) void { + @panic(ptr[0..len]); +} + +// ABI warning +const TranslateMode = extern enum { + import, + translate, +}; + +// ABI warning +const Error = extern enum { + None, + OutOfMemory, + InvalidFormat, + SemanticAnalyzeFail, + AccessDenied, + Interrupted, + SystemResources, + FileNotFound, + FileSystem, + FileTooBig, + DivByZero, + Overflow, + PathAlreadyExists, + Unexpected, + ExactDivRemainder, + NegativeDenominator, + ShiftedOutOneBits, + CCompileErrors, + EndOfFile, + IsDir, + NotDir, + UnsupportedOperatingSystem, + SharingViolation, + PipeBusy, + PrimitiveTypeNotFound, + CacheUnavailable, + PathTooLong, + CCompilerCannotFindFile, + ReadingDepFile, + InvalidDepFile, + MissingArchitecture, + MissingOperatingSystem, + UnknownArchitecture, + UnknownOperatingSystem, + UnknownABI, + InvalidFilename, + DiskQuota, + DiskSpace, + UnexpectedWriteFailure, + UnexpectedSeekFailure, + UnexpectedFileTruncationFailure, + Unimplemented, + OperationAborted, + BrokenPipe, + NoSpaceLeft, +}; + +const FILE = std.c.FILE; const ast = std.zig.ast; +const translate_c = @import("translate_c.zig"); + +/// Args should have a null terminating last arg. +export fn stage2_translate_c( + out_ast: **ast.Tree, + out_errors_ptr: *[*]translate_c.ClangErrMsg, + out_errors_len: *usize, + args_begin: [*]?[*]const u8, + args_end: [*]?[*]const u8, + mode: TranslateMode, + resources_path: [*]const u8, +) Error { + var errors: []translate_c.ClangErrMsg = undefined; + out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, switch (mode) { + .import => translate_c.Mode.import, + .translate => translate_c.Mode.translate, + }, &errors, resources_path) catch |err| switch (err) { + // TODO after https://github.com/ziglang/zig/issues/769 we can remove error.UnsupportedType + error.SemanticAnalyzeFail, error.UnsupportedType => { + out_errors_ptr.* = errors.ptr; + out_errors_len.* = errors.len; + return Error.CCompileErrors; + }, + error.OutOfMemory => return Error.OutOfMemory, + }; + return Error.None; +} -const arg = @import("fmt/arg.zig"); -const self_hosted_main = @import("fmt/main.zig"); -const Args = arg.Args; -const Flag = arg.Flag; -const errmsg = @import("fmt/errmsg.zig"); +export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void { + translate_c.freeErrors(errors_ptr[0..errors_len]); +} -var stderr_file: os.File = undefined; -var stderr: *io.OutStream(os.File.WriteError) = undefined; -var stdout: *io.OutStream(os.File.WriteError) = undefined; +export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { + const c_out_stream = &std.io.COutStream.init(output_file).stream; + _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { + error.SystemResources => return Error.SystemResources, + error.OperationAborted => return Error.OperationAborted, + error.BrokenPipe => return Error.BrokenPipe, + error.DiskQuota => return Error.DiskQuota, + error.FileTooBig => return Error.FileTooBig, + error.NoSpaceLeft => return Error.NoSpaceLeft, + error.AccessDenied => return Error.AccessDenied, + error.OutOfMemory => return Error.OutOfMemory, + error.Unexpected => return Error.Unexpected, + error.InputOutput => return Error.FileSystem, + }; + return Error.None; +} + +// TODO: just use the actual self-hosted zig fmt. Until the coroutine rewrite, we use a blocking implementation. +export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int { + if (std.debug.runtime_safety) { + fmtMain(argc, argv) catch unreachable; + } else { + fmtMain(argc, argv) catch |e| { + std.debug.warn("{}\n", @errorName(e)); + return -1; + }; + } + return 0; +} -// This brings `zig fmt` to stage 1. -pub fn main() !void { - // Here we use an ArenaAllocator backed by a DirectAllocator because `zig fmt` is a short-lived, - // one shot program. We don't need to waste time freeing memory and finding places to squish - // bytes into. So we free everything all at once at the very end. - var direct_allocator = std.heap.DirectAllocator.init(); - var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator); - const allocator = &arena.allocator; +fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void { + const allocator = std.heap.c_allocator; + var args_list = std.ArrayList([]const u8).init(allocator); + const argc_usize = @intCast(usize, argc); + var arg_i: usize = 0; + while (arg_i < argc_usize) : (arg_i += 1) { + try args_list.append(std.mem.toSliceConst(u8, argv[arg_i])); + } var stdout_file = try std.io.getStdOut(); var stdout_out_stream = stdout_file.outStream(); @@ -35,9 +151,9 @@ pub fn main() !void { stderr_file = try std.io.getStdErr(); var stderr_out_stream = stderr_file.outStream(); stderr = &stderr_out_stream.stream; - const args = try std.os.argsAlloc(allocator); - var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args[1..]); + const args = args_list.toSliceConst(); + var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args[2..]); defer flags.deinit(); if (flags.present("help")) { @@ -71,7 +187,7 @@ pub fn main() !void { const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size); defer allocator.free(source_code); - var tree = std.zig.parse(allocator, source_code) catch |err| { + const tree = std.zig.parse(allocator, source_code) catch |err| { try stderr.print("error parsing stdin: {}\n", err); os.exit(1); }; @@ -79,18 +195,18 @@ pub fn main() !void { var error_it = tree.errors.iterator(0); while (error_it.next()) |parse_error| { - try printErrMsgToFile(allocator, parse_error, &tree, "<stdin>", stderr_file, color); + try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color); } if (tree.errors.len != 0) { os.exit(1); } if (flags.present("check")) { - const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree); + const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree); const code = if (anything_changed) u8(1) else u8(0); os.exit(code); } - _ = try std.zig.render(allocator, stdout, &tree); + _ = try std.zig.render(allocator, stdout, tree); return; } @@ -166,7 +282,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void }; defer fmt.allocator.free(source_code); - var tree = std.zig.parse(fmt.allocator, source_code) catch |err| { + const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { try stderr.print("error parsing file '{}': {}\n", file_path, err); fmt.any_error = true; return; @@ -175,7 +291,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void var error_it = tree.errors.iterator(0); while (error_it.next()) |parse_error| { - try printErrMsgToFile(fmt.allocator, parse_error, &tree, file_path, stderr_file, fmt.color); + try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color); } if (tree.errors.len != 0) { fmt.any_error = true; @@ -183,17 +299,16 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void } if (check_mode) { - const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, &tree); + const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree); if (anything_changed) { try stderr.print("{}\n", file_path); fmt.any_error = true; } } else { - // TODO make this evented const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path); defer baf.destroy(); - const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), &tree); + const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree); if (anything_changed) { try stderr.print("{}\n", file_path); try baf.finish(); @@ -210,9 +325,14 @@ const Fmt = struct { const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); }; -fn printErrMsgToFile(allocator: *mem.Allocator, parse_error: *const ast.Error, tree: *ast.Tree, - path: []const u8, file: os.File, color: errmsg.Color,) !void -{ +fn printErrMsgToFile( + allocator: *mem.Allocator, + parse_error: *const ast.Error, + tree: *ast.Tree, + path: []const u8, + file: os.File, + color: errmsg.Color, +) !void { const color_on = switch (color) { errmsg.Color.Auto => file.isTty(), errmsg.Color.On => true, @@ -258,3 +378,20 @@ fn printErrMsgToFile(allocator: *mem.Allocator, parse_error: *const ast.Error, t try stream.writeByteNTimes('~', last_token.end - first_token.start); try stream.write("\n"); } + +const os = std.os; +const io = std.io; +const mem = std.mem; +const Allocator = mem.Allocator; +const ArrayList = std.ArrayList; +const Buffer = std.Buffer; + +const arg = @import("arg.zig"); +const self_hosted_main = @import("main.zig"); +const Args = arg.Args; +const Flag = arg.Flag; +const errmsg = @import("errmsg.zig"); + +var stderr_file: os.File = undefined; +var stderr: *io.OutStream(os.File.WriteError) = undefined; +var stdout: *io.OutStream(os.File.WriteError) = undefined; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig new file mode 100644 index 0000000000..703f907907 --- /dev/null +++ b/src-self-hosted/translate_c.zig @@ -0,0 +1,682 @@ +// This is the userland implementation of translate-c which will be used by both stage1 +// and stage2. Currently the only way it is used is with `zig translate-c-2`. + +const std = @import("std"); +const builtin = @import("builtin"); +const assert = std.debug.assert; +const ast = std.zig.ast; +const Token = std.zig.Token; +use @import("clang.zig"); + +pub const Mode = enum { + import, + translate, +}; + +// TODO merge with Type.Fn.CallingConvention +const CallingConvention = builtin.TypeInfo.CallingConvention; + +pub const ClangErrMsg = Stage2ErrorMsg; + +pub const Error = error{ + OutOfMemory, + UnsupportedType, +}; +pub const TransError = error{ + OutOfMemory, + UnsupportedTranslation, +}; + +const DeclTable = std.HashMap(usize, void, addrHash, addrEql); + +fn addrHash(x: usize) u32 { + switch (@typeInfo(usize).Int.bits) { + 32 => return x, + // pointers are usually aligned so we ignore the bits that are probably all 0 anyway + // usually the larger bits of addr space are unused so we just chop em off + 64 => return @truncate(u32, x >> 4), + else => @compileError("unreachable"), + } +} + +fn addrEql(a: usize, b: usize) bool { + return a == b; +} + +const Scope = struct { + id: Id, + parent: ?*Scope, + + const Id = enum { + Switch, + Var, + Block, + Root, + While, + }; + const Switch = struct { + base: Scope, + }; + + const Var = struct { + base: Scope, + c_name: []const u8, + zig_name: []const u8, + }; + + const Block = struct { + base: Scope, + block_node: *ast.Node.Block, + + /// Don't forget to set rbrace token later + fn create(c: *Context, parent: *Scope, lbrace_tok: ast.TokenIndex) !*Block { + const block = try c.a().create(Block); + block.* = Block{ + .base = Scope{ + .id = Id.Block, + .parent = parent, + }, + .block_node = try c.a().create(ast.Node.Block), + }; + block.block_node.* = ast.Node.Block{ + .base = ast.Node{ .id = ast.Node.Id.Block }, + .label = null, + .lbrace = lbrace_tok, + .statements = ast.Node.Block.StatementList.init(c.a()), + .rbrace = undefined, + }; + return block; + } + }; + + const Root = struct { + base: Scope, + }; + + const While = struct { + base: Scope, + }; +}; + +const TransResult = struct { + node: *ast.Node, + node_scope: *Scope, + child_scope: *Scope, +}; + +const Context = struct { + tree: *ast.Tree, + source_buffer: *std.Buffer, + err: Error, + source_manager: *ZigClangSourceManager, + decl_table: DeclTable, + global_scope: *Scope.Root, + mode: Mode, + + fn a(c: *Context) *std.mem.Allocator { + return &c.tree.arena_allocator.allocator; + } + + /// Convert a null-terminated C string to a slice allocated in the arena + fn str(c: *Context, s: [*]const u8) ![]u8 { + return std.mem.dupe(c.a(), u8, std.mem.toSliceConst(u8, s)); + } + + /// Convert a clang source location to a file:line:column string + fn locStr(c: *Context, loc: ZigClangSourceLocation) ![]u8 { + const spelling_loc = ZigClangSourceManager_getSpellingLoc(c.source_manager, loc); + const filename_c = ZigClangSourceManager_getFilename(c.source_manager, spelling_loc); + const filename = if (filename_c) |s| try c.str(s) else ([]const u8)("(no file)"); + + const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc); + const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc); + return std.fmt.allocPrint(c.a(), "{}:{}:{}", filename, line, column); + } +}; + +pub fn translate( + backing_allocator: *std.mem.Allocator, + args_begin: [*]?[*]const u8, + args_end: [*]?[*]const u8, + mode: Mode, + errors: *[]ClangErrMsg, + resources_path: [*]const u8, +) !*ast.Tree { + const ast_unit = ZigClangLoadFromCommandLine( + args_begin, + args_end, + &errors.ptr, + &errors.len, + resources_path, + ) orelse { + if (errors.len == 0) return error.OutOfMemory; + return error.SemanticAnalyzeFail; + }; + defer ZigClangASTUnit_delete(ast_unit); + + var tree_arena = std.heap.ArenaAllocator.init(backing_allocator); + errdefer tree_arena.deinit(); + var arena = &tree_arena.allocator; + + const root_node = try arena.create(ast.Node.Root); + root_node.* = ast.Node.Root{ + .base = ast.Node{ .id = ast.Node.Id.Root }, + .decls = ast.Node.Root.DeclList.init(arena), + .doc_comments = null, + // initialized with the eof token at the end + .eof_token = undefined, + }; + + const tree = try arena.create(ast.Tree); + tree.* = ast.Tree{ + .source = undefined, // need to use Buffer.toOwnedSlice later + .root_node = root_node, + .arena_allocator = undefined, + .tokens = ast.Tree.TokenList.init(arena), + .errors = ast.Tree.ErrorList.init(arena), + }; + tree.arena_allocator = tree_arena; + arena = &tree.arena_allocator.allocator; + + var source_buffer = try std.Buffer.initSize(arena, 0); + + var context = Context{ + .tree = tree, + .source_buffer = &source_buffer, + .source_manager = ZigClangASTUnit_getSourceManager(ast_unit), + .err = undefined, + .decl_table = DeclTable.init(arena), + .global_scope = try arena.create(Scope.Root), + .mode = mode, + }; + context.global_scope.* = Scope.Root{ + .base = Scope{ + .id = Scope.Id.Root, + .parent = null, + }, + }; + + if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) { + return context.err; + } + + _ = try appendToken(&context, .Eof, ""); + tree.source = source_buffer.toOwnedSlice(); + if (false) { + std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); + var i: usize = 0; + while (i < tree.tokens.len) : (i += 1) { + const token = tree.tokens.at(i); + std.debug.warn("{}\n", token); + } + } + return tree; +} + +extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool { + const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); + declVisitor(c, decl) catch |err| { + c.err = err; + return false; + }; + return true; +} + +fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { + switch (ZigClangDecl_getKind(decl)) { + .Function => { + return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); + }, + .Typedef => { + try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for typedefs"); + }, + .Enum => { + try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums"); + }, + .Record => { + try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for structs"); + }, + .Var => { + try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for variables"); + }, + else => { + const decl_name = try c.str(ZigClangDecl_getDeclKindName(decl)); + try emitWarning(c, ZigClangDecl_getLocation(decl), "ignoring {} declaration", decl_name); + }, + } +} + +fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { + if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice + const rp = makeRestorePoint(c); + const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); + const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); + const fn_qt = ZigClangFunctionDecl_getType(fn_decl); + const fn_type = ZigClangQualType_getTypePtr(fn_qt); + var scope = &c.global_scope.base; + const has_body = ZigClangFunctionDecl_hasBody(fn_decl); + const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); + const decl_ctx = FnDeclContext{ + .fn_name = fn_name, + .has_body = has_body, + .storage_class = storage_class, + .scope = &scope, + .is_export = switch (storage_class) { + .None => has_body, + .Extern, .Static => false, + .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern"), + .Auto => unreachable, // Not legal on functions + .Register => unreachable, // Not legal on functions + }, + }; + const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { + .FunctionProto => blk: { + const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type); + break :blk transFnProto(rp, fn_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) { + error.UnsupportedType => { + return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function"); + }, + error.OutOfMemory => return error.OutOfMemory, + }; + }, + .FunctionNoProto => blk: { + const fn_no_proto_type = @ptrCast(*const ZigClangFunctionType, fn_type); + break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) { + error.UnsupportedType => { + return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function"); + }, + error.OutOfMemory => return error.OutOfMemory, + }; + }, + else => unreachable, + }; + + if (!decl_ctx.has_body) { + const semi_tok = try appendToken(c, .Semicolon, ";"); + return addTopLevelDecl(c, fn_name, &proto_node.base); + } + + // actual function definition with body + const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); + const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.UnsupportedTranslation => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), + }; + assert(result.node.id == ast.Node.Id.Block); + proto_node.body_node = result.node; + + return addTopLevelDecl(c, fn_name, &proto_node.base); +} + +const ResultUsed = enum { + used, + unused, +}; + +const LRValue = enum { + l_value, + r_value, +}; + +fn transStmt( + rp: RestorePoint, + scope: *Scope, + stmt: *const ZigClangStmt, + result_used: ResultUsed, + lrvalue: LRValue, +) !TransResult { + const sc = ZigClangStmt_getStmtClass(stmt); + switch (sc) { + .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)), + else => { + return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangStmt_getBeginLoc(stmt), + "TODO implement translation of stmt class {}", + @tagName(sc), + ); + }, + } +} + +fn transCompoundStmtInline( + rp: RestorePoint, + parent_scope: *Scope, + stmt: *const ZigClangCompoundStmt, + block_node: *ast.Node.Block, +) TransError!TransResult { + var it = ZigClangCompoundStmt_body_begin(stmt); + const end_it = ZigClangCompoundStmt_body_end(stmt); + var scope = parent_scope; + while (it != end_it) : (it += 1) { + const result = try transStmt(rp, scope, it.*, .unused, .r_value); + scope = result.child_scope; + try block_node.statements.push(result.node); + } + return TransResult{ + .node = &block_node.base, + .child_scope = scope, + .node_scope = scope, + }; +} + +fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) !TransResult { + const lbrace_tok = try appendToken(rp.c, .LBrace, "{"); + const block_scope = try Scope.Block.create(rp.c, scope, lbrace_tok); + const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); + block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + return TransResult{ + .node = &block_scope.block_node.base, + .node_scope = inline_result.node_scope, + .child_scope = inline_result.child_scope, + }; +} + +fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { + try c.tree.root_node.decls.push(decl_node); +} + +fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) Error!*ast.Node { + return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); +} + +fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { + const canon = ZigClangQualType_getCanonicalType(qt); + return ZigClangQualType_getTypePtr(canon); +} + +const RestorePoint = struct { + c: *Context, + token_index: ast.TokenIndex, + src_buf_index: usize, + + fn activate(self: RestorePoint) void { + self.c.tree.tokens.shrink(self.token_index); + self.c.source_buffer.shrink(self.src_buf_index); + } +}; + +fn makeRestorePoint(c: *Context) RestorePoint { + return RestorePoint{ + .c = c, + .token_index = c.tree.tokens.len, + .src_buf_index = c.source_buffer.len(), + }; +} + +fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) Error!*ast.Node { + switch (ZigClangType_getTypeClass(ty)) { + .Builtin => { + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Void => return appendIdentifier(rp.c, "c_void"), + .Bool => return appendIdentifier(rp.c, "bool"), + .Char_U, .UChar, .Char_S, .Char8 => return appendIdentifier(rp.c, "u8"), + .SChar => return appendIdentifier(rp.c, "i8"), + .UShort => return appendIdentifier(rp.c, "c_ushort"), + .UInt => return appendIdentifier(rp.c, "c_uint"), + .ULong => return appendIdentifier(rp.c, "c_ulong"), + .ULongLong => return appendIdentifier(rp.c, "c_ulonglong"), + .Short => return appendIdentifier(rp.c, "c_short"), + .Int => return appendIdentifier(rp.c, "c_int"), + .Long => return appendIdentifier(rp.c, "c_long"), + .LongLong => return appendIdentifier(rp.c, "c_longlong"), + .UInt128 => return appendIdentifier(rp.c, "u128"), + .Int128 => return appendIdentifier(rp.c, "i128"), + .Float => return appendIdentifier(rp.c, "f32"), + .Double => return appendIdentifier(rp.c, "f64"), + .Float128 => return appendIdentifier(rp.c, "f128"), + .Float16 => return appendIdentifier(rp.c, "f16"), + .LongDouble => return appendIdentifier(rp.c, "c_longdouble"), + else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), + } + }, + .FunctionProto => { + const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); + const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null); + return &fn_proto.base; + }, + else => { + const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); + return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name); + }, + } +} + +const FnDeclContext = struct { + fn_name: []const u8, + has_body: bool, + storage_class: ZigClangStorageClass, + scope: **Scope, + is_export: bool, +}; + +fn transCC( + rp: RestorePoint, + fn_ty: *const ZigClangFunctionType, + source_loc: ZigClangSourceLocation, +) !CallingConvention { + const clang_cc = ZigClangFunctionType_getCallConv(fn_ty); + switch (clang_cc) { + .C => return CallingConvention.C, + .X86StdCall => return CallingConvention.Stdcall, + else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: {}", @tagName(clang_cc)), + } +} + +fn transFnProto( + rp: RestorePoint, + fn_proto_ty: *const ZigClangFunctionProtoType, + source_loc: ZigClangSourceLocation, + fn_decl_context: ?FnDeclContext, +) !*ast.Node.FnProto { + const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); + const cc = try transCC(rp, fn_ty, source_loc); + const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); + const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); + var i: usize = 0; + while (i < param_count) : (i += 1) { + return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType"); + } + + return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc); +} + +fn transFnNoProto( + rp: RestorePoint, + fn_ty: *const ZigClangFunctionType, + source_loc: ZigClangSourceLocation, + fn_decl_context: ?FnDeclContext, +) !*ast.Node.FnProto { + const cc = try transCC(rp, fn_ty, source_loc); + const is_var_args = if (fn_decl_context) |ctx| !ctx.is_export else true; + return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc); +} + +fn finishTransFnProto( + rp: RestorePoint, + fn_ty: *const ZigClangFunctionType, + source_loc: ZigClangSourceLocation, + fn_decl_context: ?FnDeclContext, + is_var_args: bool, + cc: CallingConvention, +) !*ast.Node.FnProto { + const is_export = if (fn_decl_context) |ctx| ctx.is_export else false; + + // TODO check for always_inline attribute + // TODO check for align attribute + + // pub extern fn name(...) T + const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub"); + const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; + const extern_export_inline_tok = if (is_export) + try appendToken(rp.c, .Keyword_export, "export") + else if (cc == .C) + try appendToken(rp.c, .Keyword_extern, "extern") + else + null; + const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); + const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null; + const lparen_tok = try appendToken(rp.c, .LParen, "("); + const var_args_tok = if (is_var_args) try appendToken(rp.c, .Ellipsis3, "...") else null; + const rparen_tok = try appendToken(rp.c, .RParen, ")"); + + const return_type_node = blk: { + if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { + break :blk try appendIdentifier(rp.c, "noreturn"); + } else { + const return_qt = ZigClangFunctionType_getReturnType(fn_ty); + if (ZigClangType_isVoidType(qualTypeCanon(return_qt))) { + break :blk try appendIdentifier(rp.c, "void"); + } else { + break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) { + error.UnsupportedType => { + try emitWarning(rp.c, source_loc, "unsupported function proto return type"); + return err; + }, + error.OutOfMemory => return error.OutOfMemory, + }; + } + } + }; + + const fn_proto = try rp.c.a().create(ast.Node.FnProto); + fn_proto.* = ast.Node.FnProto{ + .base = ast.Node{ .id = ast.Node.Id.FnProto }, + .doc_comments = null, + .visib_token = pub_tok, + .fn_token = fn_tok, + .name_token = name_tok, + .params = ast.Node.FnProto.ParamList.init(rp.c.a()), + .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, + .var_args_token = null, // TODO this field is broken in the AST data model + .extern_export_inline_token = extern_export_inline_tok, + .cc_token = cc_tok, + .async_attr = null, + .body_node = null, + .lib_name = null, + .align_expr = null, + .section_expr = null, + }; + if (is_var_args) { + const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl); + var_arg_node.* = ast.Node.ParamDecl{ + .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, + .doc_comments = null, + .comptime_token = null, + .noalias_token = null, + .name_token = null, + .type_node = undefined, + .var_args_token = var_args_tok, + }; + try fn_proto.params.push(&var_arg_node.base); + } + return fn_proto; +} + +fn revertAndWarn( + rp: RestorePoint, + err: var, + source_loc: ZigClangSourceLocation, + comptime format: []const u8, + args: ..., +) (@typeOf(err) || error{OutOfMemory}) { + rp.activate(); + try emitWarning(rp.c, source_loc, format, args); + return err; +} + +fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []const u8, args: ...) !void { + _ = try appendTokenFmt(c, .LineComment, "// {}: warning: " ++ format, c.locStr(loc), args); +} + +fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: ...) !void { + // const name = @compileError(msg); + const const_tok = try appendToken(c, .Keyword_const, "const"); + const name_tok = try appendToken(c, .Identifier, name); + const eq_tok = try appendToken(c, .Equal, "="); + const builtin_tok = try appendToken(c, .Builtin, "@compileError"); + const lparen_tok = try appendToken(c, .LParen, "("); + const msg_tok = try appendTokenFmt(c, .StringLiteral, "\"" ++ format ++ "\"", args); + const rparen_tok = try appendToken(c, .RParen, ")"); + const semi_tok = try appendToken(c, .Semicolon, ";"); + + const msg_node = try c.a().create(ast.Node.StringLiteral); + msg_node.* = ast.Node.StringLiteral{ + .base = ast.Node{ .id = ast.Node.Id.StringLiteral }, + .token = msg_tok, + }; + + const call_node = try c.a().create(ast.Node.BuiltinCall); + call_node.* = ast.Node.BuiltinCall{ + .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, + .builtin_token = builtin_tok, + .params = ast.Node.BuiltinCall.ParamList.init(c.a()), + .rparen_token = rparen_tok, + }; + try call_node.params.push(&msg_node.base); + + const var_decl_node = try c.a().create(ast.Node.VarDecl); + var_decl_node.* = ast.Node.VarDecl{ + .base = ast.Node{ .id = ast.Node.Id.VarDecl }, + .doc_comments = null, + .visib_token = null, + .thread_local_token = null, + .name_token = name_tok, + .eq_token = eq_tok, + .mut_token = const_tok, + .comptime_token = null, + .extern_export_token = null, + .lib_name = null, + .type_node = null, + .align_node = null, + .section_node = null, + .init_node = &call_node.base, + .semicolon_token = semi_tok, + }; + try c.tree.root_node.decls.push(&var_decl_node.base); +} + +fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex { + return appendTokenFmt(c, token_id, "{}", bytes); +} + +fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: ...) !ast.TokenIndex { + const S = struct { + fn callback(context: *Context, bytes: []const u8) error{OutOfMemory}!void { + return context.source_buffer.append(bytes); + } + }; + const start_index = c.source_buffer.len(); + errdefer c.source_buffer.shrink(start_index); + + try std.fmt.format(c, error{OutOfMemory}, S.callback, format, args); + const end_index = c.source_buffer.len(); + const token_index = c.tree.tokens.len; + const new_token = try c.tree.tokens.addOne(); + errdefer c.tree.tokens.shrink(token_index); + + new_token.* = Token{ + .id = token_id, + .start = start_index, + .end = end_index, + }; + try c.source_buffer.appendByte('\n'); + + return token_index; +} + +fn appendIdentifier(c: *Context, name: []const u8) !*ast.Node { + const token_index = try appendToken(c, .Identifier, name); + const identifier = try c.a().create(ast.Node.Identifier); + identifier.* = ast.Node.Identifier{ + .base = ast.Node{ .id = ast.Node.Id.Identifier }, + .token = token_index, + }; + return &identifier.base; +} + +pub fn freeErrors(errors: []ClangErrMsg) void { + ZigClangErrorMsg_delete(errors.ptr, errors.len); +} diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index d8c0f7b5c8..f1c7fc0b50 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -538,21 +538,21 @@ pub const Value = struct { switch (self.base.typ.id) { Type.Id.Int => { const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context); - if (self.big_int.len == 0) { + if (self.big_int.len() == 0) { return llvm.ConstNull(type_ref); } - const unsigned_val = if (self.big_int.len == 1) blk: { + const unsigned_val = if (self.big_int.len() == 1) blk: { break :blk llvm.ConstInt(type_ref, self.big_int.limbs[0], @boolToInt(false)); } else if (@sizeOf(std.math.big.Limb) == @sizeOf(u64)) blk: { break :blk llvm.ConstIntOfArbitraryPrecision( type_ref, - @intCast(c_uint, self.big_int.len), + @intCast(c_uint, self.big_int.len()), @ptrCast([*]u64, self.big_int.limbs.ptr), ); } else { @compileError("std.math.Big.Int.Limb size does not match LLVM"); }; - return if (self.big_int.positive) unsigned_val else llvm.ConstNeg(unsigned_val); + return if (self.big_int.isPositive()) unsigned_val else llvm.ConstNeg(unsigned_val); }, Type.Id.ComptimeInt => unreachable, else => unreachable, diff --git a/src/all_types.hpp b/src/all_types.hpp index 92faad1e03..ecc0d1a9bb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -55,7 +55,7 @@ struct IrExecutable { size_t mem_slot_count; size_t next_debug_id; size_t *backward_branch_count; - size_t backward_branch_quota; + size_t *backward_branch_quota; ZigFn *fn_entry; Buf *c_import_buf; AstNode *source_node; @@ -1350,6 +1350,7 @@ struct ZigFn { IrExecutable ir_executable; IrExecutable analyzed_executable; size_t prealloc_bbc; + size_t prealloc_backward_branch_quota; AstNode **param_source_nodes; Buf **param_names; @@ -1855,10 +1856,13 @@ struct CodeGen { bool strip_debug_symbols; bool is_test_build; bool is_single_threaded; + bool want_single_threaded; bool linker_rdynamic; bool each_lib_rpath; bool is_dummy_so; bool disable_gen_h; + bool bundle_compiler_rt; + bool disable_stack_probing; Buf *mmacosx_version_min; Buf *mios_version_min; @@ -2291,6 +2295,7 @@ enum IrInstructionId { IrInstructionIdVectorToArray, IrInstructionIdArrayToVector, IrInstructionIdAssertZero, + IrInstructionIdAssertNonNull, }; struct IrInstruction { @@ -3480,6 +3485,12 @@ struct IrInstructionAssertZero { IrInstruction *target; }; +struct IrInstructionAssertNonNull { + IrInstruction base; + + IrInstruction *target; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 394364c68f..57244aba6a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -969,8 +969,9 @@ static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *no Buf *type_name) { size_t backward_branch_count = 0; + size_t backward_branch_quota = default_backward_branch_quota; return ir_eval_const_value(g, scope, node, type_entry, - &backward_branch_count, default_backward_branch_quota, + &backward_branch_count, &backward_branch_quota, nullptr, nullptr, node, type_name, nullptr, nullptr); } @@ -1907,6 +1908,18 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { return ErrorNone; } +static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) { + // Only integer types are allowed by the C ABI + if(ty->id != ZigTypeIdInt) + return false; + + // According to the ANSI C standard the enumeration type should be either a + // signed char, a signed integer or an unsigned one. But GCC/Clang allow + // other integral types as a compiler extension so let's accomodate them + // aswell. + return type_allowed_in_extern(g, ty); +} + static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { assert(enum_type->id == ZigTypeIdEnum); @@ -1964,7 +1977,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { enum_type->abi_size = tag_int_type->abi_size; enum_type->abi_align = tag_int_type->abi_align; - // TODO: Are extern enums allowed to have an init_arg_expr? if (decl_node->data.container_decl.init_arg_expr != nullptr) { ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); if (type_is_invalid(wanted_tag_int_type)) { @@ -1973,24 +1985,29 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { enum_type->data.enumeration.is_invalid = true; add_node_error(g, decl_node->data.container_decl.init_arg_expr, buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); - } else if (wanted_tag_int_type->data.integral.is_signed) { - enum_type->data.enumeration.is_invalid = true; - add_node_error(g, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); - } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) { + } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern && + !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) { enum_type->data.enumeration.is_invalid = true; - add_node_error(g, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("'%s' too small to hold all bits; must be at least '%s'", - buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name))); + ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, + buf_sprintf("'%s' is not a valid tag type for an extern enum", + buf_ptr(&wanted_tag_int_type->name))); + add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr, + buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid")); } else { tag_int_type = wanted_tag_int_type; } } + enum_type->data.enumeration.tag_int_type = tag_int_type; enum_type->size_in_bits = tag_int_type->size_in_bits; enum_type->abi_size = tag_int_type->abi_size; enum_type->abi_align = tag_int_type->abi_align; + BigInt bi_one; + bigint_init_unsigned(&bi_one, 1); + + TypeEnumField *last_enum_field = nullptr; + for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; @@ -2016,60 +2033,58 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { AstNode *tag_value = field_node->data.struct_field.value; - // In this first pass we resolve explicit tag values. - // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { + // A user-specified value is available ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); if (type_is_invalid(result->type)) { enum_type->data.enumeration.is_invalid = true; continue; } + assert(result->special != ConstValSpecialRuntime); - assert(result->type->id == ZigTypeIdInt || - result->type->id == ZigTypeIdComptimeInt); - auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); - if (entry == nullptr) { - bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); + assert(result->type->id == ZigTypeIdInt || result->type->id == ZigTypeIdComptimeInt); + + bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); + } else { + // No value was explicitly specified: allocate the last value + 1 + // or, if this is the first element, zero + if (last_enum_field != nullptr) { + bigint_add(&type_enum_field->value, &last_enum_field->value, &bi_one); } else { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result->data.x_bigint, 10); + bigint_init_unsigned(&type_enum_field->value, 0); + } - ErrorMsg *msg = add_node_error(g, tag_value, - buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); - add_error_note(g, msg, entry->value, - buf_sprintf("other occurrence here")); + // Make sure we can represent this number with tag_int_type + if (!bigint_fits_in_bits(&type_enum_field->value, + tag_int_type->size_in_bits, + tag_int_type->data.integral.is_signed)) { enum_type->data.enumeration.is_invalid = true; - continue; + + Buf *val_buf = buf_alloc(); + bigint_append_buf(val_buf, &type_enum_field->value, 10); + add_node_error(g, field_node, + buf_sprintf("enumeration value %s too large for type '%s'", + buf_ptr(val_buf), buf_ptr(&tag_int_type->name))); + + break; } } - } - // Now iterate again and populate the unspecified tag values - uint32_t next_maybe_unoccupied_index = 0; + // Make sure the value is unique + auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); + if (entry != nullptr) { + enum_type->data.enumeration.is_invalid = true; - for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; - AstNode *tag_value = field_node->data.struct_field.value; + Buf *val_buf = buf_alloc(); + bigint_append_buf(val_buf, &type_enum_field->value, 10); - if (tag_value == nullptr) { - if (occupied_tag_values.size() == 0) { - bigint_init_unsigned(&type_enum_field->value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - } else { - BigInt proposed_value; - for (;;) { - bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - auto entry = occupied_tag_values.put_unique(proposed_value, field_node); - if (entry != nullptr) { - continue; - } - break; - } - bigint_init_bigint(&type_enum_field->value, &proposed_value); - } + ErrorMsg *msg = add_node_error(g, field_node, + buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); + add_error_note(g, msg, entry->value, + buf_sprintf("other occurrence here")); } + + last_enum_field = type_enum_field; } enum_type->data.enumeration.zero_bits_loop_flag = false; @@ -2607,7 +2622,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorNone; } -static void get_fully_qualified_decl_name(Buf *buf, Tld *tld) { +static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, bool is_test) { buf_resize(buf, 0); Scope *scope = tld->parent_scope; @@ -2617,15 +2632,23 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld) { ScopeDecls *decls_scope = reinterpret_cast<ScopeDecls *>(scope); buf_append_buf(buf, &decls_scope->container_type->name); if (buf_len(buf) != 0) buf_append_char(buf, NAMESPACE_SEP_CHAR); - buf_append_buf(buf, tld->name); + if (is_test) { + buf_append_str(buf, "test \""); + buf_append_buf(buf, tld->name); + buf_append_char(buf, '"'); + } else { + buf_append_buf(buf, tld->name); + } } ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { ZigFn *fn_entry = allocate<ZigFn>(1); + fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota; + fn_entry->codegen = g; fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; - fn_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota; + fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota; fn_entry->analyzed_executable.fn_entry = fn_entry; fn_entry->ir_executable.fn_entry = fn_entry; fn_entry->fn_inline = inline_value; @@ -2726,7 +2749,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { if (fn_proto->is_export || is_extern) { buf_init_from_buf(&fn_table_entry->symbol_name, tld_fn->base.name); } else { - get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base); + get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, false); } if (fn_proto->is_export) { @@ -2787,7 +2810,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } else if (source_node->type == NodeTypeTestDecl) { ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto); - get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base); + get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, true); tld_fn->fn_entry = fn_table_entry; @@ -3722,7 +3745,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { } if (g->verbose_ir) { fprintf(stderr, "\n"); - ast_render(g, stderr, fn_table_entry->body_node, 4); + ast_render(stderr, fn_table_entry->body_node, 4); fprintf(stderr, "\n{ // (IR)\n"); ir_print(g, stderr, &fn_table_entry->ir_executable, 4); fprintf(stderr, "}\n"); @@ -5155,11 +5178,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { if (bigint_cmp(&union1->tag, &union2->tag) == CmpEQ) { TypeUnionField *field = find_union_field_by_tag(a->type, &union1->tag); assert(field != nullptr); - if (type_has_bits(field->type_entry)) { - zig_panic("TODO const expr analyze union field value for equality"); - } else { + if (!type_has_bits(field->type_entry)) return true; - } + assert(find_union_field_by_tag(a->type, &union2->tag) != nullptr); + return const_values_equal(g, union1->payload, union2->payload); } return false; } @@ -6070,7 +6092,7 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) { if (g->enable_cache) { return cache_add_file_fetch(&g->cache_hash, resolved_path, contents); } else { - return os_fetch_file_path(resolved_path, contents, false); + return os_fetch_file_path(resolved_path, contents); } } @@ -7222,3 +7244,16 @@ ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type) { assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); return type->llvm_di_type; } + +void src_assert(bool ok, AstNode *source_node) { + if (ok) return; + if (source_node == nullptr) { + fprintf(stderr, "when analyzing (unknown source location): "); + } else { + fprintf(stderr, "when analyzing %s:%u:%u: ", + buf_ptr(source_node->owner->data.structure.root_struct->path), + (unsigned)source_node->line + 1, (unsigned)source_node->column + 1); + } + const char *msg = "assertion failed"; + stage2_panic(msg, strlen(msg)); +} diff --git a/src/analyze.hpp b/src/analyze.hpp index a3246fdf4d..d55733482f 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -247,4 +247,8 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type); ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type); +void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path, bool translate_c); + +void src_assert(bool ok, AstNode *source_node); + #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 16f2aafa78..95ae216f70 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -296,7 +296,6 @@ void ast_print(FILE *f, AstNode *node, int indent) { struct AstRender { - CodeGen *codegen; int indent; int indent_size; FILE *f; @@ -633,7 +632,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { if (is_printable(c)) { fprintf(ar->f, "'%c'", c); } else { - fprintf(ar->f, "'\\x%x'", (int)c); + fprintf(ar->f, "'\\x%02x'", (int)c); } break; } @@ -1170,9 +1169,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } -void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size) { +void ast_render(FILE *f, AstNode *node, int indent_size) { AstRender ar = {0}; - ar.codegen = codegen; ar.f = f; ar.indent_size = indent_size; ar.indent = 0; diff --git a/src/ast_render.hpp b/src/ast_render.hpp index 1652156eee..cf70b04694 100644 --- a/src/ast_render.hpp +++ b/src/ast_render.hpp @@ -15,6 +15,6 @@ void ast_print(FILE *f, AstNode *node, int indent); -void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size); +void ast_render(FILE *f, AstNode *node, int indent_size); #endif diff --git a/src/bigint.cpp b/src/bigint.cpp index d3178c35c6..da53a2b129 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -1395,7 +1395,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) { uint64_t shift_amt = bigint_as_unsigned(op2); if (op1->digit_count == 1) { - dest->data.digit = op1_digits[0] >> shift_amt; + dest->data.digit = (shift_amt < 64) ? op1_digits[0] >> shift_amt : 0; dest->digit_count = 1; dest->is_negative = op1->is_negative; bigint_normalize(dest); @@ -1410,12 +1410,19 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) { } dest->digit_count = op1->digit_count - digit_shift_count; - dest->data.digits = allocate<uint64_t>(dest->digit_count); + uint64_t *digits; + if (dest->digit_count == 1) { + digits = &dest->data.digit; + } else { + digits = allocate<uint64_t>(dest->digit_count); + dest->data.digits = digits; + } + uint64_t carry = 0; for (size_t op_digit_index = op1->digit_count - 1;;) { uint64_t digit = op1_digits[op_digit_index]; size_t dest_digit_index = op_digit_index - digit_shift_count; - dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count); + digits[dest_digit_index] = carry | (digit >> leftover_shift_count); carry = digit << (64 - leftover_shift_count); if (dest_digit_index == 0) { break; } diff --git a/src/buffer.hpp b/src/buffer.hpp index 789abea3e9..082d584e2c 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -10,7 +10,6 @@ #include "list.hpp" -#include <assert.h> #include <stdint.h> #include <ctype.h> #include <stdarg.h> diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp index 40ae8ceafe..55fde19003 100644 --- a/src/c_tokenizer.cpp +++ b/src/c_tokenizer.cpp @@ -124,6 +124,8 @@ static void begin_token(CTokenize *ctok, CTokId id) { case CTokIdAsterisk: case CTokIdBang: case CTokIdTilde: + case CTokIdShl: + case CTokIdLt: break; } } @@ -223,6 +225,10 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { begin_token(ctok, CTokIdDot); end_token(ctok); break; + case '<': + begin_token(ctok, CTokIdLt); + ctok->state = CTokStateGotLt; + break; case '(': begin_token(ctok, CTokIdLParen); end_token(ctok); @@ -251,6 +257,19 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { return mark_error(ctok); } break; + case CTokStateGotLt: + switch (*c) { + case '<': + ctok->cur_tok->id = CTokIdShl; + end_token(ctok); + ctok->state = CTokStateStart; + break; + default: + end_token(ctok); + ctok->state = CTokStateStart; + continue; + } + break; case CTokStateFloat: switch (*c) { case '.': @@ -791,6 +810,7 @@ found_end_of_macro: case CTokStateNumLitIntSuffixL: case CTokStateNumLitIntSuffixUL: case CTokStateNumLitIntSuffixLL: + case CTokStateGotLt: end_token(ctok); break; case CTokStateFloat: diff --git a/src/c_tokenizer.hpp b/src/c_tokenizer.hpp index d7c9e53bcf..eaca09098f 100644 --- a/src/c_tokenizer.hpp +++ b/src/c_tokenizer.hpp @@ -25,6 +25,8 @@ enum CTokId { CTokIdAsterisk, CTokIdBang, CTokIdTilde, + CTokIdShl, + CTokIdLt, }; enum CNumLitSuffix { @@ -78,6 +80,7 @@ enum CTokState { CTokStateNumLitIntSuffixL, CTokStateNumLitIntSuffixLL, CTokStateNumLitIntSuffixUL, + CTokStateGotLt, }; struct CTokenize { diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index 1f25a9982e..2a0810eced 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -256,10 +256,10 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents } if ((err = hash_file(chf->bin_digest, this_file, contents))) { - os_file_close(this_file); + os_file_close(&this_file); return err; } - os_file_close(this_file); + os_file_close(&this_file); blake2b_update(&ch->blake, chf->bin_digest, 48); @@ -300,7 +300,7 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { Buf line_buf = BUF_INIT; buf_resize(&line_buf, 512); if ((err = os_file_read_all(ch->manifest_file, &line_buf))) { - os_file_close(ch->manifest_file); + os_file_close(&ch->manifest_file); return err; } @@ -389,14 +389,14 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { OsFileAttr actual_attr; if ((err = os_file_open_r(chf->path, &this_file, &actual_attr))) { fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err)); - os_file_close(ch->manifest_file); + os_file_close(&ch->manifest_file); return ErrorCacheUnavailable; } if (chf->attr.mtime.sec == actual_attr.mtime.sec && chf->attr.mtime.nsec == actual_attr.mtime.nsec && chf->attr.inode == actual_attr.inode) { - os_file_close(this_file); + os_file_close(&this_file); } else { // we have to recompute the digest. // later we'll rewrite the manifest with the new mtime/digest values @@ -411,11 +411,11 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { uint8_t actual_digest[48]; if ((err = hash_file(actual_digest, this_file, nullptr))) { - os_file_close(this_file); - os_file_close(ch->manifest_file); + os_file_close(&this_file); + os_file_close(&ch->manifest_file); return err; } - os_file_close(this_file); + os_file_close(&this_file); if (memcmp(chf->bin_digest, actual_digest, 48) != 0) { memcpy(chf->bin_digest, actual_digest, 48); // keep going until we have the input file digests @@ -433,12 +433,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { CacheHashFile *chf = &ch->files.at(file_i); if ((err = populate_file_hash(ch, chf, nullptr))) { fprintf(stderr, "Unable to hash %s: %s\n", buf_ptr(chf->path), err_str(err)); - os_file_close(ch->manifest_file); + os_file_close(&ch->manifest_file); return ErrorCacheUnavailable; } } - if (return_code != ErrorNone) { - os_file_close(ch->manifest_file); + if (return_code != ErrorNone && return_code != ErrorInvalidFormat) { + os_file_close(&ch->manifest_file); } return return_code; } @@ -453,7 +453,7 @@ Error cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents) { CacheHashFile *chf = ch->files.add_one(); chf->path = resolved_path; if ((err = populate_file_hash(ch, chf, contents))) { - os_file_close(ch->manifest_file); + os_file_close(&ch->manifest_file); return err; } @@ -469,7 +469,7 @@ Error cache_add_file(CacheHash *ch, Buf *path) { Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) { Error err; Buf *contents = buf_alloc(); - if ((err = os_fetch_file_path(dep_file_path, contents, false))) { + if ((err = os_fetch_file_path(dep_file_path, contents))) { if (verbose) { fprintf(stderr, "unable to read .d file: %s\n", err_str(err)); } @@ -586,6 +586,6 @@ void cache_release(CacheHash *ch) { } } - os_file_close(ch->manifest_file); + os_file_close(&ch->manifest_file); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 568344fc09..d21ada1b23 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -19,6 +19,7 @@ #include "target.hpp" #include "util.hpp" #include "zig_llvm.h" +#include "userland.h" #include <stdio.h> #include <errno.h> @@ -92,7 +93,7 @@ static const char *symbols_that_llvm_depends_on[] = { }; CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, + OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc, Buf *cache_dir) { CodeGen *g = allocate<CodeGen>(1); @@ -100,19 +101,24 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget codegen_add_time_event(g, "Initialize"); g->libc = libc; - g->zig_lib_dir = zig_lib_dir; g->zig_target = target; g->cache_dir = cache_dir; + if (override_lib_dir == nullptr) { + g->zig_lib_dir = get_zig_lib_dir(); + } else { + g->zig_lib_dir = override_lib_dir; + } + if (override_std_dir == nullptr) { g->zig_std_dir = buf_alloc(); - os_path_join(zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); + os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); } else { g->zig_std_dir = override_std_dir; } g->zig_c_headers_dir = buf_alloc(); - os_path_join(zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir); + os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir); g->build_mode = build_mode; g->out_type = out_type; @@ -393,6 +399,15 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { } } +static void add_probe_stack_attr(CodeGen *g, LLVMValueRef fn_val) { + // Windows already emits its own stack probes + if (!g->disable_stack_probing && g->zig_target->os != OsWindows && + (g->zig_target->arch == ZigLLVM_x86 || + g->zig_target->arch == ZigLLVM_x86_64)) { + addLLVMFnAttrStr(fn_val, "probe-stack", "__zig_probe_stack"); + } +} + static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { switch (id) { case GlobalLinkageIdInternal: @@ -424,7 +439,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) { } static void maybe_export_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) { - if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows) { + if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows && g->is_dynamic) { LLVMSetDLLStorageClass(global_value, LLVMDLLExportStorageClass); } } @@ -495,6 +510,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { auto entry = g->exported_symbol_names.maybe_get(symbol_name); if (entry == nullptr) { fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); + + if (target_is_wasm(g->zig_target)) { + assert(fn_table_entry->proto_node->type == NodeTypeFnProto); + AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; + if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) { + addLLVMFnAttrStr(fn_table_entry->llvm_value, "wasm-import-module", buf_ptr(fn_proto->lib_name)); + } + } } else { assert(entry->value->id == TldIdFn); TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value); @@ -573,6 +596,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong"); addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4"); } + + add_probe_stack_attr(g, fn_table_entry->llvm_value); } } else { maybe_import_dll(g, fn_table_entry->llvm_value, linkage); @@ -983,10 +1008,19 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace LLVMBuildUnreachable(g->builder); } +// TODO update most callsites to call gen_assertion instead of this static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) { gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr); } +static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) { + if (ir_want_runtime_safety(g, source_instruction)) { + gen_safety_crash(g, msg_id); + } else { + LLVMBuildUnreachable(g->builder); + } +} + static LLVMValueRef get_stacksave_fn_val(CodeGen *g) { if (g->stacksave_fn_val) return g->stacksave_fn_val; @@ -1022,7 +1056,7 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) { // !0 = !{!"sp\00"} LLVMTypeRef param_types[] = { - LLVMMetadataTypeInContext(LLVMGetGlobalContext()), + LLVMMetadataTypeInContext(LLVMGetGlobalContext()), LLVMIntType(g->pointer_size_bytes * 8), }; @@ -1541,11 +1575,19 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2); Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false); - LLVMTypeRef arg_types[] = { - get_llvm_type(g, g->ptr_to_stack_trace_type), - get_llvm_type(g, g->err_tag_type), - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); + LLVMTypeRef fn_type_ref; + if (g->have_err_ret_tracing) { + LLVMTypeRef arg_types[] = { + get_llvm_type(g, g->ptr_to_stack_trace_type), + get_llvm_type(g, g->err_tag_type), + }; + fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); + } else { + LLVMTypeRef arg_types[] = { + get_llvm_type(g, g->err_tag_type), + }; + fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); + } LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); addLLVMFnAttr(fn_val, "noreturn"); addLLVMFnAttr(fn_val, "cold"); @@ -1567,7 +1609,15 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { LLVMPositionBuilderAtEnd(g->builder, entry_block); ZigLLVMClearCurrentDebugLocation(g->builder); - LLVMValueRef err_val = LLVMGetParam(fn_val, 1); + LLVMValueRef err_ret_trace_arg; + LLVMValueRef err_val; + if (g->have_err_ret_tracing) { + err_ret_trace_arg = LLVMGetParam(fn_val, 0); + err_val = LLVMGetParam(fn_val, 1); + } else { + err_ret_trace_arg = nullptr; + err_val = LLVMGetParam(fn_val, 0); + } LLVMValueRef err_table_indices[] = { LLVMConstNull(g->builtin_types.entry_usize->llvm_type), @@ -1589,7 +1639,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, ""); gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type); - gen_panic(g, global_slice, LLVMGetParam(fn_val, 0)); + gen_panic(g, global_slice, err_ret_trace_arg); LLVMPositionBuilderAtEnd(g->builder, prev_block); LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); @@ -1625,17 +1675,26 @@ static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) { static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); - LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); - if (err_ret_trace_val == nullptr) { - ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); - err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type)); + LLVMValueRef call_instruction; + if (g->have_err_ret_tracing) { + LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); + if (err_ret_trace_val == nullptr) { + ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); + err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type)); + } + LLVMValueRef args[] = { + err_ret_trace_val, + err_val, + }; + call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); + } else { + LLVMValueRef args[] = { + err_val, + }; + call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 1, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); } - LLVMValueRef args[] = { - err_ret_trace_val, - err_val, - }; - LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified), - ZigLLVM_FnInlineAuto, ""); LLVMSetTailCall(call_instruction, true); LLVMBuildUnreachable(g->builder); } @@ -3452,6 +3511,15 @@ static bool want_valgrind_support(CodeGen *g) { zig_unreachable(); } +static void gen_valgrind_undef(CodeGen *g, LLVMValueRef dest_ptr, LLVMValueRef byte_count) { + static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545; + ZigType *usize = g->builtin_types.entry_usize; + LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false); + LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false); + LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, ""); + gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero); +} + static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) { assert(type_has_bits(value_type)); uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, value_type)); @@ -3466,11 +3534,7 @@ static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_ ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); // then tell valgrind that the memory is undefined even though we just memset it if (want_valgrind_support(g)) { - static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545; - LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false); - LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false); - LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, ""); - gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero); + gen_valgrind_undef(g, dest_ptr, byte_count); } } @@ -3480,14 +3544,14 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir if (!type_has_bits(ptr_type)) return nullptr; - bool have_init_expr = !value_is_all_undef(&instruction->value->value); + bool have_init_expr = !value_is_all_undef(&instruction->value->value); if (have_init_expr) { LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); LLVMValueRef value = ir_llvm_value(g, instruction->value); gen_assign_raw(g, ptr, ptr_type, value); } else if (ir_want_runtime_safety(g, &instruction->base)) { gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type, - ir_llvm_value(g, instruction->ptr)); + ir_llvm_value(g, instruction->ptr)); } return nullptr; } @@ -3690,7 +3754,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr } FnWalk fn_walk = {}; fn_walk.id = FnWalkIdCall; - fn_walk.data.call.inst = instruction; + fn_walk.data.call.inst = instruction; fn_walk.data.call.is_var_args = is_var_args; fn_walk.data.call.gen_param_values = &gen_param_values; walk_function_params(g, fn_type, &fn_walk); @@ -3710,7 +3774,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr LLVMCallConv llvm_cc = get_llvm_cc(g, cc); LLVMValueRef result; - + if (instruction->new_stack == nullptr) { result = ZigLLVMBuildCall(g->builder, fn_val, gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); @@ -3968,19 +4032,19 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru } static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueRef maybe_handle) { - assert(maybe_type->id == ZigTypeIdOptional); + assert(maybe_type->id == ZigTypeIdOptional || + (maybe_type->id == ZigTypeIdPointer && maybe_type->data.pointer.allow_zero)); + ZigType *child_type = maybe_type->data.maybe.child_type; - if (!type_has_bits(child_type)) { + if (!type_has_bits(child_type)) return maybe_handle; - } else { - bool is_scalar = !handle_is_ptr(maybe_type); - if (is_scalar) { - return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), ""); - } else { - LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); - return gen_load_untyped(g, maybe_field_ptr, 0, false, ""); - } - } + + bool is_scalar = !handle_is_ptr(maybe_type); + if (is_scalar) + return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), ""); + + LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); + return gen_load_untyped(g, maybe_field_ptr, 0, false, ""); } static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable, @@ -4001,8 +4065,8 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -4190,7 +4254,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { LLVMTypeRef tag_int_llvm_type = get_llvm_type(g, tag_int_type); LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(get_llvm_type(g, u8_slice_type), 0), &tag_int_llvm_type, 1, false); - + Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false); LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); LLVMSetLinkage(fn_val, LLVMInternalLinkage); @@ -4490,17 +4554,27 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) { LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); - LLVMValueRef char_val = ir_llvm_value(g, instruction->byte); LLVMValueRef len_val = ir_llvm_value(g, instruction->count); LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); ZigType *ptr_type = instruction->dest_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); - ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, char_val, len_val, get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile); + bool val_is_undef = value_is_all_undef(&instruction->byte->value); + LLVMValueRef fill_char; + if (val_is_undef) { + fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); + } else { + fill_char = ir_llvm_value(g, instruction->byte); + } + ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, fill_char, len_val, get_ptr_align(g, ptr_type), + ptr_type->data.pointer.is_volatile); + + if (val_is_undef && want_valgrind_support(g)) { + gen_valgrind_undef(g, dest_ptr_casted, len_val); + } return nullptr; } @@ -5422,6 +5496,31 @@ static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable, return nullptr; } +static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executable, + IrInstructionAssertNonNull *instruction) +{ + LLVMValueRef target = ir_llvm_value(g, instruction->target); + ZigType *target_type = instruction->target->value.type; + + if (target_type->id == ZigTypeIdPointer) { + assert(target_type->data.pointer.ptr_len == PtrLenC); + LLVMValueRef non_null_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target, + LLVMConstNull(get_llvm_type(g, target_type)), ""); + + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullOk"); + LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_assertion(g, PanicMsgIdUnwrapOptionalFail, &instruction->base); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + } else { + zig_unreachable(); + } + return nullptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5676,6 +5775,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction); case IrInstructionIdAssertZero: return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction); + case IrInstructionIdAssertNonNull: + return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction); case IrInstructionIdResizeSlice: return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction); } @@ -6585,7 +6686,7 @@ static void validate_inline_fns(CodeGen *g) { } static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) { - if (var->is_thread_local && !g->is_single_threaded) { + if (var->is_thread_local && (!g->is_single_threaded || var->linkage != VarLinkageInternal)) { LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); } } @@ -6905,7 +7006,7 @@ static void do_code_gen(CodeGen *g) { ir_render(g, fn_table_entry); } - + assert(!g->errors.length); if (buf_len(&g->global_asm) != 0) { @@ -6942,6 +7043,11 @@ static void zig_llvm_emit_output(CodeGen *g) { } validate_inline_fns(g); g->link_objects.append(output_path); + if (g->bundle_compiler_rt && (g->out_type == OutTypeObj || + (g->out_type == OutTypeLib && !g->is_dynamic))) + { + zig_link_add_compiler_rt(g); + } break; case EmitFileTypeAssembly: @@ -7337,9 +7443,26 @@ static bool detect_pic(CodeGen *g) { zig_unreachable(); } +static bool detect_single_threaded(CodeGen *g) { + if (g->want_single_threaded) + return true; + if (target_is_single_threaded(g->zig_target)) { + return true; + } + return false; +} + +static bool detect_err_ret_tracing(CodeGen *g) { + return !target_is_wasm(g->zig_target) && + g->build_mode != BuildModeFastRelease && + g->build_mode != BuildModeSmallRelease; +} + Buf *codegen_generate_builtin_source(CodeGen *g) { g->have_dynamic_link = detect_dynamic_link(g); g->have_pic = detect_pic(g); + g->is_single_threaded = detect_single_threaded(g); + g->have_err_ret_tracing = detect_err_ret_tracing(g); Buf *contents = buf_alloc(); @@ -7696,7 +7819,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { assert(ContainerLayoutAuto == 0); assert(ContainerLayoutExtern == 1); assert(ContainerLayoutPacked == 2); - + assert(CallingConventionUnspecified == 0); assert(CallingConventionC == 1); assert(CallingConventionCold == 2); @@ -7814,7 +7937,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { Buf *contents; if (hit) { contents = buf_alloc(); - if ((err = os_fetch_file_path(builtin_zig_path, contents, false))) { + if ((err = os_fetch_file_path(builtin_zig_path, contents))) { fprintf(stderr, "Unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err)); exit(1); } @@ -7844,6 +7967,12 @@ static void init(CodeGen *g) { g->have_dynamic_link = detect_dynamic_link(g); g->have_pic = detect_pic(g); + g->is_single_threaded = detect_single_threaded(g); + g->have_err_ret_tracing = detect_err_ret_tracing(g); + + if (target_is_single_threaded(g->zig_target)) { + g->is_single_threaded = true; + } if (g->is_test_build) { g->subsystem = TargetSubsystemConsole; @@ -7953,8 +8082,6 @@ static void init(CodeGen *g) { } } - g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease; - define_builtin_fns(g); Error err; if ((err = define_builtin_compile_vars(g))) { @@ -8093,7 +8220,126 @@ static void detect_libc(CodeGen *g) { } } -AstNode *codegen_translate_c(CodeGen *g, Buf *full_path) { +// does not add the "cc" arg +void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path, bool translate_c) { + if (translate_c) { + args.append("-x"); + args.append("c"); + } + + if (out_dep_path != nullptr) { + args.append("-MD"); + args.append("-MV"); + args.append("-MF"); + args.append(out_dep_path); + } + + args.append("-nostdinc"); + args.append("-fno-spell-checking"); + + if (translate_c) { + // this gives us access to preprocessing entities, presumably at + // the cost of performance + args.append("-Xclang"); + args.append("-detailed-preprocessing-record"); + } else { + switch (g->err_color) { + case ErrColorAuto: + break; + case ErrColorOff: + args.append("-fno-color-diagnostics"); + args.append("-fno-caret-diagnostics"); + break; + case ErrColorOn: + args.append("-fcolor-diagnostics"); + args.append("-fcaret-diagnostics"); + break; + } + } + + args.append("-isystem"); + args.append(buf_ptr(g->zig_c_headers_dir)); + + for (size_t i = 0; i < g->libc_include_dir_len; i += 1) { + Buf *include_dir = g->libc_include_dir_list[i]; + args.append("-isystem"); + args.append(buf_ptr(include_dir)); + } + + if (g->zig_target->is_native) { + args.append("-march=native"); + } else { + args.append("-target"); + args.append(buf_ptr(&g->triple_str)); + } + if (g->zig_target->os == OsFreestanding) { + args.append("-ffreestanding"); + } + + if (!g->strip_debug_symbols) { + args.append("-g"); + } + + switch (g->build_mode) { + case BuildModeDebug: + // windows c runtime requires -D_DEBUG if using debug libraries + args.append("-D_DEBUG"); + + if (g->libc_link_lib != nullptr) { + args.append("-fstack-protector-strong"); + args.append("--param"); + args.append("ssp-buffer-size=4"); + } else { + args.append("-fno-stack-protector"); + } + args.append("-fno-omit-frame-pointer"); + break; + case BuildModeSafeRelease: + // See the comment in the BuildModeFastRelease case for why we pass -O2 rather + // than -O3 here. + args.append("-O2"); + if (g->libc_link_lib != nullptr) { + args.append("-D_FORTIFY_SOURCE=2"); + args.append("-fstack-protector-strong"); + args.append("--param"); + args.append("ssp-buffer-size=4"); + } else { + args.append("-fno-stack-protector"); + } + args.append("-fomit-frame-pointer"); + break; + case BuildModeFastRelease: + args.append("-DNDEBUG"); + // Here we pass -O2 rather than -O3 because, although we do the equivalent of + // -O3 in Zig code, the justification for the difference here is that Zig + // has better detection and prevention of undefined behavior, so -O3 is safer for + // Zig code than it is for C code. Also, C programmers are used to their code + // running in -O2 and thus the -O3 path has been tested less. + args.append("-O2"); + args.append("-fno-stack-protector"); + args.append("-fomit-frame-pointer"); + break; + case BuildModeSmallRelease: + args.append("-DNDEBUG"); + args.append("-Os"); + args.append("-fno-stack-protector"); + args.append("-fomit-frame-pointer"); + break; + } + + if (target_supports_fpic(g->zig_target) && g->have_pic) { + args.append("-fPIC"); + } + + for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { + args.append(g->clang_argv[arg_i]); + } + + +} + +void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_userland_implementation) { + Error err; Buf *src_basename = buf_alloc(); Buf *src_dirname = buf_alloc(); os_path_split(full_path, src_dirname, src_basename); @@ -8105,13 +8351,47 @@ AstNode *codegen_translate_c(CodeGen *g, Buf *full_path) { init(g); - ZigList<ErrorMsg *> errors = {0}; + Stage2TranslateMode trans_mode = buf_ends_with_str(full_path, ".h") ? + Stage2TranslateModeImport : Stage2TranslateModeTranslate; + + + ZigList<const char *> clang_argv = {0}; + add_cc_args(g, clang_argv, nullptr, true); + + clang_argv.append(buf_ptr(full_path)); + + if (g->verbose_cc) { + fprintf(stderr, "clang"); + for (size_t i = 0; i < clang_argv.length; i += 1) { + fprintf(stderr, " %s", clang_argv.at(i)); + } + fprintf(stderr, "\n"); + } + + clang_argv.append(nullptr); // to make the [start...end] argument work + + const char *resources_path = buf_ptr(g->zig_c_headers_dir); + Stage2ErrorMsg *errors_ptr; + size_t errors_len; + Stage2Ast *ast; AstNode *root_node; - Error err = parse_h_file(&root_node, &errors, buf_ptr(full_path), g, nullptr); - if (err == ErrorCCompileErrors && errors.length > 0) { - for (size_t i = 0; i < errors.length; i += 1) { - ErrorMsg *err_msg = errors.at(i); + if (use_userland_implementation) { + err = stage2_translate_c(&ast, &errors_ptr, &errors_len, + &clang_argv.at(0), &clang_argv.last(), trans_mode, resources_path); + } else { + err = parse_h_file(g, &root_node, &errors_ptr, &errors_len, &clang_argv.at(0), &clang_argv.last(), + trans_mode, resources_path); + } + + if (err == ErrorCCompileErrors && errors_len > 0) { + for (size_t i = 0; i < errors_len; i += 1) { + Stage2ErrorMsg *clang_err = &errors_ptr[i]; + ErrorMsg *err_msg = err_msg_create_with_offset( + clang_err->filename_ptr ? + buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(), + clang_err->line, clang_err->column, clang_err->offset, clang_err->source, + buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len)); print_err_msg(err_msg, g->err_color); } exit(1); @@ -8122,7 +8402,12 @@ AstNode *codegen_translate_c(CodeGen *g, Buf *full_path) { exit(1); } - return root_node; + + if (use_userland_implementation) { + stage2_render_ast(ast, out_file); + } else { + ast_render(out_file, root_node, 4); + } } static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *basename) { @@ -8233,7 +8518,7 @@ static void gen_root_source(CodeGen *g) { Error err; // No need for using the caching system for this file fetch because it is handled // separately. - if ((err = os_fetch_file_path(resolved_path, source_code, true))) { + if ((err = os_fetch_file_path(resolved_path, source_code))) { fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err)); exit(1); } @@ -8308,7 +8593,7 @@ static void gen_global_asm(CodeGen *g) { Buf *asm_file = g->assembly_files.at(i); // No need to use the caching system for these fetches because they // are handled separately. - if ((err = os_fetch_file_path(asm_file, &contents, false))) { + if ((err = os_fetch_file_path(asm_file, &contents))) { zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); } buf_append_buf(&g->global_asm, &contents); @@ -8441,90 +8726,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { args.append("cc"); Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path)); - args.append("-MD"); - args.append("-MV"); - args.append("-MF"); - args.append(buf_ptr(out_dep_path)); - - args.append("-nostdinc"); - args.append("-fno-spell-checking"); - - switch (g->err_color) { - case ErrColorAuto: - break; - case ErrColorOff: - args.append("-fno-color-diagnostics"); - args.append("-fno-caret-diagnostics"); - break; - case ErrColorOn: - args.append("-fcolor-diagnostics"); - args.append("-fcaret-diagnostics"); - break; - } - - args.append("-isystem"); - args.append(buf_ptr(g->zig_c_headers_dir)); - - for (size_t i = 0; i < g->libc_include_dir_len; i += 1) { - Buf *include_dir = g->libc_include_dir_list[i]; - args.append("-isystem"); - args.append(buf_ptr(include_dir)); - } - - if (g->zig_target->is_native) { - args.append("-march=native"); - } else { - args.append("-target"); - args.append(buf_ptr(&g->triple_str)); - } - - if (!g->strip_debug_symbols) { - args.append("-g"); - } - - switch (g->build_mode) { - case BuildModeDebug: - if (g->libc_link_lib != nullptr) { - args.append("-fstack-protector-strong"); - args.append("--param"); - args.append("ssp-buffer-size=4"); - } else { - args.append("-fno-stack-protector"); - } - args.append("-fno-omit-frame-pointer"); - break; - case BuildModeSafeRelease: - // See the comment in the BuildModeFastRelease case for why we pass -O2 rather - // than -O3 here. - args.append("-O2"); - if (g->libc_link_lib != nullptr) { - args.append("-D_FORTIFY_SOURCE=2"); - args.append("-fstack-protector-strong"); - args.append("--param"); - args.append("ssp-buffer-size=4"); - } else { - args.append("-fno-stack-protector"); - } - args.append("-fomit-frame-pointer"); - break; - case BuildModeFastRelease: - args.append("-DNDEBUG"); - // Here we pass -O2 rather than -O3 because, although we do the equivalent of - // -O3 in Zig code, the justification for the difference here is that Zig - // has better detection and prevention of undefined behavior, so -O3 is safer for - // Zig code than it is for C code. Also, C programmers are used to their code - // running in -O2 and thus the -O3 path has been tested less. - args.append("-O2"); - args.append("-fno-stack-protector"); - args.append("-fomit-frame-pointer"); - break; - case BuildModeSmallRelease: - args.append("-DNDEBUG"); - args.append("-Os"); - args.append("-fno-stack-protector"); - args.append("-fomit-frame-pointer"); - break; - } + add_cc_args(g, args, buf_ptr(out_dep_path), false); args.append("-o"); args.append(buf_ptr(out_obj_path)); @@ -8532,19 +8734,10 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { args.append("-c"); args.append(buf_ptr(c_source_file)); - if (target_supports_fpic(g->zig_target) && g->have_pic) { - args.append("-fPIC"); - } - - for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { - args.append(g->clang_argv[arg_i]); - } - for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { args.append(c_file->args.at(arg_i)); } - if (g->verbose_cc) { print_zig_cc_cmd("zig", &args); } @@ -9158,6 +9351,8 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->each_lib_rpath); cache_bool(ch, g->disable_gen_h); + cache_bool(ch, g->bundle_compiler_rt); + cache_bool(ch, g->disable_stack_probing); cache_bool(ch, want_valgrind_support(g)); cache_bool(ch, g->have_pic); cache_bool(ch, g->have_dynamic_link); @@ -9268,6 +9463,8 @@ void codegen_build_and_link(CodeGen *g) { g->have_dynamic_link = detect_dynamic_link(g); g->have_pic = detect_pic(g); + g->is_single_threaded = detect_single_threaded(g); + g->have_err_ret_tracing = detect_err_ret_tracing(g); detect_libc(g); detect_dynamic_linker(g); diff --git a/src/codegen.hpp b/src/codegen.hpp index 3befca2de5..47c0097e4b 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -12,6 +12,7 @@ #include "errmsg.hpp" #include "target.hpp" #include "libc_installation.hpp" +#include "userland.h" #include <stdio.h> @@ -43,6 +44,7 @@ void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patc void codegen_add_time_event(CodeGen *g, const char *name); void codegen_print_timing_report(CodeGen *g, FILE *f); void codegen_link(CodeGen *g); +void zig_link_add_compiler_rt(CodeGen *g); void codegen_build_and_link(CodeGen *g); ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, @@ -50,7 +52,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c void codegen_add_assembly(CodeGen *g, Buf *path); void codegen_add_object(CodeGen *g, Buf *object_path); -AstNode *codegen_translate_c(CodeGen *g, Buf *path); +void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_userland_implementation); Buf *codegen_generate_builtin_source(CodeGen *g); diff --git a/src/compiler.cpp b/src/compiler.cpp index af62173db7..8bfe87bfcd 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -179,24 +179,24 @@ Buf *get_zig_lib_dir(void) { return &saved_lib_dir; } -Buf *get_zig_std_dir() { +Buf *get_zig_std_dir(Buf *zig_lib_dir) { if (saved_std_dir.list.length != 0) { return &saved_std_dir; } buf_resize(&saved_std_dir, 0); - os_path_join(get_zig_lib_dir(), buf_create_from_str("std"), &saved_std_dir); + os_path_join(zig_lib_dir, buf_create_from_str("std"), &saved_std_dir); return &saved_std_dir; } -Buf *get_zig_special_dir() { +Buf *get_zig_special_dir(Buf *zig_lib_dir) { if (saved_special_dir.list.length != 0) { return &saved_special_dir; } buf_resize(&saved_special_dir, 0); - os_path_join(get_zig_std_dir(), buf_sprintf("special"), &saved_special_dir); + os_path_join(get_zig_std_dir(zig_lib_dir), buf_sprintf("special"), &saved_special_dir); return &saved_special_dir; } diff --git a/src/compiler.hpp b/src/compiler.hpp index f2788b9998..4d682ba2fa 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -16,7 +16,7 @@ Error get_compiler_id(Buf **result); Buf *get_self_dynamic_linker_path(void); Buf *get_zig_lib_dir(void); -Buf *get_zig_special_dir(void); -Buf *get_zig_std_dir(void); +Buf *get_zig_special_dir(Buf *zig_lib_dir); +Buf *get_zig_std_dir(Buf *zig_lib_dir); #endif diff --git a/src/error.cpp b/src/error.cpp index 84b78aba1b..69676f9cf5 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -50,6 +50,10 @@ const char *err_str(Error err) { case ErrorUnexpectedWriteFailure: return "unexpected write failure"; case ErrorUnexpectedSeekFailure: return "unexpected seek failure"; case ErrorUnexpectedFileTruncationFailure: return "unexpected file truncation failure"; + case ErrorUnimplemented: return "unimplemented"; + case ErrorOperationAborted: return "operation aborted"; + case ErrorBrokenPipe: return "broken pipe"; + case ErrorNoSpaceLeft: return "no space left"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index d943703268..3ff36e1a5f 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -8,56 +8,10 @@ #ifndef ERROR_HPP #define ERROR_HPP -#include <assert.h> - -enum Error { - ErrorNone, - ErrorNoMem, - ErrorInvalidFormat, - ErrorSemanticAnalyzeFail, - ErrorAccess, - ErrorInterrupted, - ErrorSystemResources, - ErrorFileNotFound, - ErrorFileSystem, - ErrorFileTooBig, - ErrorDivByZero, - ErrorOverflow, - ErrorPathAlreadyExists, - ErrorUnexpected, - ErrorExactDivRemainder, - ErrorNegativeDenominator, - ErrorShiftedOutOneBits, - ErrorCCompileErrors, - ErrorEndOfFile, - ErrorIsDir, - ErrorNotDir, - ErrorUnsupportedOperatingSystem, - ErrorSharingViolation, - ErrorPipeBusy, - ErrorPrimitiveTypeNotFound, - ErrorCacheUnavailable, - ErrorPathTooLong, - ErrorCCompilerCannotFindFile, - ErrorReadingDepFile, - ErrorInvalidDepFile, - ErrorMissingArchitecture, - ErrorMissingOperatingSystem, - ErrorUnknownArchitecture, - ErrorUnknownOperatingSystem, - ErrorUnknownABI, - ErrorInvalidFilename, - ErrorDiskQuota, - ErrorDiskSpace, - ErrorUnexpectedWriteFailure, - ErrorUnexpectedSeekFailure, - ErrorUnexpectedFileTruncationFailure, -}; +#include "userland.h" const char *err_str(Error err); -static inline void assertNoError(Error err) { - assert(err == ErrorNone); -} +#define assertNoError(err) assert((err) == ErrorNone); #endif diff --git a/src/ir.cpp b/src/ir.cpp index c572e3c885..e89d30232e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -188,6 +188,19 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c assert(get_src_ptr_type(const_val->type) != nullptr); assert(const_val->special == ConstValSpecialStatic); ConstExprValue *result; + + switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) { + case OnePossibleValueInvalid: + zig_unreachable(); + case OnePossibleValueYes: + result = create_const_vals(1); + result->type = const_val->type->data.pointer.child_type; + result->special = ConstValSpecialStatic; + return result; + case OnePossibleValueNo: + break; + } + switch (const_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); @@ -356,6 +369,18 @@ static void ir_ref_var(ZigVar *var) { var->ref_count += 1; } +ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { + ConstExprValue *result = ir_eval_const_value(ira->codegen, scope, node, ira->codegen->builtin_types.entry_type, + ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, + node, nullptr, ira->new_irb.exec, nullptr); + + if (type_is_invalid(result->type)) + return ira->codegen->builtin_types.entry_invalid; + + assert(result->special != ConstValSpecialRuntime); + return result->data.x_type; +} + static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) { IrBasicBlock *result = allocate<IrBasicBlock>(1); result->scope = scope; @@ -978,6 +1003,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertZero *) { return IrInstructionIdAssertZero; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *) { + return IrInstructionIdAssertNonNull; +} + template<typename T> static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -3012,6 +3041,19 @@ static IrInstruction *ir_build_assert_zero(IrAnalyze *ira, IrInstruction *source return &instruction->base; } +static IrInstruction *ir_build_assert_non_null(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *target) +{ + IrInstructionAssertNonNull *instruction = ir_build_instruction<IrInstructionAssertNonNull>(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ira->codegen->builtin_types.entry_void; + instruction->target = target; + + ir_ref_instruction(target, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -5391,10 +5433,9 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod add_node_error(irb->codegen, variable_declaration->section_expr, buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); } - if (variable_declaration->threadlocal_tok != nullptr) { - add_token_error(irb->codegen, node->owner, variable_declaration->threadlocal_tok, - buf_sprintf("function-local variable '%s' cannot be threadlocal", buf_ptr(variable_declaration->symbol))); - } + + // Parser should ensure that this never happens + assert(variable_declaration->threadlocal_tok == nullptr); // Temporarily set the name of the IrExecutable to the VariableDeclaration // so that the struct or enum from the init expression inherits the name. @@ -5767,8 +5808,10 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base); - if (!instr_is_unreachable(body_result)) + if (!instr_is_unreachable(body_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.for_expr.body, body_result)); ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); + } ir_set_cursor_at_end_and_append_block(irb, continue_block); IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false); @@ -7891,6 +7934,11 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, return ir_add_error_node(ira, source_instruction->source_node, msg); } +static void ir_assert(bool ok, IrInstruction *source_instruction) { + if (ok) return; + src_assert(ok, source_instruction->source_node); +} + // This function takes a comptime ptr and makes the child const value conform to the type // described by the pointer. static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, @@ -7943,7 +7991,7 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec return &codegen->invalid_instruction->value; } } - return &codegen->invalid_instruction->value; + zig_unreachable(); } static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { @@ -8088,6 +8136,8 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) { case 64: dest_val->data.x_f64 = bigfloat_to_f64(bigfloat); break; + case 80: + zig_panic("TODO"); case 128: dest_val->data.x_f128 = bigfloat_to_f128(bigfloat); break; @@ -9904,6 +9954,7 @@ static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *t static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) { ConstGlobalRefs *global_refs = dest->global_refs; + assert(!same_global_refs || src->global_refs != nullptr); *dest = *src; if (!same_global_refs) { dest->global_refs = global_refs; @@ -9949,6 +10000,8 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ case 64: const_val->data.x_f64 = bigfloat_to_f64(&other_val->data.x_bigfloat); break; + case 80: + zig_panic("TODO"); case 128: const_val->data.x_f128 = bigfloat_to_f128(&other_val->data.x_bigfloat); break; @@ -9978,6 +10031,8 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ case 64: const_val->data.x_f64 = bigfloat_to_f64(&bigfloat); break; + case 80: + zig_panic("TODO"); case 128: const_val->data.x_f128 = bigfloat_to_f128(&bigfloat); break; @@ -10170,6 +10225,7 @@ static void ir_finish_bb(IrAnalyze *ira) { ira->instruction_index += 1; } + size_t my_old_bb_index = ira->old_bb_index; ira->old_bb_index += 1; bool need_repeat = true; @@ -10180,7 +10236,7 @@ static void ir_finish_bb(IrAnalyze *ira) { ira->old_bb_index += 1; continue; } - if (old_bb->other->instruction_list.length != 0) { + if (old_bb->other->instruction_list.length != 0 || ira->old_bb_index == my_old_bb_index) { ira->old_bb_index += 1; continue; } @@ -10205,16 +10261,18 @@ static IrInstruction *ir_unreach_error(IrAnalyze *ira) { static bool ir_emit_backward_branch(IrAnalyze *ira, IrInstruction *source_instruction) { size_t *bbc = ira->new_irb.exec->backward_branch_count; - size_t quota = ira->new_irb.exec->backward_branch_quota; + size_t *quota = ira->new_irb.exec->backward_branch_quota; // If we're already over quota, we've already given an error message for this. - if (*bbc > quota) { + if (*bbc > *quota) { + assert(ira->codegen->errors.length > 0); return false; } *bbc += 1; - if (*bbc > quota) { - ir_add_error(ira, source_instruction, buf_sprintf("evaluation exceeded %" ZIG_PRI_usize " backwards branches", quota)); + if (*bbc > *quota) { + ir_add_error(ira, source_instruction, + buf_sprintf("evaluation exceeded %" ZIG_PRI_usize " backwards branches", *quota)); return false; } return true; @@ -10249,6 +10307,12 @@ static IrInstruction *ir_const_bool(IrAnalyze *ira, IrInstruction *source_instru return result; } +static IrInstruction *ir_const_undef(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { + IrInstruction *result = ir_const(ira, source_instruction, ty); + result->value.special = ConstValSpecialUndef; + return result; +} + static IrInstruction *ir_const_void(IrAnalyze *ira, IrInstruction *source_instruction) { return ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_void); } @@ -10295,7 +10359,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un } ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, - ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, + ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, IrExecutable *parent_exec, AstNode *expected_type_source_node) { @@ -10317,7 +10381,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); - ast_render(codegen, stderr, node, 4); + ast_render(stderr, node, 4); fprintf(stderr, "\n{ // (IR)\n"); ir_print(codegen, stderr, ir_executable, 2); fprintf(stderr, "}\n"); @@ -10562,19 +10626,34 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so assert(instr_is_comptime(value)); ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); - assert(val); + assert(val != nullptr); - IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node); - const_instruction->base.value.special = ConstValSpecialStatic; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); + result->value.special = ConstValSpecialStatic; if (get_codegen_ptr_type(wanted_type) != nullptr) { - const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull; + result->value.data.x_ptr.special = ConstPtrSpecialNull; } else if (is_opt_err_set(wanted_type)) { - const_instruction->base.value.data.x_err_set = nullptr; + result->value.data.x_err_set = nullptr; } else { - const_instruction->base.value.data.x_optional = nullptr; + result->value.data.x_optional = nullptr; } - const_instruction->base.value.type = wanted_type; - return &const_instruction->base; + return result; +} + +static IrInstruction *ir_analyze_null_to_c_pointer(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *value, ZigType *wanted_type) +{ + assert(wanted_type->id == ZigTypeIdPointer); + assert(wanted_type->data.pointer.ptr_len == PtrLenC); + assert(instr_is_comptime(value)); + + ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); + assert(val != nullptr); + + IrInstruction *result = ir_const(ira, source_instr, wanted_type); + result->value.data.x_ptr.special = ConstPtrSpecialNull; + result->value.data.x_ptr.mut = ConstPtrMutComptimeConst; + return result; } static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value, @@ -11576,6 +11655,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type); } + // cast from null literal to C pointer + if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && + actual_type->id == ZigTypeIdNull) + { + return ir_analyze_null_to_c_pointer(ira, source_instr, value, wanted_type); + } + // cast from [N]T to E![]const T if (wanted_type->id == ZigTypeIdErrorUnion && is_slice(wanted_type->data.error_union.payload_type) && @@ -12193,14 +12279,12 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * IrBinOp op_id = bin_op_instruction->op_id; bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - if (is_equality_cmp && + if (is_equality_cmp && op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdNull) { + return ir_const_bool(ira, &bin_op_instruction->base, (op_id == IrBinOpCmpEq)); + } else if (is_equality_cmp && ((op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdOptional) || - (op2->value.type->id == ZigTypeIdNull && op1->value.type->id == ZigTypeIdOptional) || - (op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdNull))) + (op2->value.type->id == ZigTypeIdNull && op1->value.type->id == ZigTypeIdOptional))) { - if (op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdNull) { - return ir_const_bool(ira, &bin_op_instruction->base, (op_id == IrBinOpCmpEq)); - } IrInstruction *maybe_op; if (op1->value.type->id == ZigTypeIdNull) { maybe_op = op2; @@ -12230,9 +12314,48 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * } else { return is_non_null; } + } else if (is_equality_cmp && + ((op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdPointer && + op2->value.type->data.pointer.ptr_len == PtrLenC) || + (op2->value.type->id == ZigTypeIdNull && op1->value.type->id == ZigTypeIdPointer && + op1->value.type->data.pointer.ptr_len == PtrLenC))) + { + IrInstruction *c_ptr_op; + if (op1->value.type->id == ZigTypeIdNull) { + c_ptr_op = op2; + } else if (op2->value.type->id == ZigTypeIdNull) { + c_ptr_op = op1; + } else { + zig_unreachable(); + } + if (instr_is_comptime(c_ptr_op)) { + ConstExprValue *c_ptr_val = ir_resolve_const(ira, c_ptr_op, UndefOk); + if (!c_ptr_val) + return ira->codegen->invalid_instruction; + if (c_ptr_val->special == ConstValSpecialUndef) + return ir_const_undef(ira, &bin_op_instruction->base, ira->codegen->builtin_types.entry_bool); + bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || + (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); + bool bool_result = (op_id == IrBinOpCmpEq) ? is_null : !is_null; + return ir_const_bool(ira, &bin_op_instruction->base, bool_result); + } + IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope, + source_node, c_ptr_op); + is_non_null->value.type = ira->codegen->builtin_types.entry_bool; + + if (op_id == IrBinOpCmpEq) { + IrInstruction *result = ir_build_bool_not(&ira->new_irb, bin_op_instruction->base.scope, + bin_op_instruction->base.source_node, is_non_null); + result->value.type = ira->codegen->builtin_types.entry_bool; + return result; + } else { + return is_non_null; + } } else if (op1->value.type->id == ZigTypeIdNull || op2->value.type->id == ZigTypeIdNull) { - ir_add_error_node(ira, source_node, buf_sprintf("only optionals (not '%s') can compare to null", - buf_ptr(&(op1->value.type->id == ZigTypeIdNull ? op2->value.type->name : op1->value.type->name)))); + ZigType *non_null_type = (op1->value.type->id == ZigTypeIdNull) ? op2->value.type : op1->value.type; + ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null", + buf_ptr(&non_null_type->name))); return ira->codegen->invalid_instruction; } @@ -13828,11 +13951,12 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i zig_unreachable(); } -static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry, ZigType *fn_type, - IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) +static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry, + ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, + IrInstruction *async_allocator_inst) { Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME); - assert(async_allocator_inst->value.type->id == ZigTypeIdPointer); + ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base); ZigType *container_type = async_allocator_inst->value.type->data.pointer.child_type; IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, realloc_field_name, &call_instruction->base, async_allocator_inst, container_type); @@ -13840,7 +13964,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c return ira->codegen->invalid_instruction; } ZigType *ptr_to_realloc_fn_type = field_ptr_inst->value.type; - assert(ptr_to_realloc_fn_type->id == ZigTypeIdPointer); + ir_assert(ptr_to_realloc_fn_type->id == ZigTypeIdPointer, &call_instruction->base); ZigType *realloc_fn_type = ptr_to_realloc_fn_type->data.pointer.child_type; if (realloc_fn_type->id != ZigTypeIdFn) { @@ -13875,7 +13999,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node IrInstruction *casted_arg; if (param_decl_node->data.param_decl.var_token == nullptr) { AstNode *param_type_node = param_decl_node->data.param_decl.type; - ZigType *param_type = analyze_type_expr(ira->codegen, *exec_scope, param_type_node); + ZigType *param_type = ir_analyze_type_expr(ira, *exec_scope, param_type_node); if (type_is_invalid(param_type)) return false; @@ -13915,7 +14039,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod } else { if (param_decl_node->data.param_decl.var_token == nullptr) { AstNode *param_type_node = param_decl_node->data.param_decl.type; - ZigType *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node); + ZigType *param_type = ir_analyze_type_expr(ira, *child_scope, param_type_node); if (type_is_invalid(param_type)) return false; @@ -14296,7 +14420,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call } AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - ZigType *specified_return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node); + ZigType *specified_return_type = ir_analyze_type_expr(ira, exec_scope, return_type_node); if (type_is_invalid(specified_return_type)) return ira->codegen->invalid_instruction; ZigType *return_type; @@ -14532,7 +14656,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call if (fn_proto_node->data.fn_proto.return_var_token == nullptr) { AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - ZigType *specified_return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node); + ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node); if (type_is_invalid(specified_return_type)) return ira->codegen->invalid_instruction; if (fn_proto_node->data.fn_proto.auto_err_set) { @@ -14559,7 +14683,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call if (call_instruction->is_async) { AstNode *async_allocator_type_node = fn_proto_node->data.fn_proto.async_allocator_type; if (async_allocator_type_node != nullptr) { - ZigType *async_allocator_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, async_allocator_type_node); + ZigType *async_allocator_type = ir_analyze_type_expr(ira, impl_fn->child_scope, async_allocator_type_node); if (type_is_invalid(async_allocator_type)) return ira->codegen->invalid_instruction; inst_fn_type_id.async_allocator_type = async_allocator_type; @@ -15822,7 +15946,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, } } - if (!is_libc && !ira->codegen->have_pic && !ira->codegen->reported_bad_link_libc_error) { + if (!is_libc && !target_is_wasm(ira->codegen->zig_target) && !ira->codegen->have_pic && !ira->codegen->reported_bad_link_libc_error) { ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("dependency on dynamic library '%s' requires enabling Position Independent Code", buf_ptr(lib_name))); @@ -16696,16 +16820,16 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, case ZigTypeIdUnreachable: case ZigTypeIdUndefined: case ZigTypeIdNull: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: case ZigTypeIdBoundFn: - case ZigTypeIdMetaType: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: - ir_add_error_node(ira, size_of_instruction->base.source_node, + ir_add_error_node(ira, type_value->source_node, buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; + case ZigTypeIdMetaType: + case ZigTypeIdEnumLiteral: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: case ZigTypeIdVoid: case ZigTypeIdBool: case ZigTypeIdInt: @@ -16732,11 +16856,30 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) { ZigType *type_entry = value->value.type; - if (type_entry->id == ZigTypeIdOptional) { + if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.allow_zero) { if (instr_is_comptime(value)) { - ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefBad); - if (!maybe_val) + ConstExprValue *c_ptr_val = ir_resolve_const(ira, value, UndefOk); + if (c_ptr_val == nullptr) + return ira->codegen->invalid_instruction; + if (c_ptr_val->special == ConstValSpecialUndef) + return ir_const_undef(ira, source_inst, ira->codegen->builtin_types.entry_bool); + bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || + (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); + return ir_const_bool(ira, source_inst, !is_null); + } + + IrInstruction *result = ir_build_test_nonnull(&ira->new_irb, + source_inst->scope, source_inst->source_node, value); + result->value.type = ira->codegen->builtin_types.entry_bool; + return result; + } else if (type_entry->id == ZigTypeIdOptional) { + if (instr_is_comptime(value)) { + ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefOk); + if (maybe_val == nullptr) return ira->codegen->invalid_instruction; + if (maybe_val->special == ConstValSpecialUndef) + return ir_const_undef(ira, source_inst, ira->codegen->builtin_types.entry_bool); return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val)); } @@ -16770,6 +16913,32 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; + if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.ptr_len == PtrLenC) { + if (instr_is_comptime(base_ptr)) { + ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { + ConstExprValue *c_ptr_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); + if (c_ptr_val == nullptr) + return ira->codegen->invalid_instruction; + bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || + (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); + if (is_null) { + ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null")); + return ira->codegen->invalid_instruction; + } + return base_ptr; + } + } + if (!safety_check_on) + return base_ptr; + IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr); + ir_build_assert_non_null(ira, source_instr, c_ptr_val); + return base_ptr; + } + if (type_entry->id != ZigTypeIdOptional) { ir_add_error_node(ira, base_ptr->source_node, buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); @@ -16784,11 +16953,11 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); if (!val) return ira->codegen->invalid_instruction; - ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); - if (maybe_val == nullptr) - return ira->codegen->invalid_instruction; - if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { + ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); + if (maybe_val == nullptr) + return ira->codegen->invalid_instruction; + if (optional_value_is_null(maybe_val)) { ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null")); return ira->codegen->invalid_instruction; @@ -17435,6 +17604,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc ConstExprValue const_val = {}; const_val.special = ConstValSpecialStatic; const_val.type = container_type; + // const_val.global_refs = allocate<ConstGlobalRefs>(1); const_val.data.x_struct.fields = create_const_vals(actual_field_count); for (size_t i = 0; i < instr_field_count; i += 1) { IrInstructionContainerInitFieldsField *field = &fields[i]; @@ -17498,7 +17668,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc if (const_val.special == ConstValSpecialStatic) { IrInstruction *result = ir_const(ira, instruction, nullptr); ConstExprValue *out_val = &result->value; - copy_const_val(out_val, &const_val, true); + copy_const_val(out_val, &const_val, false); out_val->type = container_type; for (size_t i = 0; i < instr_field_count; i += 1) { @@ -17570,6 +17740,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, ConstExprValue const_val = {}; const_val.special = ConstValSpecialStatic; const_val.type = fixed_size_array_type; + // const_val.global_refs = allocate<ConstGlobalRefs>(1); const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); @@ -17606,8 +17777,6 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, if (const_val.special == ConstValSpecialStatic) { IrInstruction *result = ir_const(ira, &instruction->base, nullptr); ConstExprValue *out_val = &result->value; - // Make sure to pass same_global_refs=false here in order not to - // zero the global_refs field for `result` (#1608) copy_const_val(out_val, &const_val, false); result->value.type = fixed_size_array_type; for (size_t i = 0; i < elem_count; i += 1) { @@ -18961,8 +19130,8 @@ static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ir if (!ir_resolve_usize(ira, instruction->new_quota->child, &new_quota)) return ira->codegen->invalid_instruction; - if (new_quota > ira->new_irb.exec->backward_branch_quota) { - ira->new_irb.exec->backward_branch_quota = new_quota; + if (new_quota > *ira->new_irb.exec->backward_branch_quota) { + *ira->new_irb.exec->backward_branch_quota = new_quota; } return ir_const_void(ira, &instruction->base); @@ -19059,24 +19228,50 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct fprintf(stderr, "@cImport source: %s\n", buf_ptr(&tmp_c_file_path)); } - ZigList<ErrorMsg *> errors = {0}; - Buf *tmp_dep_file = buf_sprintf("%s.d", buf_ptr(&tmp_c_file_path)); + + ZigList<const char *> clang_argv = {0}; + + add_cc_args(ira->codegen, clang_argv, buf_ptr(tmp_dep_file), true); + + clang_argv.append(buf_ptr(&tmp_c_file_path)); + + if (ira->codegen->verbose_cc) { + fprintf(stderr, "clang"); + for (size_t i = 0; i < clang_argv.length; i += 1) { + fprintf(stderr, " %s", clang_argv.at(i)); + } + fprintf(stderr, "\n"); + } + + clang_argv.append(nullptr); // to make the [start...end] argument work + AstNode *root_node; - if ((err = parse_h_file(&root_node, &errors, buf_ptr(&tmp_c_file_path), ira->codegen, tmp_dep_file))) { + Stage2ErrorMsg *errors_ptr; + size_t errors_len; + + const char *resources_path = buf_ptr(ira->codegen->zig_c_headers_dir); + + if ((err = parse_h_file(ira->codegen, &root_node, &errors_ptr, &errors_len, + &clang_argv.at(0), &clang_argv.last(), Stage2TranslateModeImport, resources_path))) + { if (err != ErrorCCompileErrors) { ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err))); return ira->codegen->invalid_instruction; } - assert(errors.length > 0); ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed")); if (ira->codegen->libc_link_lib == nullptr) { add_error_note(ira->codegen, parent_err_msg, node, buf_sprintf("libc headers not available; compilation does not link against libc")); } - for (size_t i = 0; i < errors.length; i += 1) { - ErrorMsg *err_msg = errors.at(i); + for (size_t i = 0; i < errors_len; i += 1) { + Stage2ErrorMsg *clang_err = &errors_ptr[i]; + ErrorMsg *err_msg = err_msg_create_with_offset( + clang_err->filename_ptr ? + buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(), + clang_err->line, clang_err->column, clang_err->offset, clang_err->source, + buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len)); err_msg_add_note(parent_err_msg, err_msg); } @@ -19106,7 +19301,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct buf_sprintf("C import failed: unable to open output file: %s", strerror(errno))); return ira->codegen->invalid_instruction; } - ast_render(ira->codegen, out_file, root_node, 4); + ast_render(out_file, root_node, 4); if (fclose(out_file) != 0) { ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to write to output file: %s", strerror(errno))); @@ -21026,18 +21221,24 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - IrInstruction *start_value = range->start->child; + IrInstruction *start_value_uncasted = range->start->child; + if (type_is_invalid(start_value_uncasted->value.type)) + return ira->codegen->invalid_instruction; + IrInstruction *start_value = ir_implicit_cast(ira, start_value_uncasted, switch_type); if (type_is_invalid(start_value->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *end_value = range->end->child; + IrInstruction *end_value_uncasted = range->end->child; + if (type_is_invalid(end_value_uncasted->value.type)) + return ira->codegen->invalid_instruction; + IrInstruction *end_value = ir_implicit_cast(ira, end_value_uncasted, switch_type); if (type_is_invalid(end_value->value.type)) return ira->codegen->invalid_instruction; - assert(start_value->value.type->id == ZigTypeIdErrorSet); + ir_assert(start_value->value.type->id == ZigTypeIdErrorSet, &instruction->base); uint32_t start_index = start_value->value.data.x_err_set->value; - assert(end_value->value.type->id == ZigTypeIdErrorSet); + ir_assert(end_value->value.type->id == ZigTypeIdErrorSet, &instruction->base); uint32_t end_index = end_value->value.data.x_err_set->value; if (start_index != end_index) { @@ -21260,7 +21461,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 } IrInstruction *result = ir_const(ira, target, result_type); - copy_const_val(&result->value, val, false); + copy_const_val(&result->value, val, true); result->value.type = result_type; return result; } @@ -21330,7 +21531,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } IrInstruction *result = ir_const(ira, source_instr, dest_type); - copy_const_val(&result->value, val, false); + copy_const_val(&result->value, val, true); result->value.type = dest_type; // Keep the bigger alignment, it can only help- @@ -21562,7 +21763,7 @@ static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNod static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { Error err; - assert(val->special == ConstValSpecialStatic); + src_assert(val->special == ConstValSpecialStatic, source_node); switch (val->type->id) { case ZigTypeIdInvalid: case ZigTypeIdMetaType: @@ -21612,7 +21813,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_panic("TODO buf_read_value_bytes enum packed"); case ContainerLayoutExtern: { ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; - assert(tag_int_type->id == ZigTypeIdInt); + src_assert(tag_int_type->id == ZigTypeIdInt, source_node); bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, codegen->is_big_endian, tag_int_type->data.integral.is_signed); return ErrorNone; @@ -21667,7 +21868,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou bigint_read_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian, false); while (src_i < src_field_count) { TypeStructField *field = &val->type->data.structure.fields[src_i]; - assert(field->gen_index != SIZE_MAX); + src_assert(field->gen_index != SIZE_MAX, source_node); if (field->gen_index != gen_i) break; ConstExprValue *field_val = &val->data.x_struct.fields[src_i]; @@ -21743,10 +21944,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ Error err; ZigType *src_type = value->value.type; - assert(get_codegen_ptr_type(src_type) == nullptr); - assert(type_can_bit_cast(src_type)); - assert(get_codegen_ptr_type(dest_type) == nullptr); - assert(type_can_bit_cast(dest_type)); + ir_assert(get_codegen_ptr_type(src_type) == nullptr, source_instr); + ir_assert(type_can_bit_cast(src_type), source_instr); + ir_assert(get_codegen_ptr_type(dest_type) == nullptr, source_instr); + ir_assert(type_can_bit_cast(dest_type), source_instr); if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; @@ -21836,8 +22037,8 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *ptr_type) { - assert(get_src_ptr_type(ptr_type) != nullptr); - assert(type_has_bits(ptr_type)); + ir_assert(get_src_ptr_type(ptr_type) != nullptr, source_instr); + ir_assert(type_has_bits(ptr_type), source_instr); IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize); if (type_is_invalid(casted_int->value.type)) @@ -21936,7 +22137,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, case TldIdFn: { TldFn *tld_fn = (TldFn *)tld; ZigFn *fn_entry = tld_fn->fn_entry; - assert(fn_entry->type_entry); + ir_assert(fn_entry->type_entry, &instruction->base); if (tld_fn->extern_lib_name != nullptr) { add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node); @@ -22134,7 +22335,7 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct ZigType *result_type = fn_type_id->param_info[arg_index].type; if (result_type == nullptr) { // Args are only unresolved if our function is generic. - assert(fn_type->data.fn.is_generic); + ir_assert(fn_type->data.fn.is_generic, &instruction->base); ir_add_error(ira, arg_index_inst, buf_sprintf("@ArgType could not resolve the type of arg %" ZIG_PRI_u64 " because '%s' is generic", @@ -22220,7 +22421,7 @@ static IrInstruction *ir_analyze_instruction_coro_begin(IrAnalyze *ira, IrInstru return ira->codegen->invalid_instruction; ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry != nullptr); + ir_assert(fn_entry != nullptr, &instruction->base); IrInstruction *result = ir_build_coro_begin(&ira->new_irb, instruction->base.scope, instruction->base.source_node, coro_id, coro_mem_ptr); result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type); @@ -22458,7 +22659,7 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) { - assert(instruction->ordering != nullptr); + ir_assert(instruction->ordering != nullptr, &instruction->base); ir_add_error(ira, instruction->ordering, buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel")); return ira->codegen->invalid_instruction; @@ -22466,7 +22667,7 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr if (instr_is_comptime(casted_ptr)) { IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr); - assert(result->value.type != nullptr); + ir_assert(result->value.type != nullptr, &instruction->base); return result; } @@ -22496,7 +22697,7 @@ static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, I return ira->codegen->invalid_instruction; ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry != nullptr); + ir_assert(fn_entry != nullptr, &instruction->base); if (type_can_fail(promise_result_type)) { fn_entry->calls_or_awaits_errorable_fn = true; @@ -22512,9 +22713,9 @@ static IrInstruction *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira if (type_is_invalid(coro_promise_ptr->value.type)) return ira->codegen->invalid_instruction; - assert(coro_promise_ptr->value.type->id == ZigTypeIdPointer); + ir_assert(coro_promise_ptr->value.type->id == ZigTypeIdPointer, &instruction->base); ZigType *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type; - assert(promise_frame_type->id == ZigTypeIdStruct); + ir_assert(promise_frame_type->id == ZigTypeIdStruct, &instruction->base); ZigType *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry; if (!type_can_fail(promise_result_type)) { @@ -22606,7 +22807,7 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS return result; } - assert(float_type->id == ZigTypeIdFloat); + ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base); if (float_type->data.floating.bit_count != 16 && float_type->data.floating.bit_count != 32 && float_type->data.floating.bit_count != 64) { @@ -22817,6 +23018,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdArrayToVector: case IrInstructionIdVectorToArray: case IrInstructionIdAssertZero: + case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: case IrInstructionIdLoadPtrGen: case IrInstructionIdBitCastGen: @@ -23096,7 +23298,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *old_instruction) { IrInstruction *new_instruction = ir_analyze_instruction_nocast(ira, old_instruction); - assert(new_instruction->value.type != nullptr); + ir_assert(new_instruction->value.type != nullptr, old_instruction); old_instruction->child = new_instruction; return new_instruction; } @@ -23221,6 +23423,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCmpxchgGen: case IrInstructionIdCmpxchgSrc: case IrInstructionIdAssertZero: + case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: case IrInstructionIdGlobalAsm: return true; diff --git a/src/ir.hpp b/src/ir.hpp index 0b85ad2c55..4fb7552212 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -14,7 +14,7 @@ bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, - ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, + ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, IrExecutable *parent_exec, AstNode *expected_type_source_node); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index dba0e4ee00..08f5cd01a4 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1003,6 +1003,12 @@ static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruct fprintf(irp->f, ")"); } +static void ir_print_assert_non_null(IrPrint *irp, IrInstructionAssertNonNull *instruction) { + fprintf(irp->f, "AssertNonNull("); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); +} + static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instruction) { fprintf(irp->f, "@resizeSlice("); ir_print_other_instruction(irp, instruction->operand); @@ -1880,6 +1886,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdAssertZero: ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction); break; + case IrInstructionIdAssertNonNull: + ir_print_assert_non_null(irp, (IrInstructionAssertNonNull *)instruction); + break; case IrInstructionIdResizeSlice: ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction); break; diff --git a/src/libc_installation.cpp b/src/libc_installation.cpp index 3ea17f1bdc..fc51fa427e 100644 --- a/src/libc_installation.cpp +++ b/src/libc_installation.cpp @@ -14,6 +14,7 @@ static const char *zig_libc_keys[] = { "include_dir", "sys_include_dir", "crt_dir", + "static_crt_dir", "msvc_lib_dir", "kernel32_lib_dir", }; @@ -34,6 +35,7 @@ static void zig_libc_init_empty(ZigLibCInstallation *libc) { buf_init_from_str(&libc->include_dir, ""); buf_init_from_str(&libc->sys_include_dir, ""); buf_init_from_str(&libc->crt_dir, ""); + buf_init_from_str(&libc->static_crt_dir, ""); buf_init_from_str(&libc->msvc_lib_dir, ""); buf_init_from_str(&libc->kernel32_lib_dir, ""); } @@ -45,7 +47,7 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget bool found_keys[array_length(zig_libc_keys)] = {}; Buf *contents = buf_alloc(); - if ((err = os_fetch_file_path(libc_file, contents, false))) { + if ((err = os_fetch_file_path(libc_file, contents))) { if (err != ErrorFileNotFound && verbose) { fprintf(stderr, "Unable to read '%s': %s\n", buf_ptr(libc_file), err_str(err)); } @@ -74,8 +76,9 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir); match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir); match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir); - match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->msvc_lib_dir); - match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->kernel32_lib_dir); + match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->static_crt_dir); + match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->msvc_lib_dir); + match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->kernel32_lib_dir); } for (size_t i = 0; i < zig_libc_keys_len; i += 1) { @@ -110,6 +113,15 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget } } + if (buf_len(&libc->static_crt_dir) == 0) { + if (target->os == OsWindows && target_abi_is_gnu(target->abi)) { + if (verbose) { + fprintf(stderr, "static_crt_dir may not be empty for %s\n", target_os_name(target->os)); + } + return ErrorSemanticAnalyzeFail; + } + } + if (buf_len(&libc->msvc_lib_dir) == 0) { if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) { if (verbose) { @@ -311,6 +323,10 @@ static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool #endif #if defined(ZIG_OS_WINDOWS) +static Error zig_libc_find_native_static_crt_dir_posix(ZigLibCInstallation *self, bool verbose) { + return zig_libc_cc_print_file_name("crtbegin.o", &self->static_crt_dir, true, verbose); +} + static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { Error err; if ((err = os_get_win32_ucrt_include_path(sdk, &self->include_dir))) { @@ -322,7 +338,7 @@ static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, return ErrorNone; } -static Error zig_libc_find_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target, +static Error zig_libc_find_native_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target, bool verbose) { Error err; @@ -398,11 +414,16 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file) { "# On POSIX it's the directory that includes `sys/errno.h`.\n" "sys_include_dir=%s\n" "\n" - "# The directory that contains `crt1.o`.\n" + "# The directory that contains `crt1.o` or `crt2.o`.\n" "# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n" "# Not needed when targeting MacOS.\n" "crt_dir=%s\n" "\n" + "# The directory that contains `crtbegin.o`.\n" + "# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n" + "# Not needed when targeting MacOS.\n" + "static_crt_dir=%s\n" + "\n" "# The directory that contains `vcruntime.lib`.\n" "# Only needed when targeting MSVC on Windows.\n" "msvc_lib_dir=%s\n" @@ -415,6 +436,7 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file) { buf_ptr(&self->include_dir), buf_ptr(&self->sys_include_dir), buf_ptr(&self->crt_dir), + buf_ptr(&self->static_crt_dir), buf_ptr(&self->msvc_lib_dir), buf_ptr(&self->kernel32_lib_dir) ); @@ -431,6 +453,8 @@ Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) { return err; if ((err = zig_libc_find_native_crt_dir_posix(self, verbose))) return err; + if ((err = zig_libc_find_native_static_crt_dir_posix(self, verbose))) + return err; return ErrorNone; } else { ZigWindowsSDK *sdk; @@ -444,7 +468,7 @@ Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) { return err; if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose))) return err; - if ((err = zig_libc_find_crt_dir_windows(self, sdk, &native_target, verbose))) + if ((err = zig_libc_find_native_crt_dir_windows(self, sdk, &native_target, verbose))) return err; return ErrorNone; case ZigFindWindowsSdkErrorOutOfMemory: diff --git a/src/libc_installation.hpp b/src/libc_installation.hpp index 765ae4ec56..8ecad7ce61 100644 --- a/src/libc_installation.hpp +++ b/src/libc_installation.hpp @@ -19,6 +19,7 @@ struct ZigLibCInstallation { Buf include_dir; Buf sys_include_dir; Buf crt_dir; + Buf static_crt_dir; Buf msvc_lib_dir; Buf kernel32_lib_dir; }; @@ -29,8 +30,6 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file); Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose); -#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_WINDOWS) Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose); -#endif #endif diff --git a/src/link.cpp b/src/link.cpp index d6093581f7..8900d0351b 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -25,6 +25,7 @@ static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, Ou CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type, parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path()); child_gen->disable_gen_h = true; + child_gen->disable_stack_probing = true; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; child_gen->verbose_ast = parent_gen->verbose_ast; child_gen->verbose_link = parent_gen->verbose_link; @@ -772,17 +773,15 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { } } -static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) { +static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) { // The Mach-O LLD code is not well maintained, and trips an assertion // when we link compiler_rt and builtin as libraries rather than objects. // Here we workaround this by having compiler_rt and builtin be objects. // TODO write our own linker. https://github.com/ziglang/zig/issues/1535 - OutType child_out_type = OutTypeLib; if (parent_gen->zig_target->os == OsMacOSX) { child_out_type = OutTypeObj; } - CodeGen *child_gen = create_child_codegen(parent_gen, full_path, child_out_type, parent_gen->libc); codegen_set_out_name(child_gen, buf_create_from_str(aname)); @@ -804,14 +803,14 @@ static Buf *build_a(CodeGen *parent_gen, const char *aname) { Buf *full_path = buf_alloc(); os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path); - return build_a_raw(parent_gen, aname, full_path); + return build_a_raw(parent_gen, aname, full_path, OutTypeLib); } -static Buf *build_compiler_rt(CodeGen *parent_gen) { +static Buf *build_compiler_rt(CodeGen *parent_gen, OutType child_out_type) { Buf *full_path = buf_alloc(); os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt.zig"), full_path); - return build_a_raw(parent_gen, "compiler_rt", full_path); + return build_a_raw(parent_gen, "compiler_rt", full_path, child_out_type); } static const char *get_darwin_arch_string(const ZigTarget *t) { @@ -1006,7 +1005,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(builtin_a_path)); } - Buf *compiler_rt_o_path = build_compiler_rt(g); + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -1091,16 +1090,35 @@ static void construct_linker_job_wasm(LinkJob *lj) { CodeGen *g = lj->codegen; lj->args.append("-error-limit=0"); - lj->args.append("--no-entry"); // So lld doesn't look for _start. + + if (g->zig_target->os != OsWASI) { + lj->args.append("--no-entry"); // So lld doesn't look for _start. + } lj->args.append("--allow-undefined"); - lj->args.append("--export-all"); lj->args.append("-o"); lj->args.append(buf_ptr(&g->output_file_path)); + auto export_it = g->exported_symbol_names.entry_iterator(); + decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr; + while ((curr_entry = export_it.next()) != nullptr) { + Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key)); + lj->args.append(buf_ptr(arg)); + } + // .o files for (size_t i = 0; i < g->link_objects.length; i += 1) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } + + if (g->out_type == OutTypeExe) { + if (g->libc_link_lib == nullptr) { + Buf *builtin_a_path = build_a(g, "builtin"); + lj->args.append(buf_ptr(builtin_a_path)); + } + + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); + lj->args.append(buf_ptr(compiler_rt_o_path)); + } } static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) { @@ -1124,53 +1142,121 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si } static void add_uefi_link_args(LinkJob *lj) { - lj->args.append("/BASE:0"); - lj->args.append("/ENTRY:EfiMain"); - lj->args.append("/OPT:REF"); - lj->args.append("/SAFESEH:NO"); - lj->args.append("/MERGE:.rdata=.data"); - lj->args.append("/ALIGN:32"); - lj->args.append("/NODEFAULTLIB"); - lj->args.append("/SECTION:.xdata,D"); + lj->args.append("-BASE:0"); + lj->args.append("-ENTRY:EfiMain"); + lj->args.append("-OPT:REF"); + lj->args.append("-SAFESEH:NO"); + lj->args.append("-MERGE:.rdata=.data"); + lj->args.append("-ALIGN:32"); + lj->args.append("-NODEFAULTLIB"); + lj->args.append("-SECTION:.xdata,D"); } -static void add_nt_link_args(LinkJob *lj, bool is_library) { +static void add_msvc_link_args(LinkJob *lj, bool is_library) { CodeGen *g = lj->codegen; - if (lj->link_in_crt) { - // TODO: https://github.com/ziglang/zig/issues/2064 - bool is_dynamic = true; // g->is_dynamic; - const char *lib_str = is_dynamic ? "" : "lib"; - const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; - - if (!is_dynamic) { - Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str); - lj->args.append(buf_ptr(cmt_lib_name)); - } else { - Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str); - lj->args.append(buf_ptr(msvcrt_lib_name)); - } + // TODO: https://github.com/ziglang/zig/issues/2064 + bool is_dynamic = true; // g->is_dynamic; + const char *lib_str = is_dynamic ? "" : "lib"; + const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; + + if (!is_dynamic) { + Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str); + lj->args.append(buf_ptr(cmt_lib_name)); + } else { + Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str); + lj->args.append(buf_ptr(msvcrt_lib_name)); + } + + Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str); + lj->args.append(buf_ptr(vcruntime_lib_name)); - Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str); - lj->args.append(buf_ptr(vcruntime_lib_name)); + Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str); + lj->args.append(buf_ptr(crt_lib_name)); - Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str); - lj->args.append(buf_ptr(crt_lib_name)); + //Visual C++ 2015 Conformance Changes + //https://msdn.microsoft.com/en-us/library/bb531344.aspx + lj->args.append("legacy_stdio_definitions.lib"); - //Visual C++ 2015 Conformance Changes - //https://msdn.microsoft.com/en-us/library/bb531344.aspx - lj->args.append("legacy_stdio_definitions.lib"); + // msvcrt depends on kernel32 and ntdll + lj->args.append("kernel32.lib"); + lj->args.append("ntdll.lib"); +} + +static const char *get_libc_file(ZigLibCInstallation *lib, const char *file) { + Buf *out_buf = buf_alloc(); + os_path_join(&lib->crt_dir, buf_create_from_str(file), out_buf); + return buf_ptr(out_buf); +} + +static const char *get_libc_static_file(ZigLibCInstallation *lib, const char *file) { + Buf *out_buf = buf_alloc(); + os_path_join(&lib->static_crt_dir, buf_create_from_str(file), out_buf); + return buf_ptr(out_buf); +} + +static void add_mingw_link_args(LinkJob *lj, bool is_library) { + CodeGen *g = lj->codegen; - // msvcrt depends on kernel32 and ntdll - lj->args.append("kernel32.lib"); - lj->args.append("ntdll.lib"); + bool is_dll = g->out_type == OutTypeLib && g->is_dynamic; + + if (g->zig_target->arch == ZigLLVM_x86) { + lj->args.append("-ALTERNATENAME:__image_base__=___ImageBase"); + } else { + lj->args.append("-ALTERNATENAME:__image_base__=__ImageBase"); + } + + if (is_dll) { + lj->args.append(get_libc_file(g->libc, "dllcrt2.o")); + } else { + lj->args.append(get_libc_file(g->libc, "crt2.o")); + } + + lj->args.append(get_libc_static_file(g->libc, "crtbegin.o")); + + lj->args.append(get_libc_file(g->libc, "libmingw32.a")); + + if (is_dll) { + lj->args.append(get_libc_static_file(g->libc, "libgcc_s.a")); + lj->args.append(get_libc_static_file(g->libc, "libgcc.a")); + } else { + lj->args.append(get_libc_static_file(g->libc, "libgcc.a")); + lj->args.append(get_libc_static_file(g->libc, "libgcc_eh.a")); + } + + lj->args.append(get_libc_static_file(g->libc, "libssp.a")); + lj->args.append(get_libc_file(g->libc, "libmoldname.a")); + lj->args.append(get_libc_file(g->libc, "libmingwex.a")); + lj->args.append(get_libc_file(g->libc, "libmsvcrt.a")); + + if (g->subsystem == TargetSubsystemWindows) { + lj->args.append(get_libc_file(g->libc, "libgdi32.a")); + lj->args.append(get_libc_file(g->libc, "libcomdlg32.a")); + } + + lj->args.append(get_libc_file(g->libc, "libadvapi32.a")); + lj->args.append(get_libc_file(g->libc, "libadvapi32.a")); + lj->args.append(get_libc_file(g->libc, "libshell32.a")); + lj->args.append(get_libc_file(g->libc, "libuser32.a")); + lj->args.append(get_libc_file(g->libc, "libkernel32.a")); + + lj->args.append(get_libc_static_file(g->libc, "crtend.o")); +} + +static void add_win_link_args(LinkJob *lj, bool is_library) { + if (lj->link_in_crt) { + if (target_abi_is_gnu(lj->codegen->zig_target->abi)) { + add_mingw_link_args(lj, is_library); + } else { + add_msvc_link_args(lj, is_library); + } } else { - lj->args.append("/NODEFAULTLIB"); + lj->args.append("-NODEFAULTLIB"); if (!is_library) { - if (g->have_winmain) { - lj->args.append("/ENTRY:WinMain"); + if (lj->codegen->have_winmain) { + lj->args.append("-ENTRY:WinMain"); } else { - lj->args.append("/ENTRY:WinMainCRTStartup"); + lj->args.append("-ENTRY:WinMainCRTStartup"); } } } @@ -1180,87 +1266,93 @@ static void construct_linker_job_coff(LinkJob *lj) { Error err; CodeGen *g = lj->codegen; - lj->args.append("/ERRORLIMIT:0"); + lj->args.append("-ERRORLIMIT:0"); - lj->args.append("/NOLOGO"); + lj->args.append("-NOLOGO"); if (!g->strip_debug_symbols) { - lj->args.append("/DEBUG"); + lj->args.append("-DEBUG"); } if (g->out_type == OutTypeExe) { // TODO compile time stack upper bound detection - lj->args.append("/STACK:16777216"); + lj->args.append("-STACK:16777216"); } coff_append_machine_arg(g, &lj->args); bool is_library = g->out_type == OutTypeLib; + if (is_library && g->is_dynamic) { + lj->args.append("-DLL"); + } + + lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); + + if (g->libc_link_lib != nullptr) { + assert(g->libc != nullptr); + + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); + + if (target_abi_is_gnu(g->zig_target->abi)) { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir)))); + } else { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir)))); + } + } + + for (size_t i = 0; i < g->lib_dirs.length; i += 1) { + const char *lib_dir = g->lib_dirs.at(i); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir))); + } + + for (size_t i = 0; i < g->link_objects.length; i += 1) { + lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); + } + switch (g->subsystem) { case TargetSubsystemAuto: if (g->zig_target->os == OsUefi) { add_uefi_link_args(lj); } else { - add_nt_link_args(lj, is_library); + add_win_link_args(lj, is_library); } break; case TargetSubsystemConsole: - lj->args.append("/SUBSYSTEM:console"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:console"); + add_win_link_args(lj, is_library); break; case TargetSubsystemEfiApplication: - lj->args.append("/SUBSYSTEM:efi_application"); + lj->args.append("-SUBSYSTEM:efi_application"); add_uefi_link_args(lj); break; case TargetSubsystemEfiBootServiceDriver: - lj->args.append("/SUBSYSTEM:efi_boot_service_driver"); + lj->args.append("-SUBSYSTEM:efi_boot_service_driver"); add_uefi_link_args(lj); break; case TargetSubsystemEfiRom: - lj->args.append("/SUBSYSTEM:efi_rom"); + lj->args.append("-SUBSYSTEM:efi_rom"); add_uefi_link_args(lj); break; case TargetSubsystemEfiRuntimeDriver: - lj->args.append("/SUBSYSTEM:efi_runtime_driver"); + lj->args.append("-SUBSYSTEM:efi_runtime_driver"); add_uefi_link_args(lj); break; case TargetSubsystemNative: - lj->args.append("/SUBSYSTEM:native"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:native"); + add_win_link_args(lj, is_library); break; case TargetSubsystemPosix: - lj->args.append("/SUBSYSTEM:posix"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:posix"); + add_win_link_args(lj, is_library); break; case TargetSubsystemWindows: - lj->args.append("/SUBSYSTEM:windows"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:windows"); + add_win_link_args(lj, is_library); break; } - lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); - - if (g->libc_link_lib != nullptr) { - assert(g->libc != nullptr); - - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); - } - - if (is_library && g->is_dynamic) { - lj->args.append("-DLL"); - } - - for (size_t i = 0; i < g->lib_dirs.length; i += 1) { - const char *lib_dir = g->lib_dirs.at(i); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir))); - } - - for (size_t i = 0; i < g->link_objects.length; i += 1) { - lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); - } - if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) { if (g->libc_link_lib == nullptr && !g->is_dummy_so) { Buf *builtin_a_path = build_a(g, "builtin"); @@ -1268,7 +1360,7 @@ static void construct_linker_job_coff(LinkJob *lj) { } // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage - Buf *compiler_rt_o_path = build_compiler_rt(g); + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -1280,11 +1372,10 @@ static void construct_linker_job_coff(LinkJob *lj) { continue; } if (link_lib->provided_explicitly) { - if (lj->codegen->zig_target->abi == ZigLLVM_GNU) { - Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name)); - lj->args.append(buf_ptr(arg)); - } - else { + if (target_abi_is_gnu(lj->codegen->zig_target->abi)) { + Buf *lib_name = buf_sprintf("lib%s.a", buf_ptr(link_lib->name)); + lj->args.append(buf_ptr(lib_name)); + } else { lj->args.append(buf_ptr(link_lib->name)); } } else { @@ -1416,18 +1507,6 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) { } } -static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) { - if (platform->major < major) { - return true; - } else if (platform->major > major) { - return false; - } - if (platform->minor < minor) { - return true; - } - return false; -} - static void construct_linker_job_macho(LinkJob *lj) { CodeGen *g = lj->codegen; @@ -1524,7 +1603,7 @@ static void construct_linker_job_macho(LinkJob *lj) { // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce if (g->out_type == OutTypeExe || is_dyn_lib) { - Buf *compiler_rt_o_path = build_compiler_rt(g); + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -1552,16 +1631,6 @@ static void construct_linker_job_macho(LinkJob *lj) { lj->args.append("dynamic_lookup"); } - if (platform.kind == MacOS) { - if (darwin_version_lt(&platform, 10, 5)) { - lj->args.append("-lgcc_s.10.4"); - } else if (darwin_version_lt(&platform, 10, 6)) { - lj->args.append("-lgcc_s.10.5"); - } - } else { - zig_panic("TODO"); - } - for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) { lj->args.append("-framework"); lj->args.append(buf_ptr(g->darwin_frameworks.at(i))); @@ -1585,6 +1654,11 @@ static void construct_linker_job(LinkJob *lj) { } } +void zig_link_add_compiler_rt(CodeGen *g) { + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeObj); + g->link_objects.append(compiler_rt_o_path); +} + void codegen_link(CodeGen *g) { codegen_add_time_event(g, "Build Dependencies"); @@ -1611,14 +1685,14 @@ void codegen_link(CodeGen *g) { if (g->out_type == OutTypeLib && !g->is_dynamic) { ZigList<const char *> file_names = {}; for (size_t i = 0; i < g->link_objects.length; i += 1) { - file_names.append((const char *)buf_ptr(g->link_objects.at(i))); + file_names.append(buf_ptr(g->link_objects.at(i))); } ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target->os); codegen_add_time_event(g, "LLVM Link"); if (g->verbose_link) { fprintf(stderr, "ar rcs %s", buf_ptr(&g->output_file_path)); - for (size_t i = 0; i < g->link_objects.length; i += 1) { - fprintf(stderr, " %s", (const char *)buf_ptr(g->link_objects.at(i))); + for (size_t i = 0; i < file_names.length; i += 1) { + fprintf(stderr, " %s", file_names.at(i)); } fprintf(stderr, "\n"); } diff --git a/src/list.hpp b/src/list.hpp index b69a369f5a..f838e44a5b 100644 --- a/src/list.hpp +++ b/src/list.hpp @@ -10,8 +10,6 @@ #include "util.hpp" -#include <assert.h> - template<typename T> struct ZigList { void deinit() { diff --git a/src/main.cpp b/src/main.cpp index bd3d574956..5659624cb7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,7 @@ #include "os.hpp" #include "target.hpp" #include "libc_installation.hpp" +#include "userland.h" #include <stdio.h> @@ -40,6 +41,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " libc [paths_file] Display native libc paths file or validate one\n" " run [source] [-- [args]] create executable and run immediately\n" " translate-c [source] convert c code to zig code\n" + " translate-c-2 [source] experimental self-hosted translate-c\n" " targets list available compilation targets\n" " test [source] create and run a test build\n" " version print version number and exit\n" @@ -52,11 +54,12 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --cache [auto|off|on] build in cache, print output path to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" " --disable-gen-h do not generate a C header file (.h)\n" - " --disable-pic disable Position Independent Code\n" - " --enable-pic enable Position Independent Code\n" " --disable-valgrind omit valgrind client requests in debug builds\n" " --enable-valgrind include valgrind client requests release builds\n" + " --disable-stack-probing workaround for macosx\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" + " -fPIC enable Position Independent Code\n" + " -fno-PIC disable Position Independent Code\n" " -ftime-report print timing diagnostics\n" " --libc [file] Provide a file which specifies libc paths\n" " --name [name] override output name\n" @@ -84,6 +87,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --override-std-dir [arg] use an alternate Zig standard library\n" "\n" "Link Options:\n" + " --bundle-compiler-rt [path] for static libraries, include compiler-rt symbols\n" " --dynamic-linker [path] set the path to ld.so\n" " --each-lib-rpath add rpath for each used dynamic library\n" " --library [lib] link against lib\n" @@ -131,19 +135,6 @@ static int print_libc_usage(const char *arg0, FILE *file, int return_code) { return return_code; } -static const char *ZIG_ZEN = "\n" -" * Communicate intent precisely.\n" -" * Edge cases matter.\n" -" * Favor reading code over writing code.\n" -" * Only one obvious way to do things.\n" -" * Runtime crashes are better than bugs.\n" -" * Compile errors are better than runtime crashes.\n" -" * Incremental improvements.\n" -" * Avoid local maximums.\n" -" * Reduce the amount one must remember.\n" -" * Minimize energy spent on coding style.\n" -" * Together we serve end users.\n"; - static bool arch_available_in_llvm(ZigLLVM_ArchType arch) { LLVMTargetRef target_ref; char *err_msg = nullptr; @@ -211,6 +202,7 @@ enum Cmd { CmdTargets, CmdTest, CmdTranslateC, + CmdTranslateCUserland, CmdVersion, CmdZen, CmdLibC, @@ -324,7 +316,7 @@ int main(int argc, char **argv) { return print_error_usage(arg0); } Buf *cmd_template_path = buf_alloc(); - os_path_join(get_zig_special_dir(), buf_create_from_str(init_cmd), cmd_template_path); + os_path_join(get_zig_special_dir(get_zig_lib_dir()), buf_create_from_str(init_cmd), cmd_template_path); Buf *build_zig_path = buf_alloc(); os_path_join(cmd_template_path, buf_create_from_str("build.zig"), build_zig_path); Buf *src_dir_path = buf_alloc(); @@ -341,7 +333,7 @@ int main(int argc, char **argv) { os_path_split(cwd, nullptr, cwd_basename); Buf *build_zig_contents = buf_alloc(); - if ((err = os_fetch_file_path(build_zig_path, build_zig_contents, false))) { + if ((err = os_fetch_file_path(build_zig_path, build_zig_contents))) { fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(build_zig_path), err_str(err)); return EXIT_FAILURE; } @@ -356,7 +348,7 @@ int main(int argc, char **argv) { } Buf *main_zig_contents = buf_alloc(); - if ((err = os_fetch_file_path(main_zig_path, main_zig_contents, false))) { + if ((err = os_fetch_file_path(main_zig_path, main_zig_contents))) { fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(main_zig_path), err_str(err)); return EXIT_FAILURE; } @@ -450,9 +442,12 @@ int main(int argc, char **argv) { int runtime_args_start = -1; bool system_linker_hack = false; TargetSubsystem subsystem = TargetSubsystemAuto; - bool is_single_threaded = false; + bool want_single_threaded = false; bool disable_gen_h = false; + bool bundle_compiler_rt = false; + bool disable_stack_probing = false; Buf *override_std_dir = nullptr; + Buf *override_lib_dir = nullptr; Buf *main_pkg_path = nullptr; ValgrindSupport valgrind_support = ValgrindSupportAuto; WantPIC want_pic = WantPICAuto; @@ -486,13 +481,27 @@ int main(int argc, char **argv) { } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) { cache_dir = argv[i + 1]; i += 1; + } else if (i + 1 < argc && strcmp(argv[i], "--override-std-dir") == 0) { + override_std_dir = buf_create_from_str(argv[i + 1]); + i += 1; + + args.append("--override-std-dir"); + args.append(buf_ptr(override_std_dir)); + } else if (i + 1 < argc && strcmp(argv[i], "--override-lib-dir") == 0) { + override_lib_dir = buf_create_from_str(argv[i + 1]); + i += 1; + + args.append("--override-lib-dir"); + args.append(buf_ptr(override_lib_dir)); } else { args.append(argv[i]); } } + Buf *zig_lib_dir = (override_lib_dir == nullptr) ? get_zig_lib_dir() : override_lib_dir; + Buf *build_runner_path = buf_alloc(); - os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path); + os_path_join(get_zig_special_dir(zig_lib_dir), buf_create_from_str("build_runner.zig"), build_runner_path); ZigTarget target; get_native_target(&target); @@ -512,7 +521,7 @@ int main(int argc, char **argv) { } CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe, - BuildModeDebug, get_zig_lib_dir(), override_std_dir, nullptr, &full_cache_dir); + BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir); g->valgrind_support = valgrind_support; g->enable_time_report = timing_info; codegen_set_out_name(g, buf_create_from_str("build")); @@ -532,23 +541,25 @@ int main(int argc, char **argv) { "Usage: %s build [options]\n" "\n" "General Options:\n" - " --help Print this help and exit\n" - " --verbose Print commands before executing them\n" - " --prefix [path] Override default install prefix\n" - " --search-prefix [path] Add a path to look for binaries, libraries, headers\n" + " --help Print this help and exit\n" + " --verbose Print commands before executing them\n" + " --prefix [path] Override default install prefix\n" + " --search-prefix [path] Add a path to look for binaries, libraries, headers\n" "\n" "Project-specific options become available when the build file is found.\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" - " --verbose-cc Enable compiler debug output for C compilation\n" + " --build-file [file] Override path to build.zig\n" + " --cache-dir [path] Override path to cache directory\n" + " --override-std-dir [arg] Override path to Zig standard library\n" + " --override-lib-dir [arg] Override path to Zig lib library\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" + " --verbose-cc Enable compiler debug output for C compilation\n" "\n" , zig_exe_path); return EXIT_SUCCESS; @@ -581,36 +592,7 @@ int main(int argc, char **argv) { } return (term.how == TerminationIdClean) ? term.code : -1; } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) { - init_all_targets(); - ZigTarget target; - get_native_target(&target); - Buf *fmt_runner_path = buf_alloc(); - os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path); - Buf *cache_dir_buf = buf_create_from_str(cache_dir ? cache_dir : default_zig_cache_name); - CodeGen *g = codegen_create(main_pkg_path, fmt_runner_path, &target, OutTypeExe, - BuildModeDebug, get_zig_lib_dir(), nullptr, nullptr, cache_dir_buf); - g->valgrind_support = valgrind_support; - g->is_single_threaded = true; - codegen_set_out_name(g, buf_create_from_str("fmt")); - g->enable_cache = true; - - codegen_build_and_link(g); - - // TODO standardize os.cpp so that the args are supposed to have the exe - ZigList<const char*> args_with_exe = {0}; - ZigList<const char*> args_without_exe = {0}; - const char *exec_path = buf_ptr(&g->output_file_path); - args_with_exe.append(exec_path); - for (int i = 2; i < argc; i += 1) { - args_with_exe.append(argv[i]); - args_without_exe.append(argv[i]); - } - args_with_exe.append(nullptr); - os_execv(exec_path, args_with_exe.items); - - Termination term; - os_spawn_process(exec_path, args_without_exe, &term); - return term.code; + return stage2_fmt(argc, argv); } for (int i = 1; i < argc; i += 1) { @@ -664,16 +646,20 @@ int main(int argc, char **argv) { valgrind_support = ValgrindSupportEnabled; } else if (strcmp(arg, "--disable-valgrind") == 0) { valgrind_support = ValgrindSupportDisabled; - } else if (strcmp(arg, "--enable-pic") == 0) { + } else if (strcmp(arg, "-fPIC") == 0) { want_pic = WantPICEnabled; - } else if (strcmp(arg, "--disable-pic") == 0) { + } else if (strcmp(arg, "-fno-PIC") == 0) { want_pic = WantPICDisabled; } else if (strcmp(arg, "--system-linker-hack") == 0) { system_linker_hack = true; } else if (strcmp(arg, "--single-threaded") == 0) { - is_single_threaded = true; + want_single_threaded = true; } else if (strcmp(arg, "--disable-gen-h") == 0) { disable_gen_h = true; + } else if (strcmp(arg, "--bundle-compiler-rt") == 0) { + bundle_compiler_rt = true; + } else if (strcmp(arg, "--disable-stack-probing") == 0) { + disable_stack_probing = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { @@ -757,6 +743,8 @@ int main(int argc, char **argv) { llvm_argv.append(argv[i]); } else if (strcmp(arg, "--override-std-dir") == 0) { override_std_dir = buf_create_from_str(argv[i]); + } else if (strcmp(arg, "--override-lib-dir") == 0) { + override_lib_dir = buf_create_from_str(argv[i]); } else if (strcmp(arg, "--main-pkg-path") == 0) { main_pkg_path = buf_create_from_str(argv[i]); } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) { @@ -775,7 +763,11 @@ int main(int argc, char **argv) { if (argv[i][0] == '-') { c_file->args.append(argv[i]); i += 1; - continue; + if (i < argc) { + continue; + } + + break; } else { c_file->source_path = argv[i]; c_source_files.append(c_file); @@ -867,6 +859,8 @@ int main(int argc, char **argv) { cmd = CmdLibC; } else if (strcmp(arg, "translate-c") == 0) { cmd = CmdTranslateC; + } else if (strcmp(arg, "translate-c-2") == 0) { + cmd = CmdTranslateCUserland; } else if (strcmp(arg, "test") == 0) { cmd = CmdTest; out_type = OutTypeExe; @@ -883,6 +877,7 @@ int main(int argc, char **argv) { case CmdBuild: case CmdRun: case CmdTranslateC: + case CmdTranslateCUserland: case CmdTest: case CmdLibC: if (!in_file) { @@ -959,10 +954,10 @@ int main(int argc, char **argv) { } case CmdBuiltin: { CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, - out_type, build_mode, get_zig_lib_dir(), override_std_dir, nullptr, nullptr); + out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr); g->valgrind_support = valgrind_support; g->want_pic = want_pic; - g->is_single_threaded = is_single_threaded; + g->want_single_threaded = want_single_threaded; Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); @@ -973,6 +968,7 @@ int main(int argc, char **argv) { case CmdRun: case CmdBuild: case CmdTranslateC: + case CmdTranslateCUserland: case CmdTest: { if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 && @@ -985,14 +981,16 @@ int main(int argc, char **argv) { " * --assembly argument\n" " * --c-source argument\n"); return print_error_usage(arg0); - } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { + } else if ((cmd == CmdTranslateC || cmd == CmdTranslateCUserland || + cmd == CmdTest || cmd == CmdRun) && !in_file) + { fprintf(stderr, "Expected source file argument.\n"); return print_error_usage(arg0); } assert(cmd != CmdBuild || out_type != OutTypeUnknown); - bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); + bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC || cmd == CmdTranslateCUserland); if (cmd == CmdRun) { out_name = "run"; @@ -1026,7 +1024,8 @@ int main(int argc, char **argv) { return print_error_usage(arg0); } - Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; + Buf *zig_root_source_file = (cmd == CmdTranslateC || cmd == CmdTranslateCUserland) ? + nullptr : in_file_buf; if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); @@ -1050,7 +1049,7 @@ int main(int argc, char **argv) { cache_dir_buf = buf_create_from_str(cache_dir); } CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode, - get_zig_lib_dir(), override_std_dir, libc, cache_dir_buf); + override_lib_dir, override_std_dir, libc, cache_dir_buf); if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2); g->valgrind_support = valgrind_support; g->want_pic = want_pic; @@ -1060,7 +1059,7 @@ int main(int argc, char **argv) { codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); codegen_set_is_test(g, cmd == CmdTest); - g->is_single_threaded = is_single_threaded; + g->want_single_threaded = want_single_threaded; codegen_set_linker_script(g, linker_script); if (each_lib_rpath) codegen_set_each_lib_rpath(g, each_lib_rpath); @@ -1079,6 +1078,8 @@ int main(int argc, char **argv) { g->verbose_cc = verbose_cc; g->output_dir = output_dir; g->disable_gen_h = disable_gen_h; + g->bundle_compiler_rt = bundle_compiler_rt; + g->disable_stack_probing = disable_stack_probing; codegen_set_errmsg_color(g, color); g->system_linker_hack = system_linker_hack; @@ -1144,14 +1145,15 @@ int main(int argc, char **argv) { codegen_print_timing_report(g, stdout); if (cmd == CmdRun) { + const char *exec_path = buf_ptr(&g->output_file_path); ZigList<const char*> args = {0}; + + args.append(exec_path); if (runtime_args_start != -1) { for (int i = runtime_args_start; i < argc; ++i) { args.append(argv[i]); } } - - const char *exec_path = buf_ptr(&g->output_file_path); args.append(nullptr); os_execv(exec_path, args.items); @@ -1169,9 +1171,8 @@ int main(int argc, char **argv) { } else { zig_unreachable(); } - } else if (cmd == CmdTranslateC) { - AstNode *root_node = codegen_translate_c(g, in_file_buf); - ast_render(g, stdout, root_node, 4); + } else if (cmd == CmdTranslateC || cmd == CmdTranslateCUserland) { + codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland); if (timing_info) codegen_print_timing_report(g, stderr); return EXIT_SUCCESS; @@ -1228,9 +1229,13 @@ int main(int argc, char **argv) { case CmdVersion: printf("%s\n", ZIG_VERSION_STRING); return EXIT_SUCCESS; - case CmdZen: - printf("%s\n", ZIG_ZEN); + case CmdZen: { + const char *ptr; + size_t len; + stage2_zen(&ptr, &len); + fwrite(ptr, len, 1, stdout); return EXIT_SUCCESS; + } case CmdTargets: return print_target_list(stdout); case CmdNone: diff --git a/src/os.cpp b/src/os.cpp index 470d222307..83c67d5818 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -751,39 +751,15 @@ Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) { #endif } -Error os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { +Error os_fetch_file(FILE *f, Buf *out_buf) { static const ssize_t buf_size = 0x2000; buf_resize(out_buf, buf_size); ssize_t actual_buf_len = 0; - bool first_read = true; - for (;;) { size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f); actual_buf_len += amt_read; - if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) { - size_t i = 0; - while (true) { - if (i > buf_len(out_buf)) { - zig_panic("shebang line exceeded %zd characters", buf_size); - } - - size_t current_pos = i; - i += 1; - - if (out_buf->list.at(current_pos) == '\n') { - break; - } - } - - ZigList<char> *list = &out_buf->list; - memmove(list->items, list->items + i, list->length - i); - list->length -= i; - - actual_buf_len -= i; - } - if (amt_read != buf_size) { if (feof(f)) { buf_resize(out_buf, actual_buf_len); @@ -794,7 +770,6 @@ Error os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { } buf_resize(out_buf, actual_buf_len + buf_size); - first_read = false; } zig_unreachable(); } @@ -864,8 +839,8 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args, FILE *stdout_f = fdopen(stdout_pipe[0], "rb"); FILE *stderr_f = fdopen(stderr_pipe[0], "rb"); - Error err1 = os_fetch_file(stdout_f, out_stdout, false); - Error err2 = os_fetch_file(stderr_f, out_stderr, false); + Error err1 = os_fetch_file(stdout_f, out_stdout); + Error err2 = os_fetch_file(stderr_f, out_stderr); fclose(stdout_f); fclose(stderr_f); @@ -1097,7 +1072,7 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { } } -Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { +Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { FILE *f = fopen(buf_ptr(full_path), "rb"); if (!f) { switch (errno) { @@ -1116,7 +1091,7 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { return ErrorFileSystem; } } - Error result = os_fetch_file(f, out_contents, skip_shebang); + Error result = os_fetch_file(f, out_contents); fclose(f); return result; } @@ -1772,8 +1747,14 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) { // TODO use /etc/passwd return ErrorFileNotFound; } - buf_resize(out_path, 0); - buf_appendf(out_path, "%s/.local/share/%s", home_dir, appname); + if (home_dir[0] == 0) { + return ErrorFileNotFound; + } + buf_init_from_str(out_path, home_dir); + if (buf_ptr(out_path)[buf_len(out_path) - 1] != '/') { + buf_append_char(out_path, '/'); + } + buf_appendf(out_path, ".local/share/%s", appname); return ErrorNone; #endif } @@ -2081,11 +2062,13 @@ Error os_file_overwrite(OsFile file, Buf *contents) { #endif } -void os_file_close(OsFile file) { +void os_file_close(OsFile *file) { #if defined(ZIG_OS_WINDOWS) - CloseHandle(file); + CloseHandle(*file); + *file = NULL; #else - close(file); + close(*file); + *file = -1; #endif } diff --git a/src/os.hpp b/src/os.hpp index 5064a6444c..058bb2020c 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -121,13 +121,13 @@ Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents); -void os_file_close(OsFile file); +void os_file_close(OsFile *file); Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); -Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); -Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); +Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); +Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd); diff --git a/src/parser.cpp b/src/parser.cpp index 9172e21b92..583accfd72 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -577,7 +577,7 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { // TopLevelDecl // <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) -// / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? VarDecl +// / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl // / KEYWORD_use Expr SEMICOLON static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { Token *first = eat_token_if(pc, TokenIdKeywordExport); @@ -591,17 +591,22 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { lib_name = eat_token_if(pc, TokenIdStringLiteral); if (first->id != TokenIdKeywordInline) { + Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); var_decl->line = first->start_line; var_decl->column = first->start_column; + var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; var_decl->data.variable_declaration.visib_mod = visib_mod; var_decl->data.variable_declaration.is_extern = first->id == TokenIdKeywordExtern; var_decl->data.variable_declaration.is_export = first->id == TokenIdKeywordExport; var_decl->data.variable_declaration.lib_name = token_buf(lib_name); return var_decl; } + + if (thread_local_kw != nullptr) + put_back_token(pc); } AstNode *fn_proto = ast_parse_fn_proto(pc); @@ -632,13 +637,18 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { ast_invalid_token_error(pc, peek_token(pc)); } + Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); var_decl->data.variable_declaration.visib_mod = visib_mod; + var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; return var_decl; } + if (thread_local_kw != nullptr) + put_back_token(pc); + AstNode *fn_proto = ast_parse_fn_proto(pc); if (fn_proto != nullptr) { AstNode *body = ast_parse_block(pc); @@ -741,17 +751,12 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { // VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON static AstNode *ast_parse_var_decl(ParseContext *pc) { - Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst); if (mut_kw == nullptr) mut_kw = eat_token_if(pc, TokenIdKeywordVar); - if (mut_kw == nullptr) { - if (thread_local_kw == nullptr) { - return nullptr; - } else { - ast_invalid_token_error(pc, peek_token(pc)); - } - } + if (mut_kw == nullptr) + return nullptr; + Token *identifier = expect_token(pc, TokenIdSymbol); AstNode *type_expr = nullptr; if (eat_token_if(pc, TokenIdColon) != nullptr) @@ -766,7 +771,6 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { expect_token(pc, TokenIdSemicolon); AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); - res->data.variable_declaration.threadlocal_tok = thread_local_kw; res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst; res->data.variable_declaration.symbol = token_buf(identifier); res->data.variable_declaration.type = type_expr; @@ -952,17 +956,10 @@ static AstNode *ast_parse_labeled_statement(ParseContext *pc) { // LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) static AstNode *ast_parse_loop_statement(ParseContext *pc) { - Token *label = ast_parse_block_label(pc); - Token *first = label; - Token *inline_token = eat_token_if(pc, TokenIdKeywordInline); - if (first == nullptr) - first = inline_token; - AstNode *for_statement = ast_parse_for_statement(pc); if (for_statement != nullptr) { assert(for_statement->type == NodeTypeForExpr); - for_statement->data.for_expr.name = token_buf(label); for_statement->data.for_expr.is_inline = inline_token != nullptr; return for_statement; } @@ -970,12 +967,11 @@ static AstNode *ast_parse_loop_statement(ParseContext *pc) { AstNode *while_statement = ast_parse_while_statement(pc); if (while_statement != nullptr) { assert(while_statement->type == NodeTypeWhileExpr); - while_statement->data.while_expr.name = token_buf(label); while_statement->data.while_expr.is_inline = inline_token != nullptr; return while_statement; } - if (first != nullptr) + if (inline_token != nullptr) ast_invalid_token_error(pc, peek_token(pc)); return nullptr; } @@ -1117,7 +1113,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc) { // CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? static AstNode *ast_parse_compare_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_compare_op, ast_parse_bitwise_expr); + return ast_parse_bin_op_expr(pc, BinOpChainOnce, ast_parse_compare_op, ast_parse_bitwise_expr); } // BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* @@ -1162,10 +1158,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) { // / Block // / CurlySuffixExpr static AstNode *ast_parse_primary_expr(ParseContext *pc) { - AstNode *enum_lit = ast_parse_enum_lit(pc); - if (enum_lit != nullptr) - return enum_lit; - AstNode *asm_expr = ast_parse_asm_expr(pc); if (asm_expr != nullptr) return asm_expr; @@ -1246,11 +1238,8 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) { } AstNode *block = ast_parse_block(pc); - if (block != nullptr) { - assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(label); + if (block != nullptr) return block; - } AstNode *curly_suffix = ast_parse_curly_suffix_expr(pc); if (curly_suffix != nullptr) @@ -1503,6 +1492,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { // <- BUILTINIDENTIFIER FnCallArguments // / CHAR_LITERAL // / ContainerDecl +// / DOT IDENTIFIER // / ErrorSetDecl // / FLOAT // / FnProto @@ -1563,6 +1553,10 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { if (container_decl != nullptr) return container_decl; + AstNode *enum_lit = ast_parse_enum_lit(pc); + if (enum_lit != nullptr) + return enum_lit; + AstNode *error_set_decl = ast_parse_error_set_decl(pc); if (error_set_decl != nullptr) return error_set_decl; @@ -1672,32 +1666,26 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { // ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto static AstNode *ast_parse_container_decl(ParseContext *pc) { - Token *extern_token = eat_token_if(pc, TokenIdKeywordExtern); - if (extern_token != nullptr) { - AstNode *res = ast_parse_container_decl_auto(pc); - if (res == nullptr) { - put_back_token(pc); - return nullptr; - } + Token *layout_token = eat_token_if(pc, TokenIdKeywordExtern); + if (layout_token == nullptr) + layout_token = eat_token_if(pc, TokenIdKeywordPacked); - assert(res->type == NodeTypeContainerDecl); - res->line = extern_token->start_line; - res->column = extern_token->start_column; - res->data.container_decl.layout = ContainerLayoutExtern; - return res; + AstNode *res = ast_parse_container_decl_auto(pc); + if (res == nullptr) { + if (layout_token != nullptr) + put_back_token(pc); + return nullptr; } - Token *packed_token = eat_token_if(pc, TokenIdKeywordPacked); - if (packed_token != nullptr) { - AstNode *res = ast_expect(pc, ast_parse_container_decl_auto); - assert(res->type == NodeTypeContainerDecl); - res->line = packed_token->start_line; - res->column = packed_token->start_column; - res->data.container_decl.layout = ContainerLayoutPacked; - return res; + assert(res->type == NodeTypeContainerDecl); + if (layout_token != nullptr) { + res->line = layout_token->start_line; + res->column = layout_token->start_column; + res->data.container_decl.layout = layout_token->id == TokenIdKeywordExtern + ? ContainerLayoutExtern + : ContainerLayoutPacked; } - - return ast_parse_container_decl_auto(pc); + return res; } // ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE @@ -1971,7 +1959,14 @@ static AstNode *ast_parse_field_init(ParseContext *pc) { return nullptr; Token *name = expect_token(pc, TokenIdSymbol); - expect_token(pc, TokenIdEq); + if (eat_token_if(pc, TokenIdEq) == nullptr) { + // Because ".Name" can also be intepreted as an enum literal, we should put back + // those two tokens again so that the parser can try to parse them as the enum + // literal later. + put_back_token(pc); + put_back_token(pc); + return nullptr; + } AstNode *expr = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeStructValueField, first); @@ -2750,12 +2745,19 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { } // ContainerDeclType -// <- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)? +// <- KEYWORD_struct +// / KEYWORD_enum (LPAREN Expr RPAREN)? // / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? static AstNode *ast_parse_container_decl_type(ParseContext *pc) { Token *first = eat_token_if(pc, TokenIdKeywordStruct); - if (first == nullptr) - first = eat_token_if(pc, TokenIdKeywordEnum); + if (first != nullptr) { + AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); + res->data.container_decl.init_arg_expr = nullptr; + res->data.container_decl.kind = ContainerKindStruct; + return res; + } + + first = eat_token_if(pc, TokenIdKeywordEnum); if (first != nullptr) { AstNode *init_arg_expr = nullptr; if (eat_token_if(pc, TokenIdLParen) != nullptr) { @@ -2764,9 +2766,7 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) { } AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); res->data.container_decl.init_arg_expr = init_arg_expr; - res->data.container_decl.kind = first->id == TokenIdKeywordStruct - ? ContainerKindStruct - : ContainerKindEnum; + res->data.container_decl.kind = ContainerKindEnum; return res; } diff --git a/src/target.cpp b/src/target.cpp index dda8188765..1954fd7e2e 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -894,10 +894,25 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case CIntTypeCount: zig_unreachable(); } + case OsIOS: + switch (id) { + case CIntTypeShort: + case CIntTypeUShort: + return 16; + case CIntTypeInt: + case CIntTypeUInt: + return 32; + case CIntTypeLong: + case CIntTypeULong: + case CIntTypeLongLong: + case CIntTypeULongLong: + return 64; + case CIntTypeCount: + zig_unreachable(); + } case OsAnanas: case OsCloudABI: case OsDragonFly: - case OsIOS: case OsKFreeBSD: case OsLv2: case OsSolaris: @@ -950,6 +965,8 @@ const char *target_exe_file_ext(const ZigTarget *target) { return ".exe"; } else if (target->os == OsUefi) { return ".efi"; + } else if (target_is_wasm(target)) { + return ".wasm"; } else { return ""; } @@ -1350,6 +1367,14 @@ bool target_is_musl(const ZigTarget *target) { return target->os == OsLinux && target_abi_is_musl(target->abi); } +bool target_is_wasm(const ZigTarget *target) { + return target->arch == ZigLLVM_wasm32 || target->arch == ZigLLVM_wasm64; +} + +bool target_is_single_threaded(const ZigTarget *target) { + return target_is_wasm(target); +} + ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { switch (os) { case OsFreestanding: diff --git a/src/target.hpp b/src/target.hpp index 4a0264c2b1..fd5c7471c3 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -170,6 +170,8 @@ bool target_abi_is_gnu(ZigLLVM_EnvironmentType abi); bool target_abi_is_musl(ZigLLVM_EnvironmentType abi); bool target_is_glibc(const ZigTarget *target); bool target_is_musl(const ZigTarget *target); +bool target_is_wasm(const ZigTarget *target); +bool target_is_single_threaded(const ZigTarget *target); uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch); diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 8abd66c0ff..c3c715cb47 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -76,10 +76,9 @@ struct TransScopeWhile { }; struct Context { - ZigList<ErrorMsg *> *errors; + AstNode *root; VisibMod visib_mod; bool want_export; - AstNode *root; HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table; @@ -112,19 +111,39 @@ static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *paren static TransScopeBlock *trans_scope_block_find(TransScope *scope); -static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_decl); -static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl); -static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *typedef_decl); +static AstNode *resolve_record_decl(Context *c, const ZigClangRecordDecl *record_decl); +static AstNode *resolve_enum_decl(Context *c, const ZigClangEnumDecl *enum_decl); +static AstNode *resolve_typedef_decl(Context *c, const ZigClangTypedefNameDecl *typedef_decl); -static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *stmt, +static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *stmt, ResultUsed result_used, TransLRValue lrval, AstNode **out_node, TransScope **out_child_scope, TransScope **out_node_scope); -static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt *stmt, AstNode **out_node); -static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval); -static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc); -static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval); -static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::QualType qt, const clang::SourceLocation &source_loc); +static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node); +static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval); +static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc); +static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc); +static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, + const ZigClangExpr *expr, TransLRValue lrval); +static AstNode *trans_ap_value(Context *c, const ZigClangAPValue *ap_value, ZigClangQualType qt, + ZigClangSourceLocation source_loc); +static bool c_is_unsigned_integer(Context *c, ZigClangQualType qt); + +static const ZigClangAPSInt *bitcast(const llvm::APSInt *src) { + return reinterpret_cast<const ZigClangAPSInt *>(src); +} + +static const ZigClangAPValue *bitcast(const clang::APValue *src) { + return reinterpret_cast<const ZigClangAPValue *>(src); +} + +static const ZigClangStmt *bitcast(const clang::Stmt *src) { + return reinterpret_cast<const ZigClangStmt *>(src); +} + +static const ZigClangExpr *bitcast(const clang::Expr *src) { + return reinterpret_cast<const ZigClangExpr *>(src); +} static ZigClangSourceLocation bitcast(clang::SourceLocation src) { ZigClangSourceLocation dest; @@ -136,14 +155,14 @@ static ZigClangQualType bitcast(clang::QualType src) { memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType)); return dest; } -static clang::QualType bitcast(ZigClangQualType src) { - clang::QualType dest; - memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType)); - return dest; -} +//static clang::QualType bitcast(ZigClangQualType src) { +// clang::QualType dest; +// memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType)); +// return dest; +//} ATTRIBUTE_PRINTF(3, 4) -static void emit_warning(Context *c, const clang::SourceLocation &clang_sl, const char *format, ...) { +static void emit_warning(Context *c, ZigClangSourceLocation sl, const char *format, ...) { if (!c->warnings_on) { return; } @@ -153,7 +172,6 @@ static void emit_warning(Context *c, const clang::SourceLocation &clang_sl, cons Buf *msg = buf_vprintf(format, ap); va_end(ap); - ZigClangSourceLocation sl = bitcast(clang_sl); const char *filename_bytes = ZigClangSourceManager_getFilename(c->source_manager, ZigClangSourceManager_getSpellingLoc(c->source_manager, sl)); Buf *path; @@ -489,107 +507,99 @@ static Buf *string_ref_to_buf(llvm::StringRef string_ref) { return buf_create_from_mem((const char *)string_ref.bytes_begin(), string_ref.size()); } -static const char *decl_name(const clang::Decl *decl) { - const clang::NamedDecl *named_decl = static_cast<const clang::NamedDecl *>(decl); - return (const char *)named_decl->getName().bytes_begin(); -} - -static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { +static AstNode *trans_create_node_apint(Context *c, const ZigClangAPSInt *aps_int) { AstNode *node = trans_create_node(c, NodeTypeIntLiteral); node->data.int_literal.bigint = allocate<BigInt>(1); - bool is_negative = aps_int.isSigned() && aps_int.isNegative(); + bool is_negative = ZigClangAPSInt_isSigned(aps_int) && ZigClangAPSInt_isNegative(aps_int); if (!is_negative) { - bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), false); + bigint_init_data(node->data.int_literal.bigint, + ZigClangAPSInt_getRawData(aps_int), + ZigClangAPSInt_getNumWords(aps_int), + false); return node; } - llvm::APSInt negated = -aps_int; - bigint_init_data(node->data.int_literal.bigint, negated.getRawData(), negated.getNumWords(), true); + const ZigClangAPSInt *negated = ZigClangAPSInt_negate(aps_int); + bigint_init_data(node->data.int_literal.bigint, ZigClangAPSInt_getRawData(negated), + ZigClangAPSInt_getNumWords(negated), true); + ZigClangAPSInt_free(negated); return node; +} +static AstNode *trans_create_node_apfloat(Context *c, const llvm::APFloat &ap_float) { + uint8_t buf[128]; + size_t written = ap_float.convertToHexString((char *)buf, 0, false, + llvm::APFloat::rmNearestTiesToEven); + AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); + node->data.float_literal.bigfloat = allocate<BigFloat>(1); + if (bigfloat_init_buf(node->data.float_literal.bigfloat, buf, written)) { + node->data.float_literal.overflow = true; + } + return node; } -static const clang::Type *qual_type_canon(clang::QualType qt) { - return qt.getCanonicalType().getTypePtr(); +static const ZigClangType *qual_type_canon(ZigClangQualType qt) { + ZigClangQualType canon = ZigClangQualType_getCanonicalType(qt); + return ZigClangQualType_getTypePtr(canon); } -static clang::QualType get_expr_qual_type(Context *c, const clang::Expr *expr) { +static ZigClangQualType get_expr_qual_type(Context *c, const ZigClangExpr *expr) { // String literals in C are `char *` but they should really be `const char *`. - if (expr->getStmtClass() == clang::Stmt::ImplicitCastExprClass) { - const clang::ImplicitCastExpr *cast_expr = static_cast<const clang::ImplicitCastExpr *>(expr); - if (cast_expr->getCastKind() == clang::CK_ArrayToPointerDecay) { - const clang::Expr *sub_expr = cast_expr->getSubExpr(); - if (sub_expr->getStmtClass() == clang::Stmt::StringLiteralClass) { - clang::QualType array_qt = sub_expr->getType(); - const clang::ArrayType *array_type = static_cast<const clang::ArrayType *>(array_qt.getTypePtr()); - clang::QualType pointee_qt = array_type->getElementType(); - pointee_qt.addConst(); - return bitcast(ZigClangASTContext_getPointerType(c->ctx, bitcast(pointee_qt))); + if (ZigClangExpr_getStmtClass(expr) == ZigClangStmt_ImplicitCastExprClass) { + const clang::ImplicitCastExpr *cast_expr = reinterpret_cast<const clang::ImplicitCastExpr *>(expr); + if ((ZigClangCK)cast_expr->getCastKind() == ZigClangCK_ArrayToPointerDecay) { + const ZigClangExpr *sub_expr = bitcast(cast_expr->getSubExpr()); + if (ZigClangExpr_getStmtClass(sub_expr) == ZigClangStmt_StringLiteralClass) { + ZigClangQualType array_qt = ZigClangExpr_getType(sub_expr); + const clang::ArrayType *array_type = reinterpret_cast<const clang::ArrayType *>( + ZigClangQualType_getTypePtr(array_qt)); + ZigClangQualType pointee_qt = bitcast(array_type->getElementType()); + ZigClangQualType_addConst(&pointee_qt); + return ZigClangASTContext_getPointerType(c->ctx, pointee_qt); } } } - return expr->getType(); + return ZigClangExpr_getType(expr); } -static clang::QualType get_expr_qual_type_before_implicit_cast(Context *c, const clang::Expr *expr) { - if (expr->getStmtClass() == clang::Stmt::ImplicitCastExprClass) { - const clang::ImplicitCastExpr *cast_expr = static_cast<const clang::ImplicitCastExpr *>(expr); - return get_expr_qual_type(c, cast_expr->getSubExpr()); +static ZigClangQualType get_expr_qual_type_before_implicit_cast(Context *c, const ZigClangExpr *expr) { + if (ZigClangExpr_getStmtClass(expr) == ZigClangStmt_ImplicitCastExprClass) { + const clang::ImplicitCastExpr *cast_expr = reinterpret_cast<const clang::ImplicitCastExpr *>(expr); + return get_expr_qual_type(c, bitcast(cast_expr->getSubExpr())); } - return expr->getType(); + return ZigClangExpr_getType(expr); } -static AstNode *get_expr_type(Context *c, const clang::Expr *expr) { - return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getBeginLoc()); -} - -static bool qual_types_equal(clang::QualType t1, clang::QualType t2) { - if (t1.isConstQualified() != t2.isConstQualified()) { - return false; - } - if (t1.isVolatileQualified() != t2.isVolatileQualified()) { - return false; - } - if (t1.isRestrictQualified() != t2.isRestrictQualified()) { - return false; - } - return t1.getTypePtr() == t2.getTypePtr(); +static AstNode *get_expr_type(Context *c, const ZigClangExpr *expr) { + return trans_qual_type(c, get_expr_qual_type(c, expr), ZigClangExpr_getBeginLoc(expr)); } static bool is_c_void_type(AstNode *node) { return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); } -static bool expr_types_equal(Context *c, const clang::Expr *expr1, const clang::Expr *expr2) { - clang::QualType t1 = get_expr_qual_type(c, expr1); - clang::QualType t2 = get_expr_qual_type(c, expr2); - - return qual_types_equal(t1, t2); +static bool qual_type_is_ptr(ZigClangQualType qt) { + const ZigClangType *ty = qual_type_canon(qt); + return ZigClangType_getTypeClass(ty) == ZigClangType_Pointer; } -static bool qual_type_is_ptr(clang::QualType qt) { - const clang::Type *ty = qual_type_canon(qt); - return ty->getTypeClass() == clang::Type::Pointer; -} - -static const clang::FunctionProtoType *qual_type_get_fn_proto(clang::QualType qt, bool *is_ptr) { - const clang::Type *ty = qual_type_canon(qt); +static const clang::FunctionProtoType *qual_type_get_fn_proto(ZigClangQualType qt, bool *is_ptr) { + const ZigClangType *ty = qual_type_canon(qt); *is_ptr = false; - if (ty->getTypeClass() == clang::Type::Pointer) { + if (ZigClangType_getTypeClass(ty) == ZigClangType_Pointer) { *is_ptr = true; - const clang::PointerType *pointer_ty = static_cast<const clang::PointerType*>(ty); - clang::QualType child_qt = pointer_ty->getPointeeType(); - ty = child_qt.getTypePtr(); + ZigClangQualType child_qt = ZigClangType_getPointeeType(ty); + ty = ZigClangQualType_getTypePtr(child_qt); } - if (ty->getTypeClass() == clang::Type::FunctionProto) { - return static_cast<const clang::FunctionProtoType*>(ty); + if (ZigClangType_getTypeClass(ty) == ZigClangType_FunctionProto) { + return reinterpret_cast<const clang::FunctionProtoType*>(ty); } return nullptr; } -static bool qual_type_is_fn_ptr(clang::QualType qt) { +static bool qual_type_is_fn_ptr(ZigClangQualType qt) { bool is_ptr; if (qual_type_get_fn_proto(qt, &is_ptr)) { return is_ptr; @@ -598,31 +608,31 @@ static bool qual_type_is_fn_ptr(clang::QualType qt) { return false; } -static uint32_t qual_type_int_bit_width(Context *c, const clang::QualType &qt, const clang::SourceLocation &source_loc) { - const clang::Type *ty = qt.getTypePtr(); - switch (ty->getTypeClass()) { - case clang::Type::Builtin: +static uint32_t qual_type_int_bit_width(Context *c, const ZigClangQualType qt, ZigClangSourceLocation source_loc) { + const ZigClangType *ty = ZigClangQualType_getTypePtr(qt); + switch (ZigClangType_getTypeClass(ty)) { + case ZigClangType_Builtin: { - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty); - switch (builtin_ty->getKind()) { - case clang::BuiltinType::Char_U: - case clang::BuiltinType::UChar: - case clang::BuiltinType::Char_S: - case clang::BuiltinType::SChar: + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(ty); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + case ZigClangBuiltinTypeChar_U: + case ZigClangBuiltinTypeUChar: + case ZigClangBuiltinTypeChar_S: + case ZigClangBuiltinTypeSChar: return 8; - case clang::BuiltinType::UInt128: - case clang::BuiltinType::Int128: + case ZigClangBuiltinTypeUInt128: + case ZigClangBuiltinTypeInt128: return 128; default: return 0; } zig_unreachable(); } - case clang::Type::Typedef: + case ZigClangType_Typedef: { - const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty); - const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); - const char *type_name = decl_name(typedef_decl); + const ZigClangTypedefType *typedef_ty = reinterpret_cast<const ZigClangTypedefType*>(ty); + const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + const char *type_name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)typedef_decl); if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { return 8; } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { @@ -642,8 +652,8 @@ static uint32_t qual_type_int_bit_width(Context *c, const clang::QualType &qt, c } -static AstNode *qual_type_to_log2_int_ref(Context *c, const clang::QualType &qt, - const clang::SourceLocation &source_loc) +static AstNode *qual_type_to_log2_int_ref(Context *c, const ZigClangQualType qt, + ZigClangSourceLocation source_loc) { uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); if (int_bit_width != 0) { @@ -675,37 +685,76 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const clang::QualType &qt, return log2int_fn_call; } -static bool qual_type_child_is_fn_proto(const clang::QualType &qt) { - if (qt.getTypePtr()->getTypeClass() == clang::Type::Paren) { - const clang::ParenType *paren_type = static_cast<const clang::ParenType *>(qt.getTypePtr()); +static bool qual_type_child_is_fn_proto(ZigClangQualType qt) { + const ZigClangType *ty = ZigClangQualType_getTypePtr(qt); + if (ZigClangType_getTypeClass(ty) == ZigClangType_Paren) { + const clang::ParenType *paren_type = reinterpret_cast<const clang::ParenType *>(ty); if (paren_type->getInnerType()->getTypeClass() == clang::Type::FunctionProto) { return true; } - } else if (qt.getTypePtr()->getTypeClass() == clang::Type::Attributed) { - const clang::AttributedType *attr_type = static_cast<const clang::AttributedType *>(qt.getTypePtr()); - return qual_type_child_is_fn_proto(attr_type->getEquivalentType()); + } else if (ZigClangType_getTypeClass(ty) == ZigClangType_Attributed) { + const clang::AttributedType *attr_type = reinterpret_cast<const clang::AttributedType *>(ty); + return qual_type_child_is_fn_proto(bitcast(attr_type->getEquivalentType())); } return false; } -static AstNode* trans_c_cast(Context *c, const clang::SourceLocation &source_location, clang::QualType dest_type, - clang::QualType src_type, AstNode *expr) +static AstNode* trans_c_ptr_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type, + ZigClangQualType src_type, AstNode *expr) +{ + const ZigClangType *ty = ZigClangQualType_getTypePtr(dest_type); + const ZigClangQualType child_type = ZigClangType_getPointeeType(ty); + + AstNode *dest_type_node = trans_type(c, ty, source_location); + AstNode *child_type_node = trans_qual_type(c, child_type, source_location); + + // Implicit downcasting from higher to lower alignment values is forbidden, + // use @alignCast to side-step this problem + AstNode *ptrcast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); + ptrcast_node->data.fn_call_expr.params.append(dest_type_node); + + if (ZigClangType_isVoidType(qual_type_canon(child_type))) { + // void has 1-byte alignment + ptrcast_node->data.fn_call_expr.params.append(expr); + } else { + AstNode *alignof_node = trans_create_node_builtin_fn_call_str(c, "alignOf"); + alignof_node->data.fn_call_expr.params.append(child_type_node); + AstNode *aligncast_node = trans_create_node_builtin_fn_call_str(c, "alignCast"); + aligncast_node->data.fn_call_expr.params.append(alignof_node); + aligncast_node->data.fn_call_expr.params.append(expr); + + ptrcast_node->data.fn_call_expr.params.append(aligncast_node); + } + + return ptrcast_node; +} + +static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type, + ZigClangQualType src_type, AstNode *expr) { // The only way void pointer casts are valid C code, is if // the value of the expression is ignored. We therefore just // return the expr, and let the system that ignores values // translate this correctly. - if (qual_type_canon(dest_type)->isVoidType()) { + if (ZigClangType_isVoidType(qual_type_canon(dest_type))) { return expr; } - if (qual_types_equal(dest_type, src_type)) { + if (ZigClangQualType_eq(dest_type, src_type)) { return expr; } if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) { - AstNode *ptr_cast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); - ptr_cast_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location)); - ptr_cast_node->data.fn_call_expr.params.append(expr); - return ptr_cast_node; + return trans_c_ptr_cast(c, source_location, dest_type, src_type, expr); + } + if (c_is_unsigned_integer(c, dest_type) && qual_type_is_ptr(src_type)) { + AstNode *addr_node = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); + addr_node->data.fn_call_expr.params.append(expr); + return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), addr_node); + } + if (c_is_unsigned_integer(c, src_type) && qual_type_is_ptr(dest_type)) { + AstNode *ptr_node = trans_create_node_builtin_fn_call_str(c, "intToPtr"); + ptr_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location)); + ptr_node->data.fn_call_expr.params.append(expr); + return ptr_node; } // TODO: maybe widen to increase size // TODO: maybe bitcast to change sign @@ -713,72 +762,72 @@ static AstNode* trans_c_cast(Context *c, const clang::SourceLocation &source_loc return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), expr); } -static bool c_is_signed_integer(Context *c, clang::QualType qt) { - const clang::Type *c_type = qual_type_canon(qt); - if (c_type->getTypeClass() != clang::Type::Builtin) +static bool c_is_signed_integer(Context *c, ZigClangQualType qt) { + const ZigClangType *c_type = qual_type_canon(qt); + if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) return false; - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type); - switch (builtin_ty->getKind()) { - case clang::BuiltinType::SChar: - case clang::BuiltinType::Short: - case clang::BuiltinType::Int: - case clang::BuiltinType::Long: - case clang::BuiltinType::LongLong: - case clang::BuiltinType::Int128: - case clang::BuiltinType::WChar_S: + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(c_type); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + case ZigClangBuiltinTypeSChar: + case ZigClangBuiltinTypeShort: + case ZigClangBuiltinTypeInt: + case ZigClangBuiltinTypeLong: + case ZigClangBuiltinTypeLongLong: + case ZigClangBuiltinTypeInt128: + case ZigClangBuiltinTypeWChar_S: return true; default: return false; } } -static bool c_is_unsigned_integer(Context *c, clang::QualType qt) { - const clang::Type *c_type = qual_type_canon(qt); - if (c_type->getTypeClass() != clang::Type::Builtin) +static bool c_is_unsigned_integer(Context *c, ZigClangQualType qt) { + const ZigClangType *c_type = qual_type_canon(qt); + if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) return false; - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type); - switch (builtin_ty->getKind()) { - case clang::BuiltinType::Char_U: - case clang::BuiltinType::UChar: - case clang::BuiltinType::Char_S: - case clang::BuiltinType::UShort: - case clang::BuiltinType::UInt: - case clang::BuiltinType::ULong: - case clang::BuiltinType::ULongLong: - case clang::BuiltinType::UInt128: - case clang::BuiltinType::WChar_U: + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(c_type); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + case ZigClangBuiltinTypeChar_U: + case ZigClangBuiltinTypeUChar: + case ZigClangBuiltinTypeChar_S: + case ZigClangBuiltinTypeUShort: + case ZigClangBuiltinTypeUInt: + case ZigClangBuiltinTypeULong: + case ZigClangBuiltinTypeULongLong: + case ZigClangBuiltinTypeUInt128: + case ZigClangBuiltinTypeWChar_U: return true; default: return false; } } -static bool c_is_builtin_type(Context *c, clang::QualType qt, clang::BuiltinType::Kind kind) { - const clang::Type *c_type = qual_type_canon(qt); - if (c_type->getTypeClass() != clang::Type::Builtin) +static bool c_is_builtin_type(Context *c, ZigClangQualType qt, ZigClangBuiltinTypeKind kind) { + const ZigClangType *c_type = qual_type_canon(qt); + if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) return false; - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type); - return builtin_ty->getKind() == kind; + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(c_type); + return ZigClangBuiltinType_getKind(builtin_ty) == kind; } -static bool c_is_float(Context *c, clang::QualType qt) { - const clang::Type *c_type = qt.getTypePtr(); - if (c_type->getTypeClass() != clang::Type::Builtin) +static bool c_is_float(Context *c, ZigClangQualType qt) { + const ZigClangType *c_type = ZigClangQualType_getTypePtr(qt); + if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) return false; - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type); - switch (builtin_ty->getKind()) { - case clang::BuiltinType::Half: - case clang::BuiltinType::Float: - case clang::BuiltinType::Double: - case clang::BuiltinType::Float128: - case clang::BuiltinType::LongDouble: + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(c_type); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + case ZigClangBuiltinTypeHalf: + case ZigClangBuiltinTypeFloat: + case ZigClangBuiltinTypeDouble: + case ZigClangBuiltinTypeFloat128: + case ZigClangBuiltinTypeLongDouble: return true; default: return false; } } -static bool qual_type_has_wrapping_overflow(Context *c, clang::QualType qt) { +static bool qual_type_has_wrapping_overflow(Context *c, ZigClangQualType qt) { if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { // float and signed integer overflow is undefined behavior. return false; @@ -788,181 +837,182 @@ static bool qual_type_has_wrapping_overflow(Context *c, clang::QualType qt) { } } -static bool type_is_opaque(Context *c, const clang::Type *ty, const clang::SourceLocation &source_loc) { - switch (ty->getTypeClass()) { - case clang::Type::Builtin: { - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty); - return builtin_ty->getKind() == clang::BuiltinType::Void; +static bool type_is_opaque(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { + switch (ZigClangType_getTypeClass(ty)) { + case ZigClangType_Builtin: { + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(ty); + return ZigClangBuiltinType_getKind(builtin_ty) == ZigClangBuiltinTypeVoid; } - case clang::Type::Record: { - const clang::RecordType *record_ty = static_cast<const clang::RecordType*>(ty); + case ZigClangType_Record: { + const clang::RecordType *record_ty = reinterpret_cast<const clang::RecordType*>(ty); return record_ty->getDecl()->getDefinition() == nullptr; } - case clang::Type::Elaborated: { - const clang::ElaboratedType *elaborated_ty = static_cast<const clang::ElaboratedType*>(ty); - return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); + case ZigClangType_Elaborated: { + const clang::ElaboratedType *elaborated_ty = reinterpret_cast<const clang::ElaboratedType*>(ty); + ZigClangQualType qt = bitcast(elaborated_ty->getNamedType()); + return type_is_opaque(c, ZigClangQualType_getTypePtr(qt), source_loc); } - case clang::Type::Typedef: { - const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty); - const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); - return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); + case ZigClangType_Typedef: { + const ZigClangTypedefType *typedef_ty = reinterpret_cast<const ZigClangTypedefType*>(ty); + const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + ZigClangQualType underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); + return type_is_opaque(c, ZigClangQualType_getTypePtr(underlying_type), source_loc); } default: return false; } } -static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::SourceLocation &source_loc) { - switch (ty->getTypeClass()) { - case clang::Type::Builtin: +static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { + switch (ZigClangType_getTypeClass(ty)) { + case ZigClangType_Builtin: { - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty); - switch (builtin_ty->getKind()) { - case clang::BuiltinType::Void: + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType *>(ty); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + case ZigClangBuiltinTypeVoid: return trans_create_node_symbol_str(c, "c_void"); - case clang::BuiltinType::Bool: + case ZigClangBuiltinTypeBool: return trans_create_node_symbol_str(c, "bool"); - case clang::BuiltinType::Char_U: - case clang::BuiltinType::UChar: - case clang::BuiltinType::Char_S: - case clang::BuiltinType::Char8: + case ZigClangBuiltinTypeChar_U: + case ZigClangBuiltinTypeUChar: + case ZigClangBuiltinTypeChar_S: + case ZigClangBuiltinTypeChar8: return trans_create_node_symbol_str(c, "u8"); - case clang::BuiltinType::SChar: + case ZigClangBuiltinTypeSChar: return trans_create_node_symbol_str(c, "i8"); - case clang::BuiltinType::UShort: + case ZigClangBuiltinTypeUShort: return trans_create_node_symbol_str(c, "c_ushort"); - case clang::BuiltinType::UInt: + case ZigClangBuiltinTypeUInt: return trans_create_node_symbol_str(c, "c_uint"); - case clang::BuiltinType::ULong: + case ZigClangBuiltinTypeULong: return trans_create_node_symbol_str(c, "c_ulong"); - case clang::BuiltinType::ULongLong: + case ZigClangBuiltinTypeULongLong: return trans_create_node_symbol_str(c, "c_ulonglong"); - case clang::BuiltinType::Short: + case ZigClangBuiltinTypeShort: return trans_create_node_symbol_str(c, "c_short"); - case clang::BuiltinType::Int: + case ZigClangBuiltinTypeInt: return trans_create_node_symbol_str(c, "c_int"); - case clang::BuiltinType::Long: + case ZigClangBuiltinTypeLong: return trans_create_node_symbol_str(c, "c_long"); - case clang::BuiltinType::LongLong: + case ZigClangBuiltinTypeLongLong: return trans_create_node_symbol_str(c, "c_longlong"); - case clang::BuiltinType::UInt128: + case ZigClangBuiltinTypeUInt128: return trans_create_node_symbol_str(c, "u128"); - case clang::BuiltinType::Int128: + case ZigClangBuiltinTypeInt128: return trans_create_node_symbol_str(c, "i128"); - case clang::BuiltinType::Float: + case ZigClangBuiltinTypeFloat: return trans_create_node_symbol_str(c, "f32"); - case clang::BuiltinType::Double: + case ZigClangBuiltinTypeDouble: return trans_create_node_symbol_str(c, "f64"); - case clang::BuiltinType::Float128: + case ZigClangBuiltinTypeFloat128: return trans_create_node_symbol_str(c, "f128"); - case clang::BuiltinType::Float16: + case ZigClangBuiltinTypeFloat16: return trans_create_node_symbol_str(c, "f16"); - case clang::BuiltinType::LongDouble: + case ZigClangBuiltinTypeLongDouble: return trans_create_node_symbol_str(c, "c_longdouble"); - case clang::BuiltinType::WChar_U: - case clang::BuiltinType::Char16: - case clang::BuiltinType::Char32: - case clang::BuiltinType::WChar_S: - case clang::BuiltinType::Half: - case clang::BuiltinType::NullPtr: - case clang::BuiltinType::ObjCId: - case clang::BuiltinType::ObjCClass: - case clang::BuiltinType::ObjCSel: - case clang::BuiltinType::OMPArraySection: - case clang::BuiltinType::Dependent: - case clang::BuiltinType::Overload: - case clang::BuiltinType::BoundMember: - case clang::BuiltinType::PseudoObject: - case clang::BuiltinType::UnknownAny: - case clang::BuiltinType::BuiltinFn: - case clang::BuiltinType::ARCUnbridgedCast: - case clang::BuiltinType::ShortAccum: - case clang::BuiltinType::Accum: - case clang::BuiltinType::LongAccum: - case clang::BuiltinType::UShortAccum: - case clang::BuiltinType::UAccum: - case clang::BuiltinType::ULongAccum: - - case clang::BuiltinType::OCLImage1dRO: - case clang::BuiltinType::OCLImage1dArrayRO: - case clang::BuiltinType::OCLImage1dBufferRO: - case clang::BuiltinType::OCLImage2dRO: - case clang::BuiltinType::OCLImage2dArrayRO: - case clang::BuiltinType::OCLImage2dDepthRO: - case clang::BuiltinType::OCLImage2dArrayDepthRO: - case clang::BuiltinType::OCLImage2dMSAARO: - case clang::BuiltinType::OCLImage2dArrayMSAARO: - case clang::BuiltinType::OCLImage2dMSAADepthRO: - case clang::BuiltinType::OCLImage2dArrayMSAADepthRO: - case clang::BuiltinType::OCLImage3dRO: - case clang::BuiltinType::OCLImage1dWO: - case clang::BuiltinType::OCLImage1dArrayWO: - case clang::BuiltinType::OCLImage1dBufferWO: - case clang::BuiltinType::OCLImage2dWO: - case clang::BuiltinType::OCLImage2dArrayWO: - case clang::BuiltinType::OCLImage2dDepthWO: - case clang::BuiltinType::OCLImage2dArrayDepthWO: - case clang::BuiltinType::OCLImage2dMSAAWO: - case clang::BuiltinType::OCLImage2dArrayMSAAWO: - case clang::BuiltinType::OCLImage2dMSAADepthWO: - case clang::BuiltinType::OCLImage2dArrayMSAADepthWO: - case clang::BuiltinType::OCLImage3dWO: - case clang::BuiltinType::OCLImage1dRW: - case clang::BuiltinType::OCLImage1dArrayRW: - case clang::BuiltinType::OCLImage1dBufferRW: - case clang::BuiltinType::OCLImage2dRW: - case clang::BuiltinType::OCLImage2dArrayRW: - case clang::BuiltinType::OCLImage2dDepthRW: - case clang::BuiltinType::OCLImage2dArrayDepthRW: - case clang::BuiltinType::OCLImage2dMSAARW: - case clang::BuiltinType::OCLImage2dArrayMSAARW: - case clang::BuiltinType::OCLImage2dMSAADepthRW: - case clang::BuiltinType::OCLImage2dArrayMSAADepthRW: - case clang::BuiltinType::OCLImage3dRW: - case clang::BuiltinType::OCLSampler: - case clang::BuiltinType::OCLEvent: - case clang::BuiltinType::OCLClkEvent: - case clang::BuiltinType::OCLQueue: - case clang::BuiltinType::OCLReserveID: - case clang::BuiltinType::ShortFract: - case clang::BuiltinType::Fract: - case clang::BuiltinType::LongFract: - case clang::BuiltinType::UShortFract: - case clang::BuiltinType::UFract: - case clang::BuiltinType::ULongFract: - case clang::BuiltinType::SatShortAccum: - case clang::BuiltinType::SatAccum: - case clang::BuiltinType::SatLongAccum: - case clang::BuiltinType::SatUShortAccum: - case clang::BuiltinType::SatUAccum: - case clang::BuiltinType::SatULongAccum: - case clang::BuiltinType::SatShortFract: - case clang::BuiltinType::SatFract: - case clang::BuiltinType::SatLongFract: - case clang::BuiltinType::SatUShortFract: - case clang::BuiltinType::SatUFract: - case clang::BuiltinType::SatULongFract: - case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload: - case clang::BuiltinType::OCLIntelSubgroupAVCImePayload: - case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload: - case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload: - case clang::BuiltinType::OCLIntelSubgroupAVCMceResult: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResult: - case clang::BuiltinType::OCLIntelSubgroupAVCRefResult: - case clang::BuiltinType::OCLIntelSubgroupAVCSicResult: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout: - case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin: - case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: + case ZigClangBuiltinTypeWChar_U: + case ZigClangBuiltinTypeChar16: + case ZigClangBuiltinTypeChar32: + case ZigClangBuiltinTypeWChar_S: + case ZigClangBuiltinTypeHalf: + case ZigClangBuiltinTypeNullPtr: + case ZigClangBuiltinTypeObjCId: + case ZigClangBuiltinTypeObjCClass: + case ZigClangBuiltinTypeObjCSel: + case ZigClangBuiltinTypeOMPArraySection: + case ZigClangBuiltinTypeDependent: + case ZigClangBuiltinTypeOverload: + case ZigClangBuiltinTypeBoundMember: + case ZigClangBuiltinTypePseudoObject: + case ZigClangBuiltinTypeUnknownAny: + case ZigClangBuiltinTypeBuiltinFn: + case ZigClangBuiltinTypeARCUnbridgedCast: + case ZigClangBuiltinTypeShortAccum: + case ZigClangBuiltinTypeAccum: + case ZigClangBuiltinTypeLongAccum: + case ZigClangBuiltinTypeUShortAccum: + case ZigClangBuiltinTypeUAccum: + case ZigClangBuiltinTypeULongAccum: + + case ZigClangBuiltinTypeOCLImage1dRO: + case ZigClangBuiltinTypeOCLImage1dArrayRO: + case ZigClangBuiltinTypeOCLImage1dBufferRO: + case ZigClangBuiltinTypeOCLImage2dRO: + case ZigClangBuiltinTypeOCLImage2dArrayRO: + case ZigClangBuiltinTypeOCLImage2dDepthRO: + case ZigClangBuiltinTypeOCLImage2dArrayDepthRO: + case ZigClangBuiltinTypeOCLImage2dMSAARO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAARO: + case ZigClangBuiltinTypeOCLImage2dMSAADepthRO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRO: + case ZigClangBuiltinTypeOCLImage3dRO: + case ZigClangBuiltinTypeOCLImage1dWO: + case ZigClangBuiltinTypeOCLImage1dArrayWO: + case ZigClangBuiltinTypeOCLImage1dBufferWO: + case ZigClangBuiltinTypeOCLImage2dWO: + case ZigClangBuiltinTypeOCLImage2dArrayWO: + case ZigClangBuiltinTypeOCLImage2dDepthWO: + case ZigClangBuiltinTypeOCLImage2dArrayDepthWO: + case ZigClangBuiltinTypeOCLImage2dMSAAWO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAAWO: + case ZigClangBuiltinTypeOCLImage2dMSAADepthWO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthWO: + case ZigClangBuiltinTypeOCLImage3dWO: + case ZigClangBuiltinTypeOCLImage1dRW: + case ZigClangBuiltinTypeOCLImage1dArrayRW: + case ZigClangBuiltinTypeOCLImage1dBufferRW: + case ZigClangBuiltinTypeOCLImage2dRW: + case ZigClangBuiltinTypeOCLImage2dArrayRW: + case ZigClangBuiltinTypeOCLImage2dDepthRW: + case ZigClangBuiltinTypeOCLImage2dArrayDepthRW: + case ZigClangBuiltinTypeOCLImage2dMSAARW: + case ZigClangBuiltinTypeOCLImage2dArrayMSAARW: + case ZigClangBuiltinTypeOCLImage2dMSAADepthRW: + case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRW: + case ZigClangBuiltinTypeOCLImage3dRW: + case ZigClangBuiltinTypeOCLSampler: + case ZigClangBuiltinTypeOCLEvent: + case ZigClangBuiltinTypeOCLClkEvent: + case ZigClangBuiltinTypeOCLQueue: + case ZigClangBuiltinTypeOCLReserveID: + case ZigClangBuiltinTypeShortFract: + case ZigClangBuiltinTypeFract: + case ZigClangBuiltinTypeLongFract: + case ZigClangBuiltinTypeUShortFract: + case ZigClangBuiltinTypeUFract: + case ZigClangBuiltinTypeULongFract: + case ZigClangBuiltinTypeSatShortAccum: + case ZigClangBuiltinTypeSatAccum: + case ZigClangBuiltinTypeSatLongAccum: + case ZigClangBuiltinTypeSatUShortAccum: + case ZigClangBuiltinTypeSatUAccum: + case ZigClangBuiltinTypeSatULongAccum: + case ZigClangBuiltinTypeSatShortFract: + case ZigClangBuiltinTypeSatFract: + case ZigClangBuiltinTypeSatLongFract: + case ZigClangBuiltinTypeSatUShortFract: + case ZigClangBuiltinTypeSatUFract: + case ZigClangBuiltinTypeSatULongFract: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCMcePayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImePayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefPayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicPayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCMceResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultSingleRefStreamout: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultDualRefStreamout: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeSingleRefStreamin: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeDualRefStreamin: emit_warning(c, source_loc, "unsupported builtin type"); return nullptr; } break; } - case clang::Type::Pointer: + case ZigClangType_Pointer: { - const clang::PointerType *pointer_ty = static_cast<const clang::PointerType*>(ty); - clang::QualType child_qt = pointer_ty->getPointeeType(); + ZigClangQualType child_qt = ZigClangType_getPointeeType(ty); AstNode *child_node = trans_qual_type(c, child_qt, source_loc); if (child_node == nullptr) { emit_warning(c, source_loc, "pointer to unsupported type"); @@ -973,29 +1023,33 @@ static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::Sourc return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } - if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) { - AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_node, PtrLenSingle); + if (type_is_opaque(c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { + AstNode *pointer_node = trans_create_node_ptr_type(c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + child_node, PtrLenSingle); return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); } else { - return trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_node, PtrLenC); + return trans_create_node_ptr_type(c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + child_node, PtrLenC); } } - case clang::Type::Typedef: + case ZigClangType_Typedef: { - const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty); - const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + const ZigClangTypedefType *typedef_ty = reinterpret_cast<const ZigClangTypedefType*>(ty); + const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); return resolve_typedef_decl(c, typedef_decl); } - case clang::Type::Elaborated: + case ZigClangType_Elaborated: { - const clang::ElaboratedType *elaborated_ty = static_cast<const clang::ElaboratedType*>(ty); + const clang::ElaboratedType *elaborated_ty = reinterpret_cast<const clang::ElaboratedType*>(ty); switch (elaborated_ty->getKeyword()) { case clang::ETK_Struct: case clang::ETK_Enum: case clang::ETK_Union: - return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); + return trans_qual_type(c, bitcast(elaborated_ty->getNamedType()), source_loc); case clang::ETK_Interface: case clang::ETK_Class: case clang::ETK_Typename: @@ -1004,81 +1058,81 @@ static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::Sourc return nullptr; } } - case clang::Type::FunctionProto: - case clang::Type::FunctionNoProto: + case ZigClangType_FunctionProto: + case ZigClangType_FunctionNoProto: { - const clang::FunctionType *fn_ty = static_cast<const clang::FunctionType*>(ty); + const ZigClangFunctionType *fn_ty = reinterpret_cast<const ZigClangFunctionType*>(ty); AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); - switch (fn_ty->getCallConv()) { - case clang::CC_C: // __attribute__((cdecl)) + switch (ZigClangFunctionType_getCallConv(fn_ty)) { + case ZigClangCallingConv_C: // __attribute__((cdecl)) proto_node->data.fn_proto.cc = CallingConventionC; proto_node->data.fn_proto.is_extern = true; break; - case clang::CC_X86StdCall: // __attribute__((stdcall)) + case ZigClangCallingConv_X86StdCall: // __attribute__((stdcall)) proto_node->data.fn_proto.cc = CallingConventionStdcall; break; - case clang::CC_X86FastCall: // __attribute__((fastcall)) + case ZigClangCallingConv_X86FastCall: // __attribute__((fastcall)) emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); return nullptr; - case clang::CC_X86ThisCall: // __attribute__((thiscall)) + case ZigClangCallingConv_X86ThisCall: // __attribute__((thiscall)) emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); return nullptr; - case clang::CC_X86VectorCall: // __attribute__((vectorcall)) + case ZigClangCallingConv_X86VectorCall: // __attribute__((vectorcall)) emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); return nullptr; - case clang::CC_X86Pascal: // __attribute__((pascal)) + case ZigClangCallingConv_X86Pascal: // __attribute__((pascal)) emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); return nullptr; - case clang::CC_Win64: // __attribute__((ms_abi)) + case ZigClangCallingConv_Win64: // __attribute__((ms_abi)) emit_warning(c, source_loc, "unsupported calling convention: win64"); return nullptr; - case clang::CC_X86_64SysV: // __attribute__((sysv_abi)) + case ZigClangCallingConv_X86_64SysV: // __attribute__((sysv_abi)) emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); return nullptr; - case clang::CC_X86RegCall: + case ZigClangCallingConv_X86RegCall: emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); return nullptr; - case clang::CC_AAPCS: // __attribute__((pcs("aapcs"))) + case ZigClangCallingConv_AAPCS: // __attribute__((pcs("aapcs"))) emit_warning(c, source_loc, "unsupported calling convention: aapcs"); return nullptr; - case clang::CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) + case ZigClangCallingConv_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); return nullptr; - case clang::CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) + case ZigClangCallingConv_IntelOclBicc: // __attribute__((intel_ocl_bicc)) emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); return nullptr; - case clang::CC_SpirFunction: // default for OpenCL functions on SPIR target + case ZigClangCallingConv_SpirFunction: // default for OpenCL functions on SPIR target emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); return nullptr; - case clang::CC_OpenCLKernel: + case ZigClangCallingConv_OpenCLKernel: emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); return nullptr; - case clang::CC_Swift: + case ZigClangCallingConv_Swift: emit_warning(c, source_loc, "unsupported calling convention: Swift"); return nullptr; - case clang::CC_PreserveMost: + case ZigClangCallingConv_PreserveMost: emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); return nullptr; - case clang::CC_PreserveAll: + case ZigClangCallingConv_PreserveAll: emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); return nullptr; - case clang::CC_AArch64VectorCall: + case ZigClangCallingConv_AArch64VectorCall: emit_warning(c, source_loc, "unsupported calling convention: AArch64VectorCall"); return nullptr; } - if (fn_ty->getNoReturnAttr()) { + if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); } else { - proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_ty->getReturnType(), - source_loc); + proto_node->data.fn_proto.return_type = trans_qual_type(c, + ZigClangFunctionType_getReturnType(fn_ty), source_loc); if (proto_node->data.fn_proto.return_type == nullptr) { emit_warning(c, source_loc, "unsupported function proto return type"); return nullptr; } // convert c_void to actual void (only for return type) - // we do want to look at the AstNode instead of clang::QualType, because + // we do want to look at the AstNode instead of ZigClangQualType, because // if they do something like: // typedef Foo void; // void foo(void) -> Foo; @@ -1094,17 +1148,17 @@ static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::Sourc proto_node->data.fn_proto.name = buf_create_from_str(fn_name); } - if (ty->getTypeClass() == clang::Type::FunctionNoProto) { + if (ZigClangType_getTypeClass(ty) == ZigClangType_FunctionNoProto) { return proto_node; } - const clang::FunctionProtoType *fn_proto_ty = static_cast<const clang::FunctionProtoType*>(ty); + const ZigClangFunctionProtoType *fn_proto_ty = reinterpret_cast<const ZigClangFunctionProtoType*>(ty); - proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); - size_t param_count = fn_proto_ty->getNumParams(); + proto_node->data.fn_proto.is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); + size_t param_count = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); for (size_t i = 0; i < param_count; i += 1) { - clang::QualType qt = fn_proto_ty->getParamType(i); + ZigClangQualType qt = ZigClangFunctionProtoType_getParamType(fn_proto_ty, i); AstNode *param_type_node = trans_qual_type(c, qt, source_loc); if (param_type_node == nullptr) { @@ -1118,7 +1172,7 @@ static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::Sourc if (param_name != nullptr) { param_node->data.param_decl.name = buf_create_from_str(param_name); } - param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); + param_node->data.param_decl.is_noalias = ZigClangQualType_isRestrictQualified(qt); param_node->data.param_decl.type = param_type_node; proto_node->data.fn_proto.params.append(param_node); } @@ -1127,20 +1181,20 @@ static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::Sourc return proto_node; } - case clang::Type::Record: + case ZigClangType_Record: { - const clang::RecordType *record_ty = static_cast<const clang::RecordType*>(ty); - return resolve_record_decl(c, record_ty->getDecl()); + const ZigClangRecordType *record_ty = reinterpret_cast<const ZigClangRecordType*>(ty); + return resolve_record_decl(c, ZigClangRecordType_getDecl(record_ty)); } - case clang::Type::Enum: + case ZigClangType_Enum: { - const clang::EnumType *enum_ty = static_cast<const clang::EnumType*>(ty); - return resolve_enum_decl(c, enum_ty->getDecl()); + const ZigClangEnumType *enum_ty = reinterpret_cast<const ZigClangEnumType*>(ty); + return resolve_enum_decl(c, ZigClangEnumType_getDecl(enum_ty)); } - case clang::Type::ConstantArray: + case ZigClangType_ConstantArray: { - const clang::ConstantArrayType *const_arr_ty = static_cast<const clang::ConstantArrayType *>(ty); - AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); + const clang::ConstantArrayType *const_arr_ty = reinterpret_cast<const clang::ConstantArrayType *>(ty); + AstNode *child_type_node = trans_qual_type(c, bitcast(const_arr_ty->getElementType()), source_loc); if (child_type_node == nullptr) { emit_warning(c, source_loc, "unresolved array element type"); return nullptr; @@ -1149,83 +1203,87 @@ static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::Sourc AstNode *size_node = trans_create_node_unsigned(c, size); return trans_create_node_array_type(c, size_node, child_type_node); } - case clang::Type::Paren: + case ZigClangType_Paren: { - const clang::ParenType *paren_ty = static_cast<const clang::ParenType *>(ty); - return trans_qual_type(c, paren_ty->getInnerType(), source_loc); + const clang::ParenType *paren_ty = reinterpret_cast<const clang::ParenType *>(ty); + return trans_qual_type(c, bitcast(paren_ty->getInnerType()), source_loc); } - case clang::Type::Decayed: + case ZigClangType_Decayed: { - const clang::DecayedType *decayed_ty = static_cast<const clang::DecayedType *>(ty); - return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); + const clang::DecayedType *decayed_ty = reinterpret_cast<const clang::DecayedType *>(ty); + return trans_qual_type(c, bitcast(decayed_ty->getDecayedType()), source_loc); } - case clang::Type::Attributed: + case ZigClangType_Attributed: { - const clang::AttributedType *attributed_ty = static_cast<const clang::AttributedType *>(ty); - return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); + const clang::AttributedType *attributed_ty = reinterpret_cast<const clang::AttributedType *>(ty); + return trans_qual_type(c, bitcast(attributed_ty->getEquivalentType()), source_loc); } - case clang::Type::IncompleteArray: + case ZigClangType_IncompleteArray: { - const clang::IncompleteArrayType *incomplete_array_ty = static_cast<const clang::IncompleteArrayType *>(ty); - clang::QualType child_qt = incomplete_array_ty->getElementType(); + const clang::IncompleteArrayType *incomplete_array_ty = reinterpret_cast<const clang::IncompleteArrayType *>(ty); + ZigClangQualType child_qt = bitcast(incomplete_array_ty->getElementType()); AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc); if (child_type_node == nullptr) { emit_warning(c, source_loc, "unresolved array element type"); return nullptr; } - AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_type_node, PtrLenC); + AstNode *pointer_node = trans_create_node_ptr_type(c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + child_type_node, PtrLenC); return pointer_node; } - case clang::Type::BlockPointer: - case clang::Type::LValueReference: - case clang::Type::RValueReference: - case clang::Type::MemberPointer: - case clang::Type::VariableArray: - case clang::Type::DependentSizedArray: - case clang::Type::DependentSizedExtVector: - case clang::Type::Vector: - case clang::Type::ExtVector: - case clang::Type::UnresolvedUsing: - case clang::Type::Adjusted: - case clang::Type::TypeOfExpr: - case clang::Type::TypeOf: - case clang::Type::Decltype: - case clang::Type::UnaryTransform: - case clang::Type::TemplateTypeParm: - case clang::Type::SubstTemplateTypeParm: - case clang::Type::SubstTemplateTypeParmPack: - case clang::Type::TemplateSpecialization: - case clang::Type::Auto: - case clang::Type::InjectedClassName: - case clang::Type::DependentName: - case clang::Type::DependentTemplateSpecialization: - case clang::Type::PackExpansion: - case clang::Type::ObjCObject: - case clang::Type::ObjCInterface: - case clang::Type::Complex: - case clang::Type::ObjCObjectPointer: - case clang::Type::Atomic: - case clang::Type::Pipe: - case clang::Type::ObjCTypeParam: - case clang::Type::DeducedTemplateSpecialization: - case clang::Type::DependentAddressSpace: - case clang::Type::DependentVector: - emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); + case ZigClangType_BlockPointer: + case ZigClangType_LValueReference: + case ZigClangType_RValueReference: + case ZigClangType_MemberPointer: + case ZigClangType_VariableArray: + case ZigClangType_DependentSizedArray: + case ZigClangType_DependentSizedExtVector: + case ZigClangType_Vector: + case ZigClangType_ExtVector: + case ZigClangType_UnresolvedUsing: + case ZigClangType_Adjusted: + case ZigClangType_TypeOfExpr: + case ZigClangType_TypeOf: + case ZigClangType_Decltype: + case ZigClangType_UnaryTransform: + case ZigClangType_TemplateTypeParm: + case ZigClangType_SubstTemplateTypeParm: + case ZigClangType_SubstTemplateTypeParmPack: + case ZigClangType_TemplateSpecialization: + case ZigClangType_Auto: + case ZigClangType_InjectedClassName: + case ZigClangType_DependentName: + case ZigClangType_DependentTemplateSpecialization: + case ZigClangType_PackExpansion: + case ZigClangType_ObjCObject: + case ZigClangType_ObjCInterface: + case ZigClangType_Complex: + case ZigClangType_ObjCObjectPointer: + case ZigClangType_Atomic: + case ZigClangType_Pipe: + case ZigClangType_ObjCTypeParam: + case ZigClangType_DeducedTemplateSpecialization: + case ZigClangType_DependentAddressSpace: + case ZigClangType_DependentVector: + emit_warning(c, source_loc, "unsupported type: '%s'", ZigClangType_getTypeClassName(ty)); return nullptr; } zig_unreachable(); } -static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc) { - return trans_type(c, qt.getTypePtr(), source_loc); +static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc) { + return trans_type(c, ZigClangQualType_getTypePtr(qt), source_loc); } -static int trans_compound_stmt_inline(Context *c, TransScope *scope, const clang::CompoundStmt *stmt, +static int trans_compound_stmt_inline(Context *c, TransScope *scope, const ZigClangCompoundStmt *stmt, AstNode *block_node, TransScope **out_node_scope) { assert(block_node->type == NodeTypeBlock); - for (clang::CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { + for (ZigClangCompoundStmt_const_body_iterator it = ZigClangCompoundStmt_body_begin(stmt), + end_it = ZigClangCompoundStmt_body_end(stmt); it != end_it; ++it) + { AstNode *child_node; scope = trans_stmt(c, scope, *it, &child_node); if (scope == nullptr) @@ -1239,7 +1297,7 @@ static int trans_compound_stmt_inline(Context *c, TransScope *scope, const clang return ErrorNone; } -static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const clang::CompoundStmt *stmt, +static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const ZigClangCompoundStmt *stmt, TransScope **out_node_scope) { TransScopeBlock *child_scope_block = trans_scope_block_create(c, scope); @@ -1251,7 +1309,7 @@ static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const clang:: static AstNode *trans_stmt_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::StmtExpr *stmt, TransScope **out_node_scope) { - AstNode *block = trans_compound_stmt(c, scope, stmt->getSubStmt(), out_node_scope); + AstNode *block = trans_compound_stmt(c, scope, (const ZigClangCompoundStmt *)stmt->getSubStmt(), out_node_scope); if (block == nullptr) return block; assert(block->type == NodeTypeBlock); @@ -1274,7 +1332,7 @@ static AstNode *trans_stmt_expr(Context *c, ResultUsed result_used, TransScope * } static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::ReturnStmt *stmt) { - const clang::Expr *value_expr = stmt->getRetValue(); + const ZigClangExpr *value_expr = bitcast(stmt->getRetValue()); if (value_expr == nullptr) { return trans_create_node(c, NodeTypeReturnExpr); } else { @@ -1289,22 +1347,62 @@ static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::Re static AstNode *trans_integer_literal(Context *c, ResultUsed result_used, const clang::IntegerLiteral *stmt) { clang::Expr::EvalResult result; if (!stmt->EvaluateAsInt(result, *reinterpret_cast<clang::ASTContext *>(c->ctx))) { - emit_warning(c, stmt->getBeginLoc(), "invalid integer literal"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "invalid integer literal"); + return nullptr; + } + AstNode *node = trans_create_node_apint(c, bitcast(&result.Val.getInt())); + return maybe_suppress_result(c, result_used, node); +} + +static AstNode *trans_floating_literal(Context *c, ResultUsed result_used, const clang::FloatingLiteral *stmt) { + llvm::APFloat result{0.0f}; + if (!stmt->EvaluateAsFloat(result, *reinterpret_cast<clang::ASTContext *>(c->ctx))) { + emit_warning(c, bitcast(stmt->getBeginLoc()), "invalid floating literal"); return nullptr; } - AstNode *node = trans_create_node_apint(c, result.Val.getInt()); + AstNode *node = trans_create_node_apfloat(c, result); return maybe_suppress_result(c, result_used, node); } +static AstNode *trans_character_literal(Context *c, ResultUsed result_used, const clang::CharacterLiteral *stmt) { + switch (stmt->getKind()) { + case clang::CharacterLiteral::CharacterKind::Ascii: + { + unsigned val = stmt->getValue(); + // C has a somewhat obscure feature called multi-character character + // constant + if (val > 255) + return trans_create_node_unsigned(c, val); + } + // fallthrough + case clang::CharacterLiteral::CharacterKind::UTF8: + { + AstNode *node = trans_create_node(c, NodeTypeCharLiteral); + node->data.char_literal.value = stmt->getValue(); + return maybe_suppress_result(c, result_used, node); + } + case clang::CharacterLiteral::CharacterKind::UTF16: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support UTF16 character literals"); + return nullptr; + case clang::CharacterLiteral::CharacterKind::UTF32: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support UTF32 character literals"); + return nullptr; + case clang::CharacterLiteral::CharacterKind::Wide: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support wide character literals"); + return nullptr; + } + zig_unreachable(); +} + static AstNode *trans_constant_expr(Context *c, ResultUsed result_used, const clang::ConstantExpr *expr) { clang::Expr::EvalResult result; if (!expr->EvaluateAsConstantExpr(result, clang::Expr::EvaluateForCodeGen, *reinterpret_cast<clang::ASTContext *>(c->ctx))) { - emit_warning(c, expr->getBeginLoc(), "invalid constant expression"); + emit_warning(c, bitcast(expr->getBeginLoc()), "invalid constant expression"); return nullptr; } - AstNode *node = trans_ap_value(c, &result.Val, expr->getType(), expr->getBeginLoc()); + AstNode *node = trans_ap_value(c, bitcast(&result.Val), bitcast(expr->getType()), bitcast(expr->getBeginLoc())); return maybe_suppress_result(c, result_used, node); } @@ -1313,9 +1411,9 @@ static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, T { AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); - clang::Expr *cond_expr = stmt->getCond(); - clang::Expr *true_expr = stmt->getTrueExpr(); - clang::Expr *false_expr = stmt->getFalseExpr(); + const ZigClangExpr *cond_expr = bitcast(stmt->getCond()); + const ZigClangExpr *true_expr = bitcast(stmt->getTrueExpr()); + const ZigClangExpr *false_expr = bitcast(stmt->getFalseExpr()); node->data.if_bool_expr.condition = trans_expr(c, ResultUsedYes, scope, cond_expr, TransRValue); if (node->data.if_bool_expr.condition == nullptr) @@ -1332,7 +1430,9 @@ static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, T return maybe_suppress_result(c, result_used, node); } -static AstNode *trans_create_bin_op(Context *c, TransScope *scope, clang::Expr *lhs, BinOpType bin_op, clang::Expr *rhs) { +static AstNode *trans_create_bin_op(Context *c, TransScope *scope, const ZigClangExpr *lhs, + BinOpType bin_op, const ZigClangExpr *rhs) +{ AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = bin_op; @@ -1347,7 +1447,9 @@ static AstNode *trans_create_bin_op(Context *c, TransScope *scope, clang::Expr * return node; } -static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, clang::Expr *lhs, BinOpType bin_op, clang::Expr *rhs) { +static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, const ZigClangExpr *lhs, + BinOpType bin_op, const ZigClangExpr *rhs) +{ assert(bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeBoolOr); AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = bin_op; @@ -1363,7 +1465,9 @@ static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, clang::E return node; } -static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, clang::Expr *lhs, clang::Expr *rhs) { +static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, + const ZigClangExpr *lhs, const ZigClangExpr *rhs) +{ if (result_used == ResultUsedNo) { // common case AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); @@ -1414,10 +1518,10 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco } } -static AstNode *trans_create_shift_op(Context *c, TransScope *scope, clang::QualType result_type, - clang::Expr *lhs_expr, BinOpType bin_op, clang::Expr *rhs_expr) +static AstNode *trans_create_shift_op(Context *c, TransScope *scope, ZigClangQualType result_type, + const ZigClangExpr *lhs_expr, BinOpType bin_op, const ZigClangExpr *rhs_expr) { - const clang::SourceLocation &rhs_location = rhs_expr->getBeginLoc(); + ZigClangSourceLocation rhs_location = ZigClangExpr_getBeginLoc(rhs_expr); AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); // lhs >> u5(rh) @@ -1434,130 +1538,130 @@ static AstNode *trans_create_shift_op(Context *c, TransScope *scope, clang::Qual static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const clang::BinaryOperator *stmt) { switch (stmt->getOpcode()) { case clang::BO_PtrMemD: - emit_warning(c, stmt->getBeginLoc(), "TODO handle more C binary operators: BO_PtrMemD"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle more C binary operators: BO_PtrMemD"); return nullptr; case clang::BO_PtrMemI: - emit_warning(c, stmt->getBeginLoc(), "TODO handle more C binary operators: BO_PtrMemI"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle more C binary operators: BO_PtrMemI"); return nullptr; case clang::BO_Cmp: - emit_warning(c, stmt->getBeginLoc(), "TODO handle more C binary operators: BO_Cmp"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle more C binary operators: BO_Cmp"); return nullptr; case clang::BO_Mul: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), - qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, - stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), + qual_type_has_wrapping_overflow(c, bitcast(stmt->getType())) ? BinOpTypeMultWrap : BinOpTypeMult, + bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Div: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) { + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) { // unsigned/float division uses the operator - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeDiv, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } else { // signed integer division uses @divTrunc AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); + AstNode *lhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getLHS()), TransLValue); if (lhs == nullptr) return nullptr; fn_call->data.fn_call_expr.params.append(lhs); - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getRHS()), TransLValue); if (rhs == nullptr) return nullptr; fn_call->data.fn_call_expr.params.append(rhs); return maybe_suppress_result(c, result_used, fn_call); } case clang::BO_Rem: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) { + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) { // unsigned/float division uses the operator - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeMod, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } else { // signed integer division uses @rem AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); + AstNode *lhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getLHS()), TransLValue); if (lhs == nullptr) return nullptr; fn_call->data.fn_call_expr.params.append(lhs); - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getRHS()), TransLValue); if (rhs == nullptr) return nullptr; fn_call->data.fn_call_expr.params.append(rhs); return maybe_suppress_result(c, result_used, fn_call); } case clang::BO_Add: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), - qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, - stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), + qual_type_has_wrapping_overflow(c, bitcast(stmt->getType())) ? BinOpTypeAddWrap : BinOpTypeAdd, + bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Sub: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), - qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, - stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), + qual_type_has_wrapping_overflow(c, bitcast(stmt->getType())) ? BinOpTypeSubWrap : BinOpTypeSub, + bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Shl: { - AstNode *node = trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); + AstNode *node = trans_create_shift_op(c, scope, bitcast(stmt->getType()), bitcast(stmt->getLHS()), BinOpTypeBitShiftLeft, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Shr: { - AstNode *node = trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); + AstNode *node = trans_create_shift_op(c, scope, bitcast(stmt->getType()), bitcast(stmt->getLHS()), BinOpTypeBitShiftRight, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_LT: { - AstNode *node =trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); + AstNode *node =trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeCmpLessThan, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_GT: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeCmpGreaterThan, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_LE: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeCmpLessOrEq, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_GE: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeCmpGreaterOrEq, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_EQ: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeCmpEq, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_NE: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeCmpNotEq, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_And: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeBinAnd, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Xor: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeBinXor, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Or: { - AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeBinOr, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_LAnd: { - AstNode *node = trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); + AstNode *node = trans_create_bool_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeBoolAnd, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_LOr: { - AstNode *node = trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); + AstNode *node = trans_create_bool_bin_op(c, scope, bitcast(stmt->getLHS()), BinOpTypeBoolOr, bitcast(stmt->getRHS())); return maybe_suppress_result(c, result_used, node); } case clang::BO_Assign: - return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS()); + return trans_create_assign(c, result_used, scope, bitcast(stmt->getLHS()), bitcast(stmt->getRHS())); case clang::BO_Comma: { TransScopeBlock *scope_block = trans_scope_block_create(c, scope); Buf *label_name = buf_create_from_str("x"); scope_block->node->data.block.name = label_name; - AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue); + AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, bitcast(stmt->getLHS()), TransRValue); if (lhs == nullptr) return nullptr; scope_block->node->data.block.statements.append(lhs); - AstNode *rhs = trans_expr(c, ResultUsedYes, &scope_block->base, stmt->getRHS(), TransRValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, &scope_block->base, bitcast(stmt->getRHS()), TransRValue); if (rhs == nullptr) return nullptr; @@ -1584,17 +1688,17 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result_used, TransScope *scope, const clang::CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { - const clang::SourceLocation &rhs_location = stmt->getRHS()->getBeginLoc(); - AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); + ZigClangSourceLocation rhs_location = bitcast(stmt->getRHS()->getBeginLoc()); + AstNode *rhs_type = qual_type_to_log2_int_ref(c, bitcast(stmt->getComputationLHSType()), rhs_location); bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); if (!use_intermediate_casts && result_used == ResultUsedNo) { // simple common case, where the C and Zig are identical: // lhs >>= rhs - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); + AstNode *lhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getLHS()), TransLValue); if (lhs == nullptr) return nullptr; - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransRValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getRHS()), TransRValue); if (rhs == nullptr) return nullptr; AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); @@ -1614,7 +1718,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result child_scope->node->data.block.name = label_name; // const _ref = &lhs; - AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); + AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, bitcast(stmt->getLHS()), TransLValue); if (lhs == nullptr) return nullptr; AstNode *addr_of_lhs = trans_create_node_addr_of(c, lhs); // TODO: avoid name collisions with generated variable names @@ -1624,20 +1728,20 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); - AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getRHS(), TransRValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, bitcast(stmt->getRHS()), TransRValue); if (rhs == nullptr) return nullptr; AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); // operation_type(*_ref) AstNode *operation_type_cast = trans_c_cast(c, rhs_location, - stmt->getComputationLHSType(), - stmt->getLHS()->getType(), + bitcast(stmt->getComputationLHSType()), + bitcast(stmt->getLHS()->getType()), trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name))); // result_type(... >> u5(rhs)) AstNode *result_type_cast = trans_c_cast(c, rhs_location, - stmt->getComputationResultType(), - stmt->getComputationLHSType(), + bitcast(stmt->getComputationResultType()), + bitcast(stmt->getComputationLHSType()), trans_create_node_bin_op(c, operation_type_cast, bin_op, @@ -1669,9 +1773,9 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, if (result_used == ResultUsedNo) { // simple common case, where the C and Zig are identical: // lhs += rhs - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); + AstNode *lhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getLHS()), TransLValue); if (lhs == nullptr) return nullptr; - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransRValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getRHS()), TransRValue); if (rhs == nullptr) return nullptr; return trans_create_node_bin_op(c, lhs, assign_op, rhs); } else { @@ -1688,7 +1792,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, child_scope->node->data.block.name = label_name; // const _ref = &lhs; - AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); + AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, bitcast(stmt->getLHS()), TransLValue); if (lhs == nullptr) return nullptr; AstNode *addr_of_lhs = trans_create_node_addr_of(c, lhs); // TODO: avoid name collisions with generated variable names @@ -1698,7 +1802,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, // *_ref = *_ref + rhs; - AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getRHS(), TransRValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, bitcast(stmt->getRHS()), TransRValue); if (rhs == nullptr) return nullptr; AstNode *assign_statement = trans_create_node_bin_op(c, @@ -1728,26 +1832,26 @@ static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_use { switch (stmt->getOpcode()) { case clang::BO_MulAssign: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); else return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimes, BinOpTypeMult); case clang::BO_DivAssign: - emit_warning(c, stmt->getBeginLoc(), "TODO handle more C compound assign operators: BO_DivAssign"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle more C compound assign operators: BO_DivAssign"); return nullptr; case clang::BO_RemAssign: - emit_warning(c, stmt->getBeginLoc(), "TODO handle more C compound assign operators: BO_RemAssign"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle more C compound assign operators: BO_RemAssign"); return nullptr; case clang::BO_Cmp: - emit_warning(c, stmt->getBeginLoc(), "TODO handle more C compound assign operators: BO_Cmp"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle more C compound assign operators: BO_Cmp"); return nullptr; case clang::BO_AddAssign: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); else return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); case clang::BO_SubAssign: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); else return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinus, BinOpTypeSub); @@ -1790,202 +1894,265 @@ static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_use } static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::ImplicitCastExpr *stmt) { - switch (stmt->getCastKind()) { - case clang::CK_LValueToRValue: - return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); - case clang::CK_IntegralCast: + switch ((ZigClangCK)stmt->getCastKind()) { + case ZigClangCK_LValueToRValue: + return trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + case ZigClangCK_IntegralCast: { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); if (target_node == nullptr) return nullptr; - AstNode *node = trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), - stmt->getSubExpr()->getType(), target_node); + AstNode *node = trans_c_cast(c, bitcast(stmt->getExprLoc()), bitcast(stmt->getType()), + bitcast(stmt->getSubExpr()->getType()), target_node); return maybe_suppress_result(c, result_used, node); } - case clang::CK_FunctionToPointerDecay: - case clang::CK_ArrayToPointerDecay: + case ZigClangCK_FunctionToPointerDecay: + case ZigClangCK_ArrayToPointerDecay: { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); if (target_node == nullptr) return nullptr; return maybe_suppress_result(c, result_used, target_node); } - case clang::CK_BitCast: + case ZigClangCK_BitCast: { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); if (target_node == nullptr) return nullptr; - if (expr_types_equal(c, stmt, stmt->getSubExpr())) { - return target_node; - } + const ZigClangQualType dest_type = get_expr_qual_type(c, bitcast(stmt)); + const ZigClangQualType src_type = get_expr_qual_type(c, bitcast(stmt->getSubExpr())); - AstNode *dest_type_node = get_expr_type(c, stmt); - - AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); - node->data.fn_call_expr.params.append(dest_type_node); - node->data.fn_call_expr.params.append(target_node); - return maybe_suppress_result(c, result_used, node); + return trans_c_cast(c, bitcast(stmt->getBeginLoc()), dest_type, src_type, target_node); } - case clang::CK_NullToPointer: - return trans_create_node_unsigned(c, 0); - case clang::CK_NoOp: - return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); - case clang::CK_Dependent: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_Dependent"); - return nullptr; - case clang::CK_LValueBitCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_LValueBitCast"); - return nullptr; - case clang::CK_BaseToDerived: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BaseToDerived"); - return nullptr; - case clang::CK_DerivedToBase: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_DerivedToBase"); - return nullptr; - case clang::CK_UncheckedDerivedToBase: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_UncheckedDerivedToBase"); + case ZigClangCK_NullToPointer: + return trans_create_node(c, NodeTypeNullLiteral); + case ZigClangCK_NoOp: + return trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + case ZigClangCK_Dependent: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_Dependent"); return nullptr; - case clang::CK_Dynamic: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_Dynamic"); + case ZigClangCK_LValueBitCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_LValueBitCast"); return nullptr; - case clang::CK_ToUnion: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ToUnion"); + case ZigClangCK_BaseToDerived: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_BaseToDerived"); return nullptr; - case clang::CK_NullToMemberPointer: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_NullToMemberPointer"); + case ZigClangCK_DerivedToBase: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_DerivedToBase"); return nullptr; - case clang::CK_BaseToDerivedMemberPointer: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); + case ZigClangCK_UncheckedDerivedToBase: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_UncheckedDerivedToBase"); return nullptr; - case clang::CK_DerivedToBaseMemberPointer: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); + case ZigClangCK_Dynamic: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_Dynamic"); return nullptr; - case clang::CK_MemberPointerToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_MemberPointerToBoolean"); + case ZigClangCK_ToUnion: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_ToUnion"); return nullptr; - case clang::CK_ReinterpretMemberPointer: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ReinterpretMemberPointer"); + case ZigClangCK_NullToMemberPointer: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_NullToMemberPointer"); return nullptr; - case clang::CK_UserDefinedConversion: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_UserDefinedConversion"); + case ZigClangCK_BaseToDerivedMemberPointer: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); return nullptr; - case clang::CK_ConstructorConversion: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ConstructorConversion"); + case ZigClangCK_DerivedToBaseMemberPointer: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); return nullptr; - case clang::CK_IntegralToPointer: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralToPointer"); + case ZigClangCK_MemberPointerToBoolean: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_MemberPointerToBoolean"); return nullptr; - case clang::CK_PointerToIntegral: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_PointerToIntegral"); + case ZigClangCK_ReinterpretMemberPointer: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_ReinterpretMemberPointer"); return nullptr; - case clang::CK_PointerToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_PointerToBoolean"); + case ZigClangCK_UserDefinedConversion: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation cast CK_UserDefinedConversion"); return nullptr; - case clang::CK_ToVoid: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ToVoid"); + case ZigClangCK_ConstructorConversion: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ConstructorConversion"); return nullptr; - case clang::CK_VectorSplat: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_VectorSplat"); - return nullptr; - case clang::CK_IntegralToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralToBoolean"); - return nullptr; - case clang::CK_IntegralToFloating: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralToFloating"); + case ZigClangCK_PointerToBoolean: + { + const clang::Expr *expr = stmt->getSubExpr(); + AstNode *val = trans_expr(c, ResultUsedYes, scope, bitcast(expr), TransRValue); + if (val == nullptr) + return nullptr; + + AstNode *val_ptr = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); + val_ptr->data.fn_call_expr.params.append(val); + + AstNode *zero = trans_create_node_unsigned(c, 0); + + // Translate as @ptrToInt((&val) != 0) + return trans_create_node_bin_op(c, val_ptr, BinOpTypeCmpNotEq, zero); + } + case ZigClangCK_ToVoid: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ToVoid"); return nullptr; - case clang::CK_FixedPointCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FixedPointCast"); + case ZigClangCK_VectorSplat: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_VectorSplat"); return nullptr; - case clang::CK_FixedPointToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FixedPointToBoolean"); + case ZigClangCK_IntegralToBoolean: + { + const clang::Expr *expr = stmt->getSubExpr(); + + bool expr_val; + if (expr->EvaluateAsBooleanCondition(expr_val, *reinterpret_cast<clang::ASTContext *>(c->ctx))) { + return trans_create_node_bool(c, expr_val); + } + + AstNode *val = trans_expr(c, ResultUsedYes, scope, bitcast(expr), TransRValue); + if (val == nullptr) + return nullptr; + + AstNode *zero = trans_create_node_unsigned(c, 0); + + // Translate as val != 0 + return trans_create_node_bin_op(c, val, BinOpTypeCmpNotEq, zero); + } + case ZigClangCK_PointerToIntegral: + { + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); + if (dest_type_node == nullptr) + return nullptr; + + AstNode *val_node = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); + val_node->data.fn_call_expr.params.append(target_node); + // @ptrToInt always returns a usize + AstNode *node = trans_create_node_builtin_fn_call_str(c, "intCast"); + node->data.fn_call_expr.params.append(dest_type_node); + node->data.fn_call_expr.params.append(val_node); + + return maybe_suppress_result(c, result_used, node); + } + case ZigClangCK_IntegralToPointer: + { + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); + if (dest_type_node == nullptr) + return nullptr; + + AstNode *node = trans_create_node_builtin_fn_call_str(c, "intToPtr"); + node->data.fn_call_expr.params.append(dest_type_node); + node->data.fn_call_expr.params.append(target_node); + + return maybe_suppress_result(c, result_used, node); + } + case ZigClangCK_IntegralToFloating: + case ZigClangCK_FloatingToIntegral: + { + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); + if (dest_type_node == nullptr) + return nullptr; + + char const *fn = (ZigClangCK)stmt->getCastKind() == ZigClangCK_IntegralToFloating ? + "intToFloat" : "floatToInt"; + AstNode *node = trans_create_node_builtin_fn_call_str(c, fn); + node->data.fn_call_expr.params.append(dest_type_node); + node->data.fn_call_expr.params.append(target_node); + + return maybe_suppress_result(c, result_used, node); + } + case ZigClangCK_FixedPointCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FixedPointCast"); return nullptr; - case clang::CK_FloatingToIntegral: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingToIntegral"); + case ZigClangCK_FixedPointToBoolean: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FixedPointToBoolean"); return nullptr; - case clang::CK_FloatingToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingToBoolean"); + case ZigClangCK_FloatingToBoolean: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingToBoolean"); return nullptr; - case clang::CK_BooleanToSignedIntegral: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_BooleanToSignedIntegral"); + case ZigClangCK_BooleanToSignedIntegral: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_BooleanToSignedIntegral"); return nullptr; - case clang::CK_FloatingCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingCast"); + case ZigClangCK_FloatingCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingCast"); return nullptr; - case clang::CK_CPointerToObjCPointerCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_CPointerToObjCPointerCast"); + case ZigClangCK_CPointerToObjCPointerCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_CPointerToObjCPointerCast"); return nullptr; - case clang::CK_BlockPointerToObjCPointerCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_BlockPointerToObjCPointerCast"); + case ZigClangCK_BlockPointerToObjCPointerCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_BlockPointerToObjCPointerCast"); return nullptr; - case clang::CK_AnyPointerToBlockPointerCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_AnyPointerToBlockPointerCast"); + case ZigClangCK_AnyPointerToBlockPointerCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_AnyPointerToBlockPointerCast"); return nullptr; - case clang::CK_ObjCObjectLValueCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ObjCObjectLValueCast"); + case ZigClangCK_ObjCObjectLValueCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ObjCObjectLValueCast"); return nullptr; - case clang::CK_FloatingRealToComplex: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingRealToComplex"); + case ZigClangCK_FloatingRealToComplex: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingRealToComplex"); return nullptr; - case clang::CK_FloatingComplexToReal: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingComplexToReal"); + case ZigClangCK_FloatingComplexToReal: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingComplexToReal"); return nullptr; - case clang::CK_FloatingComplexToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingComplexToBoolean"); + case ZigClangCK_FloatingComplexToBoolean: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingComplexToBoolean"); return nullptr; - case clang::CK_FloatingComplexCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingComplexCast"); + case ZigClangCK_FloatingComplexCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingComplexCast"); return nullptr; - case clang::CK_FloatingComplexToIntegralComplex: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_FloatingComplexToIntegralComplex"); + case ZigClangCK_FloatingComplexToIntegralComplex: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingComplexToIntegralComplex"); return nullptr; - case clang::CK_IntegralRealToComplex: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralRealToComplex"); + case ZigClangCK_IntegralRealToComplex: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralRealToComplex"); return nullptr; - case clang::CK_IntegralComplexToReal: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralComplexToReal"); + case ZigClangCK_IntegralComplexToReal: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralComplexToReal"); return nullptr; - case clang::CK_IntegralComplexToBoolean: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralComplexToBoolean"); + case ZigClangCK_IntegralComplexToBoolean: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralComplexToBoolean"); return nullptr; - case clang::CK_IntegralComplexCast: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralComplexCast"); + case ZigClangCK_IntegralComplexCast: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralComplexCast"); return nullptr; - case clang::CK_IntegralComplexToFloatingComplex: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntegralComplexToFloatingComplex"); + case ZigClangCK_IntegralComplexToFloatingComplex: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralComplexToFloatingComplex"); return nullptr; - case clang::CK_ARCProduceObject: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ARCProduceObject"); + case ZigClangCK_ARCProduceObject: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ARCProduceObject"); return nullptr; - case clang::CK_ARCConsumeObject: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ARCConsumeObject"); + case ZigClangCK_ARCConsumeObject: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ARCConsumeObject"); return nullptr; - case clang::CK_ARCReclaimReturnedObject: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ARCReclaimReturnedObject"); + case ZigClangCK_ARCReclaimReturnedObject: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ARCReclaimReturnedObject"); return nullptr; - case clang::CK_ARCExtendBlockObject: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ARCExtendBlockObject"); + case ZigClangCK_ARCExtendBlockObject: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ARCExtendBlockObject"); return nullptr; - case clang::CK_AtomicToNonAtomic: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_AtomicToNonAtomic"); + case ZigClangCK_AtomicToNonAtomic: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_AtomicToNonAtomic"); return nullptr; - case clang::CK_NonAtomicToAtomic: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_NonAtomicToAtomic"); + case ZigClangCK_NonAtomicToAtomic: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_NonAtomicToAtomic"); return nullptr; - case clang::CK_CopyAndAutoreleaseBlockObject: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_CopyAndAutoreleaseBlockObject"); + case ZigClangCK_CopyAndAutoreleaseBlockObject: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_CopyAndAutoreleaseBlockObject"); return nullptr; - case clang::CK_BuiltinFnToFnPtr: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_BuiltinFnToFnPtr"); + case ZigClangCK_BuiltinFnToFnPtr: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_BuiltinFnToFnPtr"); return nullptr; - case clang::CK_ZeroToOCLOpaqueType: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_ZeroToOCLOpaqueType"); + case ZigClangCK_ZeroToOCLOpaqueType: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ZeroToOCLOpaqueType"); return nullptr; - case clang::CK_AddressSpaceConversion: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_AddressSpaceConversion"); + case ZigClangCK_AddressSpaceConversion: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_AddressSpaceConversion"); return nullptr; - case clang::CK_IntToOCLSampler: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CK_IntToOCLSampler"); + case ZigClangCK_IntToOCLSampler: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntToOCLSampler"); return nullptr; } zig_unreachable(); @@ -1993,7 +2160,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const clang::DeclRefExpr *stmt, TransLRValue lrval) { const clang::ValueDecl *value_decl = stmt->getDecl(); - Buf *c_symbol_name = buf_create_from_str(decl_name(value_decl)); + Buf *c_symbol_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)value_decl)); Buf *zig_symbol_name = trans_lookup_zig_symbol(c, scope, c_symbol_name); if (lrval == TransLValue) { c->ptr_params.put(zig_symbol_name, true); @@ -2004,7 +2171,7 @@ static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const clang:: static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, TransScope *scope, const clang::UnaryOperator *stmt, BinOpType assign_op) { - clang::Expr *op_expr = stmt->getSubExpr(); + const ZigClangExpr *op_expr = bitcast(stmt->getSubExpr()); if (result_used == ResultUsedNo) { // common case @@ -2060,7 +2227,7 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, TransScope *scope, const clang::UnaryOperator *stmt, BinOpType assign_op) { - clang::Expr *op_expr = stmt->getSubExpr(); + const ZigClangExpr *op_expr = bitcast(stmt->getSubExpr()); if (result_used == ResultUsedNo) { // common case @@ -2110,50 +2277,50 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const clang::UnaryOperator *stmt) { switch (stmt->getOpcode()) { case clang::UO_PostInc: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); else return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); case clang::UO_PostDec: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); else return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); case clang::UO_PreInc: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); else return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); case clang::UO_PreDec: - if (qual_type_has_wrapping_overflow(c, stmt->getType())) + if (qual_type_has_wrapping_overflow(c, bitcast(stmt->getType()))) return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); else return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); case clang::UO_AddrOf: { - AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue); + AstNode *value_node = trans_expr(c, result_used, scope, bitcast(stmt->getSubExpr()), TransLValue); if (value_node == nullptr) return value_node; return trans_create_node_addr_of(c, value_node); } case clang::UO_Deref: { - AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue); + AstNode *value_node = trans_expr(c, result_used, scope, bitcast(stmt->getSubExpr()), TransRValue); if (value_node == nullptr) return nullptr; - bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType()); + bool is_fn_ptr = qual_type_is_fn_ptr(bitcast(stmt->getSubExpr()->getType())); if (is_fn_ptr) return value_node; AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node); return trans_create_node_ptr_deref(c, unwrapped); } case clang::UO_Plus: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Plus"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation UO_Plus"); return nullptr; case clang::UO_Minus: { - clang::Expr *op_expr = stmt->getSubExpr(); - if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { + const ZigClangExpr *op_expr = bitcast(stmt->getSubExpr()); + if (!qual_type_has_wrapping_overflow(c, ZigClangExpr_getType(op_expr))) { AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); node->data.prefix_op_expr.prefix_op = PrefixOpNegation; @@ -2162,7 +2329,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc return nullptr; return node; - } else if (c_is_unsigned_integer(c, op_expr->getType())) { + } else if (c_is_unsigned_integer(c, ZigClangExpr_getType(op_expr))) { // we gotta emit 0 -% x AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); @@ -2174,13 +2341,13 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; return node; } else { - emit_warning(c, stmt->getBeginLoc(), "C negation with non float non integer"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "C negation with non float non integer"); return nullptr; } } case clang::UO_Not: { - clang::Expr *op_expr = stmt->getSubExpr(); + const ZigClangExpr *op_expr = bitcast(stmt->getSubExpr()); AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); if (sub_node == nullptr) return nullptr; @@ -2189,7 +2356,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc } case clang::UO_LNot: { - clang::Expr *op_expr = stmt->getSubExpr(); + const ZigClangExpr *op_expr = bitcast(stmt->getSubExpr()); AstNode *sub_node = trans_bool_expr(c, ResultUsedYes, scope, op_expr, TransRValue); if (sub_node == nullptr) return nullptr; @@ -2197,15 +2364,15 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node); } case clang::UO_Real: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Real"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation UO_Real"); return nullptr; case clang::UO_Imag: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Imag"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation UO_Imag"); return nullptr; case clang::UO_Extension: - return trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue); + return trans_expr(c, result_used, scope, bitcast(stmt->getSubExpr()), TransLValue); case clang::UO_Coawait: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Coawait"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C translation UO_Coawait"); return nullptr; } zig_unreachable(); @@ -2225,249 +2392,250 @@ static int trans_local_declaration(Context *c, TransScope *scope, const clang::D switch (decl->getKind()) { case clang::Decl::Var: { clang::VarDecl *var_decl = (clang::VarDecl *)decl; - clang::QualType qual_type = var_decl->getTypeSourceInfo()->getType(); + ZigClangQualType qual_type = bitcast(var_decl->getTypeSourceInfo()->getType()); AstNode *init_node = nullptr; if (var_decl->hasInit()) { - init_node = trans_expr(c, ResultUsedYes, scope, var_decl->getInit(), TransRValue); + init_node = trans_expr(c, ResultUsedYes, scope, bitcast(var_decl->getInit()), TransRValue); if (init_node == nullptr) return ErrorUnexpected; } else { init_node = trans_create_node(c, NodeTypeUndefinedLiteral); } - AstNode *type_node = trans_qual_type(c, qual_type, stmt->getBeginLoc()); + AstNode *type_node = trans_qual_type(c, qual_type, bitcast(stmt->getBeginLoc())); if (type_node == nullptr) return ErrorUnexpected; - Buf *c_symbol_name = buf_create_from_str(decl_name(var_decl)); + Buf *c_symbol_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)var_decl)); TransScopeVar *var_scope = trans_scope_var_create(c, scope, c_symbol_name); scope = &var_scope->base; - AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), + AstNode *node = trans_create_node_var_decl_local(c, + ZigClangQualType_isConstQualified(qual_type), var_scope->zig_name, type_node, init_node); scope_block->node->data.block.statements.append(node); continue; } case clang::Decl::AccessSpec: - emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind AccessSpec"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle decl kind AccessSpec"); return ErrorUnexpected; case clang::Decl::Block: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Block"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Block"); return ErrorUnexpected; case clang::Decl::Captured: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Captured"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Captured"); return ErrorUnexpected; case clang::Decl::ClassScopeFunctionSpecialization: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ClassScopeFunctionSpecialization"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ClassScopeFunctionSpecialization"); return ErrorUnexpected; case clang::Decl::Empty: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Empty"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Empty"); return ErrorUnexpected; case clang::Decl::Export: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Export"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Export"); return ErrorUnexpected; case clang::Decl::ExternCContext: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExternCContext"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ExternCContext"); return ErrorUnexpected; case clang::Decl::FileScopeAsm: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C FileScopeAsm"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C FileScopeAsm"); return ErrorUnexpected; case clang::Decl::Friend: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Friend"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Friend"); return ErrorUnexpected; case clang::Decl::FriendTemplate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C FriendTemplate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C FriendTemplate"); return ErrorUnexpected; case clang::Decl::Import: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Import"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Import"); return ErrorUnexpected; case clang::Decl::LinkageSpec: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C LinkageSpec"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C LinkageSpec"); return ErrorUnexpected; case clang::Decl::Label: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Label"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Label"); return ErrorUnexpected; case clang::Decl::Namespace: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Namespace"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Namespace"); return ErrorUnexpected; case clang::Decl::NamespaceAlias: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C NamespaceAlias"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C NamespaceAlias"); return ErrorUnexpected; case clang::Decl::ObjCCompatibleAlias: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCCompatibleAlias"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCCompatibleAlias"); return ErrorUnexpected; case clang::Decl::ObjCCategory: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCCategory"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCCategory"); return ErrorUnexpected; case clang::Decl::ObjCCategoryImpl: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCCategoryImpl"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCCategoryImpl"); return ErrorUnexpected; case clang::Decl::ObjCImplementation: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCImplementation"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCImplementation"); return ErrorUnexpected; case clang::Decl::ObjCInterface: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCInterface"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCInterface"); return ErrorUnexpected; case clang::Decl::ObjCProtocol: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCProtocol"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCProtocol"); return ErrorUnexpected; case clang::Decl::ObjCMethod: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCMethod"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCMethod"); return ErrorUnexpected; case clang::Decl::ObjCProperty: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCProperty"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCProperty"); return ErrorUnexpected; case clang::Decl::BuiltinTemplate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C BuiltinTemplate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C BuiltinTemplate"); return ErrorUnexpected; case clang::Decl::ClassTemplate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ClassTemplate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ClassTemplate"); return ErrorUnexpected; case clang::Decl::FunctionTemplate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C FunctionTemplate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C FunctionTemplate"); return ErrorUnexpected; case clang::Decl::TypeAliasTemplate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TypeAliasTemplate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C TypeAliasTemplate"); return ErrorUnexpected; case clang::Decl::VarTemplate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C VarTemplate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C VarTemplate"); return ErrorUnexpected; case clang::Decl::TemplateTemplateParm: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TemplateTemplateParm"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C TemplateTemplateParm"); return ErrorUnexpected; case clang::Decl::Enum: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Enum"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Enum"); return ErrorUnexpected; case clang::Decl::Record: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Record"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Record"); return ErrorUnexpected; case clang::Decl::CXXRecord: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXRecord"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CXXRecord"); return ErrorUnexpected; case clang::Decl::ClassTemplateSpecialization: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ClassTemplateSpecialization"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ClassTemplateSpecialization"); return ErrorUnexpected; case clang::Decl::ClassTemplatePartialSpecialization: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ClassTemplatePartialSpecialization"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ClassTemplatePartialSpecialization"); return ErrorUnexpected; case clang::Decl::TemplateTypeParm: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TemplateTypeParm"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C TemplateTypeParm"); return ErrorUnexpected; case clang::Decl::ObjCTypeParam: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCTypeParam"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCTypeParam"); return ErrorUnexpected; case clang::Decl::TypeAlias: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TypeAlias"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C TypeAlias"); return ErrorUnexpected; case clang::Decl::Typedef: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Typedef"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Typedef"); return ErrorUnexpected; case clang::Decl::UnresolvedUsingTypename: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UnresolvedUsingTypename"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C UnresolvedUsingTypename"); return ErrorUnexpected; case clang::Decl::Using: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Using"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Using"); return ErrorUnexpected; case clang::Decl::UsingDirective: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UsingDirective"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C UsingDirective"); return ErrorUnexpected; case clang::Decl::UsingPack: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UsingPack"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C UsingPack"); return ErrorUnexpected; case clang::Decl::UsingShadow: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UsingShadow"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C UsingShadow"); return ErrorUnexpected; case clang::Decl::ConstructorUsingShadow: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ConstructorUsingShadow"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ConstructorUsingShadow"); return ErrorUnexpected; case clang::Decl::Binding: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Binding"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Binding"); return ErrorUnexpected; case clang::Decl::Field: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Field"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Field"); return ErrorUnexpected; case clang::Decl::ObjCAtDefsField: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtDefsField"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCAtDefsField"); return ErrorUnexpected; case clang::Decl::ObjCIvar: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIvar"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCIvar"); return ErrorUnexpected; case clang::Decl::Function: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Function"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Function"); return ErrorUnexpected; case clang::Decl::CXXDeductionGuide: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDeductionGuide"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CXXDeductionGuide"); return ErrorUnexpected; case clang::Decl::CXXMethod: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXMethod"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CXXMethod"); return ErrorUnexpected; case clang::Decl::CXXConstructor: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXConstructor"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CXXConstructor"); return ErrorUnexpected; case clang::Decl::CXXConversion: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXConversion"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CXXConversion"); return ErrorUnexpected; case clang::Decl::CXXDestructor: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDestructor"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CXXDestructor"); return ErrorUnexpected; case clang::Decl::MSProperty: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSProperty"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C MSProperty"); return ErrorUnexpected; case clang::Decl::NonTypeTemplateParm: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C NonTypeTemplateParm"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C NonTypeTemplateParm"); return ErrorUnexpected; case clang::Decl::Decomposition: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C Decomposition"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C Decomposition"); return ErrorUnexpected; case clang::Decl::ImplicitParam: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ImplicitParam"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ImplicitParam"); return ErrorUnexpected; case clang::Decl::OMPCapturedExpr: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCapturedExpr"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C OMPCapturedExpr"); return ErrorUnexpected; case clang::Decl::ParmVar: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ParmVar"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ParmVar"); return ErrorUnexpected; case clang::Decl::VarTemplateSpecialization: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C VarTemplateSpecialization"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C VarTemplateSpecialization"); return ErrorUnexpected; case clang::Decl::VarTemplatePartialSpecialization: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C VarTemplatePartialSpecialization"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C VarTemplatePartialSpecialization"); return ErrorUnexpected; case clang::Decl::EnumConstant: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C EnumConstant"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C EnumConstant"); return ErrorUnexpected; case clang::Decl::IndirectField: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C IndirectField"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C IndirectField"); return ErrorUnexpected; case clang::Decl::OMPDeclareReduction: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDeclareReduction"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C OMPDeclareReduction"); return ErrorUnexpected; case clang::Decl::UnresolvedUsingValue: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UnresolvedUsingValue"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C UnresolvedUsingValue"); return ErrorUnexpected; case clang::Decl::OMPRequires: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPRequires"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C OMPRequires"); return ErrorUnexpected; case clang::Decl::OMPThreadPrivate: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPThreadPrivate"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C OMPThreadPrivate"); return ErrorUnexpected; case clang::Decl::ObjCPropertyImpl: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCPropertyImpl"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C ObjCPropertyImpl"); return ErrorUnexpected; case clang::Decl::PragmaComment: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C PragmaComment"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C PragmaComment"); return ErrorUnexpected; case clang::Decl::PragmaDetectMismatch: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C PragmaDetectMismatch"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C PragmaDetectMismatch"); return ErrorUnexpected; case clang::Decl::StaticAssert: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C StaticAssert"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C StaticAssert"); return ErrorUnexpected; case clang::Decl::TranslationUnit: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TranslationUnit"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C TranslationUnit"); return ErrorUnexpected; } zig_unreachable(); @@ -2493,7 +2661,7 @@ static AstNode *to_enum_zero_cmp(Context *c, AstNode *expr, AstNode *enum_type) return trans_create_node_bin_op(c, expr, BinOpTypeCmpNotEq, bitcast); } -static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval) { +static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval) { AstNode *res = trans_expr(c, result_used, scope, expr, lrval); if (res == nullptr) return nullptr; @@ -2530,146 +2698,145 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * } - const clang::Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr(); - auto classs = ty->getTypeClass(); + const ZigClangType *ty = ZigClangQualType_getTypePtr(get_expr_qual_type_before_implicit_cast(c, expr)); + auto classs = ZigClangType_getTypeClass(ty); switch (classs) { - case clang::Type::Builtin: + case ZigClangType_Builtin: { - const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty); - switch (builtin_ty->getKind()) { - case clang::BuiltinType::Bool: - case clang::BuiltinType::Char_U: - case clang::BuiltinType::UChar: - case clang::BuiltinType::Char_S: - case clang::BuiltinType::SChar: - case clang::BuiltinType::UShort: - case clang::BuiltinType::UInt: - case clang::BuiltinType::ULong: - case clang::BuiltinType::ULongLong: - case clang::BuiltinType::Short: - case clang::BuiltinType::Int: - case clang::BuiltinType::Long: - case clang::BuiltinType::LongLong: - case clang::BuiltinType::UInt128: - case clang::BuiltinType::Int128: - case clang::BuiltinType::Float: - case clang::BuiltinType::Double: - case clang::BuiltinType::Float128: - case clang::BuiltinType::LongDouble: - case clang::BuiltinType::WChar_U: - case clang::BuiltinType::Char8: - case clang::BuiltinType::Char16: - case clang::BuiltinType::Char32: - case clang::BuiltinType::WChar_S: - case clang::BuiltinType::Float16: + const ZigClangBuiltinType *builtin_ty = reinterpret_cast<const ZigClangBuiltinType*>(ty); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + case ZigClangBuiltinTypeBool: + case ZigClangBuiltinTypeChar_U: + case ZigClangBuiltinTypeUChar: + case ZigClangBuiltinTypeChar_S: + case ZigClangBuiltinTypeSChar: + case ZigClangBuiltinTypeUShort: + case ZigClangBuiltinTypeUInt: + case ZigClangBuiltinTypeULong: + case ZigClangBuiltinTypeULongLong: + case ZigClangBuiltinTypeShort: + case ZigClangBuiltinTypeInt: + case ZigClangBuiltinTypeLong: + case ZigClangBuiltinTypeLongLong: + case ZigClangBuiltinTypeUInt128: + case ZigClangBuiltinTypeInt128: + case ZigClangBuiltinTypeFloat: + case ZigClangBuiltinTypeDouble: + case ZigClangBuiltinTypeFloat128: + case ZigClangBuiltinTypeLongDouble: + case ZigClangBuiltinTypeWChar_U: + case ZigClangBuiltinTypeChar8: + case ZigClangBuiltinTypeChar16: + case ZigClangBuiltinTypeChar32: + case ZigClangBuiltinTypeWChar_S: + case ZigClangBuiltinTypeFloat16: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); - case clang::BuiltinType::NullPtr: + case ZigClangBuiltinTypeNullPtr: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, - trans_create_node_unsigned(c, 0)); - - case clang::BuiltinType::Void: - case clang::BuiltinType::Half: - case clang::BuiltinType::ObjCId: - case clang::BuiltinType::ObjCClass: - case clang::BuiltinType::ObjCSel: - case clang::BuiltinType::OMPArraySection: - case clang::BuiltinType::Dependent: - case clang::BuiltinType::Overload: - case clang::BuiltinType::BoundMember: - case clang::BuiltinType::PseudoObject: - case clang::BuiltinType::UnknownAny: - case clang::BuiltinType::BuiltinFn: - case clang::BuiltinType::ARCUnbridgedCast: - case clang::BuiltinType::OCLImage1dRO: - case clang::BuiltinType::OCLImage1dArrayRO: - case clang::BuiltinType::OCLImage1dBufferRO: - case clang::BuiltinType::OCLImage2dRO: - case clang::BuiltinType::OCLImage2dArrayRO: - case clang::BuiltinType::OCLImage2dDepthRO: - case clang::BuiltinType::OCLImage2dArrayDepthRO: - case clang::BuiltinType::OCLImage2dMSAARO: - case clang::BuiltinType::OCLImage2dArrayMSAARO: - case clang::BuiltinType::OCLImage2dMSAADepthRO: - case clang::BuiltinType::OCLImage2dArrayMSAADepthRO: - case clang::BuiltinType::OCLImage3dRO: - case clang::BuiltinType::OCLImage1dWO: - case clang::BuiltinType::OCLImage1dArrayWO: - case clang::BuiltinType::OCLImage1dBufferWO: - case clang::BuiltinType::OCLImage2dWO: - case clang::BuiltinType::OCLImage2dArrayWO: - case clang::BuiltinType::OCLImage2dDepthWO: - case clang::BuiltinType::OCLImage2dArrayDepthWO: - case clang::BuiltinType::OCLImage2dMSAAWO: - case clang::BuiltinType::OCLImage2dArrayMSAAWO: - case clang::BuiltinType::OCLImage2dMSAADepthWO: - case clang::BuiltinType::OCLImage2dArrayMSAADepthWO: - case clang::BuiltinType::OCLImage3dWO: - case clang::BuiltinType::OCLImage1dRW: - case clang::BuiltinType::OCLImage1dArrayRW: - case clang::BuiltinType::OCLImage1dBufferRW: - case clang::BuiltinType::OCLImage2dRW: - case clang::BuiltinType::OCLImage2dArrayRW: - case clang::BuiltinType::OCLImage2dDepthRW: - case clang::BuiltinType::OCLImage2dArrayDepthRW: - case clang::BuiltinType::OCLImage2dMSAARW: - case clang::BuiltinType::OCLImage2dArrayMSAARW: - case clang::BuiltinType::OCLImage2dMSAADepthRW: - case clang::BuiltinType::OCLImage2dArrayMSAADepthRW: - case clang::BuiltinType::OCLImage3dRW: - case clang::BuiltinType::OCLSampler: - case clang::BuiltinType::OCLEvent: - case clang::BuiltinType::OCLClkEvent: - case clang::BuiltinType::OCLQueue: - case clang::BuiltinType::OCLReserveID: - case clang::BuiltinType::ShortAccum: - case clang::BuiltinType::Accum: - case clang::BuiltinType::LongAccum: - case clang::BuiltinType::UShortAccum: - case clang::BuiltinType::UAccum: - case clang::BuiltinType::ULongAccum: - case clang::BuiltinType::ShortFract: - case clang::BuiltinType::Fract: - case clang::BuiltinType::LongFract: - case clang::BuiltinType::UShortFract: - case clang::BuiltinType::UFract: - case clang::BuiltinType::ULongFract: - case clang::BuiltinType::SatShortAccum: - case clang::BuiltinType::SatAccum: - case clang::BuiltinType::SatLongAccum: - case clang::BuiltinType::SatUShortAccum: - case clang::BuiltinType::SatUAccum: - case clang::BuiltinType::SatULongAccum: - case clang::BuiltinType::SatShortFract: - case clang::BuiltinType::SatFract: - case clang::BuiltinType::SatLongFract: - case clang::BuiltinType::SatUShortFract: - case clang::BuiltinType::SatUFract: - case clang::BuiltinType::SatULongFract: - case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload: - case clang::BuiltinType::OCLIntelSubgroupAVCImePayload: - case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload: - case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload: - case clang::BuiltinType::OCLIntelSubgroupAVCMceResult: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResult: - case clang::BuiltinType::OCLIntelSubgroupAVCRefResult: - case clang::BuiltinType::OCLIntelSubgroupAVCSicResult: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout: - case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin: - case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: + trans_create_node(c, NodeTypeNullLiteral)); + + case ZigClangBuiltinTypeVoid: + case ZigClangBuiltinTypeHalf: + case ZigClangBuiltinTypeObjCId: + case ZigClangBuiltinTypeObjCClass: + case ZigClangBuiltinTypeObjCSel: + case ZigClangBuiltinTypeOMPArraySection: + case ZigClangBuiltinTypeDependent: + case ZigClangBuiltinTypeOverload: + case ZigClangBuiltinTypeBoundMember: + case ZigClangBuiltinTypePseudoObject: + case ZigClangBuiltinTypeUnknownAny: + case ZigClangBuiltinTypeBuiltinFn: + case ZigClangBuiltinTypeARCUnbridgedCast: + case ZigClangBuiltinTypeOCLImage1dRO: + case ZigClangBuiltinTypeOCLImage1dArrayRO: + case ZigClangBuiltinTypeOCLImage1dBufferRO: + case ZigClangBuiltinTypeOCLImage2dRO: + case ZigClangBuiltinTypeOCLImage2dArrayRO: + case ZigClangBuiltinTypeOCLImage2dDepthRO: + case ZigClangBuiltinTypeOCLImage2dArrayDepthRO: + case ZigClangBuiltinTypeOCLImage2dMSAARO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAARO: + case ZigClangBuiltinTypeOCLImage2dMSAADepthRO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRO: + case ZigClangBuiltinTypeOCLImage3dRO: + case ZigClangBuiltinTypeOCLImage1dWO: + case ZigClangBuiltinTypeOCLImage1dArrayWO: + case ZigClangBuiltinTypeOCLImage1dBufferWO: + case ZigClangBuiltinTypeOCLImage2dWO: + case ZigClangBuiltinTypeOCLImage2dArrayWO: + case ZigClangBuiltinTypeOCLImage2dDepthWO: + case ZigClangBuiltinTypeOCLImage2dArrayDepthWO: + case ZigClangBuiltinTypeOCLImage2dMSAAWO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAAWO: + case ZigClangBuiltinTypeOCLImage2dMSAADepthWO: + case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthWO: + case ZigClangBuiltinTypeOCLImage3dWO: + case ZigClangBuiltinTypeOCLImage1dRW: + case ZigClangBuiltinTypeOCLImage1dArrayRW: + case ZigClangBuiltinTypeOCLImage1dBufferRW: + case ZigClangBuiltinTypeOCLImage2dRW: + case ZigClangBuiltinTypeOCLImage2dArrayRW: + case ZigClangBuiltinTypeOCLImage2dDepthRW: + case ZigClangBuiltinTypeOCLImage2dArrayDepthRW: + case ZigClangBuiltinTypeOCLImage2dMSAARW: + case ZigClangBuiltinTypeOCLImage2dArrayMSAARW: + case ZigClangBuiltinTypeOCLImage2dMSAADepthRW: + case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRW: + case ZigClangBuiltinTypeOCLImage3dRW: + case ZigClangBuiltinTypeOCLSampler: + case ZigClangBuiltinTypeOCLEvent: + case ZigClangBuiltinTypeOCLClkEvent: + case ZigClangBuiltinTypeOCLQueue: + case ZigClangBuiltinTypeOCLReserveID: + case ZigClangBuiltinTypeShortAccum: + case ZigClangBuiltinTypeAccum: + case ZigClangBuiltinTypeLongAccum: + case ZigClangBuiltinTypeUShortAccum: + case ZigClangBuiltinTypeUAccum: + case ZigClangBuiltinTypeULongAccum: + case ZigClangBuiltinTypeShortFract: + case ZigClangBuiltinTypeFract: + case ZigClangBuiltinTypeLongFract: + case ZigClangBuiltinTypeUShortFract: + case ZigClangBuiltinTypeUFract: + case ZigClangBuiltinTypeULongFract: + case ZigClangBuiltinTypeSatShortAccum: + case ZigClangBuiltinTypeSatAccum: + case ZigClangBuiltinTypeSatLongAccum: + case ZigClangBuiltinTypeSatUShortAccum: + case ZigClangBuiltinTypeSatUAccum: + case ZigClangBuiltinTypeSatULongAccum: + case ZigClangBuiltinTypeSatShortFract: + case ZigClangBuiltinTypeSatFract: + case ZigClangBuiltinTypeSatLongFract: + case ZigClangBuiltinTypeSatUShortFract: + case ZigClangBuiltinTypeSatUFract: + case ZigClangBuiltinTypeSatULongFract: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCMcePayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImePayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefPayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicPayload: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCMceResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicResult: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultSingleRefStreamout: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultDualRefStreamout: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeSingleRefStreamin: + case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeDualRefStreamin: return res; } break; } - case clang::Type::Pointer: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, - trans_create_node_unsigned(c, 0)); + case ZigClangType_Pointer: + return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); - case clang::Type::Typedef: + case ZigClangType_Typedef: { - const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty); - const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); - auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); + const ZigClangTypedefType *typedef_ty = reinterpret_cast<const ZigClangTypedefType*>(ty); + const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + auto existing_entry = c->decl_table.maybe_get((void*)ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)); if (existing_entry) { return existing_entry->value; } @@ -2677,19 +2844,20 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * return res; } - case clang::Type::Enum: + case ZigClangType_Enum: { - const clang::EnumType *enum_ty = static_cast<const clang::EnumType*>(ty); - AstNode *enum_type = resolve_enum_decl(c, enum_ty->getDecl()); + const ZigClangEnumType *enum_ty = reinterpret_cast<const ZigClangEnumType *>(ty); + AstNode *enum_type = resolve_enum_decl(c, ZigClangEnumType_getDecl(enum_ty)); return to_enum_zero_cmp(c, res, enum_type); } - case clang::Type::Elaborated: + case ZigClangType_Elaborated: { - const clang::ElaboratedType *elaborated_ty = static_cast<const clang::ElaboratedType*>(ty); + const clang::ElaboratedType *elaborated_ty = reinterpret_cast<const clang::ElaboratedType*>(ty); switch (elaborated_ty->getKeyword()) { case clang::ETK_Enum: { - AstNode *enum_type = trans_qual_type(c, elaborated_ty->getNamedType(), expr->getBeginLoc()); + AstNode *enum_type = trans_qual_type(c, bitcast(elaborated_ty->getNamedType()), + ZigClangExpr_getBeginLoc(expr)); return to_enum_zero_cmp(c, res, enum_type); } case clang::ETK_Struct: @@ -2702,48 +2870,48 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * } } - case clang::Type::FunctionProto: - case clang::Type::Record: - case clang::Type::ConstantArray: - case clang::Type::Paren: - case clang::Type::Decayed: - case clang::Type::Attributed: - case clang::Type::IncompleteArray: - case clang::Type::BlockPointer: - case clang::Type::LValueReference: - case clang::Type::RValueReference: - case clang::Type::MemberPointer: - case clang::Type::VariableArray: - case clang::Type::DependentSizedArray: - case clang::Type::DependentSizedExtVector: - case clang::Type::Vector: - case clang::Type::ExtVector: - case clang::Type::FunctionNoProto: - case clang::Type::UnresolvedUsing: - case clang::Type::Adjusted: - case clang::Type::TypeOfExpr: - case clang::Type::TypeOf: - case clang::Type::Decltype: - case clang::Type::UnaryTransform: - case clang::Type::TemplateTypeParm: - case clang::Type::SubstTemplateTypeParm: - case clang::Type::SubstTemplateTypeParmPack: - case clang::Type::TemplateSpecialization: - case clang::Type::Auto: - case clang::Type::InjectedClassName: - case clang::Type::DependentName: - case clang::Type::DependentTemplateSpecialization: - case clang::Type::PackExpansion: - case clang::Type::ObjCObject: - case clang::Type::ObjCInterface: - case clang::Type::Complex: - case clang::Type::ObjCObjectPointer: - case clang::Type::Atomic: - case clang::Type::Pipe: - case clang::Type::ObjCTypeParam: - case clang::Type::DeducedTemplateSpecialization: - case clang::Type::DependentAddressSpace: - case clang::Type::DependentVector: + case ZigClangType_FunctionProto: + case ZigClangType_Record: + case ZigClangType_ConstantArray: + case ZigClangType_Paren: + case ZigClangType_Decayed: + case ZigClangType_Attributed: + case ZigClangType_IncompleteArray: + case ZigClangType_BlockPointer: + case ZigClangType_LValueReference: + case ZigClangType_RValueReference: + case ZigClangType_MemberPointer: + case ZigClangType_VariableArray: + case ZigClangType_DependentSizedArray: + case ZigClangType_DependentSizedExtVector: + case ZigClangType_Vector: + case ZigClangType_ExtVector: + case ZigClangType_FunctionNoProto: + case ZigClangType_UnresolvedUsing: + case ZigClangType_Adjusted: + case ZigClangType_TypeOfExpr: + case ZigClangType_TypeOf: + case ZigClangType_Decltype: + case ZigClangType_UnaryTransform: + case ZigClangType_TemplateTypeParm: + case ZigClangType_SubstTemplateTypeParm: + case ZigClangType_SubstTemplateTypeParmPack: + case ZigClangType_TemplateSpecialization: + case ZigClangType_Auto: + case ZigClangType_InjectedClassName: + case ZigClangType_DependentName: + case ZigClangType_DependentTemplateSpecialization: + case ZigClangType_PackExpansion: + case ZigClangType_ObjCObject: + case ZigClangType_ObjCInterface: + case ZigClangType_Complex: + case ZigClangType_ObjCObjectPointer: + case ZigClangType_Atomic: + case ZigClangType_Pipe: + case ZigClangType_ObjCTypeParam: + case ZigClangType_DeducedTemplateSpecialization: + case ZigClangType_DependentAddressSpace: + case ZigClangType_DependentVector: return res; } zig_unreachable(); @@ -2752,11 +2920,12 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * static AstNode *trans_while_loop(Context *c, TransScope *scope, const clang::WhileStmt *stmt) { TransScopeWhile *while_scope = trans_scope_while_create(c, scope); - while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); + while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, + bitcast(stmt->getCond()), TransRValue); if (while_scope->node->data.while_expr.condition == nullptr) return nullptr; - TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), + TransScope *body_scope = trans_stmt(c, &while_scope->base, bitcast(stmt->getBody()), &while_scope->node->data.while_expr.body); if (body_scope == nullptr) return nullptr; @@ -2769,17 +2938,18 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const clang::I // if (c) t else e AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); - TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block); + TransScope *then_scope = trans_stmt(c, scope, bitcast(stmt->getThen()), &if_node->data.if_bool_expr.then_block); if (then_scope == nullptr) return nullptr; if (stmt->getElse() != nullptr) { - TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node); + TransScope *else_scope = trans_stmt(c, scope, bitcast(stmt->getElse()), &if_node->data.if_bool_expr.else_node); if (else_scope == nullptr) return nullptr; } - if_node->data.if_bool_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); + if_node->data.if_bool_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, bitcast(stmt->getCond()), + TransRValue); if (if_node->data.if_bool_expr.condition == nullptr) return nullptr; @@ -2789,18 +2959,18 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const clang::I static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::CallExpr *stmt) { AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); - AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, stmt->getCallee(), TransRValue); + AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getCallee()), TransRValue); if (callee_raw_node == nullptr) return nullptr; bool is_ptr = false; - const clang::FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr); + const clang::FunctionProtoType *fn_ty = qual_type_get_fn_proto(bitcast(stmt->getCallee()->getType()), &is_ptr); AstNode *callee_node = nullptr; if (is_ptr && fn_ty) { - if (stmt->getCallee()->getStmtClass() == clang::Stmt::ImplicitCastExprClass) { + if ((ZigClangStmtClass)stmt->getCallee()->getStmtClass() == ZigClangStmt_ImplicitCastExprClass) { const clang::ImplicitCastExpr *implicit_cast = static_cast<const clang::ImplicitCastExpr *>(stmt->getCallee()); - if (implicit_cast->getCastKind() == clang::CK_FunctionToPointerDecay) { - if (implicit_cast->getSubExpr()->getStmtClass() == clang::Stmt::DeclRefExprClass) { + if ((ZigClangCK)implicit_cast->getCastKind() == ZigClangCK_FunctionToPointerDecay) { + if ((ZigClangStmtClass)implicit_cast->getSubExpr()->getStmtClass() == ZigClangStmt_DeclRefExprClass) { const clang::DeclRefExpr *decl_ref = static_cast<const clang::DeclRefExpr *>(implicit_cast->getSubExpr()); const clang::Decl *decl = decl_ref->getFoundDecl(); if (decl->getKind() == clang::Decl::Function) { @@ -2819,7 +2989,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * node->data.fn_call_expr.fn_ref_expr = callee_node; unsigned num_args = stmt->getNumArgs(); - const clang::Expr * const* args = stmt->getArgs(); + const ZigClangExpr * const* args = reinterpret_cast<const ZigClangExpr * const*>(stmt->getArgs()); for (unsigned i = 0; i < num_args; i += 1) { AstNode *arg_node = trans_expr(c, ResultUsedYes, scope, args[i], TransRValue); if (arg_node == nullptr) @@ -2828,7 +2998,9 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * node->data.fn_call_expr.params.append(arg_node); } - if (result_used == ResultUsedNo && fn_ty && !qual_type_canon(fn_ty->getReturnType())->isVoidType()) { + if (result_used == ResultUsedNo && fn_ty && + !ZigClangType_isVoidType(qual_type_canon(bitcast(fn_ty->getReturnType())))) + { node = trans_create_node_bin_op(c, trans_create_node_symbol_str(c, "_"), BinOpTypeAssign, node); } @@ -2838,7 +3010,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * static AstNode *trans_member_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::MemberExpr *stmt) { - AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); + AstNode *container_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getBase()), TransRValue); if (container_node == nullptr) return nullptr; @@ -2846,18 +3018,18 @@ static AstNode *trans_member_expr(Context *c, ResultUsed result_used, TransScope container_node = trans_create_node_unwrap_null(c, container_node); } - const char *name = decl_name(stmt->getMemberDecl()); + const char *name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)stmt->getMemberDecl()); AstNode *node = trans_create_node_field_access_str(c, container_node, name); return maybe_suppress_result(c, result_used, node); } static AstNode *trans_array_subscript_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::ArraySubscriptExpr *stmt) { - AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); + AstNode *container_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getBase()), TransRValue); if (container_node == nullptr) return nullptr; - AstNode *idx_node = trans_expr(c, ResultUsedYes, scope, stmt->getIdx(), TransRValue); + AstNode *idx_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getIdx()), TransRValue); if (idx_node == nullptr) return nullptr; @@ -2871,11 +3043,12 @@ static AstNode *trans_array_subscript_expr(Context *c, ResultUsed result_used, T static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::CStyleCastExpr *stmt, TransLRValue lrvalue) { - AstNode *sub_expr_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), lrvalue); + AstNode *sub_expr_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), lrvalue); if (sub_expr_node == nullptr) return nullptr; - AstNode *cast = trans_c_cast(c, stmt->getBeginLoc(), stmt->getType(), stmt->getSubExpr()->getType(), sub_expr_node); + AstNode *cast = trans_c_cast(c, bitcast(stmt->getBeginLoc()), bitcast(stmt->getType()), + bitcast(stmt->getSubExpr()->getType()), sub_expr_node); if (cast == nullptr) return nullptr; @@ -2885,7 +3058,7 @@ static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, Tran static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::UnaryExprOrTypeTraitExpr *stmt) { - AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getBeginLoc()); + AstNode *type_node = trans_qual_type(c, bitcast(stmt->getTypeOfArgument()), bitcast(stmt->getBeginLoc())); if (type_node == nullptr) return nullptr; @@ -2901,7 +3074,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang: AstNode *body_node; TransScope *child_scope; - if (stmt->getBody()->getStmtClass() == clang::Stmt::CompoundStmtClass) { + if ((ZigClangStmtClass)stmt->getBody()->getStmtClass() == ZigClangStmt_CompoundStmtClass) { // there's already a block in C, so we'll append our condition to it. // c: do { // c: a; @@ -2914,7 +3087,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang: // zig: } // We call the low level function so that we can set child_scope to the scope of the generated block. - if (trans_stmt_extra(c, &while_scope->base, stmt->getBody(), ResultUsedNo, TransRValue, &body_node, + if (trans_stmt_extra(c, &while_scope->base, bitcast(stmt->getBody()), ResultUsedNo, TransRValue, &body_node, nullptr, &child_scope)) { return nullptr; @@ -2932,7 +3105,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang: TransScopeBlock *child_block_scope = trans_scope_block_create(c, &while_scope->base); body_node = child_block_scope->node; AstNode *child_statement; - child_scope = trans_stmt(c, &child_block_scope->base, stmt->getBody(), &child_statement); + child_scope = trans_stmt(c, &child_block_scope->base, bitcast(stmt->getBody()), &child_statement); if (child_scope == nullptr) return nullptr; if (child_statement != nullptr) { body_node->data.block.statements.append(child_statement); @@ -2940,7 +3113,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang: } // if (!cond) break; - AstNode *condition_node = trans_expr(c, ResultUsedYes, child_scope, stmt->getCond(), TransRValue); + AstNode *condition_node = trans_expr(c, ResultUsedYes, child_scope, bitcast(stmt->getCond()), TransRValue); if (condition_node == nullptr) return nullptr; AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); @@ -2958,7 +3131,7 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const clang AstNode *loop_block_node; TransScopeWhile *while_scope; TransScope *cond_scope; - const clang::Stmt *init_stmt = stmt->getInit(); + const ZigClangStmt *init_stmt = bitcast(stmt->getInit()); if (init_stmt == nullptr) { while_scope = trans_scope_while_create(c, parent_scope); loop_block_node = while_scope->node; @@ -2979,35 +3152,27 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const clang child_scope->node->data.block.statements.append(while_scope->node); } - const clang::Stmt *cond_stmt = stmt->getCond(); - if (cond_stmt == nullptr) { + const ZigClangExpr *cond_expr = bitcast(stmt->getCond()); + if (cond_expr == nullptr) { while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); } else { - if (clang::Expr::classof(cond_stmt)) { - const clang::Expr *cond_expr = static_cast<const clang::Expr*>(cond_stmt); - while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, cond_expr, TransRValue); + while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, + cond_expr, TransRValue); - if (while_scope->node->data.while_expr.condition == nullptr) - return nullptr; - } else { - TransScope *end_cond_scope = trans_stmt(c, cond_scope, cond_stmt, - &while_scope->node->data.while_expr.condition); - if (end_cond_scope == nullptr) - return nullptr; - } + if (while_scope->node->data.while_expr.condition == nullptr) + return nullptr; } - const clang::Stmt *inc_stmt = stmt->getInc(); - if (inc_stmt != nullptr) { - AstNode *inc_node; - TransScope *inc_scope = trans_stmt(c, cond_scope, inc_stmt, &inc_node); - if (inc_scope == nullptr) + const ZigClangExpr *inc_expr = bitcast(stmt->getInc()); + if (inc_expr != nullptr) { + AstNode *inc_node = trans_expr(c, ResultUsedNo, cond_scope, inc_expr, TransRValue); + if (inc_node == nullptr) return nullptr; while_scope->node->data.while_expr.continue_expr = inc_node; } AstNode *body_statement; - TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), &body_statement); + TransScope *body_scope = trans_stmt(c, &while_scope->base, bitcast(stmt->getBody()), &body_statement); if (body_scope == nullptr) return nullptr; @@ -3030,7 +3195,7 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const cl switch_scope = trans_scope_switch_create(c, &block_scope->base); } else { AstNode *vars_node; - TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node); + TransScope *var_scope = trans_stmt(c, &block_scope->base, (const ZigClangStmt *)var_decl_stmt, &vars_node); if (var_scope == nullptr) return nullptr; if (vars_node != nullptr) @@ -3044,7 +3209,7 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const cl switch_scope->end_label_name = end_label_name; block_scope->node->data.block.name = end_label_name; - const clang::Expr *cond_expr = stmt->getCond(); + const ZigClangExpr *cond_expr = bitcast(stmt->getCond()); assert(cond_expr != nullptr); AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue); @@ -3053,9 +3218,9 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const cl switch_scope->switch_node->data.switch_expr.expr = expr_node; AstNode *body_node; - const clang::Stmt *body_stmt = stmt->getBody(); - if (body_stmt->getStmtClass() == clang::Stmt::CompoundStmtClass) { - if (trans_compound_stmt_inline(c, &switch_scope->base, (const clang::CompoundStmt *)body_stmt, + const ZigClangStmt *body_stmt = bitcast(stmt->getBody()); + if (ZigClangStmt_getStmtClass(body_stmt) == ZigClangStmt_CompoundStmtClass) { + if (trans_compound_stmt_inline(c, &switch_scope->base, (const ZigClangCompoundStmt *)body_stmt, block_scope->node, nullptr)) { return nullptr; @@ -3092,7 +3257,7 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const clang:: *out_node = nullptr; if (stmt->getRHS() != nullptr) { - emit_warning(c, stmt->getBeginLoc(), "TODO support GNU switch case a ... b extension"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support GNU switch case a ... b extension"); return ErrorUnexpected; } @@ -3105,7 +3270,7 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const clang:: { // Add the prong AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue); + AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, bitcast(stmt->getLHS()), TransRValue); if (item_node == nullptr) return ErrorUnexpected; prong_node->data.switch_prong.items.append(item_node); @@ -3122,7 +3287,7 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const clang:: scope_block->node->data.block.statements.append(case_block); AstNode *sub_stmt_node; - TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); + TransScope *new_scope = trans_stmt(c, parent_scope, bitcast(stmt->getSubStmt()), &sub_stmt_node); if (new_scope == nullptr) return ErrorUnexpected; if (sub_stmt_node != nullptr) @@ -3159,7 +3324,7 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const clan scope_block->node->data.block.statements.append(case_block); AstNode *sub_stmt_node; - TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); + TransScope *new_scope = trans_stmt(c, parent_scope, bitcast(stmt->getSubStmt()), &sub_stmt_node); if (new_scope == nullptr) return ErrorUnexpected; if (sub_stmt_node != nullptr) @@ -3177,13 +3342,13 @@ static AstNode *trans_string_literal(Context *c, ResultUsed result_used, TransSc return maybe_suppress_result(c, result_used, node); } case clang::StringLiteral::UTF16: - emit_warning(c, stmt->getBeginLoc(), "TODO support UTF16 string literals"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support UTF16 string literals"); return nullptr; case clang::StringLiteral::UTF32: - emit_warning(c, stmt->getBeginLoc(), "TODO support UTF32 string literals"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support UTF32 string literals"); return nullptr; case clang::StringLiteral::Wide: - emit_warning(c, stmt->getBeginLoc(), "TODO support wide string literals"); + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support wide string literals"); return nullptr; } zig_unreachable(); @@ -3222,45 +3387,45 @@ static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_ return ErrorNone; } -static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *stmt, +static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *stmt, ResultUsed result_used, TransLRValue lrvalue, AstNode **out_node, TransScope **out_child_scope, TransScope **out_node_scope) { - clang::Stmt::StmtClass sc = stmt->getStmtClass(); + ZigClangStmtClass sc = ZigClangStmt_getStmtClass(stmt); switch (sc) { - case clang::Stmt::ReturnStmtClass: + case ZigClangStmt_ReturnStmtClass: return wrap_stmt(out_node, out_child_scope, scope, trans_return_stmt(c, scope, (const clang::ReturnStmt *)stmt)); - case clang::Stmt::CompoundStmtClass: + case ZigClangStmt_CompoundStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_compound_stmt(c, scope, (const clang::CompoundStmt *)stmt, out_node_scope)); - case clang::Stmt::IntegerLiteralClass: + trans_compound_stmt(c, scope, (const ZigClangCompoundStmt *)stmt, out_node_scope)); + case ZigClangStmt_IntegerLiteralClass: return wrap_stmt(out_node, out_child_scope, scope, trans_integer_literal(c, result_used, (const clang::IntegerLiteral *)stmt)); - case clang::Stmt::ConditionalOperatorClass: + case ZigClangStmt_ConditionalOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, trans_conditional_operator(c, result_used, scope, (const clang::ConditionalOperator *)stmt)); - case clang::Stmt::BinaryOperatorClass: + case ZigClangStmt_BinaryOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, trans_binary_operator(c, result_used, scope, (const clang::BinaryOperator *)stmt)); - case clang::Stmt::CompoundAssignOperatorClass: + case ZigClangStmt_CompoundAssignOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, trans_compound_assign_operator(c, result_used, scope, (const clang::CompoundAssignOperator *)stmt)); - case clang::Stmt::ImplicitCastExprClass: + case ZigClangStmt_ImplicitCastExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_implicit_cast_expr(c, result_used, scope, (const clang::ImplicitCastExpr *)stmt)); - case clang::Stmt::DeclRefExprClass: + case ZigClangStmt_DeclRefExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_decl_ref_expr(c, scope, (const clang::DeclRefExpr *)stmt, lrvalue)); - case clang::Stmt::UnaryOperatorClass: + case ZigClangStmt_UnaryOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, trans_unary_operator(c, result_used, scope, (const clang::UnaryOperator *)stmt)); - case clang::Stmt::DeclStmtClass: + case ZigClangStmt_DeclStmtClass: return trans_local_declaration(c, scope, (const clang::DeclStmt *)stmt, out_node, out_child_scope); - case clang::Stmt::DoStmtClass: - case clang::Stmt::WhileStmtClass: { - AstNode *while_node = sc == clang::Stmt::DoStmtClass + case ZigClangStmt_DoStmtClass: + case ZigClangStmt_WhileStmtClass: { + AstNode *while_node = sc == ZigClangStmt_DoStmtClass ? trans_do_loop(c, scope, (const clang::DoStmt *)stmt) : trans_while_loop(c, scope, (const clang::WhileStmt *)stmt); @@ -3273,572 +3438,574 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *st return wrap_stmt(out_node, out_child_scope, scope, while_node); } - case clang::Stmt::IfStmtClass: + case ZigClangStmt_IfStmtClass: return wrap_stmt(out_node, out_child_scope, scope, trans_if_statement(c, scope, (const clang::IfStmt *)stmt)); - case clang::Stmt::CallExprClass: + case ZigClangStmt_CallExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_call_expr(c, result_used, scope, (const clang::CallExpr *)stmt)); - case clang::Stmt::NullStmtClass: + case ZigClangStmt_NullStmtClass: *out_node = trans_create_node(c, NodeTypeBlock); *out_child_scope = scope; return ErrorNone; - case clang::Stmt::MemberExprClass: + case ZigClangStmt_MemberExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_member_expr(c, result_used, scope, (const clang::MemberExpr *)stmt)); - case clang::Stmt::ArraySubscriptExprClass: + case ZigClangStmt_ArraySubscriptExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_array_subscript_expr(c, result_used, scope, (const clang::ArraySubscriptExpr *)stmt)); - case clang::Stmt::CStyleCastExprClass: + case ZigClangStmt_CStyleCastExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_c_style_cast_expr(c, result_used, scope, (const clang::CStyleCastExpr *)stmt, lrvalue)); - case clang::Stmt::UnaryExprOrTypeTraitExprClass: + case ZigClangStmt_UnaryExprOrTypeTraitExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_unary_expr_or_type_trait_expr(c, result_used, scope, (const clang::UnaryExprOrTypeTraitExpr *)stmt)); - case clang::Stmt::ForStmtClass: { + case ZigClangStmt_ForStmtClass: { AstNode *node = trans_for_loop(c, scope, (const clang::ForStmt *)stmt); return wrap_stmt(out_node, out_child_scope, scope, node); } - case clang::Stmt::StringLiteralClass: + case ZigClangStmt_StringLiteralClass: return wrap_stmt(out_node, out_child_scope, scope, trans_string_literal(c, result_used, scope, (const clang::StringLiteral *)stmt)); - case clang::Stmt::BreakStmtClass: + case ZigClangStmt_BreakStmtClass: return wrap_stmt(out_node, out_child_scope, scope, trans_break_stmt(c, scope, (const clang::BreakStmt *)stmt)); - case clang::Stmt::ContinueStmtClass: + case ZigClangStmt_ContinueStmtClass: return wrap_stmt(out_node, out_child_scope, scope, trans_continue_stmt(c, scope, (const clang::ContinueStmt *)stmt)); - case clang::Stmt::ParenExprClass: + case ZigClangStmt_ParenExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_expr(c, result_used, scope, ((const clang::ParenExpr*)stmt)->getSubExpr(), lrvalue)); - case clang::Stmt::SwitchStmtClass: + trans_expr(c, result_used, scope, + bitcast(((const clang::ParenExpr*)stmt)->getSubExpr()), lrvalue)); + case ZigClangStmt_SwitchStmtClass: return wrap_stmt(out_node, out_child_scope, scope, trans_switch_stmt(c, scope, (const clang::SwitchStmt *)stmt)); - case clang::Stmt::CaseStmtClass: + case ZigClangStmt_CaseStmtClass: return trans_switch_case(c, scope, (const clang::CaseStmt *)stmt, out_node, out_child_scope); - case clang::Stmt::DefaultStmtClass: + case ZigClangStmt_DefaultStmtClass: return trans_switch_default(c, scope, (const clang::DefaultStmt *)stmt, out_node, out_child_scope); - case clang::Stmt::ConstantExprClass: + case ZigClangStmt_ConstantExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_constant_expr(c, result_used, (const clang::ConstantExpr *)stmt)); - case clang::Stmt::PredefinedExprClass: + case ZigClangStmt_PredefinedExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_predefined_expr(c, result_used, scope, (const clang::PredefinedExpr *)stmt)); - case clang::Stmt::StmtExprClass: + case ZigClangStmt_StmtExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_stmt_expr(c, result_used, scope, (const clang::StmtExpr *)stmt, out_node_scope)); - case clang::Stmt::NoStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C NoStmtClass"); - return ErrorUnexpected; - case clang::Stmt::GCCAsmStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C GCCAsmStmtClass"); + case ZigClangStmt_NoStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C NoStmtClass"); return ErrorUnexpected; - case clang::Stmt::MSAsmStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSAsmStmtClass"); + case ZigClangStmt_GCCAsmStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GCCAsmStmtClass"); return ErrorUnexpected; - case clang::Stmt::AttributedStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C AttributedStmtClass"); + case ZigClangStmt_MSAsmStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSAsmStmtClass"); return ErrorUnexpected; - case clang::Stmt::CXXCatchStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXCatchStmtClass"); + case ZigClangStmt_AttributedStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AttributedStmtClass"); return ErrorUnexpected; - case clang::Stmt::CXXForRangeStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXForRangeStmtClass"); + case ZigClangStmt_CXXCatchStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXCatchStmtClass"); return ErrorUnexpected; - case clang::Stmt::CXXTryStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXTryStmtClass"); + case ZigClangStmt_CXXForRangeStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXForRangeStmtClass"); return ErrorUnexpected; - case clang::Stmt::CapturedStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CapturedStmtClass"); + case ZigClangStmt_CXXTryStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXTryStmtClass"); return ErrorUnexpected; - case clang::Stmt::CoreturnStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoreturnStmtClass"); + case ZigClangStmt_CapturedStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CapturedStmtClass"); return ErrorUnexpected; - case clang::Stmt::CoroutineBodyStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoroutineBodyStmtClass"); + case ZigClangStmt_CoreturnStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoreturnStmtClass"); return ErrorUnexpected; - case clang::Stmt::BinaryConditionalOperatorClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C BinaryConditionalOperatorClass"); + case ZigClangStmt_CoroutineBodyStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoroutineBodyStmtClass"); return ErrorUnexpected; - case clang::Stmt::AddrLabelExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C AddrLabelExprClass"); + case ZigClangStmt_BinaryConditionalOperatorClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C BinaryConditionalOperatorClass"); return ErrorUnexpected; - case clang::Stmt::ArrayInitIndexExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ArrayInitIndexExprClass"); + case ZigClangStmt_AddrLabelExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AddrLabelExprClass"); return ErrorUnexpected; - case clang::Stmt::ArrayInitLoopExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ArrayInitLoopExprClass"); + case ZigClangStmt_ArrayInitIndexExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ArrayInitIndexExprClass"); return ErrorUnexpected; - case clang::Stmt::ArrayTypeTraitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ArrayTypeTraitExprClass"); + case ZigClangStmt_ArrayInitLoopExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ArrayInitLoopExprClass"); return ErrorUnexpected; - case clang::Stmt::AsTypeExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C AsTypeExprClass"); + case ZigClangStmt_ArrayTypeTraitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ArrayTypeTraitExprClass"); return ErrorUnexpected; - case clang::Stmt::AtomicExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C AtomicExprClass"); + case ZigClangStmt_AsTypeExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AsTypeExprClass"); return ErrorUnexpected; - case clang::Stmt::BlockExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C BlockExprClass"); + case ZigClangStmt_AtomicExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AtomicExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXBindTemporaryExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXBindTemporaryExprClass"); + case ZigClangStmt_BlockExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C BlockExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXBoolLiteralExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXBoolLiteralExprClass"); + case ZigClangStmt_CXXBindTemporaryExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXBindTemporaryExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXConstructExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXConstructExprClass"); + case ZigClangStmt_CXXBoolLiteralExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXBoolLiteralExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXTemporaryObjectExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXTemporaryObjectExprClass"); + case ZigClangStmt_CXXConstructExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXConstructExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXDefaultArgExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDefaultArgExprClass"); + case ZigClangStmt_CXXTemporaryObjectExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXTemporaryObjectExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXDefaultInitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDefaultInitExprClass"); + case ZigClangStmt_CXXDefaultArgExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDefaultArgExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXDeleteExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDeleteExprClass"); + case ZigClangStmt_CXXDefaultInitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDefaultInitExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXDependentScopeMemberExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDependentScopeMemberExprClass"); + case ZigClangStmt_CXXDeleteExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDeleteExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXFoldExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXFoldExprClass"); + case ZigClangStmt_CXXDependentScopeMemberExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDependentScopeMemberExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXInheritedCtorInitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXInheritedCtorInitExprClass"); + case ZigClangStmt_CXXFoldExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXFoldExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXNewExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXNewExprClass"); + case ZigClangStmt_CXXInheritedCtorInitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXInheritedCtorInitExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXNoexceptExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXNoexceptExprClass"); + case ZigClangStmt_CXXNewExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXNewExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXNullPtrLiteralExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXNullPtrLiteralExprClass"); + case ZigClangStmt_CXXNoexceptExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXNoexceptExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXPseudoDestructorExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXPseudoDestructorExprClass"); + case ZigClangStmt_CXXNullPtrLiteralExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXNullPtrLiteralExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXScalarValueInitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXScalarValueInitExprClass"); + case ZigClangStmt_CXXPseudoDestructorExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXPseudoDestructorExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXStdInitializerListExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXStdInitializerListExprClass"); + case ZigClangStmt_CXXScalarValueInitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXScalarValueInitExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXThisExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXThisExprClass"); + case ZigClangStmt_CXXStdInitializerListExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXStdInitializerListExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXThrowExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXThrowExprClass"); + case ZigClangStmt_CXXThisExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXThisExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXTypeidExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXTypeidExprClass"); + case ZigClangStmt_CXXThrowExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXThrowExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXUnresolvedConstructExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXUnresolvedConstructExprClass"); + case ZigClangStmt_CXXTypeidExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXTypeidExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXUuidofExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXUuidofExprClass"); + case ZigClangStmt_CXXUnresolvedConstructExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXUnresolvedConstructExprClass"); return ErrorUnexpected; - case clang::Stmt::CUDAKernelCallExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CUDAKernelCallExprClass"); + case ZigClangStmt_CXXUuidofExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXUuidofExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXMemberCallExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXMemberCallExprClass"); + case ZigClangStmt_CUDAKernelCallExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CUDAKernelCallExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXOperatorCallExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXOperatorCallExprClass"); + case ZigClangStmt_CXXMemberCallExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXMemberCallExprClass"); return ErrorUnexpected; - case clang::Stmt::UserDefinedLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UserDefinedLiteralClass"); + case ZigClangStmt_CXXOperatorCallExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXOperatorCallExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXFunctionalCastExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXFunctionalCastExprClass"); + case ZigClangStmt_UserDefinedLiteralClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C UserDefinedLiteralClass"); return ErrorUnexpected; - case clang::Stmt::CXXConstCastExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXConstCastExprClass"); + case ZigClangStmt_CXXFunctionalCastExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXFunctionalCastExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXDynamicCastExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDynamicCastExprClass"); + case ZigClangStmt_CXXConstCastExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXConstCastExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXReinterpretCastExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXReinterpretCastExprClass"); + case ZigClangStmt_CXXDynamicCastExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDynamicCastExprClass"); return ErrorUnexpected; - case clang::Stmt::CXXStaticCastExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXStaticCastExprClass"); + case ZigClangStmt_CXXReinterpretCastExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXReinterpretCastExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCBridgedCastExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCBridgedCastExprClass"); + case ZigClangStmt_CXXStaticCastExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXStaticCastExprClass"); return ErrorUnexpected; - case clang::Stmt::CharacterLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CharacterLiteralClass"); + case ZigClangStmt_ObjCBridgedCastExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBridgedCastExprClass"); return ErrorUnexpected; - case clang::Stmt::ChooseExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ChooseExprClass"); + case ZigClangStmt_CharacterLiteralClass: + return wrap_stmt(out_node, out_child_scope, scope, + trans_character_literal(c, result_used, (const clang::CharacterLiteral *)stmt)); return ErrorUnexpected; - case clang::Stmt::CompoundLiteralExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CompoundLiteralExprClass"); + case ZigClangStmt_ChooseExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ChooseExprClass"); return ErrorUnexpected; - case clang::Stmt::ConvertVectorExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ConvertVectorExprClass"); + case ZigClangStmt_CompoundLiteralExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CompoundLiteralExprClass"); return ErrorUnexpected; - case clang::Stmt::CoawaitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoawaitExprClass"); + case ZigClangStmt_ConvertVectorExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ConvertVectorExprClass"); return ErrorUnexpected; - case clang::Stmt::CoyieldExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoyieldExprClass"); + case ZigClangStmt_CoawaitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoawaitExprClass"); return ErrorUnexpected; - case clang::Stmt::DependentCoawaitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C DependentCoawaitExprClass"); + case ZigClangStmt_CoyieldExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoyieldExprClass"); return ErrorUnexpected; - case clang::Stmt::DependentScopeDeclRefExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C DependentScopeDeclRefExprClass"); + case ZigClangStmt_DependentCoawaitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DependentCoawaitExprClass"); return ErrorUnexpected; - case clang::Stmt::DesignatedInitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C DesignatedInitExprClass"); + case ZigClangStmt_DependentScopeDeclRefExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DependentScopeDeclRefExprClass"); return ErrorUnexpected; - case clang::Stmt::DesignatedInitUpdateExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C DesignatedInitUpdateExprClass"); + case ZigClangStmt_DesignatedInitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DesignatedInitExprClass"); return ErrorUnexpected; - case clang::Stmt::ExpressionTraitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExpressionTraitExprClass"); + case ZigClangStmt_DesignatedInitUpdateExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DesignatedInitUpdateExprClass"); return ErrorUnexpected; - case clang::Stmt::ExtVectorElementExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExtVectorElementExprClass"); + case ZigClangStmt_ExpressionTraitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExpressionTraitExprClass"); return ErrorUnexpected; - case clang::Stmt::FixedPointLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C FixedPointLiteralClass"); + case ZigClangStmt_ExtVectorElementExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExtVectorElementExprClass"); return ErrorUnexpected; - case clang::Stmt::FloatingLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C FloatingLiteralClass"); + case ZigClangStmt_FixedPointLiteralClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C FixedPointLiteralClass"); return ErrorUnexpected; - case clang::Stmt::ExprWithCleanupsClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExprWithCleanupsClass"); + case ZigClangStmt_FloatingLiteralClass: + return wrap_stmt(out_node, out_child_scope, scope, + trans_floating_literal(c, result_used, (const clang::FloatingLiteral *)stmt)); + case ZigClangStmt_ExprWithCleanupsClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExprWithCleanupsClass"); return ErrorUnexpected; - case clang::Stmt::FunctionParmPackExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C FunctionParmPackExprClass"); + case ZigClangStmt_FunctionParmPackExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C FunctionParmPackExprClass"); return ErrorUnexpected; - case clang::Stmt::GNUNullExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C GNUNullExprClass"); + case ZigClangStmt_GNUNullExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GNUNullExprClass"); return ErrorUnexpected; - case clang::Stmt::GenericSelectionExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C GenericSelectionExprClass"); + case ZigClangStmt_GenericSelectionExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GenericSelectionExprClass"); return ErrorUnexpected; - case clang::Stmt::ImaginaryLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ImaginaryLiteralClass"); + case ZigClangStmt_ImaginaryLiteralClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ImaginaryLiteralClass"); return ErrorUnexpected; - case clang::Stmt::ImplicitValueInitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ImplicitValueInitExprClass"); + case ZigClangStmt_ImplicitValueInitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ImplicitValueInitExprClass"); return ErrorUnexpected; - case clang::Stmt::InitListExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C InitListExprClass"); + case ZigClangStmt_InitListExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C InitListExprClass"); return ErrorUnexpected; - case clang::Stmt::LambdaExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C LambdaExprClass"); + case ZigClangStmt_LambdaExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C LambdaExprClass"); return ErrorUnexpected; - case clang::Stmt::MSPropertyRefExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSPropertyRefExprClass"); + case ZigClangStmt_MSPropertyRefExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSPropertyRefExprClass"); return ErrorUnexpected; - case clang::Stmt::MSPropertySubscriptExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSPropertySubscriptExprClass"); + case ZigClangStmt_MSPropertySubscriptExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSPropertySubscriptExprClass"); return ErrorUnexpected; - case clang::Stmt::MaterializeTemporaryExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C MaterializeTemporaryExprClass"); + case ZigClangStmt_MaterializeTemporaryExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MaterializeTemporaryExprClass"); return ErrorUnexpected; - case clang::Stmt::NoInitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C NoInitExprClass"); + case ZigClangStmt_NoInitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C NoInitExprClass"); return ErrorUnexpected; - case clang::Stmt::OMPArraySectionExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPArraySectionExprClass"); + case ZigClangStmt_OMPArraySectionExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPArraySectionExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCArrayLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCArrayLiteralClass"); + case ZigClangStmt_ObjCArrayLiteralClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCArrayLiteralClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAvailabilityCheckExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAvailabilityCheckExprClass"); + case ZigClangStmt_ObjCAvailabilityCheckExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAvailabilityCheckExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCBoolLiteralExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCBoolLiteralExprClass"); + case ZigClangStmt_ObjCBoolLiteralExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBoolLiteralExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCBoxedExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCBoxedExprClass"); + case ZigClangStmt_ObjCBoxedExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBoxedExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCDictionaryLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCDictionaryLiteralClass"); + case ZigClangStmt_ObjCDictionaryLiteralClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCDictionaryLiteralClass"); return ErrorUnexpected; - case clang::Stmt::ObjCEncodeExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCEncodeExprClass"); + case ZigClangStmt_ObjCEncodeExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCEncodeExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCIndirectCopyRestoreExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIndirectCopyRestoreExprClass"); + case ZigClangStmt_ObjCIndirectCopyRestoreExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCIndirectCopyRestoreExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCIsaExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIsaExprClass"); + case ZigClangStmt_ObjCIsaExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCIsaExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCIvarRefExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIvarRefExprClass"); + case ZigClangStmt_ObjCIvarRefExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCIvarRefExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCMessageExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCMessageExprClass"); + case ZigClangStmt_ObjCMessageExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCMessageExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCPropertyRefExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCPropertyRefExprClass"); + case ZigClangStmt_ObjCPropertyRefExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCPropertyRefExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCProtocolExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCProtocolExprClass"); + case ZigClangStmt_ObjCProtocolExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCProtocolExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCSelectorExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCSelectorExprClass"); + case ZigClangStmt_ObjCSelectorExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCSelectorExprClass"); return ErrorUnexpected; - case clang::Stmt::ObjCStringLiteralClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCStringLiteralClass"); + case ZigClangStmt_ObjCStringLiteralClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCStringLiteralClass"); return ErrorUnexpected; - case clang::Stmt::ObjCSubscriptRefExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCSubscriptRefExprClass"); + case ZigClangStmt_ObjCSubscriptRefExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCSubscriptRefExprClass"); return ErrorUnexpected; - case clang::Stmt::OffsetOfExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OffsetOfExprClass"); + case ZigClangStmt_OffsetOfExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OffsetOfExprClass"); return ErrorUnexpected; - case clang::Stmt::OpaqueValueExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OpaqueValueExprClass"); + case ZigClangStmt_OpaqueValueExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OpaqueValueExprClass"); return ErrorUnexpected; - case clang::Stmt::UnresolvedLookupExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UnresolvedLookupExprClass"); + case ZigClangStmt_UnresolvedLookupExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C UnresolvedLookupExprClass"); return ErrorUnexpected; - case clang::Stmt::UnresolvedMemberExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C UnresolvedMemberExprClass"); + case ZigClangStmt_UnresolvedMemberExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C UnresolvedMemberExprClass"); return ErrorUnexpected; - case clang::Stmt::PackExpansionExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C PackExpansionExprClass"); + case ZigClangStmt_PackExpansionExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C PackExpansionExprClass"); return ErrorUnexpected; - case clang::Stmt::ParenListExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ParenListExprClass"); + case ZigClangStmt_ParenListExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ParenListExprClass"); return ErrorUnexpected; - case clang::Stmt::PseudoObjectExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C PseudoObjectExprClass"); + case ZigClangStmt_PseudoObjectExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C PseudoObjectExprClass"); return ErrorUnexpected; - case clang::Stmt::ShuffleVectorExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ShuffleVectorExprClass"); + case ZigClangStmt_ShuffleVectorExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ShuffleVectorExprClass"); return ErrorUnexpected; - case clang::Stmt::SizeOfPackExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SizeOfPackExprClass"); + case ZigClangStmt_SizeOfPackExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SizeOfPackExprClass"); return ErrorUnexpected; - case clang::Stmt::SubstNonTypeTemplateParmExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SubstNonTypeTemplateParmExprClass"); + case ZigClangStmt_SubstNonTypeTemplateParmExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SubstNonTypeTemplateParmExprClass"); return ErrorUnexpected; - case clang::Stmt::SubstNonTypeTemplateParmPackExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); + case ZigClangStmt_SubstNonTypeTemplateParmPackExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); return ErrorUnexpected; - case clang::Stmt::TypeTraitExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TypeTraitExprClass"); + case ZigClangStmt_TypeTraitExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C TypeTraitExprClass"); return ErrorUnexpected; - case clang::Stmt::TypoExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C TypoExprClass"); + case ZigClangStmt_TypoExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C TypoExprClass"); return ErrorUnexpected; - case clang::Stmt::VAArgExprClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C VAArgExprClass"); + case ZigClangStmt_VAArgExprClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C VAArgExprClass"); return ErrorUnexpected; - case clang::Stmt::GotoStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C GotoStmtClass"); + case ZigClangStmt_GotoStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GotoStmtClass"); return ErrorUnexpected; - case clang::Stmt::IndirectGotoStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C IndirectGotoStmtClass"); + case ZigClangStmt_IndirectGotoStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C IndirectGotoStmtClass"); return ErrorUnexpected; - case clang::Stmt::LabelStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C LabelStmtClass"); + case ZigClangStmt_LabelStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C LabelStmtClass"); return ErrorUnexpected; - case clang::Stmt::MSDependentExistsStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSDependentExistsStmtClass"); + case ZigClangStmt_MSDependentExistsStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSDependentExistsStmtClass"); return ErrorUnexpected; - case clang::Stmt::OMPAtomicDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPAtomicDirectiveClass"); + case ZigClangStmt_OMPAtomicDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPAtomicDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPBarrierDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPBarrierDirectiveClass"); + case ZigClangStmt_OMPBarrierDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPBarrierDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPCancelDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCancelDirectiveClass"); + case ZigClangStmt_OMPCancelDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPCancelDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPCancellationPointDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCancellationPointDirectiveClass"); + case ZigClangStmt_OMPCancellationPointDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPCancellationPointDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPCriticalDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCriticalDirectiveClass"); + case ZigClangStmt_OMPCriticalDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPCriticalDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPFlushDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPFlushDirectiveClass"); + case ZigClangStmt_OMPFlushDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPFlushDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPDistributeDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeDirectiveClass"); + case ZigClangStmt_OMPDistributeDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPDistributeParallelForDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeParallelForDirectiveClass"); + case ZigClangStmt_OMPDistributeParallelForDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeParallelForDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPDistributeParallelForSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); + case ZigClangStmt_OMPDistributeParallelForSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPDistributeSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeSimdDirectiveClass"); + case ZigClangStmt_OMPDistributeSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPForDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPForDirectiveClass"); + case ZigClangStmt_OMPForDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPForDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPForSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPForSimdDirectiveClass"); + case ZigClangStmt_OMPForSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPForSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPParallelForDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelForDirectiveClass"); + case ZigClangStmt_OMPParallelForDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelForDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPParallelForSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelForSimdDirectiveClass"); + case ZigClangStmt_OMPParallelForSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelForSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSimdDirectiveClass"); + case ZigClangStmt_OMPSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetParallelForSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); + case ZigClangStmt_OMPTargetParallelForSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetSimdDirectiveClass"); + case ZigClangStmt_OMPTargetSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetTeamsDistributeDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); + case ZigClangStmt_OMPTargetTeamsDistributeDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); + case ZigClangStmt_OMPTargetTeamsDistributeParallelForDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); + case ZigClangStmt_OMPTargetTeamsDistributeParallelForSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); + case ZigClangStmt_OMPTargetTeamsDistributeSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTaskLoopDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskLoopDirectiveClass"); + case ZigClangStmt_OMPTaskLoopDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskLoopDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTaskLoopSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskLoopSimdDirectiveClass"); + case ZigClangStmt_OMPTaskLoopSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskLoopSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTeamsDistributeDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeDirectiveClass"); + case ZigClangStmt_OMPTeamsDistributeDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTeamsDistributeParallelForDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); + case ZigClangStmt_OMPTeamsDistributeParallelForDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); + case ZigClangStmt_OMPTeamsDistributeParallelForSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTeamsDistributeSimdDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); + case ZigClangStmt_OMPTeamsDistributeSimdDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPMasterDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPMasterDirectiveClass"); + case ZigClangStmt_OMPMasterDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPMasterDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPOrderedDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPOrderedDirectiveClass"); + case ZigClangStmt_OMPOrderedDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPOrderedDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPParallelDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelDirectiveClass"); + case ZigClangStmt_OMPParallelDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPParallelSectionsDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelSectionsDirectiveClass"); + case ZigClangStmt_OMPParallelSectionsDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelSectionsDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPSectionDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSectionDirectiveClass"); + case ZigClangStmt_OMPSectionDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSectionDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPSectionsDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSectionsDirectiveClass"); + case ZigClangStmt_OMPSectionsDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSectionsDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPSingleDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSingleDirectiveClass"); + case ZigClangStmt_OMPSingleDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSingleDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetDataDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetDataDirectiveClass"); + case ZigClangStmt_OMPTargetDataDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetDataDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetDirectiveClass"); + case ZigClangStmt_OMPTargetDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetEnterDataDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetEnterDataDirectiveClass"); + case ZigClangStmt_OMPTargetEnterDataDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetEnterDataDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetExitDataDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetExitDataDirectiveClass"); + case ZigClangStmt_OMPTargetExitDataDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetExitDataDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetParallelDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetParallelDirectiveClass"); + case ZigClangStmt_OMPTargetParallelDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetParallelDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetParallelForDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetParallelForDirectiveClass"); + case ZigClangStmt_OMPTargetParallelForDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetParallelForDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetTeamsDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDirectiveClass"); + case ZigClangStmt_OMPTargetTeamsDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTargetUpdateDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetUpdateDirectiveClass"); + case ZigClangStmt_OMPTargetUpdateDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetUpdateDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTaskDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskDirectiveClass"); + case ZigClangStmt_OMPTaskDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTaskgroupDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskgroupDirectiveClass"); + case ZigClangStmt_OMPTaskgroupDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskgroupDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTaskwaitDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskwaitDirectiveClass"); + case ZigClangStmt_OMPTaskwaitDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskwaitDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTaskyieldDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskyieldDirectiveClass"); + case ZigClangStmt_OMPTaskyieldDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskyieldDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::OMPTeamsDirectiveClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDirectiveClass"); + case ZigClangStmt_OMPTeamsDirectiveClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDirectiveClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAtCatchStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtCatchStmtClass"); + case ZigClangStmt_ObjCAtCatchStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtCatchStmtClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAtFinallyStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtFinallyStmtClass"); + case ZigClangStmt_ObjCAtFinallyStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtFinallyStmtClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAtSynchronizedStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtSynchronizedStmtClass"); + case ZigClangStmt_ObjCAtSynchronizedStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtSynchronizedStmtClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAtThrowStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtThrowStmtClass"); + case ZigClangStmt_ObjCAtThrowStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtThrowStmtClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAtTryStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtTryStmtClass"); + case ZigClangStmt_ObjCAtTryStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtTryStmtClass"); return ErrorUnexpected; - case clang::Stmt::ObjCAutoreleasePoolStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAutoreleasePoolStmtClass"); + case ZigClangStmt_ObjCAutoreleasePoolStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAutoreleasePoolStmtClass"); return ErrorUnexpected; - case clang::Stmt::ObjCForCollectionStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCForCollectionStmtClass"); + case ZigClangStmt_ObjCForCollectionStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCForCollectionStmtClass"); return ErrorUnexpected; - case clang::Stmt::SEHExceptStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHExceptStmtClass"); + case ZigClangStmt_SEHExceptStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHExceptStmtClass"); return ErrorUnexpected; - case clang::Stmt::SEHFinallyStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHFinallyStmtClass"); + case ZigClangStmt_SEHFinallyStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHFinallyStmtClass"); return ErrorUnexpected; - case clang::Stmt::SEHLeaveStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHLeaveStmtClass"); + case ZigClangStmt_SEHLeaveStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHLeaveStmtClass"); return ErrorUnexpected; - case clang::Stmt::SEHTryStmtClass: - emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHTryStmtClass"); + case ZigClangStmt_SEHTryStmtClass: + emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHTryStmtClass"); return ErrorUnexpected; } zig_unreachable(); } // Returns null if there was an error -static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, +static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval) { AstNode *result_node; TransScope *result_scope; - if (trans_stmt_extra(c, scope, expr, result_used, lrval, &result_node, &result_scope, nullptr)) { + if (trans_stmt_extra(c, scope, (const ZigClangStmt *)expr, result_used, lrval, &result_node, &result_scope, nullptr)) { return nullptr; } return result_node; @@ -3846,7 +4013,7 @@ static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope // Statements have no result and no concept of L or R value. // Returns child scope, or null if there was an error -static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt *stmt, AstNode **out_node) { +static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node) { TransScope *child_scope; if (trans_stmt_extra(c, scope, stmt, ResultUsedNo, TransRValue, out_node, &child_scope, nullptr)) { return nullptr; @@ -3854,34 +4021,36 @@ static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt * return child_scope; } -static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) { - Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); +static void visit_fn_decl(Context *c, const ZigClangFunctionDecl *fn_decl) { + Buf *fn_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)fn_decl)); if (get_global(c, fn_name)) { // we already saw this function return; } - AstNode *proto_node = trans_qual_type(c, fn_decl->getType(), fn_decl->getLocation()); + AstNode *proto_node = trans_qual_type(c, ZigClangFunctionDecl_getType(fn_decl), + ZigClangFunctionDecl_getLocation(fn_decl)); if (proto_node == nullptr) { - emit_warning(c, fn_decl->getLocation(), "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); + emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), + "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); return; } proto_node->data.fn_proto.name = fn_name; - proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); + proto_node->data.fn_proto.is_extern = !ZigClangFunctionDecl_hasBody(fn_decl); - clang::StorageClass sc = fn_decl->getStorageClass(); - if (sc == clang::SC_None) { + ZigClangStorageClass sc = ZigClangFunctionDecl_getStorageClass(fn_decl); + if (sc == ZigClangStorageClass_None) { proto_node->data.fn_proto.visib_mod = c->visib_mod; - proto_node->data.fn_proto.is_export = fn_decl->hasBody() ? c->want_export : false; - } else if (sc == clang::SC_Extern || sc == clang::SC_Static) { + proto_node->data.fn_proto.is_export = ZigClangFunctionDecl_hasBody(fn_decl) ? c->want_export : false; + } else if (sc == ZigClangStorageClass_Extern || sc == ZigClangStorageClass_Static) { proto_node->data.fn_proto.visib_mod = c->visib_mod; - } else if (sc == clang::SC_PrivateExtern) { - emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); + } else if (sc == ZigClangStorageClass_PrivateExtern) { + emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), "unsupported storage class: private extern"); return; } else { - emit_warning(c, fn_decl->getLocation(), "unsupported storage class: unknown"); + emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), "unsupported storage class: unknown"); return; } @@ -3889,8 +4058,8 @@ static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) { for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { AstNode *param_node = proto_node->data.fn_proto.params.at(i); - const clang::ParmVarDecl *param = fn_decl->getParamDecl(i); - const char *name = decl_name(param); + const ZigClangParmVarDecl *param = ZigClangFunctionDecl_getParamDecl(fn_decl, i); + const char *name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)param); Buf *proto_param_name; if (strlen(name) != 0) { @@ -3908,7 +4077,7 @@ static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) { param_node->data.param_decl.name = scope_var->zig_name; } - if (!fn_decl->hasBody()) { + if (!ZigClangFunctionDecl_hasBody(fn_decl)) { // just a prototype add_top_level_decl(c, proto_node->data.fn_proto.name, proto_node); return; @@ -3916,11 +4085,11 @@ static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) { // actual function definition with body c->ptr_params.clear(); - clang::Stmt *body = fn_decl->getBody(); + const ZigClangStmt *body = ZigClangFunctionDecl_getBody(fn_decl); AstNode *actual_body_node; TransScope *result_scope = trans_stmt(c, scope, body, &actual_body_node); if (result_scope == nullptr) { - emit_warning(c, fn_decl->getLocation(), "unable to translate function"); + emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), "unable to translate function"); return; } assert(actual_body_node != nullptr); @@ -3958,20 +4127,20 @@ static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) { add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); } -static AstNode *resolve_typdef_as_builtin(Context *c, const clang::TypedefNameDecl *typedef_decl, const char *primitive_name) { +static AstNode *resolve_typdef_as_builtin(Context *c, const ZigClangTypedefNameDecl *typedef_decl, const char *primitive_name) { AstNode *node = trans_create_node_symbol_str(c, primitive_name); c->decl_table.put(typedef_decl, node); return node; } -static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *typedef_decl) { - auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); +static AstNode *resolve_typedef_decl(Context *c, const ZigClangTypedefNameDecl *typedef_decl) { + auto existing_entry = c->decl_table.maybe_get((void*)ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)); if (existing_entry) { return existing_entry->value; } - clang::QualType child_qt = typedef_decl->getUnderlyingType(); - Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); + ZigClangQualType child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); + Buf *type_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)typedef_decl)); if (buf_eql_str(type_name, "uint8_t")) { return resolve_typdef_as_builtin(c, typedef_decl, "u8"); @@ -4005,11 +4174,12 @@ static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *t // trans_qual_type here might cause us to look at this typedef again so we put the item in the map first AstNode *symbol_node = trans_create_node_symbol(c, type_name); - c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node); + c->decl_table.put(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl), symbol_node); - AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); + AstNode *type_node = trans_qual_type(c, child_qt, ZigClangTypedefNameDecl_getLocation(typedef_decl)); if (type_node == nullptr) { - emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); + emit_warning(c, ZigClangTypedefNameDecl_getLocation(typedef_decl), + "typedef %s - unresolved child type", buf_ptr(type_name)); c->decl_table.put(typedef_decl, nullptr); // TODO add global var with type_name equal to @compileError("unable to resolve C type") return nullptr; @@ -4019,33 +4189,33 @@ static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *t return symbol_node; } -struct AstNode *demote_enum_to_opaque(Context *c, const clang::EnumDecl *enum_decl, - Buf *full_type_name, Buf *bare_name) +struct AstNode *demote_enum_to_opaque(Context *c, const ZigClangEnumDecl *enum_decl, Buf *full_type_name, + Buf *bare_name) { AstNode *opaque_node = trans_create_node_opaque(c); if (full_type_name == nullptr) { - c->decl_table.put(enum_decl->getCanonicalDecl(), opaque_node); + c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), opaque_node); return opaque_node; } AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, opaque_node); - c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); + c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), symbol_node); return symbol_node; } -static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) { - auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); +static AstNode *resolve_enum_decl(Context *c, const ZigClangEnumDecl *enum_decl) { + auto existing_entry = c->decl_table.maybe_get(ZigClangEnumDecl_getCanonicalDecl(enum_decl)); if (existing_entry) { return existing_entry->value; } - const char *raw_name = decl_name(enum_decl); + const char *raw_name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)enum_decl); bool is_anonymous = (raw_name[0] == 0); Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); - const clang::EnumDecl *enum_def = enum_decl->getDefinition(); + const ZigClangEnumDecl *enum_def = ZigClangEnumDecl_getDefinition(enum_decl); if (!enum_def) { return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); } @@ -4053,8 +4223,8 @@ static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) bool pure_enum = true; uint32_t field_count = 0; - for (auto it = enum_def->enumerator_begin(), - it_end = enum_def->enumerator_end(); + for (auto it = reinterpret_cast<const clang::EnumDecl *>(enum_def)->enumerator_begin(), + it_end = reinterpret_cast<const clang::EnumDecl *>(enum_def)->enumerator_end(); it != it_end; ++it, field_count += 1) { const clang::EnumConstantDecl *enum_const = *it; @@ -4062,7 +4232,8 @@ static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) pure_enum = false; } } - AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); + AstNode *tag_int_type = trans_qual_type(c, ZigClangEnumDecl_getIntegerType(enum_decl), + ZigClangEnumDecl_getLocation(enum_decl)); assert(tag_int_type); AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); @@ -4071,20 +4242,20 @@ static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) // TODO only emit this tag type if the enum tag type is not the default. // I don't know what the default is, need to figure out how clang is deciding. // it appears to at least be different across gcc/msvc - if (!c_is_builtin_type(c, enum_decl->getIntegerType(), clang::BuiltinType::UInt) && - !c_is_builtin_type(c, enum_decl->getIntegerType(), clang::BuiltinType::Int)) + if (!c_is_builtin_type(c, ZigClangEnumDecl_getIntegerType(enum_decl), ZigClangBuiltinTypeUInt) && + !c_is_builtin_type(c, ZigClangEnumDecl_getIntegerType(enum_decl), ZigClangBuiltinTypeInt)) { enum_node->data.container_decl.init_arg_expr = tag_int_type; } enum_node->data.container_decl.fields.resize(field_count); uint32_t i = 0; - for (auto it = enum_def->enumerator_begin(), - it_end = enum_def->enumerator_end(); + for (auto it = reinterpret_cast<const clang::EnumDecl *>(enum_def)->enumerator_begin(), + it_end = reinterpret_cast<const clang::EnumDecl *>(enum_def)->enumerator_end(); it != it_end; ++it, i += 1) { const clang::EnumConstantDecl *enum_const = *it; - Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); + Buf *enum_val_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)enum_const)); Buf *field_name; if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); @@ -4092,7 +4263,8 @@ static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) field_name = enum_val_name; } - AstNode *int_node = pure_enum && !is_anonymous ? nullptr : trans_create_node_apint(c, enum_const->getInitVal()); + AstNode *int_node = pure_enum && !is_anonymous ? + nullptr : trans_create_node_apint(c, bitcast(&enum_const->getInitVal())); AstNode *field_node = trans_create_node(c, NodeTypeStructField); field_node->data.struct_field.name = field_name; field_node->data.struct_field.type = nullptr; @@ -4102,7 +4274,7 @@ static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) // in C each enum value is in the global namespace. so we put them there too. // at this point we can rely on the enum emitting successfully if (is_anonymous) { - Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); + Buf *enum_val_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)enum_const)); add_global_var(c, enum_val_name, int_node); } else { AstNode *field_access_node = trans_create_node_field_access(c, @@ -4112,73 +4284,74 @@ static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) } if (is_anonymous) { - c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); + c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), enum_node); return enum_node; } else { AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, enum_node); - c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); + c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), symbol_node); return enum_node; } } -static AstNode *demote_struct_to_opaque(Context *c, const clang::RecordDecl *record_decl, +static AstNode *demote_struct_to_opaque(Context *c, const ZigClangRecordDecl *record_decl, Buf *full_type_name, Buf *bare_name) { AstNode *opaque_node = trans_create_node_opaque(c); if (full_type_name == nullptr) { - c->decl_table.put(record_decl->getCanonicalDecl(), opaque_node); + c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), opaque_node); return opaque_node; } AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); add_global_weak_alias(c, bare_name, full_type_name); add_global_var(c, full_type_name, opaque_node); - c->decl_table.put(record_decl->getCanonicalDecl(), symbol_node); + c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), symbol_node); return symbol_node; } -static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_decl) { - auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); +static AstNode *resolve_record_decl(Context *c, const ZigClangRecordDecl *record_decl) { + auto existing_entry = c->decl_table.maybe_get(ZigClangRecordDecl_getCanonicalDecl(record_decl)); if (existing_entry) { return existing_entry->value; } - const char *raw_name = decl_name(record_decl); + const char *raw_name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)record_decl); const char *container_kind_name; ContainerKind container_kind; - if (record_decl->isUnion()) { + if (ZigClangRecordDecl_isUnion(record_decl)) { container_kind_name = "union"; container_kind = ContainerKindUnion; - } else if (record_decl->isStruct()) { + } else if (ZigClangRecordDecl_isStruct(record_decl)) { container_kind_name = "struct"; container_kind = ContainerKindStruct; } else { - emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct or union", raw_name); - c->decl_table.put(record_decl->getCanonicalDecl(), nullptr); + emit_warning(c, ZigClangRecordDecl_getLocation(record_decl), + "skipping record %s, not a struct or union", raw_name); + c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), nullptr); return nullptr; } - bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0; + bool is_anonymous = ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) || raw_name[0] == 0; Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); Buf *full_type_name = (bare_name == nullptr) ? nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name)); - clang::RecordDecl *record_def = record_decl->getDefinition(); + const ZigClangRecordDecl *record_def = ZigClangRecordDecl_getDefinition(record_decl); if (record_def == nullptr) { return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); } // count fields and validate uint32_t field_count = 0; - for (auto it = record_def->field_begin(), - it_end = record_def->field_end(); + for (auto it = reinterpret_cast<const clang::RecordDecl *>(record_def)->field_begin(), + it_end = reinterpret_cast<const clang::RecordDecl *>(record_def)->field_end(); it != it_end; ++it, field_count += 1) { const clang::FieldDecl *field_decl = *it; if (field_decl->isBitField()) { - emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield", + emit_warning(c, bitcast(field_decl->getLocation()), "%s %s demoted to opaque type - has bitfield", container_kind_name, is_anonymous ? "(anon)" : buf_ptr(bare_name)); return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); @@ -4195,24 +4368,25 @@ static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_ // must be before fields in case a circular reference happens if (is_anonymous) { - c->decl_table.put(record_decl->getCanonicalDecl(), struct_node); + c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), struct_node); } else { - c->decl_table.put(record_decl->getCanonicalDecl(), trans_create_node_symbol(c, full_type_name)); + c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), trans_create_node_symbol(c, full_type_name)); } uint32_t i = 0; - for (auto it = record_def->field_begin(), - it_end = record_def->field_end(); + for (auto it = reinterpret_cast<const clang::RecordDecl *>(record_def)->field_begin(), + it_end = reinterpret_cast<const clang::RecordDecl *>(record_def)->field_end(); it != it_end; ++it, i += 1) { const clang::FieldDecl *field_decl = *it; AstNode *field_node = trans_create_node(c, NodeTypeStructField); - field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); - field_node->data.struct_field.type = trans_qual_type(c, field_decl->getType(), field_decl->getLocation()); + field_node->data.struct_field.name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)field_decl)); + field_node->data.struct_field.type = trans_qual_type(c, bitcast(field_decl->getType()), + bitcast(field_decl->getLocation())); if (field_node->data.struct_field.type == nullptr) { - emit_warning(c, field_decl->getLocation(), + emit_warning(c, bitcast(field_decl->getLocation()), "%s %s demoted to opaque type - unresolved type", container_kind_name, is_anonymous ? "(anon)" : buf_ptr(bare_name)); @@ -4232,17 +4406,19 @@ static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_ } } -static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::QualType qt, const clang::SourceLocation &source_loc) { - switch (ap_value->getKind()) { - case clang::APValue::Int: - return trans_create_node_apint(c, ap_value->getInt()); - case clang::APValue::Uninitialized: +static AstNode *trans_ap_value(Context *c, const ZigClangAPValue *ap_value, ZigClangQualType qt, + ZigClangSourceLocation source_loc) +{ + switch (ZigClangAPValue_getKind(ap_value)) { + case ZigClangAPValueInt: + return trans_create_node_apint(c, ZigClangAPValue_getInt(ap_value)); + case ZigClangAPValueUninitialized: return trans_create_node(c, NodeTypeUndefinedLiteral); - case clang::APValue::Array: { + case ZigClangAPValueArray: { emit_warning(c, source_loc, "TODO add a test case for this code"); - unsigned init_count = ap_value->getArrayInitializedElts(); - unsigned all_count = ap_value->getArraySize(); + unsigned init_count = ZigClangAPValue_getArrayInitializedElts(ap_value); + unsigned all_count = ZigClangAPValue_getArraySize(ap_value); unsigned leftover_count = all_count - init_count; AstNode *init_node = trans_create_node(c, NodeTypeContainerInitExpr); AstNode *arr_type_node = trans_qual_type(c, qt, source_loc); @@ -4252,11 +4428,12 @@ static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::Qual init_node->data.container_init_expr.type = arr_type_node; init_node->data.container_init_expr.kind = ContainerInitKindArray; - clang::QualType child_qt = qt.getTypePtr()->getAsArrayTypeUnsafe()->getElementType(); + const clang::Type *qt_type = reinterpret_cast<const clang::Type *>(ZigClangQualType_getTypePtr(qt)); + ZigClangQualType child_qt = bitcast(qt_type->getAsArrayTypeUnsafe()->getElementType()); for (size_t i = 0; i < init_count; i += 1) { - clang::APValue &elem_ap_val = ap_value->getArrayInitializedElt(i); - AstNode *elem_node = trans_ap_value(c, &elem_ap_val, child_qt, source_loc); + const ZigClangAPValue *elem_ap_val = ZigClangAPValue_getArrayInitializedElt(ap_value, i); + AstNode *elem_node = trans_ap_value(c, elem_ap_val, child_qt, source_loc); if (elem_node == nullptr) return nullptr; init_node->data.container_init_expr.entries.append(elem_node); @@ -4265,8 +4442,8 @@ static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::Qual return init_node; } - clang::APValue &filler_ap_val = ap_value->getArrayFiller(); - AstNode *filler_node = trans_ap_value(c, &filler_ap_val, child_qt, source_loc); + const ZigClangAPValue *filler_ap_val = ZigClangAPValue_getArrayFiller(ap_value); + AstNode *filler_node = trans_ap_value(c, filler_ap_val, child_qt, source_loc); if (filler_node == nullptr) return nullptr; @@ -4293,37 +4470,37 @@ static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::Qual return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node); } - case clang::APValue::LValue: { - const clang::APValue::LValueBase lval_base = ap_value->getLValueBase(); - if (const clang::Expr *expr = lval_base.dyn_cast<const clang::Expr *>()) { + case ZigClangAPValueLValue: { + const ZigClangAPValueLValueBase lval_base = ZigClangAPValue_getLValueBase(ap_value); + if (const ZigClangExpr *expr = ZigClangAPValueLValueBase_dyn_cast_Expr(lval_base)) { return trans_expr(c, ResultUsedYes, &c->global_scope->base, expr, TransRValue); } //const clang::ValueDecl *value_decl = lval_base.get<const clang::ValueDecl *>(); emit_warning(c, source_loc, "TODO handle initializer LValue clang::ValueDecl"); return nullptr; } - case clang::APValue::Float: + case ZigClangAPValueFloat: emit_warning(c, source_loc, "unsupported initializer value kind: Float"); return nullptr; - case clang::APValue::ComplexInt: + case ZigClangAPValueComplexInt: emit_warning(c, source_loc, "unsupported initializer value kind: ComplexInt"); return nullptr; - case clang::APValue::ComplexFloat: + case ZigClangAPValueComplexFloat: emit_warning(c, source_loc, "unsupported initializer value kind: ComplexFloat"); return nullptr; - case clang::APValue::Vector: + case ZigClangAPValueVector: emit_warning(c, source_loc, "unsupported initializer value kind: Vector"); return nullptr; - case clang::APValue::Struct: + case ZigClangAPValueStruct: emit_warning(c, source_loc, "unsupported initializer value kind: Struct"); return nullptr; - case clang::APValue::Union: + case ZigClangAPValueUnion: emit_warning(c, source_loc, "unsupported initializer value kind: Union"); return nullptr; - case clang::APValue::MemberPointer: + case ZigClangAPValueMemberPointer: emit_warning(c, source_loc, "unsupported initializer value kind: MemberPointer"); return nullptr; - case clang::APValue::AddrLabelDiff: + case ZigClangAPValueAddrLabelDiff: emit_warning(c, source_loc, "unsupported initializer value kind: AddrLabelDiff"); return nullptr; } @@ -4331,42 +4508,42 @@ static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::Qual } static void visit_var_decl(Context *c, const clang::VarDecl *var_decl) { - Buf *name = buf_create_from_str(decl_name(var_decl)); + Buf *name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)var_decl)); switch (var_decl->getTLSKind()) { case clang::VarDecl::TLS_None: break; case clang::VarDecl::TLS_Static: - emit_warning(c, var_decl->getLocation(), + emit_warning(c, bitcast(var_decl->getLocation()), "ignoring variable '%s' - static thread local storage", buf_ptr(name)); return; case clang::VarDecl::TLS_Dynamic: - emit_warning(c, var_decl->getLocation(), + emit_warning(c, bitcast(var_decl->getLocation()), "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); return; } - clang::QualType qt = var_decl->getType(); - AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); + ZigClangQualType qt = bitcast(var_decl->getType()); + AstNode *var_type = trans_qual_type(c, qt, bitcast(var_decl->getLocation())); if (var_type == nullptr) { - emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); + emit_warning(c, bitcast(var_decl->getLocation()), "ignoring variable '%s' - unresolved type", buf_ptr(name)); return; } bool is_extern = var_decl->hasExternalStorage(); bool is_static = var_decl->isFileVarDecl(); - bool is_const = qt.isConstQualified(); + bool is_const = ZigClangQualType_isConstQualified(qt); if (is_static && !is_extern) { AstNode *init_node; if (var_decl->hasInit()) { - clang::APValue *ap_value = var_decl->evaluateValue(); + const ZigClangAPValue *ap_value = bitcast(var_decl->evaluateValue()); if (ap_value == nullptr) { - emit_warning(c, var_decl->getLocation(), + emit_warning(c, bitcast(var_decl->getLocation()), "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); return; } - init_node = trans_ap_value(c, ap_value, qt, var_decl->getLocation()); + init_node = trans_ap_value(c, ap_value, qt, bitcast(var_decl->getLocation())); if (init_node == nullptr) return; } else { @@ -4385,33 +4562,32 @@ static void visit_var_decl(Context *c, const clang::VarDecl *var_decl) { return; } - emit_warning(c, var_decl->getLocation(), + emit_warning(c, bitcast(var_decl->getLocation()), "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); return; } -static bool decl_visitor(void *context, const ZigClangDecl *zdecl) { - const clang::Decl *decl = reinterpret_cast<const clang::Decl *>(zdecl); +static bool decl_visitor(void *context, const ZigClangDecl *decl) { Context *c = (Context*)context; - switch (decl->getKind()) { - case clang::Decl::Function: - visit_fn_decl(c, static_cast<const clang::FunctionDecl*>(decl)); + switch (ZigClangDecl_getKind(decl)) { + case ZigClangDeclFunction: + visit_fn_decl(c, reinterpret_cast<const ZigClangFunctionDecl*>(decl)); break; - case clang::Decl::Typedef: - resolve_typedef_decl(c, static_cast<const clang::TypedefNameDecl *>(decl)); + case ZigClangDeclTypedef: + resolve_typedef_decl(c, reinterpret_cast<const ZigClangTypedefNameDecl *>(decl)); break; - case clang::Decl::Enum: - resolve_enum_decl(c, static_cast<const clang::EnumDecl *>(decl)); + case ZigClangDeclEnum: + resolve_enum_decl(c, reinterpret_cast<const ZigClangEnumDecl *>(decl)); break; - case clang::Decl::Record: - resolve_record_decl(c, static_cast<const clang::RecordDecl *>(decl)); + case ZigClangDeclRecord: + resolve_record_decl(c, reinterpret_cast<const ZigClangRecordDecl *>(decl)); break; - case clang::Decl::Var: - visit_var_decl(c, static_cast<const clang::VarDecl *>(decl)); + case ZigClangDeclVar: + visit_var_decl(c, reinterpret_cast<const clang::VarDecl *>(decl)); break; default: - emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); + emit_warning(c, ZigClangDecl_getLocation(decl), "ignoring %s decl", ZigClangDecl_getDeclKindName(decl)); } return true; @@ -4720,6 +4896,8 @@ static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok case CTokIdAsterisk: case CTokIdBang: case CTokIdTilde: + case CTokIdShl: + case CTokIdLt: // not able to make sense of this return nullptr; } @@ -4751,6 +4929,13 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t *tok_i += 1; node = trans_create_node_ptr_type(c, false, false, node, PtrLenC); + } else if (first_tok->id == CTokIdShl) { + *tok_i += 1; + + AstNode *rhs_node = parse_ctok_expr(c, ctok, tok_i); + if (rhs_node == nullptr) + return nullptr; + node = trans_create_node_bin_op(c, node, BinOpTypeBitShiftLeft, rhs_node); } else { return node; } @@ -4846,10 +5031,10 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) { clang::MacroDefinitionRecord *macro = static_cast<clang::MacroDefinitionRecord *>(entity); const char *raw_name = macro->getName()->getNameStart(); clang::SourceRange range = macro->getSourceRange(); - clang::SourceLocation begin_loc = range.getBegin(); - clang::SourceLocation end_loc = range.getEnd(); + ZigClangSourceLocation begin_loc = bitcast(range.getBegin()); + ZigClangSourceLocation end_loc = bitcast(range.getEnd()); - if (begin_loc == end_loc) { + if (ZigClangSourceLocation_eq(begin_loc, end_loc)) { // this means it is a macro without a value // we don't care about such things continue; @@ -4859,21 +5044,22 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) { continue; } - const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, bitcast(begin_loc)); + const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, begin_loc); process_macro(c, &ctok, name, begin_c); } } } } -Error parse_h_file(AstNode **out_root_node, ZigList<ErrorMsg *> *errors, const char *target_file, - CodeGen *codegen, Buf *tmp_dep_file) +Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, + Stage2ErrorMsg **errors_ptr, size_t *errors_len, + const char **args_begin, const char **args_end, + Stage2TranslateMode mode, const char *resources_path) { Context context = {0}; Context *c = &context; c->warnings_on = codegen->verbose_cimport; - c->errors = errors; - if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { + if (mode == Stage2TranslateModeImport) { c->visib_mod = VisibModPub; c->want_export = false; } else { @@ -4887,161 +5073,10 @@ Error parse_h_file(AstNode **out_root_node, ZigList<ErrorMsg *> *errors, const c c->codegen = codegen; c->global_scope = trans_scope_root_create(c); - ZigList<const char *> clang_argv = {0}; - - clang_argv.append("-x"); - clang_argv.append("c"); - - if (tmp_dep_file != nullptr) { - clang_argv.append("-MD"); - clang_argv.append("-MV"); - clang_argv.append("-MF"); - clang_argv.append(buf_ptr(tmp_dep_file)); - } - - if (c->codegen->zig_target->is_native) { - char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS"); - if (ZIG_PARSEC_CFLAGS) { - Buf tmp_buf = BUF_INIT; - char *start = ZIG_PARSEC_CFLAGS; - char *space = strstr(start, " "); - while (space) { - if (space - start > 0) { - buf_init_from_mem(&tmp_buf, start, space - start); - clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); - } - start = space + 1; - space = strstr(start, " "); - } - buf_init_from_str(&tmp_buf, start); - clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); - } - } - - clang_argv.append("-nobuiltininc"); - clang_argv.append("-nostdinc"); - clang_argv.append("-nostdinc++"); - if (codegen->libc_link_lib == nullptr) { - clang_argv.append("-nolibc"); - } - - clang_argv.append("-isystem"); - clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); - - for (size_t i = 0; i < codegen->libc_include_dir_len; i += 1) { - Buf *include_dir = codegen->libc_include_dir_list[i]; - clang_argv.append("-isystem"); - clang_argv.append(buf_ptr(include_dir)); - } - - // windows c runtime requires -D_DEBUG if using debug libraries - if (codegen->build_mode == BuildModeDebug) { - clang_argv.append("-D_DEBUG"); - } - - for (size_t i = 0; i < codegen->clang_argv_len; i += 1) { - clang_argv.append(codegen->clang_argv[i]); - } - - // we don't need spell checking and it slows things down - clang_argv.append("-fno-spell-checking"); - - // this gives us access to preprocessing entities, presumably at - // the cost of performance - clang_argv.append("-Xclang"); - clang_argv.append("-detailed-preprocessing-record"); - - if (c->codegen->zig_target->is_native) { - clang_argv.append("-march=native"); - } else { - clang_argv.append("-target"); - clang_argv.append(buf_ptr(&c->codegen->triple_str)); - } - - clang_argv.append(target_file); - - if (codegen->verbose_cc) { - fprintf(stderr, "clang"); - for (size_t i = 0; i < clang_argv.length; i += 1) { - fprintf(stderr, " %s", clang_argv.at(i)); - } - fprintf(stderr, "\n"); - } - - // to make the [start...end] argument work - clang_argv.append(nullptr); - - clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions)); - - std::shared_ptr<clang::PCHContainerOperations> pch_container_ops = std::make_shared<clang::PCHContainerOperations>(); - - bool only_local_decls = true; - bool capture_diagnostics = true; - bool user_files_are_volatile = true; - bool allow_pch_with_compiler_errors = false; - bool single_file_parse = false; - bool for_serialization = false; - const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); - std::unique_ptr<clang::ASTUnit> err_unit; - ZigClangASTUnit *ast_unit = reinterpret_cast<ZigClangASTUnit *>(clang::ASTUnit::LoadFromCommandLine( - &clang_argv.at(0), &clang_argv.last(), - pch_container_ops, diags, resources_path, - only_local_decls, capture_diagnostics, clang::None, true, 0, clang::TU_Complete, - false, false, allow_pch_with_compiler_errors, clang::SkipFunctionBodiesScope::None, - single_file_parse, user_files_are_volatile, for_serialization, clang::None, &err_unit, - nullptr)); - - // Early failures in LoadFromCommandLine may return with ErrUnit unset. - if (!ast_unit && !err_unit) { - return ErrorFileSystem; - } - - if (diags->getClient()->getNumErrors() > 0) { - if (ast_unit) { - err_unit = std::unique_ptr<clang::ASTUnit>(reinterpret_cast<clang::ASTUnit *>(ast_unit)); - } - - for (clang::ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), - it_end = err_unit->stored_diag_end(); - it != it_end; ++it) - { - switch (it->getLevel()) { - case clang::DiagnosticsEngine::Ignored: - case clang::DiagnosticsEngine::Note: - case clang::DiagnosticsEngine::Remark: - case clang::DiagnosticsEngine::Warning: - continue; - case clang::DiagnosticsEngine::Error: - case clang::DiagnosticsEngine::Fatal: - break; - } - llvm::StringRef msg_str_ref = it->getMessage(); - Buf *msg = string_ref_to_buf(msg_str_ref); - clang::FullSourceLoc fsl = it->getLocation(); - if (fsl.hasManager()) { - clang::FileID file_id = fsl.getFileID(); - clang::StringRef filename = fsl.getManager().getFilename(fsl); - unsigned line = fsl.getSpellingLineNumber() - 1; - unsigned column = fsl.getSpellingColumnNumber() - 1; - unsigned offset = fsl.getManager().getFileOffset(fsl); - const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); - Buf *path; - if (filename.empty()) { - path = buf_alloc(); - } else { - path = string_ref_to_buf(filename); - } - - ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); - - c->errors->append(err_msg); - } else { - // NOTE the only known way this gets triggered right now is if you have a lot of errors - // clang emits "too many errors emitted, stopping now" - fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg)); - } - } - + ZigClangASTUnit *ast_unit = ZigClangLoadFromCommandLine(args_begin, args_end, errors_ptr, errors_len, + resources_path); + if (ast_unit == nullptr) { + if (*errors_len == 0) return ErrorNoMem; return ErrorCCompileErrors; } @@ -5059,5 +5094,7 @@ Error parse_h_file(AstNode **out_root_node, ZigList<ErrorMsg *> *errors, const c *out_root_node = c->root; + ZigClangASTUnit_delete(ast_unit); + return ErrorNone; } diff --git a/src/translate_c.hpp b/src/translate_c.hpp index 21461d2813..4eac26ddb5 100644 --- a/src/translate_c.hpp +++ b/src/translate_c.hpp @@ -11,7 +11,9 @@ #include "all_types.hpp" -Error parse_h_file(AstNode **out_root_node, ZigList<ErrorMsg *> *errors, const char *target_file, - CodeGen *codegen, Buf *tmp_dep_file); +Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, + Stage2ErrorMsg **errors_ptr, size_t *errors_len, + const char **args_begin, const char **args_end, + Stage2TranslateMode mode, const char *resources_path); #endif diff --git a/src/userland.cpp b/src/userland.cpp new file mode 100644 index 0000000000..20740711e5 --- /dev/null +++ b/src/userland.cpp @@ -0,0 +1,44 @@ +// This file is a shim for zig1. The real implementations of these are in +// src-self-hosted/stage1.zig + +#include "userland.h" +#include "ast_render.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +Error stage2_translate_c(struct Stage2Ast **out_ast, + struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len, + const char **args_begin, const char **args_end, enum Stage2TranslateMode mode, + const char *resources_path) +{ + const char *msg = "stage0 called stage2_translate_c"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len) { + const char *msg = "stage0 called stage2_free_clang_errors"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_zen(const char **ptr, size_t *len) { + const char *msg = "stage0 called stage2_zen"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_panic(const char *ptr, size_t len) { + fwrite(ptr, 1, len, stderr); + fprintf(stderr, "\n"); + fflush(stderr); + abort(); +} + +void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file) { + const char *msg = "stage0 called stage2_render_ast"; + stage2_panic(msg, strlen(msg)); +} + +int stage2_fmt(int argc, char **argv) { + const char *msg = "stage0 called stage2_fmt"; + stage2_panic(msg, strlen(msg)); +} diff --git a/src/userland.h b/src/userland.h new file mode 100644 index 0000000000..e48b80d0c2 --- /dev/null +++ b/src/userland.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_USERLAND_H +#define ZIG_USERLAND_H + +#include <stddef.h> +#include <stdio.h> + +#ifdef __cplusplus +#define ZIG_EXTERN_C extern "C" +#else +#define ZIG_EXTERN_C +#endif + +#if defined(_MSC_VER) +#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#endif + +// ABI warning: the types and declarations in this file must match both those in +// userland.cpp and src-self-hosted/stage1.zig. + +// ABI warning +enum Error { + ErrorNone, + ErrorNoMem, + ErrorInvalidFormat, + ErrorSemanticAnalyzeFail, + ErrorAccess, + ErrorInterrupted, + ErrorSystemResources, + ErrorFileNotFound, + ErrorFileSystem, + ErrorFileTooBig, + ErrorDivByZero, + ErrorOverflow, + ErrorPathAlreadyExists, + ErrorUnexpected, + ErrorExactDivRemainder, + ErrorNegativeDenominator, + ErrorShiftedOutOneBits, + ErrorCCompileErrors, + ErrorEndOfFile, + ErrorIsDir, + ErrorNotDir, + ErrorUnsupportedOperatingSystem, + ErrorSharingViolation, + ErrorPipeBusy, + ErrorPrimitiveTypeNotFound, + ErrorCacheUnavailable, + ErrorPathTooLong, + ErrorCCompilerCannotFindFile, + ErrorReadingDepFile, + ErrorInvalidDepFile, + ErrorMissingArchitecture, + ErrorMissingOperatingSystem, + ErrorUnknownArchitecture, + ErrorUnknownOperatingSystem, + ErrorUnknownABI, + ErrorInvalidFilename, + ErrorDiskQuota, + ErrorDiskSpace, + ErrorUnexpectedWriteFailure, + ErrorUnexpectedSeekFailure, + ErrorUnexpectedFileTruncationFailure, + ErrorUnimplemented, + ErrorOperationAborted, + ErrorBrokenPipe, + ErrorNoSpaceLeft, +}; + +// ABI warning +enum Stage2TranslateMode { + Stage2TranslateModeImport, + Stage2TranslateModeTranslate, +}; + +// ABI warning +struct Stage2ErrorMsg { + const char *filename_ptr; // can be null + size_t filename_len; + const char *msg_ptr; + size_t msg_len; + const char *source; // valid until the ASTUnit is freed. can be null + unsigned line; // 0 based + unsigned column; // 0 based + unsigned offset; // byte offset into source +}; + +// ABI warning +struct Stage2Ast; + +// ABI warning +ZIG_EXTERN_C enum Error stage2_translate_c(struct Stage2Ast **out_ast, + struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len, + const char **args_begin, const char **args_end, enum Stage2TranslateMode mode, + const char *resources_path); + +// ABI warning +ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len); + +// ABI warning +ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file); + +// ABI warning +ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len); + +// ABI warning +ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); + +// ABI warning +ZIG_EXTERN_C int stage2_fmt(int argc, char **argv); + +#endif diff --git a/src/util.cpp b/src/util.cpp index 192d74e766..9a6a382993 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -10,17 +10,25 @@ #include <stdarg.h> #include "util.hpp" +#include "userland.h" void zig_panic(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); - fprintf(stderr, "\n"); fflush(stderr); va_end(ap); + stage2_panic(nullptr, 0); abort(); } +void assert(bool ok) { + if (!ok) { + const char *msg = "Assertion failed. This is a bug in the Zig compiler."; + stage2_panic(msg, strlen(msg)); + } +} + uint32_t int_hash(int i) { return (uint32_t)(i % UINT32_MAX); } diff --git a/src/util.hpp b/src/util.hpp index 64c85033e3..f1942dd480 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -48,6 +48,10 @@ void zig_panic(const char *format, ...); #define zig_unreachable() zig_panic("unreachable: %s:%s:%d", __FILE__, __func__, __LINE__) +// Assertions in stage1 are always on, and they call zig @panic. +#undef assert +void assert(bool ok); + #if defined(_MSC_VER) static inline int clzll(unsigned long long mask) { unsigned long lz; diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 230c3c3116..b558fa318c 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -28,41 +28,41 @@ #endif // Detect additions to the enum -void zig2clang_BO(ZigClangBO op) { +void ZigClang_detect_enum_BO(clang::BinaryOperatorKind op) { switch (op) { - case ZigClangBO_PtrMemD: - case ZigClangBO_PtrMemI: - case ZigClangBO_Cmp: - case ZigClangBO_Mul: - case ZigClangBO_Div: - case ZigClangBO_Rem: - case ZigClangBO_Add: - case ZigClangBO_Sub: - case ZigClangBO_Shl: - case ZigClangBO_Shr: - case ZigClangBO_LT: - case ZigClangBO_GT: - case ZigClangBO_LE: - case ZigClangBO_GE: - case ZigClangBO_EQ: - case ZigClangBO_NE: - case ZigClangBO_And: - case ZigClangBO_Xor: - case ZigClangBO_Or: - case ZigClangBO_LAnd: - case ZigClangBO_LOr: - case ZigClangBO_Assign: - case ZigClangBO_Comma: - case ZigClangBO_MulAssign: - case ZigClangBO_DivAssign: - case ZigClangBO_RemAssign: - case ZigClangBO_AddAssign: - case ZigClangBO_SubAssign: - case ZigClangBO_ShlAssign: - case ZigClangBO_ShrAssign: - case ZigClangBO_AndAssign: - case ZigClangBO_XorAssign: - case ZigClangBO_OrAssign: + case clang::BO_PtrMemD: + case clang::BO_PtrMemI: + case clang::BO_Cmp: + case clang::BO_Mul: + case clang::BO_Div: + case clang::BO_Rem: + case clang::BO_Add: + case clang::BO_Sub: + case clang::BO_Shl: + case clang::BO_Shr: + case clang::BO_LT: + case clang::BO_GT: + case clang::BO_LE: + case clang::BO_GE: + case clang::BO_EQ: + case clang::BO_NE: + case clang::BO_And: + case clang::BO_Xor: + case clang::BO_Or: + case clang::BO_LAnd: + case clang::BO_LOr: + case clang::BO_Assign: + case clang::BO_Comma: + case clang::BO_MulAssign: + case clang::BO_DivAssign: + case clang::BO_RemAssign: + case clang::BO_AddAssign: + case clang::BO_SubAssign: + case clang::BO_ShlAssign: + case clang::BO_ShrAssign: + case clang::BO_AndAssign: + case clang::BO_XorAssign: + case clang::BO_OrAssign: break; } } @@ -101,23 +101,23 @@ static_assert((clang::BinaryOperatorKind)ZigClangBO_SubAssign == clang::BO_SubAs static_assert((clang::BinaryOperatorKind)ZigClangBO_Xor == clang::BO_Xor, ""); static_assert((clang::BinaryOperatorKind)ZigClangBO_XorAssign == clang::BO_XorAssign, ""); -// This function detects additions to the enum -void zig2clang_UO(ZigClangUO op) { +// Detect additions to the enum +void ZigClang_detect_enum_UO(clang::UnaryOperatorKind op) { switch (op) { - case ZigClangUO_AddrOf: - case ZigClangUO_Coawait: - case ZigClangUO_Deref: - case ZigClangUO_Extension: - case ZigClangUO_Imag: - case ZigClangUO_LNot: - case ZigClangUO_Minus: - case ZigClangUO_Not: - case ZigClangUO_Plus: - case ZigClangUO_PostDec: - case ZigClangUO_PostInc: - case ZigClangUO_PreDec: - case ZigClangUO_PreInc: - case ZigClangUO_Real: + case clang::UO_AddrOf: + case clang::UO_Coawait: + case clang::UO_Deref: + case clang::UO_Extension: + case clang::UO_Imag: + case clang::UO_LNot: + case clang::UO_Minus: + case clang::UO_Not: + case clang::UO_Plus: + case clang::UO_PostDec: + case clang::UO_PostInc: + case clang::UO_PreDec: + case clang::UO_PreInc: + case clang::UO_Real: break; } } @@ -137,6 +137,1125 @@ static_assert((clang::UnaryOperatorKind)ZigClangUO_PreDec == clang::UO_PreDec, " static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, ""); static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, ""); +// Detect additions to the enum +void ZigClang_detect_enum_CK(clang::CastKind x) { + switch (x) { + case clang::CK_ARCConsumeObject: + case clang::CK_ARCExtendBlockObject: + case clang::CK_ARCProduceObject: + case clang::CK_ARCReclaimReturnedObject: + case clang::CK_AddressSpaceConversion: + case clang::CK_AnyPointerToBlockPointerCast: + case clang::CK_ArrayToPointerDecay: + case clang::CK_AtomicToNonAtomic: + case clang::CK_BaseToDerived: + case clang::CK_BaseToDerivedMemberPointer: + case clang::CK_BitCast: + case clang::CK_BlockPointerToObjCPointerCast: + case clang::CK_BooleanToSignedIntegral: + case clang::CK_BuiltinFnToFnPtr: + case clang::CK_CPointerToObjCPointerCast: + case clang::CK_ConstructorConversion: + case clang::CK_CopyAndAutoreleaseBlockObject: + case clang::CK_Dependent: + case clang::CK_DerivedToBase: + case clang::CK_DerivedToBaseMemberPointer: + case clang::CK_Dynamic: + case clang::CK_FloatingCast: + case clang::CK_FloatingComplexCast: + case clang::CK_FloatingComplexToBoolean: + case clang::CK_FloatingComplexToIntegralComplex: + case clang::CK_FloatingComplexToReal: + case clang::CK_FloatingRealToComplex: + case clang::CK_FloatingToBoolean: + case clang::CK_FloatingToIntegral: + case clang::CK_FunctionToPointerDecay: + case clang::CK_IntToOCLSampler: + case clang::CK_IntegralCast: + case clang::CK_IntegralComplexCast: + case clang::CK_IntegralComplexToBoolean: + case clang::CK_IntegralComplexToFloatingComplex: + case clang::CK_IntegralComplexToReal: + case clang::CK_IntegralRealToComplex: + case clang::CK_IntegralToBoolean: + case clang::CK_IntegralToFloating: + case clang::CK_IntegralToPointer: + case clang::CK_LValueBitCast: + case clang::CK_LValueToRValue: + case clang::CK_MemberPointerToBoolean: + case clang::CK_NoOp: + case clang::CK_NonAtomicToAtomic: + case clang::CK_NullToMemberPointer: + case clang::CK_NullToPointer: + case clang::CK_ObjCObjectLValueCast: + case clang::CK_PointerToBoolean: + case clang::CK_PointerToIntegral: + case clang::CK_ReinterpretMemberPointer: + case clang::CK_ToUnion: + case clang::CK_ToVoid: + case clang::CK_UncheckedDerivedToBase: + case clang::CK_UserDefinedConversion: + case clang::CK_VectorSplat: + case clang::CK_ZeroToOCLOpaqueType: + case clang::CK_FixedPointCast: + case clang::CK_FixedPointToBoolean: + break; + } +}; + +static_assert((clang::CastKind)ZigClangCK_Dependent == clang::CK_Dependent, ""); +static_assert((clang::CastKind)ZigClangCK_BitCast == clang::CK_BitCast, ""); +static_assert((clang::CastKind)ZigClangCK_LValueBitCast == clang::CK_LValueBitCast, ""); +static_assert((clang::CastKind)ZigClangCK_LValueToRValue == clang::CK_LValueToRValue, ""); +static_assert((clang::CastKind)ZigClangCK_NoOp == clang::CK_NoOp, ""); +static_assert((clang::CastKind)ZigClangCK_BaseToDerived == clang::CK_BaseToDerived, ""); +static_assert((clang::CastKind)ZigClangCK_DerivedToBase == clang::CK_DerivedToBase, ""); +static_assert((clang::CastKind)ZigClangCK_UncheckedDerivedToBase == clang::CK_UncheckedDerivedToBase, ""); +static_assert((clang::CastKind)ZigClangCK_Dynamic == clang::CK_Dynamic, ""); +static_assert((clang::CastKind)ZigClangCK_ToUnion == clang::CK_ToUnion, ""); +static_assert((clang::CastKind)ZigClangCK_ArrayToPointerDecay == clang::CK_ArrayToPointerDecay, ""); +static_assert((clang::CastKind)ZigClangCK_FunctionToPointerDecay == clang::CK_FunctionToPointerDecay, ""); +static_assert((clang::CastKind)ZigClangCK_NullToPointer == clang::CK_NullToPointer, ""); +static_assert((clang::CastKind)ZigClangCK_NullToMemberPointer == clang::CK_NullToMemberPointer, ""); +static_assert((clang::CastKind)ZigClangCK_BaseToDerivedMemberPointer == clang::CK_BaseToDerivedMemberPointer, ""); +static_assert((clang::CastKind)ZigClangCK_DerivedToBaseMemberPointer == clang::CK_DerivedToBaseMemberPointer, ""); +static_assert((clang::CastKind)ZigClangCK_MemberPointerToBoolean == clang::CK_MemberPointerToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_ReinterpretMemberPointer == clang::CK_ReinterpretMemberPointer, ""); +static_assert((clang::CastKind)ZigClangCK_UserDefinedConversion == clang::CK_UserDefinedConversion, ""); +static_assert((clang::CastKind)ZigClangCK_ConstructorConversion == clang::CK_ConstructorConversion, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralToPointer == clang::CK_IntegralToPointer, ""); +static_assert((clang::CastKind)ZigClangCK_PointerToIntegral == clang::CK_PointerToIntegral, ""); +static_assert((clang::CastKind)ZigClangCK_PointerToBoolean == clang::CK_PointerToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_ToVoid == clang::CK_ToVoid, ""); +static_assert((clang::CastKind)ZigClangCK_VectorSplat == clang::CK_VectorSplat, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralCast == clang::CK_IntegralCast, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralToBoolean == clang::CK_IntegralToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralToFloating == clang::CK_IntegralToFloating, ""); +static_assert((clang::CastKind)ZigClangCK_FixedPointCast == clang::CK_FixedPointCast, ""); +static_assert((clang::CastKind)ZigClangCK_FixedPointToBoolean == clang::CK_FixedPointToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingToIntegral == clang::CK_FloatingToIntegral, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingToBoolean == clang::CK_FloatingToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_BooleanToSignedIntegral == clang::CK_BooleanToSignedIntegral, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingCast == clang::CK_FloatingCast, ""); +static_assert((clang::CastKind)ZigClangCK_CPointerToObjCPointerCast == clang::CK_CPointerToObjCPointerCast, ""); +static_assert((clang::CastKind)ZigClangCK_BlockPointerToObjCPointerCast == clang::CK_BlockPointerToObjCPointerCast, ""); +static_assert((clang::CastKind)ZigClangCK_AnyPointerToBlockPointerCast == clang::CK_AnyPointerToBlockPointerCast, ""); +static_assert((clang::CastKind)ZigClangCK_ObjCObjectLValueCast == clang::CK_ObjCObjectLValueCast, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingRealToComplex == clang::CK_FloatingRealToComplex, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingComplexToReal == clang::CK_FloatingComplexToReal, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingComplexToBoolean == clang::CK_FloatingComplexToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingComplexCast == clang::CK_FloatingComplexCast, ""); +static_assert((clang::CastKind)ZigClangCK_FloatingComplexToIntegralComplex == clang::CK_FloatingComplexToIntegralComplex, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralRealToComplex == clang::CK_IntegralRealToComplex, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralComplexToReal == clang::CK_IntegralComplexToReal, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralComplexToBoolean == clang::CK_IntegralComplexToBoolean, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralComplexCast == clang::CK_IntegralComplexCast, ""); +static_assert((clang::CastKind)ZigClangCK_IntegralComplexToFloatingComplex == clang::CK_IntegralComplexToFloatingComplex, ""); +static_assert((clang::CastKind)ZigClangCK_ARCProduceObject == clang::CK_ARCProduceObject, ""); +static_assert((clang::CastKind)ZigClangCK_ARCConsumeObject == clang::CK_ARCConsumeObject, ""); +static_assert((clang::CastKind)ZigClangCK_ARCReclaimReturnedObject == clang::CK_ARCReclaimReturnedObject, ""); +static_assert((clang::CastKind)ZigClangCK_ARCExtendBlockObject == clang::CK_ARCExtendBlockObject, ""); +static_assert((clang::CastKind)ZigClangCK_AtomicToNonAtomic == clang::CK_AtomicToNonAtomic, ""); +static_assert((clang::CastKind)ZigClangCK_NonAtomicToAtomic == clang::CK_NonAtomicToAtomic, ""); +static_assert((clang::CastKind)ZigClangCK_CopyAndAutoreleaseBlockObject == clang::CK_CopyAndAutoreleaseBlockObject, ""); +static_assert((clang::CastKind)ZigClangCK_BuiltinFnToFnPtr == clang::CK_BuiltinFnToFnPtr, ""); +static_assert((clang::CastKind)ZigClangCK_ZeroToOCLOpaqueType == clang::CK_ZeroToOCLOpaqueType, ""); +static_assert((clang::CastKind)ZigClangCK_AddressSpaceConversion == clang::CK_AddressSpaceConversion, ""); +static_assert((clang::CastKind)ZigClangCK_IntToOCLSampler == clang::CK_IntToOCLSampler, ""); + +// Detect additions to the enum +void ZigClang_detect_enum_TypeClass(clang::Type::TypeClass ty) { + switch (ty) { + case clang::Type::Builtin: + case clang::Type::Complex: + case clang::Type::Pointer: + case clang::Type::BlockPointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: + case clang::Type::ConstantArray: + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::DependentAddressSpace: + case clang::Type::Vector: + case clang::Type::DependentVector: + case clang::Type::ExtVector: + case clang::Type::FunctionProto: + case clang::Type::FunctionNoProto: + case clang::Type::UnresolvedUsing: + case clang::Type::Paren: + case clang::Type::Typedef: + case clang::Type::Adjusted: + case clang::Type::Decayed: + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: + case clang::Type::UnaryTransform: + case clang::Type::Record: + case clang::Type::Enum: + case clang::Type::Elaborated: + case clang::Type::Attributed: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::TemplateSpecialization: + case clang::Type::Auto: + case clang::Type::DeducedTemplateSpecialization: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCTypeParam: + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + case clang::Type::ObjCObjectPointer: + case clang::Type::Pipe: + case clang::Type::Atomic: + break; + } +} + +static_assert((clang::Type::TypeClass)ZigClangType_Builtin == clang::Type::Builtin, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Complex == clang::Type::Complex, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Pointer == clang::Type::Pointer, ""); +static_assert((clang::Type::TypeClass)ZigClangType_BlockPointer == clang::Type::BlockPointer, ""); +static_assert((clang::Type::TypeClass)ZigClangType_LValueReference == clang::Type::LValueReference, ""); +static_assert((clang::Type::TypeClass)ZigClangType_RValueReference == clang::Type::RValueReference, ""); +static_assert((clang::Type::TypeClass)ZigClangType_MemberPointer == clang::Type::MemberPointer, ""); +static_assert((clang::Type::TypeClass)ZigClangType_ConstantArray == clang::Type::ConstantArray, ""); +static_assert((clang::Type::TypeClass)ZigClangType_IncompleteArray == clang::Type::IncompleteArray, ""); +static_assert((clang::Type::TypeClass)ZigClangType_VariableArray == clang::Type::VariableArray, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DependentSizedArray == clang::Type::DependentSizedArray, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DependentSizedExtVector == clang::Type::DependentSizedExtVector, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DependentAddressSpace == clang::Type::DependentAddressSpace, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Vector == clang::Type::Vector, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DependentVector == clang::Type::DependentVector, ""); +static_assert((clang::Type::TypeClass)ZigClangType_ExtVector == clang::Type::ExtVector, ""); +static_assert((clang::Type::TypeClass)ZigClangType_FunctionProto == clang::Type::FunctionProto, ""); +static_assert((clang::Type::TypeClass)ZigClangType_FunctionNoProto == clang::Type::FunctionNoProto, ""); +static_assert((clang::Type::TypeClass)ZigClangType_UnresolvedUsing == clang::Type::UnresolvedUsing, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Paren == clang::Type::Paren, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Typedef == clang::Type::Typedef, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Adjusted == clang::Type::Adjusted, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Decayed == clang::Type::Decayed, ""); +static_assert((clang::Type::TypeClass)ZigClangType_TypeOfExpr == clang::Type::TypeOfExpr, ""); +static_assert((clang::Type::TypeClass)ZigClangType_TypeOf == clang::Type::TypeOf, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Decltype == clang::Type::Decltype, ""); +static_assert((clang::Type::TypeClass)ZigClangType_UnaryTransform == clang::Type::UnaryTransform, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Record == clang::Type::Record, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Enum == clang::Type::Enum, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Elaborated == clang::Type::Elaborated, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Attributed == clang::Type::Attributed, ""); +static_assert((clang::Type::TypeClass)ZigClangType_TemplateTypeParm == clang::Type::TemplateTypeParm, ""); +static_assert((clang::Type::TypeClass)ZigClangType_SubstTemplateTypeParm == clang::Type::SubstTemplateTypeParm, ""); +static_assert((clang::Type::TypeClass)ZigClangType_SubstTemplateTypeParmPack == clang::Type::SubstTemplateTypeParmPack, ""); +static_assert((clang::Type::TypeClass)ZigClangType_TemplateSpecialization == clang::Type::TemplateSpecialization, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Auto == clang::Type::Auto, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DeducedTemplateSpecialization == clang::Type::DeducedTemplateSpecialization, ""); +static_assert((clang::Type::TypeClass)ZigClangType_InjectedClassName == clang::Type::InjectedClassName, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DependentName == clang::Type::DependentName, ""); +static_assert((clang::Type::TypeClass)ZigClangType_DependentTemplateSpecialization == clang::Type::DependentTemplateSpecialization, ""); +static_assert((clang::Type::TypeClass)ZigClangType_PackExpansion == clang::Type::PackExpansion, ""); +static_assert((clang::Type::TypeClass)ZigClangType_ObjCTypeParam == clang::Type::ObjCTypeParam, ""); +static_assert((clang::Type::TypeClass)ZigClangType_ObjCObject == clang::Type::ObjCObject, ""); +static_assert((clang::Type::TypeClass)ZigClangType_ObjCInterface == clang::Type::ObjCInterface, ""); +static_assert((clang::Type::TypeClass)ZigClangType_ObjCObjectPointer == clang::Type::ObjCObjectPointer, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Pipe == clang::Type::Pipe, ""); +static_assert((clang::Type::TypeClass)ZigClangType_Atomic == clang::Type::Atomic, ""); + +// Detect additions to the enum +void ZigClang_detect_enum_StmtClass(clang::Stmt::StmtClass x) { + switch (x) { + case clang::Stmt::NoStmtClass: + case clang::Stmt::NullStmtClass: + case clang::Stmt::CompoundStmtClass: + case clang::Stmt::LabelStmtClass: + case clang::Stmt::AttributedStmtClass: + case clang::Stmt::IfStmtClass: + case clang::Stmt::SwitchStmtClass: + case clang::Stmt::WhileStmtClass: + case clang::Stmt::DoStmtClass: + case clang::Stmt::ForStmtClass: + case clang::Stmt::GotoStmtClass: + case clang::Stmt::IndirectGotoStmtClass: + case clang::Stmt::ContinueStmtClass: + case clang::Stmt::BreakStmtClass: + case clang::Stmt::ReturnStmtClass: + case clang::Stmt::DeclStmtClass: + case clang::Stmt::CaseStmtClass: + case clang::Stmt::DefaultStmtClass: + case clang::Stmt::CapturedStmtClass: + case clang::Stmt::GCCAsmStmtClass: + case clang::Stmt::MSAsmStmtClass: + case clang::Stmt::ObjCAtTryStmtClass: + case clang::Stmt::ObjCAtCatchStmtClass: + case clang::Stmt::ObjCAtFinallyStmtClass: + case clang::Stmt::ObjCAtThrowStmtClass: + case clang::Stmt::ObjCAtSynchronizedStmtClass: + case clang::Stmt::ObjCForCollectionStmtClass: + case clang::Stmt::ObjCAutoreleasePoolStmtClass: + case clang::Stmt::CXXCatchStmtClass: + case clang::Stmt::CXXTryStmtClass: + case clang::Stmt::CXXForRangeStmtClass: + case clang::Stmt::CoroutineBodyStmtClass: + case clang::Stmt::CoreturnStmtClass: + case clang::Stmt::PredefinedExprClass: + case clang::Stmt::DeclRefExprClass: + case clang::Stmt::IntegerLiteralClass: + case clang::Stmt::FixedPointLiteralClass: + case clang::Stmt::FloatingLiteralClass: + case clang::Stmt::ImaginaryLiteralClass: + case clang::Stmt::StringLiteralClass: + case clang::Stmt::CharacterLiteralClass: + case clang::Stmt::ParenExprClass: + case clang::Stmt::UnaryOperatorClass: + case clang::Stmt::OffsetOfExprClass: + case clang::Stmt::UnaryExprOrTypeTraitExprClass: + case clang::Stmt::ArraySubscriptExprClass: + case clang::Stmt::OMPArraySectionExprClass: + case clang::Stmt::CallExprClass: + case clang::Stmt::MemberExprClass: + case clang::Stmt::BinaryOperatorClass: + case clang::Stmt::CompoundAssignOperatorClass: + case clang::Stmt::ConditionalOperatorClass: + case clang::Stmt::BinaryConditionalOperatorClass: + case clang::Stmt::ImplicitCastExprClass: + case clang::Stmt::CStyleCastExprClass: + case clang::Stmt::CompoundLiteralExprClass: + case clang::Stmt::ExtVectorElementExprClass: + case clang::Stmt::InitListExprClass: + case clang::Stmt::DesignatedInitExprClass: + case clang::Stmt::DesignatedInitUpdateExprClass: + case clang::Stmt::ImplicitValueInitExprClass: + case clang::Stmt::NoInitExprClass: + case clang::Stmt::ArrayInitLoopExprClass: + case clang::Stmt::ArrayInitIndexExprClass: + case clang::Stmt::ParenListExprClass: + case clang::Stmt::VAArgExprClass: + case clang::Stmt::GenericSelectionExprClass: + case clang::Stmt::PseudoObjectExprClass: + case clang::Stmt::ConstantExprClass: + case clang::Stmt::AtomicExprClass: + case clang::Stmt::AddrLabelExprClass: + case clang::Stmt::StmtExprClass: + case clang::Stmt::ChooseExprClass: + case clang::Stmt::GNUNullExprClass: + case clang::Stmt::CXXOperatorCallExprClass: + case clang::Stmt::CXXMemberCallExprClass: + case clang::Stmt::CXXStaticCastExprClass: + case clang::Stmt::CXXDynamicCastExprClass: + case clang::Stmt::CXXReinterpretCastExprClass: + case clang::Stmt::CXXConstCastExprClass: + case clang::Stmt::CXXFunctionalCastExprClass: + case clang::Stmt::CXXTypeidExprClass: + case clang::Stmt::UserDefinedLiteralClass: + case clang::Stmt::CXXBoolLiteralExprClass: + case clang::Stmt::CXXNullPtrLiteralExprClass: + case clang::Stmt::CXXThisExprClass: + case clang::Stmt::CXXThrowExprClass: + case clang::Stmt::CXXDefaultArgExprClass: + case clang::Stmt::CXXDefaultInitExprClass: + case clang::Stmt::CXXScalarValueInitExprClass: + case clang::Stmt::CXXStdInitializerListExprClass: + case clang::Stmt::CXXNewExprClass: + case clang::Stmt::CXXDeleteExprClass: + case clang::Stmt::CXXPseudoDestructorExprClass: + case clang::Stmt::TypeTraitExprClass: + case clang::Stmt::ArrayTypeTraitExprClass: + case clang::Stmt::ExpressionTraitExprClass: + case clang::Stmt::DependentScopeDeclRefExprClass: + case clang::Stmt::CXXConstructExprClass: + case clang::Stmt::CXXInheritedCtorInitExprClass: + case clang::Stmt::CXXBindTemporaryExprClass: + case clang::Stmt::ExprWithCleanupsClass: + case clang::Stmt::CXXTemporaryObjectExprClass: + case clang::Stmt::CXXUnresolvedConstructExprClass: + case clang::Stmt::CXXDependentScopeMemberExprClass: + case clang::Stmt::UnresolvedLookupExprClass: + case clang::Stmt::UnresolvedMemberExprClass: + case clang::Stmt::CXXNoexceptExprClass: + case clang::Stmt::PackExpansionExprClass: + case clang::Stmt::SizeOfPackExprClass: + case clang::Stmt::SubstNonTypeTemplateParmExprClass: + case clang::Stmt::SubstNonTypeTemplateParmPackExprClass: + case clang::Stmt::FunctionParmPackExprClass: + case clang::Stmt::MaterializeTemporaryExprClass: + case clang::Stmt::LambdaExprClass: + case clang::Stmt::CXXFoldExprClass: + case clang::Stmt::CoawaitExprClass: + case clang::Stmt::DependentCoawaitExprClass: + case clang::Stmt::CoyieldExprClass: + case clang::Stmt::ObjCStringLiteralClass: + case clang::Stmt::ObjCBoxedExprClass: + case clang::Stmt::ObjCArrayLiteralClass: + case clang::Stmt::ObjCDictionaryLiteralClass: + case clang::Stmt::ObjCEncodeExprClass: + case clang::Stmt::ObjCMessageExprClass: + case clang::Stmt::ObjCSelectorExprClass: + case clang::Stmt::ObjCProtocolExprClass: + case clang::Stmt::ObjCIvarRefExprClass: + case clang::Stmt::ObjCPropertyRefExprClass: + case clang::Stmt::ObjCIsaExprClass: + case clang::Stmt::ObjCIndirectCopyRestoreExprClass: + case clang::Stmt::ObjCBoolLiteralExprClass: + case clang::Stmt::ObjCSubscriptRefExprClass: + case clang::Stmt::ObjCAvailabilityCheckExprClass: + case clang::Stmt::ObjCBridgedCastExprClass: + case clang::Stmt::CUDAKernelCallExprClass: + case clang::Stmt::ShuffleVectorExprClass: + case clang::Stmt::ConvertVectorExprClass: + case clang::Stmt::BlockExprClass: + case clang::Stmt::OpaqueValueExprClass: + case clang::Stmt::TypoExprClass: + case clang::Stmt::MSPropertyRefExprClass: + case clang::Stmt::MSPropertySubscriptExprClass: + case clang::Stmt::CXXUuidofExprClass: + case clang::Stmt::SEHTryStmtClass: + case clang::Stmt::SEHExceptStmtClass: + case clang::Stmt::SEHFinallyStmtClass: + case clang::Stmt::SEHLeaveStmtClass: + case clang::Stmt::MSDependentExistsStmtClass: + case clang::Stmt::AsTypeExprClass: + case clang::Stmt::OMPParallelDirectiveClass: + case clang::Stmt::OMPSimdDirectiveClass: + case clang::Stmt::OMPForDirectiveClass: + case clang::Stmt::OMPForSimdDirectiveClass: + case clang::Stmt::OMPSectionsDirectiveClass: + case clang::Stmt::OMPSectionDirectiveClass: + case clang::Stmt::OMPSingleDirectiveClass: + case clang::Stmt::OMPMasterDirectiveClass: + case clang::Stmt::OMPCriticalDirectiveClass: + case clang::Stmt::OMPParallelForDirectiveClass: + case clang::Stmt::OMPParallelForSimdDirectiveClass: + case clang::Stmt::OMPParallelSectionsDirectiveClass: + case clang::Stmt::OMPTaskDirectiveClass: + case clang::Stmt::OMPTaskyieldDirectiveClass: + case clang::Stmt::OMPBarrierDirectiveClass: + case clang::Stmt::OMPTaskwaitDirectiveClass: + case clang::Stmt::OMPTaskgroupDirectiveClass: + case clang::Stmt::OMPFlushDirectiveClass: + case clang::Stmt::OMPOrderedDirectiveClass: + case clang::Stmt::OMPAtomicDirectiveClass: + case clang::Stmt::OMPTargetDirectiveClass: + case clang::Stmt::OMPTargetDataDirectiveClass: + case clang::Stmt::OMPTargetEnterDataDirectiveClass: + case clang::Stmt::OMPTargetExitDataDirectiveClass: + case clang::Stmt::OMPTargetParallelDirectiveClass: + case clang::Stmt::OMPTargetParallelForDirectiveClass: + case clang::Stmt::OMPTargetUpdateDirectiveClass: + case clang::Stmt::OMPTeamsDirectiveClass: + case clang::Stmt::OMPCancellationPointDirectiveClass: + case clang::Stmt::OMPCancelDirectiveClass: + case clang::Stmt::OMPTaskLoopDirectiveClass: + case clang::Stmt::OMPTaskLoopSimdDirectiveClass: + case clang::Stmt::OMPDistributeDirectiveClass: + case clang::Stmt::OMPDistributeParallelForDirectiveClass: + case clang::Stmt::OMPDistributeParallelForSimdDirectiveClass: + case clang::Stmt::OMPDistributeSimdDirectiveClass: + case clang::Stmt::OMPTargetParallelForSimdDirectiveClass: + case clang::Stmt::OMPTargetSimdDirectiveClass: + case clang::Stmt::OMPTeamsDistributeDirectiveClass: + case clang::Stmt::OMPTeamsDistributeSimdDirectiveClass: + case clang::Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: + case clang::Stmt::OMPTeamsDistributeParallelForDirectiveClass: + case clang::Stmt::OMPTargetTeamsDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: + break; + } +} + +static_assert((clang::Stmt::StmtClass)ZigClangStmt_NoStmtClass == clang::Stmt::NoStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_NullStmtClass == clang::Stmt::NullStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CompoundStmtClass == clang::Stmt::CompoundStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_LabelStmtClass == clang::Stmt::LabelStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_AttributedStmtClass == clang::Stmt::AttributedStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_IfStmtClass == clang::Stmt::IfStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SwitchStmtClass == clang::Stmt::SwitchStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_WhileStmtClass == clang::Stmt::WhileStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DoStmtClass == clang::Stmt::DoStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ForStmtClass == clang::Stmt::ForStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_GotoStmtClass == clang::Stmt::GotoStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_IndirectGotoStmtClass == clang::Stmt::IndirectGotoStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ContinueStmtClass == clang::Stmt::ContinueStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_BreakStmtClass == clang::Stmt::BreakStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ReturnStmtClass == clang::Stmt::ReturnStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DeclStmtClass == clang::Stmt::DeclStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CaseStmtClass == clang::Stmt::CaseStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DefaultStmtClass == clang::Stmt::DefaultStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CapturedStmtClass == clang::Stmt::CapturedStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_GCCAsmStmtClass == clang::Stmt::GCCAsmStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_MSAsmStmtClass == clang::Stmt::MSAsmStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAtTryStmtClass == clang::Stmt::ObjCAtTryStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAtCatchStmtClass == clang::Stmt::ObjCAtCatchStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAtFinallyStmtClass == clang::Stmt::ObjCAtFinallyStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAtThrowStmtClass == clang::Stmt::ObjCAtThrowStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAtSynchronizedStmtClass == clang::Stmt::ObjCAtSynchronizedStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCForCollectionStmtClass == clang::Stmt::ObjCForCollectionStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAutoreleasePoolStmtClass == clang::Stmt::ObjCAutoreleasePoolStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXCatchStmtClass == clang::Stmt::CXXCatchStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXTryStmtClass == clang::Stmt::CXXTryStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXForRangeStmtClass == clang::Stmt::CXXForRangeStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CoroutineBodyStmtClass == clang::Stmt::CoroutineBodyStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CoreturnStmtClass == clang::Stmt::CoreturnStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_PredefinedExprClass == clang::Stmt::PredefinedExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DeclRefExprClass == clang::Stmt::DeclRefExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_IntegerLiteralClass == clang::Stmt::IntegerLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_FixedPointLiteralClass == clang::Stmt::FixedPointLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_FloatingLiteralClass == clang::Stmt::FloatingLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ImaginaryLiteralClass == clang::Stmt::ImaginaryLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_StringLiteralClass == clang::Stmt::StringLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CharacterLiteralClass == clang::Stmt::CharacterLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ParenExprClass == clang::Stmt::ParenExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_UnaryOperatorClass == clang::Stmt::UnaryOperatorClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OffsetOfExprClass == clang::Stmt::OffsetOfExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_UnaryExprOrTypeTraitExprClass == clang::Stmt::UnaryExprOrTypeTraitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ArraySubscriptExprClass == clang::Stmt::ArraySubscriptExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPArraySectionExprClass == clang::Stmt::OMPArraySectionExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CallExprClass == clang::Stmt::CallExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_MemberExprClass == clang::Stmt::MemberExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_BinaryOperatorClass == clang::Stmt::BinaryOperatorClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CompoundAssignOperatorClass == clang::Stmt::CompoundAssignOperatorClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ConditionalOperatorClass == clang::Stmt::ConditionalOperatorClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_BinaryConditionalOperatorClass == clang::Stmt::BinaryConditionalOperatorClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ImplicitCastExprClass == clang::Stmt::ImplicitCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CStyleCastExprClass == clang::Stmt::CStyleCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CompoundLiteralExprClass == clang::Stmt::CompoundLiteralExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ExtVectorElementExprClass == clang::Stmt::ExtVectorElementExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_InitListExprClass == clang::Stmt::InitListExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DesignatedInitExprClass == clang::Stmt::DesignatedInitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DesignatedInitUpdateExprClass == clang::Stmt::DesignatedInitUpdateExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ImplicitValueInitExprClass == clang::Stmt::ImplicitValueInitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_NoInitExprClass == clang::Stmt::NoInitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ArrayInitLoopExprClass == clang::Stmt::ArrayInitLoopExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ArrayInitIndexExprClass == clang::Stmt::ArrayInitIndexExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ParenListExprClass == clang::Stmt::ParenListExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_VAArgExprClass == clang::Stmt::VAArgExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_GenericSelectionExprClass == clang::Stmt::GenericSelectionExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_PseudoObjectExprClass == clang::Stmt::PseudoObjectExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ConstantExprClass == clang::Stmt::ConstantExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_AtomicExprClass == clang::Stmt::AtomicExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_AddrLabelExprClass == clang::Stmt::AddrLabelExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_StmtExprClass == clang::Stmt::StmtExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ChooseExprClass == clang::Stmt::ChooseExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_GNUNullExprClass == clang::Stmt::GNUNullExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXOperatorCallExprClass == clang::Stmt::CXXOperatorCallExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXMemberCallExprClass == clang::Stmt::CXXMemberCallExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXStaticCastExprClass == clang::Stmt::CXXStaticCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXDynamicCastExprClass == clang::Stmt::CXXDynamicCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXReinterpretCastExprClass == clang::Stmt::CXXReinterpretCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXConstCastExprClass == clang::Stmt::CXXConstCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXFunctionalCastExprClass == clang::Stmt::CXXFunctionalCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXTypeidExprClass == clang::Stmt::CXXTypeidExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_UserDefinedLiteralClass == clang::Stmt::UserDefinedLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXBoolLiteralExprClass == clang::Stmt::CXXBoolLiteralExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXNullPtrLiteralExprClass == clang::Stmt::CXXNullPtrLiteralExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXThisExprClass == clang::Stmt::CXXThisExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXThrowExprClass == clang::Stmt::CXXThrowExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXDefaultArgExprClass == clang::Stmt::CXXDefaultArgExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXDefaultInitExprClass == clang::Stmt::CXXDefaultInitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXScalarValueInitExprClass == clang::Stmt::CXXScalarValueInitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXStdInitializerListExprClass == clang::Stmt::CXXStdInitializerListExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXNewExprClass == clang::Stmt::CXXNewExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXDeleteExprClass == clang::Stmt::CXXDeleteExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXPseudoDestructorExprClass == clang::Stmt::CXXPseudoDestructorExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_TypeTraitExprClass == clang::Stmt::TypeTraitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ArrayTypeTraitExprClass == clang::Stmt::ArrayTypeTraitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ExpressionTraitExprClass == clang::Stmt::ExpressionTraitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DependentScopeDeclRefExprClass == clang::Stmt::DependentScopeDeclRefExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXConstructExprClass == clang::Stmt::CXXConstructExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXInheritedCtorInitExprClass == clang::Stmt::CXXInheritedCtorInitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXBindTemporaryExprClass == clang::Stmt::CXXBindTemporaryExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ExprWithCleanupsClass == clang::Stmt::ExprWithCleanupsClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXTemporaryObjectExprClass == clang::Stmt::CXXTemporaryObjectExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXUnresolvedConstructExprClass == clang::Stmt::CXXUnresolvedConstructExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXDependentScopeMemberExprClass == clang::Stmt::CXXDependentScopeMemberExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_UnresolvedLookupExprClass == clang::Stmt::UnresolvedLookupExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_UnresolvedMemberExprClass == clang::Stmt::UnresolvedMemberExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXNoexceptExprClass == clang::Stmt::CXXNoexceptExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_PackExpansionExprClass == clang::Stmt::PackExpansionExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SizeOfPackExprClass == clang::Stmt::SizeOfPackExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SubstNonTypeTemplateParmExprClass == clang::Stmt::SubstNonTypeTemplateParmExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SubstNonTypeTemplateParmPackExprClass == clang::Stmt::SubstNonTypeTemplateParmPackExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_FunctionParmPackExprClass == clang::Stmt::FunctionParmPackExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_MaterializeTemporaryExprClass == clang::Stmt::MaterializeTemporaryExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_LambdaExprClass == clang::Stmt::LambdaExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXFoldExprClass == clang::Stmt::CXXFoldExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CoawaitExprClass == clang::Stmt::CoawaitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_DependentCoawaitExprClass == clang::Stmt::DependentCoawaitExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CoyieldExprClass == clang::Stmt::CoyieldExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCStringLiteralClass == clang::Stmt::ObjCStringLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCBoxedExprClass == clang::Stmt::ObjCBoxedExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCArrayLiteralClass == clang::Stmt::ObjCArrayLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCDictionaryLiteralClass == clang::Stmt::ObjCDictionaryLiteralClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCEncodeExprClass == clang::Stmt::ObjCEncodeExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCMessageExprClass == clang::Stmt::ObjCMessageExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCSelectorExprClass == clang::Stmt::ObjCSelectorExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCProtocolExprClass == clang::Stmt::ObjCProtocolExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCIvarRefExprClass == clang::Stmt::ObjCIvarRefExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCPropertyRefExprClass == clang::Stmt::ObjCPropertyRefExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCIsaExprClass == clang::Stmt::ObjCIsaExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCIndirectCopyRestoreExprClass == clang::Stmt::ObjCIndirectCopyRestoreExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCBoolLiteralExprClass == clang::Stmt::ObjCBoolLiteralExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCSubscriptRefExprClass == clang::Stmt::ObjCSubscriptRefExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCAvailabilityCheckExprClass == clang::Stmt::ObjCAvailabilityCheckExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ObjCBridgedCastExprClass == clang::Stmt::ObjCBridgedCastExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CUDAKernelCallExprClass == clang::Stmt::CUDAKernelCallExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ShuffleVectorExprClass == clang::Stmt::ShuffleVectorExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_ConvertVectorExprClass == clang::Stmt::ConvertVectorExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_BlockExprClass == clang::Stmt::BlockExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OpaqueValueExprClass == clang::Stmt::OpaqueValueExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_TypoExprClass == clang::Stmt::TypoExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_MSPropertyRefExprClass == clang::Stmt::MSPropertyRefExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_MSPropertySubscriptExprClass == clang::Stmt::MSPropertySubscriptExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_CXXUuidofExprClass == clang::Stmt::CXXUuidofExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SEHTryStmtClass == clang::Stmt::SEHTryStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SEHExceptStmtClass == clang::Stmt::SEHExceptStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SEHFinallyStmtClass == clang::Stmt::SEHFinallyStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_SEHLeaveStmtClass == clang::Stmt::SEHLeaveStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_MSDependentExistsStmtClass == clang::Stmt::MSDependentExistsStmtClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_AsTypeExprClass == clang::Stmt::AsTypeExprClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPParallelDirectiveClass == clang::Stmt::OMPParallelDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPSimdDirectiveClass == clang::Stmt::OMPSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPForDirectiveClass == clang::Stmt::OMPForDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPForSimdDirectiveClass == clang::Stmt::OMPForSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPSectionsDirectiveClass == clang::Stmt::OMPSectionsDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPSectionDirectiveClass == clang::Stmt::OMPSectionDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPSingleDirectiveClass == clang::Stmt::OMPSingleDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPMasterDirectiveClass == clang::Stmt::OMPMasterDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPCriticalDirectiveClass == clang::Stmt::OMPCriticalDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPParallelForDirectiveClass == clang::Stmt::OMPParallelForDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPParallelForSimdDirectiveClass == clang::Stmt::OMPParallelForSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPParallelSectionsDirectiveClass == clang::Stmt::OMPParallelSectionsDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTaskDirectiveClass == clang::Stmt::OMPTaskDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTaskyieldDirectiveClass == clang::Stmt::OMPTaskyieldDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPBarrierDirectiveClass == clang::Stmt::OMPBarrierDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTaskwaitDirectiveClass == clang::Stmt::OMPTaskwaitDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTaskgroupDirectiveClass == clang::Stmt::OMPTaskgroupDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPFlushDirectiveClass == clang::Stmt::OMPFlushDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPOrderedDirectiveClass == clang::Stmt::OMPOrderedDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPAtomicDirectiveClass == clang::Stmt::OMPAtomicDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetDirectiveClass == clang::Stmt::OMPTargetDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetDataDirectiveClass == clang::Stmt::OMPTargetDataDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetEnterDataDirectiveClass == clang::Stmt::OMPTargetEnterDataDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetExitDataDirectiveClass == clang::Stmt::OMPTargetExitDataDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetParallelDirectiveClass == clang::Stmt::OMPTargetParallelDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetParallelForDirectiveClass == clang::Stmt::OMPTargetParallelForDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetUpdateDirectiveClass == clang::Stmt::OMPTargetUpdateDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTeamsDirectiveClass == clang::Stmt::OMPTeamsDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPCancellationPointDirectiveClass == clang::Stmt::OMPCancellationPointDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPCancelDirectiveClass == clang::Stmt::OMPCancelDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTaskLoopDirectiveClass == clang::Stmt::OMPTaskLoopDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTaskLoopSimdDirectiveClass == clang::Stmt::OMPTaskLoopSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPDistributeDirectiveClass == clang::Stmt::OMPDistributeDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPDistributeParallelForDirectiveClass == clang::Stmt::OMPDistributeParallelForDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPDistributeParallelForSimdDirectiveClass == clang::Stmt::OMPDistributeParallelForSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPDistributeSimdDirectiveClass == clang::Stmt::OMPDistributeSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetParallelForSimdDirectiveClass == clang::Stmt::OMPTargetParallelForSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetSimdDirectiveClass == clang::Stmt::OMPTargetSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTeamsDistributeDirectiveClass == clang::Stmt::OMPTeamsDistributeDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTeamsDistributeSimdDirectiveClass == clang::Stmt::OMPTeamsDistributeSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTeamsDistributeParallelForSimdDirectiveClass == clang::Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTeamsDistributeParallelForDirectiveClass == clang::Stmt::OMPTeamsDistributeParallelForDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetTeamsDirectiveClass == clang::Stmt::OMPTargetTeamsDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetTeamsDistributeDirectiveClass == clang::Stmt::OMPTargetTeamsDistributeDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetTeamsDistributeParallelForDirectiveClass == clang::Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetTeamsDistributeParallelForSimdDirectiveClass == clang::Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass, ""); +static_assert((clang::Stmt::StmtClass)ZigClangStmt_OMPTargetTeamsDistributeSimdDirectiveClass == clang::Stmt::OMPTargetTeamsDistributeSimdDirectiveClass, ""); + +void ZigClang_detect_enum_APValueKind(clang::APValue::ValueKind x) { + switch (x) { + case clang::APValue::Uninitialized: + case clang::APValue::Int: + case clang::APValue::Float: + case clang::APValue::ComplexInt: + case clang::APValue::ComplexFloat: + case clang::APValue::LValue: + case clang::APValue::Vector: + case clang::APValue::Array: + case clang::APValue::Struct: + case clang::APValue::Union: + case clang::APValue::MemberPointer: + case clang::APValue::AddrLabelDiff: + break; + } +} + +static_assert((clang::APValue::ValueKind)ZigClangAPValueUninitialized == clang::APValue::Uninitialized, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueInt == clang::APValue::Int, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueFloat == clang::APValue::Float, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueComplexInt == clang::APValue::ComplexInt, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueComplexFloat == clang::APValue::ComplexFloat, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueLValue == clang::APValue::LValue, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueVector == clang::APValue::Vector, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueArray == clang::APValue::Array, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueStruct == clang::APValue::Struct, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueUnion == clang::APValue::Union, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueMemberPointer == clang::APValue::MemberPointer, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValueAddrLabelDiff == clang::APValue::AddrLabelDiff, ""); + + +void ZigClang_detect_enum_DeclKind(clang::Decl::Kind x) { + switch (x) { + case clang::Decl::AccessSpec: + case clang::Decl::Block: + case clang::Decl::Captured: + case clang::Decl::ClassScopeFunctionSpecialization: + case clang::Decl::Empty: + case clang::Decl::Export: + case clang::Decl::ExternCContext: + case clang::Decl::FileScopeAsm: + case clang::Decl::Friend: + case clang::Decl::FriendTemplate: + case clang::Decl::Import: + case clang::Decl::LinkageSpec: + case clang::Decl::Label: + case clang::Decl::Namespace: + case clang::Decl::NamespaceAlias: + case clang::Decl::ObjCCompatibleAlias: + case clang::Decl::ObjCCategory: + case clang::Decl::ObjCCategoryImpl: + case clang::Decl::ObjCImplementation: + case clang::Decl::ObjCInterface: + case clang::Decl::ObjCProtocol: + case clang::Decl::ObjCMethod: + case clang::Decl::ObjCProperty: + case clang::Decl::BuiltinTemplate: + case clang::Decl::ClassTemplate: + case clang::Decl::FunctionTemplate: + case clang::Decl::TypeAliasTemplate: + case clang::Decl::VarTemplate: + case clang::Decl::TemplateTemplateParm: + case clang::Decl::Enum: + case clang::Decl::Record: + case clang::Decl::CXXRecord: + case clang::Decl::ClassTemplateSpecialization: + case clang::Decl::ClassTemplatePartialSpecialization: + case clang::Decl::TemplateTypeParm: + case clang::Decl::ObjCTypeParam: + case clang::Decl::TypeAlias: + case clang::Decl::Typedef: + case clang::Decl::UnresolvedUsingTypename: + case clang::Decl::Using: + case clang::Decl::UsingDirective: + case clang::Decl::UsingPack: + case clang::Decl::UsingShadow: + case clang::Decl::ConstructorUsingShadow: + case clang::Decl::Binding: + case clang::Decl::Field: + case clang::Decl::ObjCAtDefsField: + case clang::Decl::ObjCIvar: + case clang::Decl::Function: + case clang::Decl::CXXDeductionGuide: + case clang::Decl::CXXMethod: + case clang::Decl::CXXConstructor: + case clang::Decl::CXXConversion: + case clang::Decl::CXXDestructor: + case clang::Decl::MSProperty: + case clang::Decl::NonTypeTemplateParm: + case clang::Decl::Var: + case clang::Decl::Decomposition: + case clang::Decl::ImplicitParam: + case clang::Decl::OMPCapturedExpr: + case clang::Decl::ParmVar: + case clang::Decl::VarTemplateSpecialization: + case clang::Decl::VarTemplatePartialSpecialization: + case clang::Decl::EnumConstant: + case clang::Decl::IndirectField: + case clang::Decl::OMPDeclareReduction: + case clang::Decl::UnresolvedUsingValue: + case clang::Decl::OMPRequires: + case clang::Decl::OMPThreadPrivate: + case clang::Decl::ObjCPropertyImpl: + case clang::Decl::PragmaComment: + case clang::Decl::PragmaDetectMismatch: + case clang::Decl::StaticAssert: + case clang::Decl::TranslationUnit: + break; + } +} + +static_assert((clang::Decl::Kind)ZigClangDeclAccessSpec == clang::Decl::AccessSpec, ""); +static_assert((clang::Decl::Kind)ZigClangDeclBlock == clang::Decl::Block, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCaptured == clang::Decl::Captured, ""); +static_assert((clang::Decl::Kind)ZigClangDeclClassScopeFunctionSpecialization == clang::Decl::ClassScopeFunctionSpecialization, ""); +static_assert((clang::Decl::Kind)ZigClangDeclEmpty == clang::Decl::Empty, ""); +static_assert((clang::Decl::Kind)ZigClangDeclExport == clang::Decl::Export, ""); +static_assert((clang::Decl::Kind)ZigClangDeclExternCContext == clang::Decl::ExternCContext, ""); +static_assert((clang::Decl::Kind)ZigClangDeclFileScopeAsm == clang::Decl::FileScopeAsm, ""); +static_assert((clang::Decl::Kind)ZigClangDeclFriend == clang::Decl::Friend, ""); +static_assert((clang::Decl::Kind)ZigClangDeclFriendTemplate == clang::Decl::FriendTemplate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclImport == clang::Decl::Import, ""); +static_assert((clang::Decl::Kind)ZigClangDeclLinkageSpec == clang::Decl::LinkageSpec, ""); +static_assert((clang::Decl::Kind)ZigClangDeclLabel == clang::Decl::Label, ""); +static_assert((clang::Decl::Kind)ZigClangDeclNamespace == clang::Decl::Namespace, ""); +static_assert((clang::Decl::Kind)ZigClangDeclNamespaceAlias == clang::Decl::NamespaceAlias, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCCompatibleAlias == clang::Decl::ObjCCompatibleAlias, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCCategory == clang::Decl::ObjCCategory, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCCategoryImpl == clang::Decl::ObjCCategoryImpl, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCImplementation == clang::Decl::ObjCImplementation, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCInterface == clang::Decl::ObjCInterface, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCProtocol == clang::Decl::ObjCProtocol, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCMethod == clang::Decl::ObjCMethod, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCProperty == clang::Decl::ObjCProperty, ""); +static_assert((clang::Decl::Kind)ZigClangDeclBuiltinTemplate == clang::Decl::BuiltinTemplate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclClassTemplate == clang::Decl::ClassTemplate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclFunctionTemplate == clang::Decl::FunctionTemplate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclTypeAliasTemplate == clang::Decl::TypeAliasTemplate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclVarTemplate == clang::Decl::VarTemplate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclTemplateTemplateParm == clang::Decl::TemplateTemplateParm, ""); +static_assert((clang::Decl::Kind)ZigClangDeclEnum == clang::Decl::Enum, ""); +static_assert((clang::Decl::Kind)ZigClangDeclRecord == clang::Decl::Record, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCXXRecord == clang::Decl::CXXRecord, ""); +static_assert((clang::Decl::Kind)ZigClangDeclClassTemplateSpecialization == clang::Decl::ClassTemplateSpecialization, ""); +static_assert((clang::Decl::Kind)ZigClangDeclClassTemplatePartialSpecialization == clang::Decl::ClassTemplatePartialSpecialization, ""); +static_assert((clang::Decl::Kind)ZigClangDeclTemplateTypeParm == clang::Decl::TemplateTypeParm, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCTypeParam == clang::Decl::ObjCTypeParam, ""); +static_assert((clang::Decl::Kind)ZigClangDeclTypeAlias == clang::Decl::TypeAlias, ""); +static_assert((clang::Decl::Kind)ZigClangDeclTypedef == clang::Decl::Typedef, ""); +static_assert((clang::Decl::Kind)ZigClangDeclUnresolvedUsingTypename == clang::Decl::UnresolvedUsingTypename, ""); +static_assert((clang::Decl::Kind)ZigClangDeclUsing == clang::Decl::Using, ""); +static_assert((clang::Decl::Kind)ZigClangDeclUsingDirective == clang::Decl::UsingDirective, ""); +static_assert((clang::Decl::Kind)ZigClangDeclUsingPack == clang::Decl::UsingPack, ""); +static_assert((clang::Decl::Kind)ZigClangDeclUsingShadow == clang::Decl::UsingShadow, ""); +static_assert((clang::Decl::Kind)ZigClangDeclConstructorUsingShadow == clang::Decl::ConstructorUsingShadow, ""); +static_assert((clang::Decl::Kind)ZigClangDeclBinding == clang::Decl::Binding, ""); +static_assert((clang::Decl::Kind)ZigClangDeclField == clang::Decl::Field, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCAtDefsField == clang::Decl::ObjCAtDefsField, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCIvar == clang::Decl::ObjCIvar, ""); +static_assert((clang::Decl::Kind)ZigClangDeclFunction == clang::Decl::Function, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCXXDeductionGuide == clang::Decl::CXXDeductionGuide, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCXXMethod == clang::Decl::CXXMethod, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCXXConstructor == clang::Decl::CXXConstructor, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCXXConversion == clang::Decl::CXXConversion, ""); +static_assert((clang::Decl::Kind)ZigClangDeclCXXDestructor == clang::Decl::CXXDestructor, ""); +static_assert((clang::Decl::Kind)ZigClangDeclMSProperty == clang::Decl::MSProperty, ""); +static_assert((clang::Decl::Kind)ZigClangDeclNonTypeTemplateParm == clang::Decl::NonTypeTemplateParm, ""); +static_assert((clang::Decl::Kind)ZigClangDeclVar == clang::Decl::Var, ""); +static_assert((clang::Decl::Kind)ZigClangDeclDecomposition == clang::Decl::Decomposition, ""); +static_assert((clang::Decl::Kind)ZigClangDeclImplicitParam == clang::Decl::ImplicitParam, ""); +static_assert((clang::Decl::Kind)ZigClangDeclOMPCapturedExpr == clang::Decl::OMPCapturedExpr, ""); +static_assert((clang::Decl::Kind)ZigClangDeclParmVar == clang::Decl::ParmVar, ""); +static_assert((clang::Decl::Kind)ZigClangDeclVarTemplateSpecialization == clang::Decl::VarTemplateSpecialization, ""); +static_assert((clang::Decl::Kind)ZigClangDeclVarTemplatePartialSpecialization == clang::Decl::VarTemplatePartialSpecialization, ""); +static_assert((clang::Decl::Kind)ZigClangDeclEnumConstant == clang::Decl::EnumConstant, ""); +static_assert((clang::Decl::Kind)ZigClangDeclIndirectField == clang::Decl::IndirectField, ""); +static_assert((clang::Decl::Kind)ZigClangDeclOMPDeclareReduction == clang::Decl::OMPDeclareReduction, ""); +static_assert((clang::Decl::Kind)ZigClangDeclUnresolvedUsingValue == clang::Decl::UnresolvedUsingValue, ""); +static_assert((clang::Decl::Kind)ZigClangDeclOMPRequires == clang::Decl::OMPRequires, ""); +static_assert((clang::Decl::Kind)ZigClangDeclOMPThreadPrivate == clang::Decl::OMPThreadPrivate, ""); +static_assert((clang::Decl::Kind)ZigClangDeclObjCPropertyImpl == clang::Decl::ObjCPropertyImpl, ""); +static_assert((clang::Decl::Kind)ZigClangDeclPragmaComment == clang::Decl::PragmaComment, ""); +static_assert((clang::Decl::Kind)ZigClangDeclPragmaDetectMismatch == clang::Decl::PragmaDetectMismatch, ""); +static_assert((clang::Decl::Kind)ZigClangDeclStaticAssert == clang::Decl::StaticAssert, ""); +static_assert((clang::Decl::Kind)ZigClangDeclTranslationUnit == clang::Decl::TranslationUnit, ""); + +void ZigClang_detect_enum_BuiltinTypeKind(clang::BuiltinType::Kind x) { + switch (x) { + case clang::BuiltinType::OCLImage1dRO: + case clang::BuiltinType::OCLImage1dArrayRO: + case clang::BuiltinType::OCLImage1dBufferRO: + case clang::BuiltinType::OCLImage2dRO: + case clang::BuiltinType::OCLImage2dArrayRO: + case clang::BuiltinType::OCLImage2dDepthRO: + case clang::BuiltinType::OCLImage2dArrayDepthRO: + case clang::BuiltinType::OCLImage2dMSAARO: + case clang::BuiltinType::OCLImage2dArrayMSAARO: + case clang::BuiltinType::OCLImage2dMSAADepthRO: + case clang::BuiltinType::OCLImage2dArrayMSAADepthRO: + case clang::BuiltinType::OCLImage3dRO: + case clang::BuiltinType::OCLImage1dWO: + case clang::BuiltinType::OCLImage1dArrayWO: + case clang::BuiltinType::OCLImage1dBufferWO: + case clang::BuiltinType::OCLImage2dWO: + case clang::BuiltinType::OCLImage2dArrayWO: + case clang::BuiltinType::OCLImage2dDepthWO: + case clang::BuiltinType::OCLImage2dArrayDepthWO: + case clang::BuiltinType::OCLImage2dMSAAWO: + case clang::BuiltinType::OCLImage2dArrayMSAAWO: + case clang::BuiltinType::OCLImage2dMSAADepthWO: + case clang::BuiltinType::OCLImage2dArrayMSAADepthWO: + case clang::BuiltinType::OCLImage3dWO: + case clang::BuiltinType::OCLImage1dRW: + case clang::BuiltinType::OCLImage1dArrayRW: + case clang::BuiltinType::OCLImage1dBufferRW: + case clang::BuiltinType::OCLImage2dRW: + case clang::BuiltinType::OCLImage2dArrayRW: + case clang::BuiltinType::OCLImage2dDepthRW: + case clang::BuiltinType::OCLImage2dArrayDepthRW: + case clang::BuiltinType::OCLImage2dMSAARW: + case clang::BuiltinType::OCLImage2dArrayMSAARW: + case clang::BuiltinType::OCLImage2dMSAADepthRW: + case clang::BuiltinType::OCLImage2dArrayMSAADepthRW: + case clang::BuiltinType::OCLImage3dRW: + case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload: + case clang::BuiltinType::OCLIntelSubgroupAVCImePayload: + case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload: + case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload: + case clang::BuiltinType::OCLIntelSubgroupAVCMceResult: + case clang::BuiltinType::OCLIntelSubgroupAVCImeResult: + case clang::BuiltinType::OCLIntelSubgroupAVCRefResult: + case clang::BuiltinType::OCLIntelSubgroupAVCSicResult: + case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout: + case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout: + case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin: + case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: + case clang::BuiltinType::Void: + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char8: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::ShortAccum: + case clang::BuiltinType::Accum: + case clang::BuiltinType::LongAccum: + case clang::BuiltinType::UShortAccum: + case clang::BuiltinType::UAccum: + case clang::BuiltinType::ULongAccum: + case clang::BuiltinType::ShortFract: + case clang::BuiltinType::Fract: + case clang::BuiltinType::LongFract: + case clang::BuiltinType::UShortFract: + case clang::BuiltinType::UFract: + case clang::BuiltinType::ULongFract: + case clang::BuiltinType::SatShortAccum: + case clang::BuiltinType::SatAccum: + case clang::BuiltinType::SatLongAccum: + case clang::BuiltinType::SatUShortAccum: + case clang::BuiltinType::SatUAccum: + case clang::BuiltinType::SatULongAccum: + case clang::BuiltinType::SatShortFract: + case clang::BuiltinType::SatFract: + case clang::BuiltinType::SatLongFract: + case clang::BuiltinType::SatUShortFract: + case clang::BuiltinType::SatUFract: + case clang::BuiltinType::SatULongFract: + case clang::BuiltinType::Half: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + case clang::BuiltinType::Float16: + case clang::BuiltinType::Float128: + case clang::BuiltinType::NullPtr: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + case clang::BuiltinType::OCLSampler: + case clang::BuiltinType::OCLEvent: + case clang::BuiltinType::OCLClkEvent: + case clang::BuiltinType::OCLQueue: + case clang::BuiltinType::OCLReserveID: + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::PseudoObject: + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::ARCUnbridgedCast: + case clang::BuiltinType::OMPArraySection: + break; + } +} + +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dRO == clang::BuiltinType::OCLImage1dRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dArrayRO == clang::BuiltinType::OCLImage1dArrayRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dBufferRO == clang::BuiltinType::OCLImage1dBufferRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dRO == clang::BuiltinType::OCLImage2dRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayRO == clang::BuiltinType::OCLImage2dArrayRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dDepthRO == clang::BuiltinType::OCLImage2dDepthRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayDepthRO == clang::BuiltinType::OCLImage2dArrayDepthRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dMSAARO == clang::BuiltinType::OCLImage2dMSAARO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayMSAARO == clang::BuiltinType::OCLImage2dArrayMSAARO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dMSAADepthRO == clang::BuiltinType::OCLImage2dMSAADepthRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRO == clang::BuiltinType::OCLImage2dArrayMSAADepthRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage3dRO == clang::BuiltinType::OCLImage3dRO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dWO == clang::BuiltinType::OCLImage1dWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dArrayWO == clang::BuiltinType::OCLImage1dArrayWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dBufferWO == clang::BuiltinType::OCLImage1dBufferWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dWO == clang::BuiltinType::OCLImage2dWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayWO == clang::BuiltinType::OCLImage2dArrayWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dDepthWO == clang::BuiltinType::OCLImage2dDepthWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayDepthWO == clang::BuiltinType::OCLImage2dArrayDepthWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dMSAAWO == clang::BuiltinType::OCLImage2dMSAAWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayMSAAWO == clang::BuiltinType::OCLImage2dArrayMSAAWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dMSAADepthWO == clang::BuiltinType::OCLImage2dMSAADepthWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayMSAADepthWO == clang::BuiltinType::OCLImage2dArrayMSAADepthWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage3dWO == clang::BuiltinType::OCLImage3dWO, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dRW == clang::BuiltinType::OCLImage1dRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dArrayRW == clang::BuiltinType::OCLImage1dArrayRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage1dBufferRW == clang::BuiltinType::OCLImage1dBufferRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dRW == clang::BuiltinType::OCLImage2dRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayRW == clang::BuiltinType::OCLImage2dArrayRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dDepthRW == clang::BuiltinType::OCLImage2dDepthRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayDepthRW == clang::BuiltinType::OCLImage2dArrayDepthRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dMSAARW == clang::BuiltinType::OCLImage2dMSAARW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayMSAARW == clang::BuiltinType::OCLImage2dArrayMSAARW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dMSAADepthRW == clang::BuiltinType::OCLImage2dMSAADepthRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRW == clang::BuiltinType::OCLImage2dArrayMSAADepthRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLImage3dRW == clang::BuiltinType::OCLImage3dRW, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCMcePayload == clang::BuiltinType::OCLIntelSubgroupAVCMcePayload, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCImePayload == clang::BuiltinType::OCLIntelSubgroupAVCImePayload, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCRefPayload == clang::BuiltinType::OCLIntelSubgroupAVCRefPayload, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCSicPayload == clang::BuiltinType::OCLIntelSubgroupAVCSicPayload, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCMceResult == clang::BuiltinType::OCLIntelSubgroupAVCMceResult, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResult == clang::BuiltinType::OCLIntelSubgroupAVCImeResult, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCRefResult == clang::BuiltinType::OCLIntelSubgroupAVCRefResult, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCSicResult == clang::BuiltinType::OCLIntelSubgroupAVCSicResult, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultSingleRefStreamout == clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultDualRefStreamout == clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCImeSingleRefStreamin == clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLIntelSubgroupAVCImeDualRefStreamin == clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeVoid == clang::BuiltinType::Void, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeBool == clang::BuiltinType::Bool, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeChar_U == clang::BuiltinType::Char_U, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUChar == clang::BuiltinType::UChar, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeWChar_U == clang::BuiltinType::WChar_U, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeChar8 == clang::BuiltinType::Char8, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeChar16 == clang::BuiltinType::Char16, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeChar32 == clang::BuiltinType::Char32, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUShort == clang::BuiltinType::UShort, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUInt == clang::BuiltinType::UInt, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeULong == clang::BuiltinType::ULong, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeULongLong == clang::BuiltinType::ULongLong, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUInt128 == clang::BuiltinType::UInt128, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeChar_S == clang::BuiltinType::Char_S, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSChar == clang::BuiltinType::SChar, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeWChar_S == clang::BuiltinType::WChar_S, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeShort == clang::BuiltinType::Short, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeInt == clang::BuiltinType::Int, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeLong == clang::BuiltinType::Long, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeLongLong == clang::BuiltinType::LongLong, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeInt128 == clang::BuiltinType::Int128, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeShortAccum == clang::BuiltinType::ShortAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeAccum == clang::BuiltinType::Accum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeLongAccum == clang::BuiltinType::LongAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUShortAccum == clang::BuiltinType::UShortAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUAccum == clang::BuiltinType::UAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeULongAccum == clang::BuiltinType::ULongAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeShortFract == clang::BuiltinType::ShortFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeFract == clang::BuiltinType::Fract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeLongFract == clang::BuiltinType::LongFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUShortFract == clang::BuiltinType::UShortFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUFract == clang::BuiltinType::UFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeULongFract == clang::BuiltinType::ULongFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatShortAccum == clang::BuiltinType::SatShortAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatAccum == clang::BuiltinType::SatAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatLongAccum == clang::BuiltinType::SatLongAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatUShortAccum == clang::BuiltinType::SatUShortAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatUAccum == clang::BuiltinType::SatUAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatULongAccum == clang::BuiltinType::SatULongAccum, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatShortFract == clang::BuiltinType::SatShortFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatFract == clang::BuiltinType::SatFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatLongFract == clang::BuiltinType::SatLongFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatUShortFract == clang::BuiltinType::SatUShortFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatUFract == clang::BuiltinType::SatUFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeSatULongFract == clang::BuiltinType::SatULongFract, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeHalf == clang::BuiltinType::Half, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeFloat == clang::BuiltinType::Float, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeDouble == clang::BuiltinType::Double, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeLongDouble == clang::BuiltinType::LongDouble, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeFloat16 == clang::BuiltinType::Float16, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeFloat128 == clang::BuiltinType::Float128, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeNullPtr == clang::BuiltinType::NullPtr, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeObjCId == clang::BuiltinType::ObjCId, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeObjCClass == clang::BuiltinType::ObjCClass, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeObjCSel == clang::BuiltinType::ObjCSel, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLSampler == clang::BuiltinType::OCLSampler, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLEvent == clang::BuiltinType::OCLEvent, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLClkEvent == clang::BuiltinType::OCLClkEvent, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLQueue == clang::BuiltinType::OCLQueue, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOCLReserveID == clang::BuiltinType::OCLReserveID, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeDependent == clang::BuiltinType::Dependent, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOverload == clang::BuiltinType::Overload, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeBoundMember == clang::BuiltinType::BoundMember, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypePseudoObject == clang::BuiltinType::PseudoObject, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeUnknownAny == clang::BuiltinType::UnknownAny, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeBuiltinFn == clang::BuiltinType::BuiltinFn, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeARCUnbridgedCast == clang::BuiltinType::ARCUnbridgedCast, ""); +static_assert((clang::BuiltinType::Kind)ZigClangBuiltinTypeOMPArraySection == clang::BuiltinType::OMPArraySection, ""); + +void ZigClang_detect_enum_CallingConv(clang::CallingConv x) { + switch (x) { + case clang::CC_C: + case clang::CC_X86StdCall: + case clang::CC_X86FastCall: + case clang::CC_X86ThisCall: + case clang::CC_X86VectorCall: + case clang::CC_X86Pascal: + case clang::CC_Win64: + case clang::CC_X86_64SysV: + case clang::CC_X86RegCall: + case clang::CC_AAPCS: + case clang::CC_AAPCS_VFP: + case clang::CC_IntelOclBicc: + case clang::CC_SpirFunction: + case clang::CC_OpenCLKernel: + case clang::CC_Swift: + case clang::CC_PreserveMost: + case clang::CC_PreserveAll: + case clang::CC_AArch64VectorCall: + break; + } +} + +static_assert((clang::CallingConv)ZigClangCallingConv_C == clang::CC_C, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86StdCall == clang::CC_X86StdCall, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86FastCall == clang::CC_X86FastCall, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86ThisCall == clang::CC_X86ThisCall, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86VectorCall == clang::CC_X86VectorCall, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86Pascal == clang::CC_X86Pascal, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_Win64 == clang::CC_Win64, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86_64SysV == clang::CC_X86_64SysV, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_X86RegCall == clang::CC_X86RegCall, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_AAPCS == clang::CC_AAPCS, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_AAPCS_VFP == clang::CC_AAPCS_VFP, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_IntelOclBicc == clang::CC_IntelOclBicc, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_SpirFunction == clang::CC_SpirFunction, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_OpenCLKernel == clang::CC_OpenCLKernel, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_Swift == clang::CC_Swift, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_PreserveMost == clang::CC_PreserveMost, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_PreserveAll == clang::CC_PreserveAll, ""); +static_assert((clang::CallingConv)ZigClangCallingConv_AArch64VectorCall == clang::CC_AArch64VectorCall, ""); + +void ZigClang_detect_enum_StorageClass(clang::StorageClass x) { + switch (x) { + case clang::SC_None: + case clang::SC_Extern: + case clang::SC_Static: + case clang::SC_PrivateExtern: + case clang::SC_Auto: + case clang::SC_Register: + break; + } +} + +static_assert((clang::StorageClass)ZigClangStorageClass_None == clang::SC_None, ""); +static_assert((clang::StorageClass)ZigClangStorageClass_Extern == clang::SC_Extern, ""); +static_assert((clang::StorageClass)ZigClangStorageClass_Static == clang::SC_Static, ""); +static_assert((clang::StorageClass)ZigClangStorageClass_PrivateExtern == clang::SC_PrivateExtern, ""); +static_assert((clang::StorageClass)ZigClangStorageClass_Auto == clang::SC_Auto, ""); +static_assert((clang::StorageClass)ZigClangStorageClass_Register == clang::SC_Register, ""); + + static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), ""); static ZigClangSourceLocation bitcast(clang::SourceLocation src) { ZigClangSourceLocation dest; @@ -161,6 +1280,26 @@ static clang::QualType bitcast(ZigClangQualType src) { return dest; } +static_assert(sizeof(ZigClangAPValueLValueBase) == sizeof(clang::APValue::LValueBase), ""); +static ZigClangAPValueLValueBase bitcast(clang::APValue::LValueBase src) { + ZigClangAPValueLValueBase dest; + memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangAPValueLValueBase)); + return dest; +} +static clang::APValue::LValueBase bitcast(ZigClangAPValueLValueBase src) { + clang::APValue::LValueBase dest; + memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangAPValueLValueBase)); + return dest; +} + +static_assert(sizeof(ZigClangCompoundStmt_const_body_iterator) == sizeof(clang::CompoundStmt::const_body_iterator), ""); +static ZigClangCompoundStmt_const_body_iterator bitcast(clang::CompoundStmt::const_body_iterator src) { + ZigClangCompoundStmt_const_body_iterator dest; + memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangCompoundStmt_const_body_iterator)); + return dest; +} + + ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, ZigClangSourceLocation Loc) { @@ -196,6 +1335,10 @@ ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* sel return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T))); } +unsigned ZigClangASTContext_getTypeAlign(const ZigClangASTContext* self, ZigClangQualType T) { + return reinterpret_cast<const clang::ASTContext *>(self)->getTypeAlign(bitcast(T)); +} + ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) { clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext(); return reinterpret_cast<ZigClangASTContext *>(result); @@ -212,3 +1355,477 @@ bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *contex return reinterpret_cast<clang::ASTUnit *>(self)->visitLocalTopLevelDecls(context, reinterpret_cast<bool (*)(void *, const clang::Decl *)>(Fn)); } + +const ZigClangRecordDecl *ZigClangRecordType_getDecl(const ZigClangRecordType *record_ty) { + const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordType *>(record_ty)->getDecl(); + return reinterpret_cast<const ZigClangRecordDecl *>(record_decl); +} + +const ZigClangEnumDecl *ZigClangEnumType_getDecl(const ZigClangEnumType *enum_ty) { + const clang::EnumDecl *enum_decl = reinterpret_cast<const clang::EnumType *>(enum_ty)->getDecl(); + return reinterpret_cast<const ZigClangEnumDecl *>(enum_decl); +} + +const ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const ZigClangRecordDecl *record_decl) { + const clang::TagDecl *tag_decl = reinterpret_cast<const clang::RecordDecl*>(record_decl)->getCanonicalDecl(); + return reinterpret_cast<const ZigClangTagDecl *>(tag_decl); +} + +const ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const ZigClangEnumDecl *enum_decl) { + const clang::TagDecl *tag_decl = reinterpret_cast<const clang::EnumDecl*>(enum_decl)->getCanonicalDecl(); + return reinterpret_cast<const ZigClangTagDecl *>(tag_decl); +} + +const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const ZigClangTypedefNameDecl *self) { + const clang::TypedefNameDecl *decl = reinterpret_cast<const clang::TypedefNameDecl*>(self)->getCanonicalDecl(); + return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl); +} + +const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) { + const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); + const clang::RecordDecl *definition = record_decl->getDefinition(); + return reinterpret_cast<const ZigClangRecordDecl *>(definition); +} + +const ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const ZigClangEnumDecl *zig_enum_decl) { + const clang::EnumDecl *enum_decl = reinterpret_cast<const clang::EnumDecl *>(zig_enum_decl); + const clang::EnumDecl *definition = enum_decl->getDefinition(); + return reinterpret_cast<const ZigClangEnumDecl *>(definition); +} + +bool ZigClangRecordDecl_isUnion(const ZigClangRecordDecl *record_decl) { + return reinterpret_cast<const clang::RecordDecl*>(record_decl)->isUnion(); +} + +bool ZigClangRecordDecl_isStruct(const ZigClangRecordDecl *record_decl) { + return reinterpret_cast<const clang::RecordDecl*>(record_decl)->isStruct(); +} + +bool ZigClangRecordDecl_isAnonymousStructOrUnion(const ZigClangRecordDecl *record_decl) { + return reinterpret_cast<const clang::RecordDecl*>(record_decl)->isAnonymousStructOrUnion(); +} + +const char *ZigClangDecl_getName_bytes_begin(const ZigClangDecl *zig_decl) { + const clang::Decl *decl = reinterpret_cast<const clang::Decl *>(zig_decl); + const clang::NamedDecl *named_decl = static_cast<const clang::NamedDecl *>(decl); + return (const char *)named_decl->getName().bytes_begin(); +} + +ZigClangDeclKind ZigClangDecl_getKind(const struct ZigClangDecl *self) { + auto casted = reinterpret_cast<const clang::Decl *>(self); + return (ZigClangDeclKind)casted->getKind(); +} + +const char *ZigClangDecl_getDeclKindName(const struct ZigClangDecl *self) { + auto casted = reinterpret_cast<const clang::Decl *>(self); + return casted->getDeclKindName(); +} + +ZigClangSourceLocation ZigClangRecordDecl_getLocation(const ZigClangRecordDecl *zig_record_decl) { + const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); + return bitcast(record_decl->getLocation()); +} + +ZigClangSourceLocation ZigClangEnumDecl_getLocation(const ZigClangEnumDecl *self) { + auto casted = reinterpret_cast<const clang::EnumDecl *>(self); + return bitcast(casted->getLocation()); +} + +ZigClangSourceLocation ZigClangTypedefNameDecl_getLocation(const ZigClangTypedefNameDecl *self) { + auto casted = reinterpret_cast<const clang::TypedefNameDecl *>(self); + return bitcast(casted->getLocation()); +} + +ZigClangSourceLocation ZigClangDecl_getLocation(const ZigClangDecl *self) { + auto casted = reinterpret_cast<const clang::Decl *>(self); + return bitcast(casted->getLocation()); +} + +bool ZigClangSourceLocation_eq(ZigClangSourceLocation zig_a, ZigClangSourceLocation zig_b) { + clang::SourceLocation a = bitcast(zig_a); + clang::SourceLocation b = bitcast(zig_b); + return a == b; +} + +ZigClangQualType ZigClangEnumDecl_getIntegerType(const ZigClangEnumDecl *self) { + return bitcast(reinterpret_cast<const clang::EnumDecl *>(self)->getIntegerType()); +} + +struct ZigClangQualType ZigClangFunctionDecl_getType(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast<const clang::FunctionDecl *>(self); + return bitcast(casted->getType()); +} + +struct ZigClangSourceLocation ZigClangFunctionDecl_getLocation(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast<const clang::FunctionDecl *>(self); + return bitcast(casted->getLocation()); +} + +bool ZigClangFunctionDecl_hasBody(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast<const clang::FunctionDecl *>(self); + return casted->hasBody(); +} + +enum ZigClangStorageClass ZigClangFunctionDecl_getStorageClass(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast<const clang::FunctionDecl *>(self); + return (ZigClangStorageClass)casted->getStorageClass(); +} + +const struct ZigClangParmVarDecl *ZigClangFunctionDecl_getParamDecl(const struct ZigClangFunctionDecl *self, + unsigned i) +{ + auto casted = reinterpret_cast<const clang::FunctionDecl *>(self); + const clang::ParmVarDecl *parm_var_decl = casted->getParamDecl(i); + return reinterpret_cast<const ZigClangParmVarDecl *>(parm_var_decl); +} + +const struct ZigClangStmt *ZigClangFunctionDecl_getBody(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast<const clang::FunctionDecl *>(self); + const clang::Stmt *stmt = casted->getBody(); + return reinterpret_cast<const ZigClangStmt *>(stmt); +} + +const ZigClangTypedefNameDecl *ZigClangTypedefType_getDecl(const ZigClangTypedefType *self) { + auto casted = reinterpret_cast<const clang::TypedefType *>(self); + const clang::TypedefNameDecl *name_decl = casted->getDecl(); + return reinterpret_cast<const ZigClangTypedefNameDecl *>(name_decl); +} + +ZigClangQualType ZigClangTypedefNameDecl_getUnderlyingType(const ZigClangTypedefNameDecl *self) { + auto casted = reinterpret_cast<const clang::TypedefNameDecl *>(self); + clang::QualType ty = casted->getUnderlyingType(); + return bitcast(ty); +} + +ZigClangQualType ZigClangQualType_getCanonicalType(ZigClangQualType self) { + clang::QualType qt = bitcast(self); + return bitcast(qt.getCanonicalType()); +} + +const ZigClangType *ZigClangQualType_getTypePtr(ZigClangQualType self) { + clang::QualType qt = bitcast(self); + const clang::Type *ty = qt.getTypePtr(); + return reinterpret_cast<const ZigClangType *>(ty); +} + +void ZigClangQualType_addConst(ZigClangQualType *self) { + reinterpret_cast<clang::QualType *>(self)->addConst(); +} + +bool ZigClangQualType_eq(ZigClangQualType zig_t1, ZigClangQualType zig_t2) { + clang::QualType t1 = bitcast(zig_t1); + clang::QualType t2 = bitcast(zig_t2); + if (t1.isConstQualified() != t2.isConstQualified()) { + return false; + } + if (t1.isVolatileQualified() != t2.isVolatileQualified()) { + return false; + } + if (t1.isRestrictQualified() != t2.isRestrictQualified()) { + return false; + } + return t1.getTypePtr() == t2.getTypePtr(); +} + +bool ZigClangQualType_isConstQualified(ZigClangQualType self) { + clang::QualType qt = bitcast(self); + return qt.isConstQualified(); +} + +bool ZigClangQualType_isVolatileQualified(ZigClangQualType self) { + clang::QualType qt = bitcast(self); + return qt.isVolatileQualified(); +} + +bool ZigClangQualType_isRestrictQualified(ZigClangQualType self) { + clang::QualType qt = bitcast(self); + return qt.isRestrictQualified(); +} + +ZigClangTypeClass ZigClangType_getTypeClass(const ZigClangType *self) { + auto casted = reinterpret_cast<const clang::Type *>(self); + clang::Type::TypeClass tc = casted->getTypeClass(); + return (ZigClangTypeClass)tc; +} + +ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self) { + auto casted = reinterpret_cast<const clang::Type *>(self); + return bitcast(casted->getPointeeType()); +} + +bool ZigClangType_isVoidType(const ZigClangType *self) { + auto casted = reinterpret_cast<const clang::Type *>(self); + return casted->isVoidType(); +} + +const char *ZigClangType_getTypeClassName(const ZigClangType *self) { + auto casted = reinterpret_cast<const clang::Type *>(self); + return casted->getTypeClassName(); +} + +ZigClangSourceLocation ZigClangStmt_getBeginLoc(const ZigClangStmt *self) { + auto casted = reinterpret_cast<const clang::Stmt *>(self); + return bitcast(casted->getBeginLoc()); +} + +bool ZigClangStmt_classof_Expr(const ZigClangStmt *self) { + auto casted = reinterpret_cast<const clang::Stmt *>(self); + return clang::Expr::classof(casted); +} + +ZigClangStmtClass ZigClangStmt_getStmtClass(const ZigClangStmt *self) { + auto casted = reinterpret_cast<const clang::Stmt *>(self); + return (ZigClangStmtClass)casted->getStmtClass(); +} + +ZigClangStmtClass ZigClangExpr_getStmtClass(const ZigClangExpr *self) { + auto casted = reinterpret_cast<const clang::Expr *>(self); + return (ZigClangStmtClass)casted->getStmtClass(); +} + +ZigClangQualType ZigClangExpr_getType(const ZigClangExpr *self) { + auto casted = reinterpret_cast<const clang::Expr *>(self); + return bitcast(casted->getType()); +} + +ZigClangSourceLocation ZigClangExpr_getBeginLoc(const ZigClangExpr *self) { + auto casted = reinterpret_cast<const clang::Expr *>(self); + return bitcast(casted->getBeginLoc()); +} + +ZigClangAPValueKind ZigClangAPValue_getKind(const ZigClangAPValue *self) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + return (ZigClangAPValueKind)casted->getKind(); +} + +const ZigClangAPSInt *ZigClangAPValue_getInt(const ZigClangAPValue *self) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + const llvm::APSInt *result = &casted->getInt(); + return reinterpret_cast<const ZigClangAPSInt *>(result); +} + +unsigned ZigClangAPValue_getArrayInitializedElts(const ZigClangAPValue *self) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + return casted->getArrayInitializedElts(); +} + +const ZigClangAPValue *ZigClangAPValue_getArrayInitializedElt(const ZigClangAPValue *self, unsigned i) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + const clang::APValue *result = &casted->getArrayInitializedElt(i); + return reinterpret_cast<const ZigClangAPValue *>(result); +} + +const ZigClangAPValue *ZigClangAPValue_getArrayFiller(const ZigClangAPValue *self) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + const clang::APValue *result = &casted->getArrayFiller(); + return reinterpret_cast<const ZigClangAPValue *>(result); +} + +unsigned ZigClangAPValue_getArraySize(const ZigClangAPValue *self) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + return casted->getArraySize(); +} + +const ZigClangAPSInt *ZigClangAPSInt_negate(const ZigClangAPSInt *self) { + auto casted = reinterpret_cast<const llvm::APSInt *>(self); + llvm::APSInt *result = new llvm::APSInt(); + *result = *casted; + *result = -*result; + return reinterpret_cast<const ZigClangAPSInt *>(result); +} + +void ZigClangAPSInt_free(const ZigClangAPSInt *self) { + auto casted = reinterpret_cast<const llvm::APSInt *>(self); + delete casted; +} + +bool ZigClangAPSInt_isSigned(const ZigClangAPSInt *self) { + auto casted = reinterpret_cast<const llvm::APSInt *>(self); + return casted->isSigned(); +} + +bool ZigClangAPSInt_isNegative(const ZigClangAPSInt *self) { + auto casted = reinterpret_cast<const llvm::APSInt *>(self); + return casted->isNegative(); +} + +const uint64_t *ZigClangAPSInt_getRawData(const ZigClangAPSInt *self) { + auto casted = reinterpret_cast<const llvm::APSInt *>(self); + return casted->getRawData(); +} + +unsigned ZigClangAPSInt_getNumWords(const ZigClangAPSInt *self) { + auto casted = reinterpret_cast<const llvm::APSInt *>(self); + return casted->getNumWords(); +} + +const ZigClangExpr *ZigClangAPValueLValueBase_dyn_cast_Expr(ZigClangAPValueLValueBase self) { + clang::APValue::LValueBase casted = bitcast(self); + const clang::Expr *expr = casted.dyn_cast<const clang::Expr *>(); + return reinterpret_cast<const ZigClangExpr *>(expr); +} + +ZigClangAPValueLValueBase ZigClangAPValue_getLValueBase(const ZigClangAPValue *self) { + auto casted = reinterpret_cast<const clang::APValue *>(self); + clang::APValue::LValueBase lval_base = casted->getLValueBase(); + return bitcast(lval_base); +} + +ZigClangASTUnit *ZigClangLoadFromCommandLine(const char **args_begin, const char **args_end, + struct Stage2ErrorMsg **errors_ptr, size_t *errors_len, const char *resources_path) +{ + clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions)); + + std::shared_ptr<clang::PCHContainerOperations> pch_container_ops = std::make_shared<clang::PCHContainerOperations>(); + + bool only_local_decls = true; + bool capture_diagnostics = true; + bool user_files_are_volatile = true; + bool allow_pch_with_compiler_errors = false; + bool single_file_parse = false; + bool for_serialization = false; + std::unique_ptr<clang::ASTUnit> *err_unit = new std::unique_ptr<clang::ASTUnit>(); + clang::ASTUnit *ast_unit = clang::ASTUnit::LoadFromCommandLine( + args_begin, args_end, + pch_container_ops, diags, resources_path, + only_local_decls, capture_diagnostics, clang::None, true, 0, clang::TU_Complete, + false, false, allow_pch_with_compiler_errors, clang::SkipFunctionBodiesScope::None, + single_file_parse, user_files_are_volatile, for_serialization, clang::None, err_unit, + nullptr); + + // Early failures in LoadFromCommandLine may return with ErrUnit unset. + if (!ast_unit && !err_unit) { + return nullptr; + } + + if (diags->getClient()->getNumErrors() > 0) { + if (ast_unit) { + *err_unit = std::unique_ptr<clang::ASTUnit>(ast_unit); + } + + size_t cap = 4; + *errors_len = 0; + *errors_ptr = reinterpret_cast<Stage2ErrorMsg*>(malloc(cap * sizeof(Stage2ErrorMsg))); + if (*errors_ptr == nullptr) { + return nullptr; + } + + for (clang::ASTUnit::stored_diag_iterator it = (*err_unit)->stored_diag_begin(), + it_end = (*err_unit)->stored_diag_end(); + it != it_end; ++it) + { + switch (it->getLevel()) { + case clang::DiagnosticsEngine::Ignored: + case clang::DiagnosticsEngine::Note: + case clang::DiagnosticsEngine::Remark: + case clang::DiagnosticsEngine::Warning: + continue; + case clang::DiagnosticsEngine::Error: + case clang::DiagnosticsEngine::Fatal: + break; + } + llvm::StringRef msg_str_ref = it->getMessage(); + if (*errors_len >= cap) { + cap *= 2; + Stage2ErrorMsg *new_errors = reinterpret_cast<Stage2ErrorMsg *>( + realloc(*errors_ptr, cap * sizeof(Stage2ErrorMsg))); + if (new_errors == nullptr) { + free(*errors_ptr); + *errors_ptr = nullptr; + *errors_len = 0; + return nullptr; + } + *errors_ptr = new_errors; + } + Stage2ErrorMsg *msg = *errors_ptr + *errors_len; + *errors_len += 1; + msg->msg_ptr = (const char *)msg_str_ref.bytes_begin(); + msg->msg_len = msg_str_ref.size(); + + clang::FullSourceLoc fsl = it->getLocation(); + if (fsl.hasManager()) { + clang::FileID file_id = fsl.getFileID(); + clang::StringRef filename = fsl.getManager().getFilename(fsl); + if (filename.empty()) { + msg->filename_ptr = nullptr; + } else { + msg->filename_ptr = (const char *)filename.bytes_begin(); + msg->filename_len = filename.size(); + } + msg->source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); + msg->line = fsl.getSpellingLineNumber() - 1; + msg->column = fsl.getSpellingColumnNumber() - 1; + msg->offset = fsl.getManager().getFileOffset(fsl); + } else { + // The only known way this gets triggered right now is if you have a lot of errors + // clang emits "too many errors emitted, stopping now" + msg->filename_ptr = nullptr; + msg->source = nullptr; + } + } + + if (*errors_len == 0) { + free(*errors_ptr); + *errors_ptr = nullptr; + } + + return nullptr; + } + + return reinterpret_cast<ZigClangASTUnit *>(ast_unit); +} + +void ZigClangErrorMsg_delete(Stage2ErrorMsg *ptr, size_t len) { + free(ptr); +} + +void ZigClangASTUnit_delete(struct ZigClangASTUnit *self) { + delete reinterpret_cast<clang::ASTUnit *>(self); +} + +enum ZigClangBuiltinTypeKind ZigClangBuiltinType_getKind(const struct ZigClangBuiltinType *self) { + auto casted = reinterpret_cast<const clang::BuiltinType *>(self); + return (ZigClangBuiltinTypeKind)casted->getKind(); +} + +bool ZigClangFunctionType_getNoReturnAttr(const struct ZigClangFunctionType *self) { + auto casted = reinterpret_cast<const clang::FunctionType *>(self); + return casted->getNoReturnAttr(); +} + +enum ZigClangCallingConv ZigClangFunctionType_getCallConv(const struct ZigClangFunctionType *self) { + auto casted = reinterpret_cast<const clang::FunctionType *>(self); + return (ZigClangCallingConv)casted->getCallConv(); +} + +struct ZigClangQualType ZigClangFunctionType_getReturnType(const struct ZigClangFunctionType *self) { + auto casted = reinterpret_cast<const clang::FunctionType *>(self); + return bitcast(casted->getReturnType()); +} + +bool ZigClangFunctionProtoType_isVariadic(const struct ZigClangFunctionProtoType *self) { + auto casted = reinterpret_cast<const clang::FunctionProtoType *>(self); + return casted->isVariadic(); +} + +unsigned ZigClangFunctionProtoType_getNumParams(const struct ZigClangFunctionProtoType *self) { + auto casted = reinterpret_cast<const clang::FunctionProtoType *>(self); + return casted->getNumParams(); +} + +struct ZigClangQualType ZigClangFunctionProtoType_getParamType(const struct ZigClangFunctionProtoType *self, + unsigned index) +{ + auto casted = reinterpret_cast<const clang::FunctionProtoType *>(self); + return bitcast(casted->getParamType(index)); +} + +ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_begin(const struct ZigClangCompoundStmt *self) { + auto casted = reinterpret_cast<const clang::CompoundStmt *>(self); + return bitcast(casted->body_begin()); +} + +ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_end(const struct ZigClangCompoundStmt *self) { + auto casted = reinterpret_cast<const clang::CompoundStmt *>(self); + return bitcast(casted->body_end()); +} diff --git a/src/zig_clang.h b/src/zig_clang.h index c7d749cbd9..fd74536b28 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -8,14 +8,13 @@ #ifndef ZIG_ZIG_CLANG_H #define ZIG_ZIG_CLANG_H -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif +#include "userland.h" +#include <inttypes.h> +#include <stdbool.h> // ATTENTION: If you modify this file, be sure to update the corresponding -// extern function declarations in the self-hosted compiler. +// extern function declarations in the self-hosted compiler file +// src-self-hosted/clang.zig. struct ZigClangSourceLocation { unsigned ID; @@ -25,7 +24,14 @@ struct ZigClangQualType { void *ptr; }; +struct ZigClangAPValueLValueBase { + void *Ptr; + unsigned CallIndex; + unsigned Version; +}; + struct ZigClangAPValue; +struct ZigClangAPSInt; struct ZigClangASTContext; struct ZigClangASTUnit; struct ZigClangArraySubscriptExpr; @@ -82,10 +88,10 @@ struct ZigClangSkipFunctionBodiesScope; struct ZigClangSourceManager; struct ZigClangSourceRange; struct ZigClangStmt; -struct ZigClangStorageClass; struct ZigClangStringLiteral; struct ZigClangStringRef; struct ZigClangSwitchStmt; +struct ZigClangTagDecl; struct ZigClangType; struct ZigClangTypedefNameDecl; struct ZigClangTypedefType; @@ -94,6 +100,9 @@ struct ZigClangUnaryOperator; struct ZigClangValueDecl; struct ZigClangVarDecl; struct ZigClangWhileStmt; +struct ZigClangFunctionType; + +typedef struct ZigClangStmt *const * ZigClangCompoundStmt_const_body_iterator; enum ZigClangBO { ZigClangBO_PtrMemD, @@ -148,112 +157,674 @@ enum ZigClangUO { ZigClangUO_Coawait, }; -//struct ZigClangCC_AAPCS; -//struct ZigClangCC_AAPCS_VFP; -//struct ZigClangCC_C; -//struct ZigClangCC_IntelOclBicc; -//struct ZigClangCC_OpenCLKernel; -//struct ZigClangCC_PreserveAll; -//struct ZigClangCC_PreserveMost; -//struct ZigClangCC_SpirFunction; -//struct ZigClangCC_Swift; -//struct ZigClangCC_Win64; -//struct ZigClangCC_X86FastCall; -//struct ZigClangCC_X86Pascal; -//struct ZigClangCC_X86RegCall; -//struct ZigClangCC_X86StdCall; -//struct ZigClangCC_X86ThisCall; -//struct ZigClangCC_X86VectorCall; -//struct ZigClangCC_X86_64SysV; - -//struct ZigClangCK_ARCConsumeObject; -//struct ZigClangCK_ARCExtendBlockObject; -//struct ZigClangCK_ARCProduceObject; -//struct ZigClangCK_ARCReclaimReturnedObject; -//struct ZigClangCK_AddressSpaceConversion; -//struct ZigClangCK_AnyPointerToBlockPointerCast; -//struct ZigClangCK_ArrayToPointerDecay; -//struct ZigClangCK_AtomicToNonAtomic; -//struct ZigClangCK_BaseToDerived; -//struct ZigClangCK_BaseToDerivedMemberPointer; -//struct ZigClangCK_BitCast; -//struct ZigClangCK_BlockPointerToObjCPointerCast; -//struct ZigClangCK_BooleanToSignedIntegral; -//struct ZigClangCK_BuiltinFnToFnPtr; -//struct ZigClangCK_CPointerToObjCPointerCast; -//struct ZigClangCK_ConstructorConversion; -//struct ZigClangCK_CopyAndAutoreleaseBlockObject; -//struct ZigClangCK_Dependent; -//struct ZigClangCK_DerivedToBase; -//struct ZigClangCK_DerivedToBaseMemberPointer; -//struct ZigClangCK_Dynamic; -//struct ZigClangCK_FloatingCast; -//struct ZigClangCK_FloatingComplexCast; -//struct ZigClangCK_FloatingComplexToBoolean; -//struct ZigClangCK_FloatingComplexToIntegralComplex; -//struct ZigClangCK_FloatingComplexToReal; -//struct ZigClangCK_FloatingRealToComplex; -//struct ZigClangCK_FloatingToBoolean; -//struct ZigClangCK_FloatingToIntegral; -//struct ZigClangCK_FunctionToPointerDecay; -//struct ZigClangCK_IntToOCLSampler; -//struct ZigClangCK_IntegralCast; -//struct ZigClangCK_IntegralComplexCast; -//struct ZigClangCK_IntegralComplexToBoolean; -//struct ZigClangCK_IntegralComplexToFloatingComplex; -//struct ZigClangCK_IntegralComplexToReal; -//struct ZigClangCK_IntegralRealToComplex; -//struct ZigClangCK_IntegralToBoolean; -//struct ZigClangCK_IntegralToFloating; -//struct ZigClangCK_IntegralToPointer; -//struct ZigClangCK_LValueBitCast; -//struct ZigClangCK_LValueToRValue; -//struct ZigClangCK_MemberPointerToBoolean; -//struct ZigClangCK_NoOp; -//struct ZigClangCK_NonAtomicToAtomic; -//struct ZigClangCK_NullToMemberPointer; -//struct ZigClangCK_NullToPointer; -//struct ZigClangCK_ObjCObjectLValueCast; -//struct ZigClangCK_PointerToBoolean; -//struct ZigClangCK_PointerToIntegral; -//struct ZigClangCK_ReinterpretMemberPointer; -//struct ZigClangCK_ToUnion; -//struct ZigClangCK_ToVoid; -//struct ZigClangCK_UncheckedDerivedToBase; -//struct ZigClangCK_UserDefinedConversion; -//struct ZigClangCK_VectorSplat; -//struct ZigClangCK_ZeroToOCLEvent; -//struct ZigClangCK_ZeroToOCLQueue; - -//struct ZigClangETK_Class; -//struct ZigClangETK_Enum; -//struct ZigClangETK_Interface; -//struct ZigClangETK_None; -//struct ZigClangETK_Struct; -//struct ZigClangETK_Typename; -//struct ZigClangETK_Union; - -//struct ZigClangSC_None; -//struct ZigClangSC_PrivateExtern; -//struct ZigClangSC_Static; - -//struct ZigClangTU_Complete; - -ZIG_EXTERN_C ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *, - ZigClangSourceLocation Loc); -ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *, - ZigClangSourceLocation SpellingLoc); -ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *, - ZigClangSourceLocation Loc); -ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *, - ZigClangSourceLocation Loc); -ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *, - ZigClangSourceLocation SL); - -ZIG_EXTERN_C ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext*, ZigClangQualType T); - -ZIG_EXTERN_C ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *); -ZIG_EXTERN_C ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *); -ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *, void *context, - bool (*Fn)(void *context, const ZigClangDecl *decl)); +enum ZigClangTypeClass { + ZigClangType_Builtin, + ZigClangType_Complex, + ZigClangType_Pointer, + ZigClangType_BlockPointer, + ZigClangType_LValueReference, + ZigClangType_RValueReference, + ZigClangType_MemberPointer, + ZigClangType_ConstantArray, + ZigClangType_IncompleteArray, + ZigClangType_VariableArray, + ZigClangType_DependentSizedArray, + ZigClangType_DependentSizedExtVector, + ZigClangType_DependentAddressSpace, + ZigClangType_Vector, + ZigClangType_DependentVector, + ZigClangType_ExtVector, + ZigClangType_FunctionProto, + ZigClangType_FunctionNoProto, + ZigClangType_UnresolvedUsing, + ZigClangType_Paren, + ZigClangType_Typedef, + ZigClangType_Adjusted, + ZigClangType_Decayed, + ZigClangType_TypeOfExpr, + ZigClangType_TypeOf, + ZigClangType_Decltype, + ZigClangType_UnaryTransform, + ZigClangType_Record, + ZigClangType_Enum, + ZigClangType_Elaborated, + ZigClangType_Attributed, + ZigClangType_TemplateTypeParm, + ZigClangType_SubstTemplateTypeParm, + ZigClangType_SubstTemplateTypeParmPack, + ZigClangType_TemplateSpecialization, + ZigClangType_Auto, + ZigClangType_DeducedTemplateSpecialization, + ZigClangType_InjectedClassName, + ZigClangType_DependentName, + ZigClangType_DependentTemplateSpecialization, + ZigClangType_PackExpansion, + ZigClangType_ObjCTypeParam, + ZigClangType_ObjCObject, + ZigClangType_ObjCInterface, + ZigClangType_ObjCObjectPointer, + ZigClangType_Pipe, + ZigClangType_Atomic, +}; + +enum ZigClangStmtClass { + ZigClangStmt_NoStmtClass = 0, + ZigClangStmt_GCCAsmStmtClass, + ZigClangStmt_MSAsmStmtClass, + ZigClangStmt_AttributedStmtClass, + ZigClangStmt_BreakStmtClass, + ZigClangStmt_CXXCatchStmtClass, + ZigClangStmt_CXXForRangeStmtClass, + ZigClangStmt_CXXTryStmtClass, + ZigClangStmt_CapturedStmtClass, + ZigClangStmt_CompoundStmtClass, + ZigClangStmt_ContinueStmtClass, + ZigClangStmt_CoreturnStmtClass, + ZigClangStmt_CoroutineBodyStmtClass, + ZigClangStmt_DeclStmtClass, + ZigClangStmt_DoStmtClass, + ZigClangStmt_BinaryConditionalOperatorClass, + ZigClangStmt_ConditionalOperatorClass, + ZigClangStmt_AddrLabelExprClass, + ZigClangStmt_ArrayInitIndexExprClass, + ZigClangStmt_ArrayInitLoopExprClass, + ZigClangStmt_ArraySubscriptExprClass, + ZigClangStmt_ArrayTypeTraitExprClass, + ZigClangStmt_AsTypeExprClass, + ZigClangStmt_AtomicExprClass, + ZigClangStmt_BinaryOperatorClass, + ZigClangStmt_CompoundAssignOperatorClass, + ZigClangStmt_BlockExprClass, + ZigClangStmt_CXXBindTemporaryExprClass, + ZigClangStmt_CXXBoolLiteralExprClass, + ZigClangStmt_CXXConstructExprClass, + ZigClangStmt_CXXTemporaryObjectExprClass, + ZigClangStmt_CXXDefaultArgExprClass, + ZigClangStmt_CXXDefaultInitExprClass, + ZigClangStmt_CXXDeleteExprClass, + ZigClangStmt_CXXDependentScopeMemberExprClass, + ZigClangStmt_CXXFoldExprClass, + ZigClangStmt_CXXInheritedCtorInitExprClass, + ZigClangStmt_CXXNewExprClass, + ZigClangStmt_CXXNoexceptExprClass, + ZigClangStmt_CXXNullPtrLiteralExprClass, + ZigClangStmt_CXXPseudoDestructorExprClass, + ZigClangStmt_CXXScalarValueInitExprClass, + ZigClangStmt_CXXStdInitializerListExprClass, + ZigClangStmt_CXXThisExprClass, + ZigClangStmt_CXXThrowExprClass, + ZigClangStmt_CXXTypeidExprClass, + ZigClangStmt_CXXUnresolvedConstructExprClass, + ZigClangStmt_CXXUuidofExprClass, + ZigClangStmt_CallExprClass, + ZigClangStmt_CUDAKernelCallExprClass, + ZigClangStmt_CXXMemberCallExprClass, + ZigClangStmt_CXXOperatorCallExprClass, + ZigClangStmt_UserDefinedLiteralClass, + ZigClangStmt_CStyleCastExprClass, + ZigClangStmt_CXXFunctionalCastExprClass, + ZigClangStmt_CXXConstCastExprClass, + ZigClangStmt_CXXDynamicCastExprClass, + ZigClangStmt_CXXReinterpretCastExprClass, + ZigClangStmt_CXXStaticCastExprClass, + ZigClangStmt_ObjCBridgedCastExprClass, + ZigClangStmt_ImplicitCastExprClass, + ZigClangStmt_CharacterLiteralClass, + ZigClangStmt_ChooseExprClass, + ZigClangStmt_CompoundLiteralExprClass, + ZigClangStmt_ConvertVectorExprClass, + ZigClangStmt_CoawaitExprClass, + ZigClangStmt_CoyieldExprClass, + ZigClangStmt_DeclRefExprClass, + ZigClangStmt_DependentCoawaitExprClass, + ZigClangStmt_DependentScopeDeclRefExprClass, + ZigClangStmt_DesignatedInitExprClass, + ZigClangStmt_DesignatedInitUpdateExprClass, + ZigClangStmt_ExpressionTraitExprClass, + ZigClangStmt_ExtVectorElementExprClass, + ZigClangStmt_FixedPointLiteralClass, + ZigClangStmt_FloatingLiteralClass, + ZigClangStmt_ConstantExprClass, + ZigClangStmt_ExprWithCleanupsClass, + ZigClangStmt_FunctionParmPackExprClass, + ZigClangStmt_GNUNullExprClass, + ZigClangStmt_GenericSelectionExprClass, + ZigClangStmt_ImaginaryLiteralClass, + ZigClangStmt_ImplicitValueInitExprClass, + ZigClangStmt_InitListExprClass, + ZigClangStmt_IntegerLiteralClass, + ZigClangStmt_LambdaExprClass, + ZigClangStmt_MSPropertyRefExprClass, + ZigClangStmt_MSPropertySubscriptExprClass, + ZigClangStmt_MaterializeTemporaryExprClass, + ZigClangStmt_MemberExprClass, + ZigClangStmt_NoInitExprClass, + ZigClangStmt_OMPArraySectionExprClass, + ZigClangStmt_ObjCArrayLiteralClass, + ZigClangStmt_ObjCAvailabilityCheckExprClass, + ZigClangStmt_ObjCBoolLiteralExprClass, + ZigClangStmt_ObjCBoxedExprClass, + ZigClangStmt_ObjCDictionaryLiteralClass, + ZigClangStmt_ObjCEncodeExprClass, + ZigClangStmt_ObjCIndirectCopyRestoreExprClass, + ZigClangStmt_ObjCIsaExprClass, + ZigClangStmt_ObjCIvarRefExprClass, + ZigClangStmt_ObjCMessageExprClass, + ZigClangStmt_ObjCPropertyRefExprClass, + ZigClangStmt_ObjCProtocolExprClass, + ZigClangStmt_ObjCSelectorExprClass, + ZigClangStmt_ObjCStringLiteralClass, + ZigClangStmt_ObjCSubscriptRefExprClass, + ZigClangStmt_OffsetOfExprClass, + ZigClangStmt_OpaqueValueExprClass, + ZigClangStmt_UnresolvedLookupExprClass, + ZigClangStmt_UnresolvedMemberExprClass, + ZigClangStmt_PackExpansionExprClass, + ZigClangStmt_ParenExprClass, + ZigClangStmt_ParenListExprClass, + ZigClangStmt_PredefinedExprClass, + ZigClangStmt_PseudoObjectExprClass, + ZigClangStmt_ShuffleVectorExprClass, + ZigClangStmt_SizeOfPackExprClass, + ZigClangStmt_StmtExprClass, + ZigClangStmt_StringLiteralClass, + ZigClangStmt_SubstNonTypeTemplateParmExprClass, + ZigClangStmt_SubstNonTypeTemplateParmPackExprClass, + ZigClangStmt_TypeTraitExprClass, + ZigClangStmt_TypoExprClass, + ZigClangStmt_UnaryExprOrTypeTraitExprClass, + ZigClangStmt_UnaryOperatorClass, + ZigClangStmt_VAArgExprClass, + ZigClangStmt_ForStmtClass, + ZigClangStmt_GotoStmtClass, + ZigClangStmt_IfStmtClass, + ZigClangStmt_IndirectGotoStmtClass, + ZigClangStmt_LabelStmtClass, + ZigClangStmt_MSDependentExistsStmtClass, + ZigClangStmt_NullStmtClass, + ZigClangStmt_OMPAtomicDirectiveClass, + ZigClangStmt_OMPBarrierDirectiveClass, + ZigClangStmt_OMPCancelDirectiveClass, + ZigClangStmt_OMPCancellationPointDirectiveClass, + ZigClangStmt_OMPCriticalDirectiveClass, + ZigClangStmt_OMPFlushDirectiveClass, + ZigClangStmt_OMPDistributeDirectiveClass, + ZigClangStmt_OMPDistributeParallelForDirectiveClass, + ZigClangStmt_OMPDistributeParallelForSimdDirectiveClass, + ZigClangStmt_OMPDistributeSimdDirectiveClass, + ZigClangStmt_OMPForDirectiveClass, + ZigClangStmt_OMPForSimdDirectiveClass, + ZigClangStmt_OMPParallelForDirectiveClass, + ZigClangStmt_OMPParallelForSimdDirectiveClass, + ZigClangStmt_OMPSimdDirectiveClass, + ZigClangStmt_OMPTargetParallelForSimdDirectiveClass, + ZigClangStmt_OMPTargetSimdDirectiveClass, + ZigClangStmt_OMPTargetTeamsDistributeDirectiveClass, + ZigClangStmt_OMPTargetTeamsDistributeParallelForDirectiveClass, + ZigClangStmt_OMPTargetTeamsDistributeParallelForSimdDirectiveClass, + ZigClangStmt_OMPTargetTeamsDistributeSimdDirectiveClass, + ZigClangStmt_OMPTaskLoopDirectiveClass, + ZigClangStmt_OMPTaskLoopSimdDirectiveClass, + ZigClangStmt_OMPTeamsDistributeDirectiveClass, + ZigClangStmt_OMPTeamsDistributeParallelForDirectiveClass, + ZigClangStmt_OMPTeamsDistributeParallelForSimdDirectiveClass, + ZigClangStmt_OMPTeamsDistributeSimdDirectiveClass, + ZigClangStmt_OMPMasterDirectiveClass, + ZigClangStmt_OMPOrderedDirectiveClass, + ZigClangStmt_OMPParallelDirectiveClass, + ZigClangStmt_OMPParallelSectionsDirectiveClass, + ZigClangStmt_OMPSectionDirectiveClass, + ZigClangStmt_OMPSectionsDirectiveClass, + ZigClangStmt_OMPSingleDirectiveClass, + ZigClangStmt_OMPTargetDataDirectiveClass, + ZigClangStmt_OMPTargetDirectiveClass, + ZigClangStmt_OMPTargetEnterDataDirectiveClass, + ZigClangStmt_OMPTargetExitDataDirectiveClass, + ZigClangStmt_OMPTargetParallelDirectiveClass, + ZigClangStmt_OMPTargetParallelForDirectiveClass, + ZigClangStmt_OMPTargetTeamsDirectiveClass, + ZigClangStmt_OMPTargetUpdateDirectiveClass, + ZigClangStmt_OMPTaskDirectiveClass, + ZigClangStmt_OMPTaskgroupDirectiveClass, + ZigClangStmt_OMPTaskwaitDirectiveClass, + ZigClangStmt_OMPTaskyieldDirectiveClass, + ZigClangStmt_OMPTeamsDirectiveClass, + ZigClangStmt_ObjCAtCatchStmtClass, + ZigClangStmt_ObjCAtFinallyStmtClass, + ZigClangStmt_ObjCAtSynchronizedStmtClass, + ZigClangStmt_ObjCAtThrowStmtClass, + ZigClangStmt_ObjCAtTryStmtClass, + ZigClangStmt_ObjCAutoreleasePoolStmtClass, + ZigClangStmt_ObjCForCollectionStmtClass, + ZigClangStmt_ReturnStmtClass, + ZigClangStmt_SEHExceptStmtClass, + ZigClangStmt_SEHFinallyStmtClass, + ZigClangStmt_SEHLeaveStmtClass, + ZigClangStmt_SEHTryStmtClass, + ZigClangStmt_CaseStmtClass, + ZigClangStmt_DefaultStmtClass, + ZigClangStmt_SwitchStmtClass, + ZigClangStmt_WhileStmtClass, +}; + +enum ZigClangCK { + ZigClangCK_Dependent, + ZigClangCK_BitCast, + ZigClangCK_LValueBitCast, + ZigClangCK_LValueToRValue, + ZigClangCK_NoOp, + ZigClangCK_BaseToDerived, + ZigClangCK_DerivedToBase, + ZigClangCK_UncheckedDerivedToBase, + ZigClangCK_Dynamic, + ZigClangCK_ToUnion, + ZigClangCK_ArrayToPointerDecay, + ZigClangCK_FunctionToPointerDecay, + ZigClangCK_NullToPointer, + ZigClangCK_NullToMemberPointer, + ZigClangCK_BaseToDerivedMemberPointer, + ZigClangCK_DerivedToBaseMemberPointer, + ZigClangCK_MemberPointerToBoolean, + ZigClangCK_ReinterpretMemberPointer, + ZigClangCK_UserDefinedConversion, + ZigClangCK_ConstructorConversion, + ZigClangCK_IntegralToPointer, + ZigClangCK_PointerToIntegral, + ZigClangCK_PointerToBoolean, + ZigClangCK_ToVoid, + ZigClangCK_VectorSplat, + ZigClangCK_IntegralCast, + ZigClangCK_IntegralToBoolean, + ZigClangCK_IntegralToFloating, + ZigClangCK_FixedPointCast, + ZigClangCK_FixedPointToBoolean, + ZigClangCK_FloatingToIntegral, + ZigClangCK_FloatingToBoolean, + ZigClangCK_BooleanToSignedIntegral, + ZigClangCK_FloatingCast, + ZigClangCK_CPointerToObjCPointerCast, + ZigClangCK_BlockPointerToObjCPointerCast, + ZigClangCK_AnyPointerToBlockPointerCast, + ZigClangCK_ObjCObjectLValueCast, + ZigClangCK_FloatingRealToComplex, + ZigClangCK_FloatingComplexToReal, + ZigClangCK_FloatingComplexToBoolean, + ZigClangCK_FloatingComplexCast, + ZigClangCK_FloatingComplexToIntegralComplex, + ZigClangCK_IntegralRealToComplex, + ZigClangCK_IntegralComplexToReal, + ZigClangCK_IntegralComplexToBoolean, + ZigClangCK_IntegralComplexCast, + ZigClangCK_IntegralComplexToFloatingComplex, + ZigClangCK_ARCProduceObject, + ZigClangCK_ARCConsumeObject, + ZigClangCK_ARCReclaimReturnedObject, + ZigClangCK_ARCExtendBlockObject, + ZigClangCK_AtomicToNonAtomic, + ZigClangCK_NonAtomicToAtomic, + ZigClangCK_CopyAndAutoreleaseBlockObject, + ZigClangCK_BuiltinFnToFnPtr, + ZigClangCK_ZeroToOCLOpaqueType, + ZigClangCK_AddressSpaceConversion, + ZigClangCK_IntToOCLSampler, +}; + +enum ZigClangAPValueKind { + ZigClangAPValueUninitialized, + ZigClangAPValueInt, + ZigClangAPValueFloat, + ZigClangAPValueComplexInt, + ZigClangAPValueComplexFloat, + ZigClangAPValueLValue, + ZigClangAPValueVector, + ZigClangAPValueArray, + ZigClangAPValueStruct, + ZigClangAPValueUnion, + ZigClangAPValueMemberPointer, + ZigClangAPValueAddrLabelDiff, +}; + +enum ZigClangDeclKind { + ZigClangDeclAccessSpec, + ZigClangDeclBlock, + ZigClangDeclCaptured, + ZigClangDeclClassScopeFunctionSpecialization, + ZigClangDeclEmpty, + ZigClangDeclExport, + ZigClangDeclExternCContext, + ZigClangDeclFileScopeAsm, + ZigClangDeclFriend, + ZigClangDeclFriendTemplate, + ZigClangDeclImport, + ZigClangDeclLinkageSpec, + ZigClangDeclLabel, + ZigClangDeclNamespace, + ZigClangDeclNamespaceAlias, + ZigClangDeclObjCCompatibleAlias, + ZigClangDeclObjCCategory, + ZigClangDeclObjCCategoryImpl, + ZigClangDeclObjCImplementation, + ZigClangDeclObjCInterface, + ZigClangDeclObjCProtocol, + ZigClangDeclObjCMethod, + ZigClangDeclObjCProperty, + ZigClangDeclBuiltinTemplate, + ZigClangDeclClassTemplate, + ZigClangDeclFunctionTemplate, + ZigClangDeclTypeAliasTemplate, + ZigClangDeclVarTemplate, + ZigClangDeclTemplateTemplateParm, + ZigClangDeclEnum, + ZigClangDeclRecord, + ZigClangDeclCXXRecord, + ZigClangDeclClassTemplateSpecialization, + ZigClangDeclClassTemplatePartialSpecialization, + ZigClangDeclTemplateTypeParm, + ZigClangDeclObjCTypeParam, + ZigClangDeclTypeAlias, + ZigClangDeclTypedef, + ZigClangDeclUnresolvedUsingTypename, + ZigClangDeclUsing, + ZigClangDeclUsingDirective, + ZigClangDeclUsingPack, + ZigClangDeclUsingShadow, + ZigClangDeclConstructorUsingShadow, + ZigClangDeclBinding, + ZigClangDeclField, + ZigClangDeclObjCAtDefsField, + ZigClangDeclObjCIvar, + ZigClangDeclFunction, + ZigClangDeclCXXDeductionGuide, + ZigClangDeclCXXMethod, + ZigClangDeclCXXConstructor, + ZigClangDeclCXXConversion, + ZigClangDeclCXXDestructor, + ZigClangDeclMSProperty, + ZigClangDeclNonTypeTemplateParm, + ZigClangDeclVar, + ZigClangDeclDecomposition, + ZigClangDeclImplicitParam, + ZigClangDeclOMPCapturedExpr, + ZigClangDeclParmVar, + ZigClangDeclVarTemplateSpecialization, + ZigClangDeclVarTemplatePartialSpecialization, + ZigClangDeclEnumConstant, + ZigClangDeclIndirectField, + ZigClangDeclOMPDeclareReduction, + ZigClangDeclUnresolvedUsingValue, + ZigClangDeclOMPRequires, + ZigClangDeclOMPThreadPrivate, + ZigClangDeclObjCPropertyImpl, + ZigClangDeclPragmaComment, + ZigClangDeclPragmaDetectMismatch, + ZigClangDeclStaticAssert, + ZigClangDeclTranslationUnit, +}; + +enum ZigClangBuiltinTypeKind { + ZigClangBuiltinTypeOCLImage1dRO, + ZigClangBuiltinTypeOCLImage1dArrayRO, + ZigClangBuiltinTypeOCLImage1dBufferRO, + ZigClangBuiltinTypeOCLImage2dRO, + ZigClangBuiltinTypeOCLImage2dArrayRO, + ZigClangBuiltinTypeOCLImage2dDepthRO, + ZigClangBuiltinTypeOCLImage2dArrayDepthRO, + ZigClangBuiltinTypeOCLImage2dMSAARO, + ZigClangBuiltinTypeOCLImage2dArrayMSAARO, + ZigClangBuiltinTypeOCLImage2dMSAADepthRO, + ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRO, + ZigClangBuiltinTypeOCLImage3dRO, + ZigClangBuiltinTypeOCLImage1dWO, + ZigClangBuiltinTypeOCLImage1dArrayWO, + ZigClangBuiltinTypeOCLImage1dBufferWO, + ZigClangBuiltinTypeOCLImage2dWO, + ZigClangBuiltinTypeOCLImage2dArrayWO, + ZigClangBuiltinTypeOCLImage2dDepthWO, + ZigClangBuiltinTypeOCLImage2dArrayDepthWO, + ZigClangBuiltinTypeOCLImage2dMSAAWO, + ZigClangBuiltinTypeOCLImage2dArrayMSAAWO, + ZigClangBuiltinTypeOCLImage2dMSAADepthWO, + ZigClangBuiltinTypeOCLImage2dArrayMSAADepthWO, + ZigClangBuiltinTypeOCLImage3dWO, + ZigClangBuiltinTypeOCLImage1dRW, + ZigClangBuiltinTypeOCLImage1dArrayRW, + ZigClangBuiltinTypeOCLImage1dBufferRW, + ZigClangBuiltinTypeOCLImage2dRW, + ZigClangBuiltinTypeOCLImage2dArrayRW, + ZigClangBuiltinTypeOCLImage2dDepthRW, + ZigClangBuiltinTypeOCLImage2dArrayDepthRW, + ZigClangBuiltinTypeOCLImage2dMSAARW, + ZigClangBuiltinTypeOCLImage2dArrayMSAARW, + ZigClangBuiltinTypeOCLImage2dMSAADepthRW, + ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRW, + ZigClangBuiltinTypeOCLImage3dRW, + ZigClangBuiltinTypeOCLIntelSubgroupAVCMcePayload, + ZigClangBuiltinTypeOCLIntelSubgroupAVCImePayload, + ZigClangBuiltinTypeOCLIntelSubgroupAVCRefPayload, + ZigClangBuiltinTypeOCLIntelSubgroupAVCSicPayload, + ZigClangBuiltinTypeOCLIntelSubgroupAVCMceResult, + ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResult, + ZigClangBuiltinTypeOCLIntelSubgroupAVCRefResult, + ZigClangBuiltinTypeOCLIntelSubgroupAVCSicResult, + ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultSingleRefStreamout, + ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultDualRefStreamout, + ZigClangBuiltinTypeOCLIntelSubgroupAVCImeSingleRefStreamin, + ZigClangBuiltinTypeOCLIntelSubgroupAVCImeDualRefStreamin, + ZigClangBuiltinTypeVoid, + ZigClangBuiltinTypeBool, + ZigClangBuiltinTypeChar_U, + ZigClangBuiltinTypeUChar, + ZigClangBuiltinTypeWChar_U, + ZigClangBuiltinTypeChar8, + ZigClangBuiltinTypeChar16, + ZigClangBuiltinTypeChar32, + ZigClangBuiltinTypeUShort, + ZigClangBuiltinTypeUInt, + ZigClangBuiltinTypeULong, + ZigClangBuiltinTypeULongLong, + ZigClangBuiltinTypeUInt128, + ZigClangBuiltinTypeChar_S, + ZigClangBuiltinTypeSChar, + ZigClangBuiltinTypeWChar_S, + ZigClangBuiltinTypeShort, + ZigClangBuiltinTypeInt, + ZigClangBuiltinTypeLong, + ZigClangBuiltinTypeLongLong, + ZigClangBuiltinTypeInt128, + ZigClangBuiltinTypeShortAccum, + ZigClangBuiltinTypeAccum, + ZigClangBuiltinTypeLongAccum, + ZigClangBuiltinTypeUShortAccum, + ZigClangBuiltinTypeUAccum, + ZigClangBuiltinTypeULongAccum, + ZigClangBuiltinTypeShortFract, + ZigClangBuiltinTypeFract, + ZigClangBuiltinTypeLongFract, + ZigClangBuiltinTypeUShortFract, + ZigClangBuiltinTypeUFract, + ZigClangBuiltinTypeULongFract, + ZigClangBuiltinTypeSatShortAccum, + ZigClangBuiltinTypeSatAccum, + ZigClangBuiltinTypeSatLongAccum, + ZigClangBuiltinTypeSatUShortAccum, + ZigClangBuiltinTypeSatUAccum, + ZigClangBuiltinTypeSatULongAccum, + ZigClangBuiltinTypeSatShortFract, + ZigClangBuiltinTypeSatFract, + ZigClangBuiltinTypeSatLongFract, + ZigClangBuiltinTypeSatUShortFract, + ZigClangBuiltinTypeSatUFract, + ZigClangBuiltinTypeSatULongFract, + ZigClangBuiltinTypeHalf, + ZigClangBuiltinTypeFloat, + ZigClangBuiltinTypeDouble, + ZigClangBuiltinTypeLongDouble, + ZigClangBuiltinTypeFloat16, + ZigClangBuiltinTypeFloat128, + ZigClangBuiltinTypeNullPtr, + ZigClangBuiltinTypeObjCId, + ZigClangBuiltinTypeObjCClass, + ZigClangBuiltinTypeObjCSel, + ZigClangBuiltinTypeOCLSampler, + ZigClangBuiltinTypeOCLEvent, + ZigClangBuiltinTypeOCLClkEvent, + ZigClangBuiltinTypeOCLQueue, + ZigClangBuiltinTypeOCLReserveID, + ZigClangBuiltinTypeDependent, + ZigClangBuiltinTypeOverload, + ZigClangBuiltinTypeBoundMember, + ZigClangBuiltinTypePseudoObject, + ZigClangBuiltinTypeUnknownAny, + ZigClangBuiltinTypeBuiltinFn, + ZigClangBuiltinTypeARCUnbridgedCast, + ZigClangBuiltinTypeOMPArraySection, +}; + +enum ZigClangCallingConv { + ZigClangCallingConv_C, // __attribute__((cdecl)) + ZigClangCallingConv_X86StdCall, // __attribute__((stdcall)) + ZigClangCallingConv_X86FastCall, // __attribute__((fastcall)) + ZigClangCallingConv_X86ThisCall, // __attribute__((thiscall)) + ZigClangCallingConv_X86VectorCall, // __attribute__((vectorcall)) + ZigClangCallingConv_X86Pascal, // __attribute__((pascal)) + ZigClangCallingConv_Win64, // __attribute__((ms_abi)) + ZigClangCallingConv_X86_64SysV, // __attribute__((sysv_abi)) + ZigClangCallingConv_X86RegCall, // __attribute__((regcall)) + ZigClangCallingConv_AAPCS, // __attribute__((pcs("aapcs"))) + ZigClangCallingConv_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) + ZigClangCallingConv_IntelOclBicc, // __attribute__((intel_ocl_bicc)) + ZigClangCallingConv_SpirFunction, // default for OpenCL functions on SPIR target + ZigClangCallingConv_OpenCLKernel, // inferred for OpenCL kernels + ZigClangCallingConv_Swift, // __attribute__((swiftcall)) + ZigClangCallingConv_PreserveMost, // __attribute__((preserve_most)) + ZigClangCallingConv_PreserveAll, // __attribute__((preserve_all)) + ZigClangCallingConv_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) +}; + +enum ZigClangStorageClass { + // These are legal on both functions and variables. + ZigClangStorageClass_None, + ZigClangStorageClass_Extern, + ZigClangStorageClass_Static, + ZigClangStorageClass_PrivateExtern, + + // These are only legal on variables. + ZigClangStorageClass_Auto, + ZigClangStorageClass_Register, +}; + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, + struct ZigClangSourceLocation Loc); +ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, + struct ZigClangSourceLocation SpellingLoc); +ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingLineNumber(const struct ZigClangSourceManager *, + struct ZigClangSourceLocation Loc); +ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const struct ZigClangSourceManager *, + struct ZigClangSourceLocation Loc); +ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const struct ZigClangSourceManager *, + struct ZigClangSourceLocation SL); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangASTContext_getPointerType(const struct ZigClangASTContext*, struct ZigClangQualType T); + + +// Can return null. +ZIG_EXTERN_C struct ZigClangASTUnit *ZigClangLoadFromCommandLine(const char **args_begin, const char **args_end, + struct Stage2ErrorMsg **errors_ptr, size_t *errors_len, const char *resources_path); +ZIG_EXTERN_C void ZigClangASTUnit_delete(struct ZigClangASTUnit *); +ZIG_EXTERN_C void ZigClangErrorMsg_delete(struct Stage2ErrorMsg *ptr, size_t len); + +ZIG_EXTERN_C struct ZigClangASTContext *ZigClangASTUnit_getASTContext(struct ZigClangASTUnit *); +ZIG_EXTERN_C struct ZigClangSourceManager *ZigClangASTUnit_getSourceManager(struct ZigClangASTUnit *); +ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(struct ZigClangASTUnit *, void *context, + bool (*Fn)(void *context, const struct ZigClangDecl *decl)); + +ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordType_getDecl(const struct ZigClangRecordType *record_ty); +ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struct ZigClangEnumType *record_ty); + +ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl); +ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *); +ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *); + +ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *); +ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *); + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangRecordDecl_getLocation(const struct ZigClangRecordDecl *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangEnumDecl_getLocation(const struct ZigClangEnumDecl *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangTypedefNameDecl_getLocation(const struct ZigClangTypedefNameDecl *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDecl_getLocation(const struct ZigClangDecl *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionDecl_getType(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFunctionDecl_getLocation(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C bool ZigClangFunctionDecl_hasBody(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C enum ZigClangStorageClass ZigClangFunctionDecl_getStorageClass(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C const struct ZigClangParmVarDecl *ZigClangFunctionDecl_getParamDecl(const struct ZigClangFunctionDecl *, unsigned i); +ZIG_EXTERN_C const struct ZigClangStmt *ZigClangFunctionDecl_getBody(const struct ZigClangFunctionDecl *); + +ZIG_EXTERN_C bool ZigClangRecordDecl_isUnion(const struct ZigClangRecordDecl *record_decl); +ZIG_EXTERN_C bool ZigClangRecordDecl_isStruct(const struct ZigClangRecordDecl *record_decl); +ZIG_EXTERN_C bool ZigClangRecordDecl_isAnonymousStructOrUnion(const struct ZigClangRecordDecl *record_decl); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangEnumDecl_getIntegerType(const struct ZigClangEnumDecl *); + +ZIG_EXTERN_C const char *ZigClangDecl_getName_bytes_begin(const struct ZigClangDecl *decl); +ZIG_EXTERN_C enum ZigClangDeclKind ZigClangDecl_getKind(const struct ZigClangDecl *decl); +ZIG_EXTERN_C const char *ZigClangDecl_getDeclKindName(const struct ZigClangDecl *decl); + +ZIG_EXTERN_C bool ZigClangSourceLocation_eq(struct ZigClangSourceLocation a, struct ZigClangSourceLocation b); + +ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefType_getDecl(const struct ZigClangTypedefType *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangTypedefNameDecl_getUnderlyingType(const struct ZigClangTypedefNameDecl *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangQualType_getCanonicalType(struct ZigClangQualType); +ZIG_EXTERN_C const struct ZigClangType *ZigClangQualType_getTypePtr(struct ZigClangQualType); +ZIG_EXTERN_C void ZigClangQualType_addConst(struct ZigClangQualType *); +ZIG_EXTERN_C bool ZigClangQualType_eq(struct ZigClangQualType, struct ZigClangQualType); +ZIG_EXTERN_C bool ZigClangQualType_isConstQualified(struct ZigClangQualType); +ZIG_EXTERN_C bool ZigClangQualType_isVolatileQualified(struct ZigClangQualType); +ZIG_EXTERN_C bool ZigClangQualType_isRestrictQualified(struct ZigClangQualType); + +ZIG_EXTERN_C enum ZigClangTypeClass ZigClangType_getTypeClass(const struct ZigClangType *self); +ZIG_EXTERN_C struct ZigClangQualType ZigClangType_getPointeeType(const struct ZigClangType *self); +ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self); +ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self); + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangStmt_getBeginLoc(const struct ZigClangStmt *self); +ZIG_EXTERN_C enum ZigClangStmtClass ZigClangStmt_getStmtClass(const struct ZigClangStmt *self); +ZIG_EXTERN_C bool ZigClangStmt_classof_Expr(const struct ZigClangStmt *self); + +ZIG_EXTERN_C enum ZigClangStmtClass ZigClangExpr_getStmtClass(const struct ZigClangExpr *self); +ZIG_EXTERN_C struct ZigClangQualType ZigClangExpr_getType(const struct ZigClangExpr *self); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangExpr_getBeginLoc(const struct ZigClangExpr *self); + +ZIG_EXTERN_C enum ZigClangAPValueKind ZigClangAPValue_getKind(const struct ZigClangAPValue *self); +ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPValue_getInt(const struct ZigClangAPValue *self); +ZIG_EXTERN_C unsigned ZigClangAPValue_getArrayInitializedElts(const struct ZigClangAPValue *self); +ZIG_EXTERN_C const struct ZigClangAPValue *ZigClangAPValue_getArrayInitializedElt(const struct ZigClangAPValue *self, unsigned i); +ZIG_EXTERN_C const struct ZigClangAPValue *ZigClangAPValue_getArrayFiller(const struct ZigClangAPValue *self); +ZIG_EXTERN_C unsigned ZigClangAPValue_getArraySize(const struct ZigClangAPValue *self); +ZIG_EXTERN_C struct ZigClangAPValueLValueBase ZigClangAPValue_getLValueBase(const struct ZigClangAPValue *self); + +ZIG_EXTERN_C bool ZigClangAPSInt_isSigned(const struct ZigClangAPSInt *self); +ZIG_EXTERN_C bool ZigClangAPSInt_isNegative(const struct ZigClangAPSInt *self); +ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPSInt_negate(const struct ZigClangAPSInt *self); +ZIG_EXTERN_C void ZigClangAPSInt_free(const struct ZigClangAPSInt *self); +ZIG_EXTERN_C const uint64_t *ZigClangAPSInt_getRawData(const struct ZigClangAPSInt *self); +ZIG_EXTERN_C unsigned ZigClangAPSInt_getNumWords(const struct ZigClangAPSInt *self); + +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAPValueLValueBase_dyn_cast_Expr(struct ZigClangAPValueLValueBase self); + +ZIG_EXTERN_C enum ZigClangBuiltinTypeKind ZigClangBuiltinType_getKind(const struct ZigClangBuiltinType *self); + +ZIG_EXTERN_C bool ZigClangFunctionType_getNoReturnAttr(const struct ZigClangFunctionType *self); +ZIG_EXTERN_C enum ZigClangCallingConv ZigClangFunctionType_getCallConv(const struct ZigClangFunctionType *self); +ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionType_getReturnType(const struct ZigClangFunctionType *self); + +ZIG_EXTERN_C bool ZigClangFunctionProtoType_isVariadic(const struct ZigClangFunctionProtoType *self); +ZIG_EXTERN_C unsigned ZigClangFunctionProtoType_getNumParams(const struct ZigClangFunctionProtoType *self); +ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionProtoType_getParamType(const struct ZigClangFunctionProtoType *self, unsigned i); + + +ZIG_EXTERN_C ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_begin(const struct ZigClangCompoundStmt *self); +ZIG_EXTERN_C ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_end(const struct ZigClangCompoundStmt *self); + #endif diff --git a/std/array_list.zig b/std/array_list.zig index b173dab747..ca7d5f911e 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -111,6 +111,17 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { new_item_ptr.* = item; } + pub fn orderedRemove(self: *Self, i: usize) T { + const newlen = self.len - 1; + if (newlen == i) return self.pop(); + + const old_item = self.at(i); + for (self.items[i..newlen]) |*b, j| b.* = self.items[i + 1 + j]; + self.items[newlen] = undefined; + self.len = newlen; + return old_item; + } + /// Removes the element at the specified index and returns it. /// The empty slot is filled from the end of the list. pub fn swapRemove(self: *Self, i: usize) T { @@ -279,6 +290,33 @@ test "std.ArrayList.basic" { testing.expect(list.pop() == 33); } +test "std.ArrayList.orderedRemove" { + var list = ArrayList(i32).init(debug.global_allocator); + defer list.deinit(); + + try list.append(1); + try list.append(2); + try list.append(3); + try list.append(4); + try list.append(5); + try list.append(6); + try list.append(7); + + //remove from middle + testing.expectEqual(i32(4), list.orderedRemove(3)); + testing.expectEqual(i32(5), list.at(3)); + testing.expectEqual(usize(6), list.len); + + //remove from end + testing.expectEqual(i32(7), list.orderedRemove(5)); + testing.expectEqual(usize(5), list.len); + + //remove from front + testing.expectEqual(i32(1), list.orderedRemove(0)); + testing.expectEqual(i32(2), list.at(0)); + testing.expectEqual(usize(4), list.len); +} + test "std.ArrayList.swapRemove" { var list = ArrayList(i32).init(debug.global_allocator); defer list.deinit(); diff --git a/std/build.zig b/std/build.zig index 2bd4a9b08f..b5ec97ab5f 100644 --- a/std/build.zig +++ b/std/build.zig @@ -50,6 +50,8 @@ pub const Builder = struct { build_root: []const u8, cache_root: []const u8, release_mode: ?builtin.Mode, + override_std_dir: ?[]const u8, + override_lib_dir: ?[]const u8, pub const CStd = enum { C89, @@ -133,6 +135,8 @@ pub const Builder = struct { }, .have_install_step = false, .release_mode = null, + .override_std_dir = null, + .override_lib_dir = null, }; self.detectNativeSystemPaths(); self.default_step = self.step("default", "Build the project"); @@ -937,8 +941,11 @@ pub const LibExeObjStep = struct { verbose_link: bool, verbose_cc: bool, disable_gen_h: bool, + bundle_compiler_rt: bool, + disable_stack_probing: bool, c_std: Builder.CStd, override_std_dir: ?[]const u8, + override_lib_dir: ?[]const u8, main_pkg_path: ?[]const u8, exec_cmd_args: ?[]const ?[]const u8, name_prefix: []const u8, @@ -1039,11 +1046,14 @@ pub const LibExeObjStep = struct { .c_std = Builder.CStd.C99, .system_linker_hack = false, .override_std_dir = null, + .override_lib_dir = null, .main_pkg_path = null, .exec_cmd_args = null, .name_prefix = "", .filter = null, .disable_gen_h = false, + .bundle_compiler_rt = false, + .disable_stack_probing = false, .output_dir = null, .need_system_paths = false, .single_threaded = false, @@ -1446,6 +1456,12 @@ pub const LibExeObjStep = struct { if (self.disable_gen_h) { try zig_args.append("--disable-gen-h"); } + if (self.bundle_compiler_rt) { + try zig_args.append("--bundle-compiler-rt"); + } + if (self.disable_stack_probing) { + try zig_args.append("--disable-stack-probing"); + } switch (self.target) { Target.Native => {}, @@ -1528,6 +1544,17 @@ pub const LibExeObjStep = struct { if (self.override_std_dir) |dir| { try zig_args.append("--override-std-dir"); try zig_args.append(builder.pathFromRoot(dir)); + } else if (self.builder.override_std_dir) |dir| { + try zig_args.append("--override-std-dir"); + try zig_args.append(builder.pathFromRoot(dir)); + } + + if (self.override_lib_dir) |dir| { + try zig_args.append("--override-lib-dir"); + try zig_args.append(builder.pathFromRoot(dir)); + } else if (self.builder.override_lib_dir) |dir| { + try zig_args.append("--override-lib-dir"); + try zig_args.append(builder.pathFromRoot(dir)); } if (self.main_pkg_path) |dir| { @@ -12,6 +12,12 @@ pub use switch (builtin.os) { // TODO https://github.com/ziglang/zig/issues/265 on this whole file +pub const FILE = @OpaqueType(); +pub extern "c" fn fopen(filename: [*]const u8, modes: [*]const u8) ?*FILE; +pub extern "c" fn fclose(stream: *FILE) c_int; +pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; +pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; + pub extern "c" fn abort() noreturn; pub extern "c" fn exit(code: c_int) noreturn; pub extern "c" fn isatty(fd: c_int) c_int; diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 2f2f4c0a1b..b6cf15bf31 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct { }; pub const msghdr = extern struct { - msg_name: *u8, + /// optional address + msg_name: ?*sockaddr, + /// size of address msg_namelen: socklen_t, - msg_iov: *iovec, + /// scatter/gather array + msg_iov: [*]iovec, + /// # elements in msg_iov msg_iovlen: i32, - __pad1: i32, - msg_control: *u8, + /// ancillary data + msg_control: ?*c_void, + /// ancillary data buffer len msg_controllen: socklen_t, - __pad2: socklen_t, + /// flags on received message + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + /// optional address + msg_name: ?*const sockaddr, + /// size of address + msg_namelen: socklen_t, + /// scatter/gather array + msg_iov: [*]iovec_const, + /// # elements in msg_iov + msg_iovlen: i32, + /// ancillary data + msg_control: ?*c_void, + /// ancillary data buffer len + msg_controllen: socklen_t, + /// flags on received message msg_flags: i32, }; diff --git a/std/c/linux.zig b/std/c/linux.zig index b0dadf071d..48e359f361 100644 --- a/std/c/linux.zig +++ b/std/c/linux.zig @@ -1,3 +1,4 @@ +const linux = @import("../os/linux.zig"); pub use @import("../os/linux/errno.zig"); pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int; @@ -11,3 +12,6 @@ pub const pthread_attr_t = extern struct { /// See std.elf for constants for this pub extern fn getauxval(__type: c_ulong) c_ulong; + +pub const dl_iterate_phdr_callback = extern fn (info: *linux.dl_phdr_info, size: usize, data: ?*c_void) c_int; +pub extern fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; diff --git a/std/c/netbsd.zig b/std/c/netbsd.zig index 796d45dafc..2c07ee296b 100644 --- a/std/c/netbsd.zig +++ b/std/c/netbsd.zig @@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct { }; pub const msghdr = extern struct { - msg_name: *u8, + /// optional address + msg_name: ?*sockaddr, + /// size of address msg_namelen: socklen_t, - msg_iov: *iovec, + /// scatter/gather array + msg_iov: [*]iovec, + /// # elements in msg_iov msg_iovlen: i32, - __pad1: i32, - msg_control: *u8, + /// ancillary data + msg_control: ?*c_void, + /// ancillary data buffer len msg_controllen: socklen_t, - __pad2: socklen_t, + /// flags on received message + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + /// optional address + msg_name: ?*const sockaddr, + /// size of address + msg_namelen: socklen_t, + /// scatter/gather array + msg_iov: [*]iovec_const, + /// # elements in msg_iov + msg_iovlen: i32, + /// ancillary data + msg_control: ?*c_void, + /// ancillary data buffer len + msg_controllen: socklen_t, + /// flags on received message msg_flags: i32, }; diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 78ef700bdf..796b5c6e4f 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -142,7 +142,7 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] assert(in.len >= out.len); assert(counter +% (in.len >> 6) >= counter); - var cursor: u64 = 0; + var cursor: usize = 0; var k: [8]u32 = undefined; var c: [4]u32 = undefined; @@ -161,7 +161,8 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); const block_size = (1 << 6); - const big_block = (block_size << 32); + // The full block size is greater than the address space on a 32bit machine + const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); // first partial big block if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { diff --git a/std/debug.zig b/std/debug.zig index c85a982059..d017f96144 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -13,6 +13,8 @@ const ArrayList = std.ArrayList; const builtin = @import("builtin"); const maxInt = std.math.maxInt; +const leb = @import("debug/leb128.zig"); + pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator; pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator; @@ -214,14 +216,14 @@ pub fn writeStackTrace( tty_color: bool, ) !void { var frame_index: usize = 0; - var frames_left: usize = stack_trace.index; + var frames_left: usize = std.math.min(stack_trace.index, stack_trace.instruction_addresses.len); while (frames_left != 0) : ({ frames_left -= 1; frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; }) { const return_address = stack_trace.instruction_addresses[frame_index]; - try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); + try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color); } } @@ -263,7 +265,7 @@ pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color } var it = StackIterator.init(start_addr); while (it.next()) |return_address| { - try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); + try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color); } } @@ -376,7 +378,6 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in, // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection. - const subsection_end_index = sect_offset + subsect_hdr.Length; while (line_index < subsection_end_index) { @@ -690,9 +691,9 @@ pub fn printSourceAtAddressDwarf( return; }; const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); - if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| { + if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address)) |line_info| { defer line_info.deinit(); - const symbol_name = "???"; + const symbol_name = getSymbolNameDwarf(debug_info, address) orelse "???"; try printLineInfo( out_stream, line_info, @@ -969,6 +970,8 @@ fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Sec pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void { di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator); di.compile_unit_list = ArrayList(CompileUnit).init(allocator); + di.func_list = ArrayList(Func).init(allocator); + try scanAllFunctions(di); try scanAllCompileUnits(di); } @@ -992,6 +995,7 @@ pub fn openElfDebugInfo( .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")), .abbrev_table_list = undefined, .compile_unit_list = undefined, + .func_list = undefined, }; try openDwarfDebugInfo(&di, allocator); return di; @@ -1162,6 +1166,7 @@ pub const DwarfInfo = struct { debug_ranges: ?Section, abbrev_table_list: ArrayList(AbbrevTableHeader), compile_unit_list: ArrayList(CompileUnit), + func_list: ArrayList(Func), pub const Section = struct { offset: usize, @@ -1178,7 +1183,7 @@ pub const DwarfInfo = struct { }; pub const DebugInfo = switch (builtin.os) { - builtin.Os.macosx => struct { + builtin.Os.macosx, builtin.Os.ios => struct { symbols: []const MachoSymbol, strings: []const u8, ofiles: OFileTable, @@ -1213,7 +1218,6 @@ const CompileUnit = struct { version: u16, is_64: bool, die: *Die, - index: usize, pc_range: ?PcRange, }; @@ -1244,21 +1248,19 @@ const FormValue = union(enum) { ExprLoc: []u8, Flag: bool, SecOffset: u64, - Ref: []u8, + Ref: u64, RefAddr: u64, - RefSig8: u64, String: []u8, StrPtr: u64, }; const Constant = struct { - payload: []u8, + payload: u64, signed: bool, fn asUnsignedLe(self: *const Constant) !u64 { - if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readVarInt(u64, self.payload, builtin.Endian.Little); + return self.payload; } }; @@ -1304,6 +1306,14 @@ const Die = struct { }; } + fn getAttrRef(self: *const Die, id: u64) !u64 { + const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; + return switch (form_value.*) { + FormValue.Ref => |value| value, + else => error.InvalidDebugInfo, + }; + } + fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 { const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; return switch (form_value.*) { @@ -1443,11 +1453,18 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) ! return parseFormValueBlockLen(allocator, in_stream, block_len); } -fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue { +fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue { return FormValue{ .Const = Constant{ .signed = signed, - .payload = try readAllocBytes(allocator, in_stream, size), + .payload = switch (size) { + 1 => try in_stream.readIntLittle(u8), + 2 => try in_stream.readIntLittle(u16), + 4 => try in_stream.readIntLittle(u32), + 8 => try in_stream.readIntLittle(u64), + -1 => if (signed) @bitCast(u64, try leb.readILEB128(i64, in_stream)) else try leb.readULEB128(u64, in_stream), + else => @compileError("Invalid size"), + }, }, }; } @@ -1460,14 +1477,17 @@ fn parseFormValueTargetAddrSize(in_stream: var) !u64 { return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable; } -fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const buf = try readAllocBytes(allocator, in_stream, size); - return FormValue{ .Ref = buf }; -} - -fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue { - const block_len = try in_stream.readIntLittle(T); - return parseFormValueRefLen(allocator, in_stream, block_len); +fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue { + return FormValue{ + .Ref = switch (size) { + 1 => try in_stream.readIntLittle(u8), + 2 => try in_stream.readIntLittle(u16), + 4 => try in_stream.readIntLittle(u32), + 8 => try in_stream.readIntLittle(u64), + -1 => try leb.readULEB128(u64, in_stream), + else => unreachable, + }, + }; } fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue { @@ -1477,7 +1497,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), DW.FORM_block => x: { - const block_len = try readULeb128(in_stream); + const block_len = try leb.readULEB128(usize, in_stream); return parseFormValueBlockLen(allocator, in_stream, block_len); }, DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1), @@ -1485,12 +1505,11 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4), DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8), DW.FORM_udata, DW.FORM_sdata => { - const block_len = try readULeb128(in_stream); const signed = form_id == DW.FORM_sdata; - return parseFormValueConstant(allocator, in_stream, signed, block_len); + return parseFormValueConstant(allocator, in_stream, signed, -1); }, DW.FORM_exprloc => { - const size = try readULeb128(in_stream); + const size = try leb.readULEB128(usize, in_stream); const buf = try readAllocBytes(allocator, in_stream, size); return FormValue{ .ExprLoc = buf }; }, @@ -1498,22 +1517,19 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 DW.FORM_flag_present => FormValue{ .Flag = true }, DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8), - DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16), - DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32), - DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64), - DW.FORM_ref_udata => { - const ref_len = try readULeb128(in_stream); - return parseFormValueRefLen(allocator, in_stream, ref_len); - }, + DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, 1), + DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, 2), + DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, 4), + DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, 8), + DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1), DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) }, + DW.FORM_ref_sig8 => FormValue{ .Ref = try in_stream.readIntLittle(u64) }, DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) }, DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, DW.FORM_indirect => { - const child_form_id = try readULeb128(in_stream); + const child_form_id = try leb.readULEB128(u64, in_stream); return parseFormValue(allocator, in_stream, child_form_id, is_64); }, else => error.InvalidDebugInfo, @@ -1523,19 +1539,19 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable { var result = AbbrevTable.init(di.allocator()); while (true) { - const abbrev_code = try readULeb128(di.dwarf_in_stream); + const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); if (abbrev_code == 0) return result; try result.append(AbbrevTableEntry{ .abbrev_code = abbrev_code, - .tag_id = try readULeb128(di.dwarf_in_stream), + .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream), .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes, .attrs = ArrayList(AbbrevAttr).init(di.allocator()), }); const attrs = &result.items[result.len - 1].attrs; while (true) { - const attr_id = try readULeb128(di.dwarf_in_stream); - const form_id = try readULeb128(di.dwarf_in_stream); + const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream); + const form_id = try leb.readULEB128(u64, di.dwarf_in_stream); if (attr_id == 0 and form_id == 0) break; try attrs.append(AbbrevAttr{ .attr_id = attr_id, @@ -1568,8 +1584,28 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con return null; } +fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { + const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); + if (abbrev_code == 0) return null; + const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; + + var result = Die{ + .tag_id = table_entry.tag_id, + .has_children = table_entry.has_children, + .attrs = ArrayList(Die.Attr).init(di.allocator()), + }; + try result.attrs.resize(table_entry.attrs.len); + for (table_entry.attrs.toSliceConst()) |attr, i| { + result.attrs.items[i] = Die.Attr{ + .id = attr.attr_id, + .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64), + }; + } + return result; +} + fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { - const abbrev_code = try readULeb128(di.dwarf_in_stream); + const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; var result = Die{ @@ -1682,9 +1718,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u while (true) { const file_name = readStringMem(&ptr); if (file_name.len == 0) break; - const dir_index = try readULeb128Mem(&ptr); - const mtime = try readULeb128Mem(&ptr); - const len_bytes = try readULeb128Mem(&ptr); + const dir_index = try leb.readULEB128Mem(usize, &ptr); + const mtime = try leb.readULEB128Mem(usize, &ptr); + const len_bytes = try leb.readULEB128Mem(usize, &ptr); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1698,7 +1734,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u const opcode = readByteMem(&ptr); if (opcode == DW.LNS_extended_op) { - const op_size = try readULeb128Mem(&ptr); + const op_size = try leb.readULEB128Mem(u64, &ptr); if (op_size < 1) return error.InvalidDebugInfo; var sub_op = readByteMem(&ptr); switch (sub_op) { @@ -1713,9 +1749,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u }, DW.LNE_define_file => { const file_name = readStringMem(&ptr); - const dir_index = try readULeb128Mem(&ptr); - const mtime = try readULeb128Mem(&ptr); - const len_bytes = try readULeb128Mem(&ptr); + const dir_index = try leb.readULEB128Mem(usize, &ptr); + const mtime = try leb.readULEB128Mem(usize, &ptr); + const len_bytes = try leb.readULEB128Mem(usize, &ptr); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1743,19 +1779,19 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u prog.basic_block = false; }, DW.LNS_advance_pc => { - const arg = try readULeb128Mem(&ptr); + const arg = try leb.readULEB128Mem(u64, &ptr); prog.address += arg * minimum_instruction_length; }, DW.LNS_advance_line => { - const arg = try readILeb128Mem(&ptr); + const arg = try leb.readILEB128Mem(i64, &ptr); prog.line += arg; }, DW.LNS_set_file => { - const arg = try readULeb128Mem(&ptr); + const arg = try leb.readULEB128Mem(u64, &ptr); prog.file = arg; }, DW.LNS_set_column => { - const arg = try readULeb128Mem(&ptr); + const arg = try leb.readULEB128Mem(u64, &ptr); prog.column = arg; }, DW.LNS_negate_stmt => { @@ -1787,182 +1823,292 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); + const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list); - const debug_line_end = di.debug_line.offset + di.debug_line.size; - var this_offset = di.debug_line.offset; - var this_index: usize = 0; + assert(line_info_offset < di.debug_line.size); - while (this_offset < debug_line_end) : (this_index += 1) { - try di.dwarf_seekable_stream.seekTo(this_offset); + try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset); - var is_64: bool = undefined; - const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); - if (unit_length == 0) return error.MissingDebugInfo; - const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); + var is_64: bool = undefined; + const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); + if (unit_length == 0) { + return error.MissingDebugInfo; + } + const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - if (compile_unit.index != this_index) { - this_offset += next_offset; - continue; - } + const version = try di.dwarf_in_stream.readInt(u16, di.endian); + // TODO support 3 and 5 + if (version != 2 and version != 4) return error.InvalidDebugInfo; - const version = try di.dwarf_in_stream.readInt(u16, di.endian); - // TODO support 3 and 5 - if (version != 2 and version != 4) return error.InvalidDebugInfo; + const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); + const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; + + const minimum_instruction_length = try di.dwarf_in_stream.readByte(); + if (minimum_instruction_length == 0) return error.InvalidDebugInfo; + + if (version >= 4) { + // maximum_operations_per_instruction + _ = try di.dwarf_in_stream.readByte(); + } + + const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0; + const line_base = try di.dwarf_in_stream.readByteSigned(); + + const line_range = try di.dwarf_in_stream.readByte(); + if (line_range == 0) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); - const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; + const opcode_base = try di.dwarf_in_stream.readByte(); - const minimum_instruction_length = try di.dwarf_in_stream.readByte(); - if (minimum_instruction_length == 0) return error.InvalidDebugInfo; + const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); - if (version >= 4) { - // maximum_operations_per_instruction - _ = try di.dwarf_in_stream.readByte(); + { + var i: usize = 0; + while (i < opcode_base - 1) : (i += 1) { + standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte(); } + } - const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0; - const line_base = try di.dwarf_in_stream.readByteSigned(); + var include_directories = ArrayList([]u8).init(di.allocator()); + try include_directories.append(compile_unit_cwd); + while (true) { + const dir = try di.readString(); + if (dir.len == 0) break; + try include_directories.append(dir); + } + + var file_entries = ArrayList(FileEntry).init(di.allocator()); + var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); - const line_range = try di.dwarf_in_stream.readByte(); - if (line_range == 0) return error.InvalidDebugInfo; + while (true) { + const file_name = try di.readString(); + if (file_name.len == 0) break; + const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream); + const mtime = try leb.readULEB128(usize, di.dwarf_in_stream); + const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream); + try file_entries.append(FileEntry{ + .file_name = file_name, + .dir_index = dir_index, + .mtime = mtime, + .len_bytes = len_bytes, + }); + } - const opcode_base = try di.dwarf_in_stream.readByte(); + try di.dwarf_seekable_stream.seekTo(prog_start_offset); - const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); + while (true) { + const opcode = try di.dwarf_in_stream.readByte(); - { - var i: usize = 0; - while (i < opcode_base - 1) : (i += 1) { - standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte(); + if (opcode == DW.LNS_extended_op) { + const op_size = try leb.readULEB128(u64, di.dwarf_in_stream); + if (op_size < 1) return error.InvalidDebugInfo; + var sub_op = try di.dwarf_in_stream.readByte(); + switch (sub_op) { + DW.LNE_end_sequence => { + prog.end_sequence = true; + if (try prog.checkLineMatch()) |info| return info; + return error.MissingDebugInfo; + }, + DW.LNE_set_address => { + const addr = try di.dwarf_in_stream.readInt(usize, di.endian); + prog.address = addr; + }, + DW.LNE_define_file => { + const file_name = try di.readString(); + const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream); + const mtime = try leb.readULEB128(usize, di.dwarf_in_stream); + const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream); + try file_entries.append(FileEntry{ + .file_name = file_name, + .dir_index = dir_index, + .mtime = mtime, + .len_bytes = len_bytes, + }); + }, + else => { + const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; + try di.dwarf_seekable_stream.seekForward(fwd_amt); + }, + } + } else if (opcode >= opcode_base) { + // special opcodes + const adjusted_opcode = opcode - opcode_base; + const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range); + const inc_line = i32(line_base) + i32(adjusted_opcode % line_range); + prog.line += inc_line; + prog.address += inc_addr; + if (try prog.checkLineMatch()) |info| return info; + prog.basic_block = false; + } else { + switch (opcode) { + DW.LNS_copy => { + if (try prog.checkLineMatch()) |info| return info; + prog.basic_block = false; + }, + DW.LNS_advance_pc => { + const arg = try leb.readULEB128(u64, di.dwarf_in_stream); + prog.address += arg * minimum_instruction_length; + }, + DW.LNS_advance_line => { + const arg = try leb.readILEB128(i64, di.dwarf_in_stream); + prog.line += arg; + }, + DW.LNS_set_file => { + const arg = try leb.readULEB128(u64, di.dwarf_in_stream); + prog.file = arg; + }, + DW.LNS_set_column => { + const arg = try leb.readULEB128(u64, di.dwarf_in_stream); + prog.column = arg; + }, + DW.LNS_negate_stmt => { + prog.is_stmt = !prog.is_stmt; + }, + DW.LNS_set_basic_block => { + prog.basic_block = true; + }, + DW.LNS_const_add_pc => { + const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range); + prog.address += inc_addr; + }, + DW.LNS_fixed_advance_pc => { + const arg = try di.dwarf_in_stream.readInt(u16, di.endian); + prog.address += arg; + }, + DW.LNS_set_prologue_end => {}, + else => { + if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; + const len_bytes = standard_opcode_lengths[opcode - 1]; + try di.dwarf_seekable_stream.seekForward(len_bytes); + }, } } + } - var include_directories = ArrayList([]u8).init(di.allocator()); - try include_directories.append(compile_unit_cwd); - while (true) { - const dir = try di.readString(); - if (dir.len == 0) break; - try include_directories.append(dir); - } + return error.MissingDebugInfo; +} - var file_entries = ArrayList(FileEntry).init(di.allocator()); - var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); +const Func = struct { + pc_range: ?PcRange, + name: ?[]u8, +}; - while (true) { - const file_name = try di.readString(); - if (file_name.len == 0) break; - const dir_index = try readULeb128(di.dwarf_in_stream); - const mtime = try readULeb128(di.dwarf_in_stream); - const len_bytes = try readULeb128(di.dwarf_in_stream); - try file_entries.append(FileEntry{ - .file_name = file_name, - .dir_index = dir_index, - .mtime = mtime, - .len_bytes = len_bytes, - }); +fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]const u8 { + for (di.func_list.toSliceConst()) |*func| { + if (func.pc_range) |range| { + if (address >= range.start and address < range.end) { + return func.name; + } } + } + + return null; +} - try di.dwarf_seekable_stream.seekTo(prog_start_offset); +fn scanAllFunctions(di: *DwarfInfo) !void { + const debug_info_end = di.debug_info.offset + di.debug_info.size; + var this_unit_offset = di.debug_info.offset; - while (true) { - const opcode = try di.dwarf_in_stream.readByte(); - - if (opcode == DW.LNS_extended_op) { - const op_size = try readULeb128(di.dwarf_in_stream); - if (op_size < 1) return error.InvalidDebugInfo; - var sub_op = try di.dwarf_in_stream.readByte(); - switch (sub_op) { - DW.LNE_end_sequence => { - prog.end_sequence = true; - if (try prog.checkLineMatch()) |info| return info; - return error.MissingDebugInfo; - }, - DW.LNE_set_address => { - const addr = try di.dwarf_in_stream.readInt(usize, di.endian); - prog.address = addr; - }, - DW.LNE_define_file => { - const file_name = try di.readString(); - const dir_index = try readULeb128(di.dwarf_in_stream); - const mtime = try readULeb128(di.dwarf_in_stream); - const len_bytes = try readULeb128(di.dwarf_in_stream); - try file_entries.append(FileEntry{ - .file_name = file_name, - .dir_index = dir_index, - .mtime = mtime, - .len_bytes = len_bytes, - }); - }, - else => { - const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; - try di.dwarf_seekable_stream.seekForward(fwd_amt); - }, - } - } else if (opcode >= opcode_base) { - // special opcodes - const adjusted_opcode = opcode - opcode_base; - const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range); - const inc_line = i32(line_base) + i32(adjusted_opcode % line_range); - prog.line += inc_line; - prog.address += inc_addr; - if (try prog.checkLineMatch()) |info| return info; - prog.basic_block = false; - } else { - switch (opcode) { - DW.LNS_copy => { - if (try prog.checkLineMatch()) |info| return info; - prog.basic_block = false; - }, - DW.LNS_advance_pc => { - const arg = try readULeb128(di.dwarf_in_stream); - prog.address += arg * minimum_instruction_length; - }, - DW.LNS_advance_line => { - const arg = try readILeb128(di.dwarf_in_stream); - prog.line += arg; - }, - DW.LNS_set_file => { - const arg = try readULeb128(di.dwarf_in_stream); - prog.file = arg; - }, - DW.LNS_set_column => { - const arg = try readULeb128(di.dwarf_in_stream); - prog.column = arg; - }, - DW.LNS_negate_stmt => { - prog.is_stmt = !prog.is_stmt; - }, - DW.LNS_set_basic_block => { - prog.basic_block = true; - }, - DW.LNS_const_add_pc => { - const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range); - prog.address += inc_addr; - }, - DW.LNS_fixed_advance_pc => { - const arg = try di.dwarf_in_stream.readInt(u16, di.endian); - prog.address += arg; - }, - DW.LNS_set_prologue_end => {}, - else => { - if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; - const len_bytes = standard_opcode_lengths[opcode - 1]; - try di.dwarf_seekable_stream.seekForward(len_bytes); - }, - } + while (this_unit_offset < debug_info_end) { + try di.dwarf_seekable_stream.seekTo(this_unit_offset); + + var is_64: bool = undefined; + const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); + if (unit_length == 0) return; + const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); + + const version = try di.dwarf_in_stream.readInt(u16, di.endian); + if (version < 2 or version > 5) return error.InvalidDebugInfo; + + const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); + + const address_size = try di.dwarf_in_stream.readByte(); + if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; + + const compile_unit_pos = try di.dwarf_seekable_stream.getPos(); + const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset); + + try di.dwarf_seekable_stream.seekTo(compile_unit_pos); + + const next_unit_pos = this_unit_offset + next_offset; + + while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) { + const die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse continue; + const after_die_offset = try di.dwarf_seekable_stream.getPos(); + + switch (die_obj.tag_id) { + DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => { + const fn_name = x: { + var depth: i32 = 3; + var this_die_obj = die_obj; + // Prenvent endless loops + while (depth > 0) : (depth -= 1) { + if (this_die_obj.getAttr(DW.AT_name)) |_| { + const name = try this_die_obj.getAttrString(di, DW.AT_name); + break :x name; + } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| { + // Follow the DIE it points to and repeat + const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin); + if (ref_offset > next_offset) return error.InvalidDebugInfo; + try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset); + this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| { + // Follow the DIE it points to and repeat + const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification); + if (ref_offset > next_offset) return error.InvalidDebugInfo; + try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset); + this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + } else { + break :x null; + } + } + + break :x null; + }; + + const pc_range = x: { + if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| { + if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| { + const pc_end = switch (high_pc_value.*) { + FormValue.Address => |value| value, + FormValue.Const => |value| b: { + const offset = try value.asUnsignedLe(); + break :b (low_pc + offset); + }, + else => return error.InvalidDebugInfo, + }; + break :x PcRange{ + .start = low_pc, + .end = pc_end, + }; + } else { + break :x null; + } + } else |err| { + if (err != error.MissingDebugInfo) return err; + break :x null; + } + }; + + try di.func_list.append(Func{ + .name = fn_name, + .pc_range = pc_range, + }); + }, + else => { + continue; + }, } + + try di.dwarf_seekable_stream.seekTo(after_die_offset); } - this_offset += next_offset; + this_unit_offset += next_offset; } - - return error.MissingDebugInfo; } fn scanAllCompileUnits(di: *DwarfInfo) !void { const debug_info_end = di.debug_info.offset + di.debug_info.size; var this_unit_offset = di.debug_info.offset; - var cu_index: usize = 0; while (this_unit_offset < debug_info_end) { try di.dwarf_seekable_stream.seekTo(this_unit_offset); @@ -2019,11 +2165,9 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { .is_64 = is_64, .pc_range = pc_range, .die = compile_unit_die, - .index = cu_index, }); this_unit_offset += next_offset; - cu_index += 1; } } @@ -2098,52 +2242,6 @@ fn readStringMem(ptr: *[*]const u8) []const u8 { return result; } -fn readULeb128Mem(ptr: *[*]const u8) !u64 { - var result: u64 = 0; - var shift: usize = 0; - var i: usize = 0; - - while (true) { - const byte = ptr.*[i]; - i += 1; - - var operand: u64 = undefined; - - if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo; - - result |= operand; - - if ((byte & 0b10000000) == 0) { - ptr.* += i; - return result; - } - - shift += 7; - } -} -fn readILeb128Mem(ptr: *[*]const u8) !i64 { - var result: i64 = 0; - var shift: usize = 0; - var i: usize = 0; - - while (true) { - const byte = ptr.*[i]; - i += 1; - - var operand: i64 = undefined; - if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo; - - result |= operand; - shift += 7; - - if ((byte & 0b10000000) == 0) { - if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift)); - ptr.* += i; - return result; - } - } -} - fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { const first_32_bits = try in_stream.readIntLittle(u32); is_64.* = (first_32_bits == 0xffffffff); @@ -2155,46 +2253,6 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) } } -fn readULeb128(in_stream: var) !u64 { - var result: u64 = 0; - var shift: usize = 0; - - while (true) { - const byte = try in_stream.readByte(); - - var operand: u64 = undefined; - - if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo; - - result |= operand; - - if ((byte & 0b10000000) == 0) return result; - - shift += 7; - } -} - -fn readILeb128(in_stream: var) !i64 { - var result: i64 = 0; - var shift: usize = 0; - - while (true) { - const byte = try in_stream.readByte(); - - var operand: i64 = undefined; - - if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo; - - result |= operand; - shift += 7; - - if ((byte & 0b10000000) == 0) { - if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift)); - return result; - } - } -} - /// This should only be used in temporary test programs. pub const global_allocator = &global_fixed_allocator.allocator; var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); diff --git a/std/debug/failing_allocator.zig b/std/debug/failing_allocator.zig index 7a89460513..5776d23194 100644 --- a/std/debug/failing_allocator.zig +++ b/std/debug/failing_allocator.zig @@ -10,6 +10,7 @@ pub const FailingAllocator = struct { internal_allocator: *mem.Allocator, allocated_bytes: usize, freed_bytes: usize, + allocations: usize, deallocations: usize, pub fn init(allocator: *mem.Allocator, fail_index: usize) FailingAllocator { @@ -19,6 +20,7 @@ pub const FailingAllocator = struct { .index = 0, .allocated_bytes = 0, .freed_bytes = 0, + .allocations = 0, .deallocations = 0, .allocator = mem.Allocator{ .reallocFn = realloc, @@ -39,19 +41,25 @@ pub const FailingAllocator = struct { new_size, new_align, ); - if (new_size <= old_mem.len) { + if (new_size < old_mem.len) { self.freed_bytes += old_mem.len - new_size; - } else { + if (new_size == 0) + self.deallocations += 1; + } else if (new_size > old_mem.len) { self.allocated_bytes += new_size - old_mem.len; + if (old_mem.len == 0) + self.allocations += 1; } - self.deallocations += 1; self.index += 1; return result; } fn shrink(allocator: *mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); - self.freed_bytes += old_mem.len - new_size; - return self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + const r = self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + self.freed_bytes += old_mem.len - r.len; + if (new_size == 0) + self.deallocations += 1; + return r; } }; diff --git a/std/debug/leb128.zig b/std/debug/leb128.zig new file mode 100644 index 0000000000..2801877839 --- /dev/null +++ b/std/debug/leb128.zig @@ -0,0 +1,228 @@ +const std = @import("std"); +const testing = std.testing; + +pub fn readULEB128(comptime T: type, in_stream: var) !T { + const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + + var result: T = 0; + var shift: usize = 0; + + while (true) { + const byte = try in_stream.readByte(); + + if (shift > T.bit_count) + return error.Overflow; + + var operand: T = undefined; + if (@shlWithOverflow(T, byte & 0x7f, @intCast(ShiftT, shift), &operand)) + return error.Overflow; + + result |= operand; + + if ((byte & 0x80) == 0) + return result; + + shift += 7; + } +} + +pub fn readULEB128Mem(comptime T: type, ptr: *[*]const u8) !T { + const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + + var result: T = 0; + var shift: usize = 0; + var i: usize = 0; + + while (true) : (i += 1) { + const byte = ptr.*[i]; + + if (shift > T.bit_count) + return error.Overflow; + + var operand: T = undefined; + if (@shlWithOverflow(T, byte & 0x7f, @intCast(ShiftT, shift), &operand)) + return error.Overflow; + + result |= operand; + + if ((byte & 0x80) == 0) { + ptr.* += i; + return result; + } + + shift += 7; + } +} + +pub fn readILEB128(comptime T: type, in_stream: var) !T { + const UT = @IntType(false, T.bit_count); + const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + + var result: UT = 0; + var shift: usize = 0; + + while (true) { + const byte = u8(try in_stream.readByte()); + + if (shift > T.bit_count) + return error.Overflow; + + var operand: UT = undefined; + if (@shlWithOverflow(UT, UT(byte & 0x7f), @intCast(ShiftT, shift), &operand)) { + if (byte != 0x7f) + return error.Overflow; + } + + result |= operand; + + shift += 7; + + if ((byte & 0x80) == 0) { + if (shift < T.bit_count and (byte & 0x40) != 0) { + result |= @bitCast(UT, @intCast(T, -1)) << @intCast(ShiftT, shift); + } + return @bitCast(T, result); + } + } +} + +pub fn readILEB128Mem(comptime T: type, ptr: *[*]const u8) !T { + const UT = @IntType(false, T.bit_count); + const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + + var result: UT = 0; + var shift: usize = 0; + var i: usize = 0; + + while (true) : (i += 1) { + const byte = ptr.*[i]; + + if (shift > T.bit_count) + return error.Overflow; + + var operand: UT = undefined; + if (@shlWithOverflow(UT, UT(byte & 0x7f), @intCast(ShiftT, shift), &operand)) { + if (byte != 0x7f) + return error.Overflow; + } + + result |= operand; + + shift += 7; + + if ((byte & 0x80) == 0) { + if (shift < T.bit_count and (byte & 0x40) != 0) { + result |= @bitCast(UT, @intCast(T, -1)) << @intCast(ShiftT, shift); + } + ptr.* += i; + return @bitCast(T, result); + } + } +} + +fn test_read_stream_ileb128(comptime T: type, encoded: []const u8) !T { + var in_stream = std.io.SliceInStream.init(encoded); + return try readILEB128(T, &in_stream.stream); +} + +fn test_read_stream_uleb128(comptime T: type, encoded: []const u8) !T { + var in_stream = std.io.SliceInStream.init(encoded); + return try readULEB128(T, &in_stream.stream); +} + +fn test_read_ileb128(comptime T: type, encoded: []const u8) !T { + var in_stream = std.io.SliceInStream.init(encoded); + const v1 = readILEB128(T, &in_stream.stream); + var in_ptr = encoded.ptr; + const v2 = readILEB128Mem(T, &in_ptr); + testing.expectEqual(v1, v2); + return v1; +} + +fn test_read_uleb128(comptime T: type, encoded: []const u8) !T { + var in_stream = std.io.SliceInStream.init(encoded); + const v1 = readULEB128(T, &in_stream.stream); + var in_ptr = encoded.ptr; + const v2 = readULEB128Mem(T, &in_ptr); + testing.expectEqual(v1, v2); + return v1; +} + +test "deserialize signed LEB128" { + // Truncated + testing.expectError(error.EndOfStream, test_read_stream_ileb128(i64, "\x80")); + + // Overflow + testing.expectError(error.Overflow, test_read_ileb128(i8, "\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_ileb128(i16, "\x80\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_ileb128(i32, "\x80\x80\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_ileb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_ileb128(i8, "\xff\x7e")); + + // Decode SLEB128 + testing.expect((try test_read_ileb128(i64, "\x00")) == 0); + testing.expect((try test_read_ileb128(i64, "\x01")) == 1); + testing.expect((try test_read_ileb128(i64, "\x3f")) == 63); + testing.expect((try test_read_ileb128(i64, "\x40")) == -64); + testing.expect((try test_read_ileb128(i64, "\x41")) == -63); + testing.expect((try test_read_ileb128(i64, "\x7f")) == -1); + testing.expect((try test_read_ileb128(i64, "\x80\x01")) == 128); + testing.expect((try test_read_ileb128(i64, "\x81\x01")) == 129); + testing.expect((try test_read_ileb128(i64, "\xff\x7e")) == -129); + testing.expect((try test_read_ileb128(i64, "\x80\x7f")) == -128); + testing.expect((try test_read_ileb128(i64, "\x81\x7f")) == -127); + testing.expect((try test_read_ileb128(i64, "\xc0\x00")) == 64); + testing.expect((try test_read_ileb128(i64, "\xc7\x9f\x7f")) == -12345); + testing.expect((try test_read_ileb128(i8, "\xff\x7f")) == -1); + testing.expect((try test_read_ileb128(i16, "\xff\xff\x7f")) == -1); + testing.expect((try test_read_ileb128(i32, "\xff\xff\xff\xff\x7f")) == -1); + testing.expect((try test_read_ileb128(i32, "\x80\x80\x80\x80\x08")) == -0x80000000); + testing.expect((try test_read_ileb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01")) == @bitCast(i64, @intCast(u64, 0x8000000000000000))); + testing.expect((try test_read_ileb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x40")) == -0x4000000000000000); + testing.expect((try test_read_ileb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x7f")) == -0x8000000000000000); + + // Decode unnormalized SLEB128 with extra padding bytes. + testing.expect((try test_read_ileb128(i64, "\x80\x00")) == 0); + testing.expect((try test_read_ileb128(i64, "\x80\x80\x00")) == 0); + testing.expect((try test_read_ileb128(i64, "\xff\x00")) == 0x7f); + testing.expect((try test_read_ileb128(i64, "\xff\x80\x00")) == 0x7f); + testing.expect((try test_read_ileb128(i64, "\x80\x81\x00")) == 0x80); + testing.expect((try test_read_ileb128(i64, "\x80\x81\x80\x00")) == 0x80); +} + +test "deserialize unsigned LEB128" { + // Truncated + testing.expectError(error.EndOfStream, test_read_stream_uleb128(u64, "\x80")); + + // Overflow + testing.expectError(error.Overflow, test_read_uleb128(u8, "\x80\x02")); + testing.expectError(error.Overflow, test_read_uleb128(u8, "\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_uleb128(u16, "\x80\x80\x84")); + testing.expectError(error.Overflow, test_read_uleb128(u16, "\x80\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_uleb128(u32, "\x80\x80\x80\x80\x90")); + testing.expectError(error.Overflow, test_read_uleb128(u32, "\x80\x80\x80\x80\x40")); + testing.expectError(error.Overflow, test_read_uleb128(u64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x40")); + + // Decode ULEB128 + testing.expect((try test_read_uleb128(u64, "\x00")) == 0); + testing.expect((try test_read_uleb128(u64, "\x01")) == 1); + testing.expect((try test_read_uleb128(u64, "\x3f")) == 63); + testing.expect((try test_read_uleb128(u64, "\x40")) == 64); + testing.expect((try test_read_uleb128(u64, "\x7f")) == 0x7f); + testing.expect((try test_read_uleb128(u64, "\x80\x01")) == 0x80); + testing.expect((try test_read_uleb128(u64, "\x81\x01")) == 0x81); + testing.expect((try test_read_uleb128(u64, "\x90\x01")) == 0x90); + testing.expect((try test_read_uleb128(u64, "\xff\x01")) == 0xff); + testing.expect((try test_read_uleb128(u64, "\x80\x02")) == 0x100); + testing.expect((try test_read_uleb128(u64, "\x81\x02")) == 0x101); + testing.expect((try test_read_uleb128(u64, "\x80\xc1\x80\x80\x10")) == 4294975616); + testing.expect((try test_read_uleb128(u64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01")) == 0x8000000000000000); + + // Decode ULEB128 with extra padding bytes + testing.expect((try test_read_uleb128(u64, "\x80\x00")) == 0); + testing.expect((try test_read_uleb128(u64, "\x80\x80\x00")) == 0); + testing.expect((try test_read_uleb128(u64, "\xff\x00")) == 0x7f); + testing.expect((try test_read_uleb128(u64, "\xff\x80\x00")) == 0x7f); + testing.expect((try test_read_uleb128(u64, "\x80\x81\x00")) == 0x80); + testing.expect((try test_read_uleb128(u64, "\x80\x81\x80\x00")) == 0x80); +} diff --git a/std/dwarf.zig b/std/dwarf.zig index 2cf8ed953e..2f3b29302d 100644 --- a/std/dwarf.zig +++ b/std/dwarf.zig @@ -13,6 +13,7 @@ pub const TAG_reference_type = 0x10; pub const TAG_compile_unit = 0x11; pub const TAG_string_type = 0x12; pub const TAG_structure_type = 0x13; +pub const TAG_subroutine = 0x14; pub const TAG_subroutine_type = 0x15; pub const TAG_typedef = 0x16; pub const TAG_union_type = 0x17; @@ -241,6 +242,9 @@ pub const AT_const_expr = 0x6c; pub const AT_enum_class = 0x6d; pub const AT_linkage_name = 0x6e; +// DWARF 5 +pub const AT_alignment = 0x88; + pub const AT_lo_user = 0x2000; // Implementation-defined range start. pub const AT_hi_user = 0x3fff; // Implementation-defined range end. diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 698b0eb216..b2064311db 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -19,6 +19,89 @@ pub const DynLib = switch (builtin.os) { else => void, }; +// The link_map structure is not completely specified beside the fields +// reported below, any libc is free to store additional data in the remaining +// space. +// An iterator is provided in order to traverse the linked list in a idiomatic +// fashion. +const LinkMap = extern struct { + l_addr: usize, + l_name: [*]const u8, + l_ld: ?*elf.Dyn, + l_next: ?*LinkMap, + l_prev: ?*LinkMap, + + pub const Iterator = struct { + current: ?*LinkMap, + + fn end(self: *Iterator) bool { + return self.current == null; + } + + fn next(self: *Iterator) ?*LinkMap { + if (self.current) |it| { + self.current = it.l_next; + return it; + } + return null; + } + }; +}; + +const RDebug = extern struct { + r_version: i32, + r_map: ?*LinkMap, + r_brk: usize, + r_ldbase: usize, +}; + +fn elf_get_va_offset(phdrs: []elf.Phdr) !usize { + for (phdrs) |*phdr| { + if (phdr.p_type == elf.PT_LOAD) { + return @ptrToInt(phdr) - phdr.p_vaddr; + } + } + return error.InvalidExe; +} + +pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator { + const va_offset = try elf_get_va_offset(phdrs); + + const dyn_table = init: { + for (phdrs) |*phdr| { + if (phdr.p_type == elf.PT_DYNAMIC) { + const ptr = @intToPtr([*]elf.Dyn, va_offset + phdr.p_vaddr); + break :init ptr[0..phdr.p_memsz / @sizeOf(elf.Dyn)]; + } + } + // No PT_DYNAMIC means this is either a statically-linked program or a + // badly corrupted one + return LinkMap.Iterator{.current = null}; + }; + + const link_map_ptr = init: { + for (dyn_table) |*dyn| { + switch (dyn.d_tag) { + elf.DT_DEBUG => { + const r_debug = @intToPtr(*RDebug, dyn.d_un.d_ptr); + if (r_debug.r_version != 1) return error.InvalidExe; + break :init r_debug.r_map; + }, + elf.DT_PLTGOT => { + const got_table = @intToPtr([*]usize, dyn.d_un.d_ptr); + // The address to the link_map structure is stored in the + // second slot + break :init @intToPtr(?*LinkMap, got_table[1]); + }, + else => { } + } + } + return error.InvalidExe; + }; + + return LinkMap.Iterator{.current = link_map_ptr}; +} + pub const LinuxDynLib = struct { elf_lib: ElfLib, fd: i32, diff --git a/std/elf.zig b/std/elf.zig index d0ec5fb2ae..49f2f7d137 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -877,6 +877,11 @@ pub const Phdr = switch (@sizeOf(usize)) { 8 => Elf64_Phdr, else => @compileError("expected pointer size of 32 or 64"), }; +pub const Dyn = switch (@sizeOf(usize)) { + 4 => Elf32_Dyn, + 8 => Elf64_Dyn, + else => @compileError("expected pointer size of 32 or 64"), +}; pub const Shdr = switch (@sizeOf(usize)) { 4 => Elf32_Shdr, 8 => Elf64_Shdr, diff --git a/std/fmt.zig b/std/fmt.zig index 6402271563..e4738d430d 100644 --- a/std/fmt.zig +++ b/std/fmt.zig @@ -8,6 +8,8 @@ const builtin = @import("builtin"); const errol = @import("fmt/errol.zig"); const lossyCast = std.math.lossyCast; +pub const default_max_depth = 3; + /// Renders fmt string with args, calling output with slices of bytes. /// If `output` returns an error, the error is returned from `format` and /// `output` is not called again. @@ -49,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), start_index = i; }, '}' => { - try formatType(args[next_arg], fmt[0..0], context, Errors, output); + try formatType(args[next_arg], fmt[0..0], context, Errors, output, default_max_depth); next_arg += 1; state = State.Start; start_index = i + 1; @@ -69,7 +71,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), State.FormatString => switch (c) { '}' => { const s = start_index + 1; - try formatType(args[next_arg], fmt[s..i], context, Errors, output); + try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth); next_arg += 1; state = State.Start; start_index = i + 1; @@ -108,6 +110,7 @@ pub fn formatType( context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, + max_depth: usize, ) Errors!void { const T = @typeOf(value); switch (@typeInfo(T)) { @@ -122,16 +125,16 @@ pub fn formatType( }, builtin.TypeId.Optional => { if (value) |payload| { - return formatType(payload, fmt, context, Errors, output); + return formatType(payload, fmt, context, Errors, output, max_depth); } else { return output(context, "null"); } }, builtin.TypeId.ErrorUnion => { if (value) |payload| { - return formatType(payload, fmt, context, Errors, output); + return formatType(payload, fmt, context, Errors, output, max_depth); } else |err| { - return formatType(err, fmt, context, Errors, output); + return formatType(err, fmt, context, Errors, output, max_depth); } }, builtin.TypeId.ErrorSet => { @@ -164,10 +167,13 @@ pub fn formatType( switch (comptime @typeId(T)) { builtin.TypeId.Enum => { try output(context, "."); - try formatType(@tagName(value), "", context, Errors, output); + try formatType(@tagName(value), "", context, Errors, output, max_depth); return; }, builtin.TypeId.Struct => { + if (max_depth == 0) { + return output(context, "{ ... }"); + } comptime var field_i = 0; inline while (field_i < @memberCount(T)) : (field_i += 1) { if (field_i == 0) { @@ -177,11 +183,14 @@ pub fn formatType( } try output(context, @memberName(T, field_i)); try output(context, " = "); - try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output); + try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth-1); } try output(context, " }"); }, builtin.TypeId.Union => { + if (max_depth == 0) { + return output(context, "{ ... }"); + } const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { try output(context, "{ ."); @@ -189,7 +198,7 @@ pub fn formatType( try output(context, " = "); inline for (info.fields) |u_field| { if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) { - try formatType(@field(value, u_field.name), "", context, Errors, output); + try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth-1); } } try output(context, " }"); @@ -210,7 +219,7 @@ pub fn formatType( return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)); }, builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => { - return formatType(value.*, fmt, context, Errors, output); + return formatType(value.*, fmt, context, Errors, output, max_depth); }, else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)), }, @@ -986,17 +995,17 @@ test "fmt.format" { { var buf1: [32]u8 = undefined; var context = BufPrintContext{ .remaining = buf1[0..] }; - try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite); + try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth); var res = buf1[0 .. buf1.len - context.remaining.len]; testing.expect(mem.eql(u8, res, "1234")); context = BufPrintContext{ .remaining = buf1[0..] }; - try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); + try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth); res = buf1[0 .. buf1.len - context.remaining.len]; testing.expect(mem.eql(u8, res, "a")); context = BufPrintContext{ .remaining = buf1[0..] }; - try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); + try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth); res = buf1[0 .. buf1.len - context.remaining.len]; testing.expect(mem.eql(u8, res, "1100")); } @@ -1364,6 +1373,20 @@ test "fmt.format" { try testFmt("E.Two", "{}", inst); } + //self-referential struct format + { + const S = struct { + const SelfType = @This(); + a: ?*SelfType, + }; + + var inst = S{ + .a = null, + }; + inst.a = &inst; + + try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst); + } //print bytes as hex { const some_bytes = "\xCA\xFE\xBA\xBE"; @@ -1449,3 +1472,64 @@ test "fmt.formatIntValue with comptime_int" { try formatIntValue(value, "", &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append); assert(mem.eql(u8, buf.toSlice(), "123456789123456789")); } + +test "fmt.formatType max_depth" { + const Vec2 = struct { + const SelfType = @This(); + x: f32, + y: f32, + + pub fn format( + self: SelfType, + comptime fmt: []const u8, + context: var, + comptime Errors: type, + output: fn (@typeOf(context), []const u8) Errors!void, + ) Errors!void { + return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y); + } + }; + const E = enum { + One, + Two, + Three, + }; + const TU = union(enum) { + const SelfType = @This(); + float: f32, + int: u32, + ptr: ?*SelfType, + }; + const S = struct { + const SelfType = @This(); + a: ?*SelfType, + tu: TU, + e: E, + vec: Vec2, + }; + + var inst = S{ + .a = null, + .tu = TU{ .ptr = null }, + .e = E.Two, + .vec = Vec2{ .x = 10.2, .y = 2.22 }, + }; + inst.a = &inst; + inst.tu.ptr = &inst.tu; + + var buf0 = try std.Buffer.init(std.debug.global_allocator, ""); + try formatType(inst, "", &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0); + assert(mem.eql(u8, buf0.toSlice(), "S{ ... }")); + + var buf1 = try std.Buffer.init(std.debug.global_allocator, ""); + try formatType(inst, "", &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1); + assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); + + var buf2 = try std.Buffer.init(std.debug.global_allocator, ""); + try formatType(inst, "", &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2); + assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); + + var buf3 = try std.Buffer.init(std.debug.global_allocator, ""); + try formatType(inst, "", &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3); + assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); +} diff --git a/std/hash_map.zig b/std/hash_map.zig index f4c0b87167..9cd1ea052c 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -118,7 +118,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 }; } self.incrementModificationCount(); - try self.ensureCapacity(); + try self.autoCapacity(); const put_result = self.internalPut(key); assert(put_result.old_kv == null); return GetOrPutResult{ @@ -135,15 +135,37 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 return res.kv; } - fn ensureCapacity(self: *Self) !void { - if (self.entries.len == 0) { - return self.initCapacity(16); + fn optimizedCapacity(expected_count: usize) usize { + // ensure that the hash map will be at most 60% full if + // expected_count items are put into it + var optimized_capacity = expected_count * 5 / 3; + // round capacity to the next power of two + const pow = math.log2_int_ceil(usize, optimized_capacity); + return math.pow(usize, 2, pow); + } + + /// Increases capacity so that the hash map will be at most + /// 60% full when expected_count items are put into it + pub fn ensureCapacity(self: *Self, expected_count: usize) !void { + const optimized_capacity = optimizedCapacity(expected_count); + return self.ensureCapacityExact(optimized_capacity); + } + + /// Sets the capacity to the new capacity if the new + /// capacity is greater than the current capacity. + /// New capacity must be a power of two. + fn ensureCapacityExact(self: *Self, new_capacity: usize) !void { + const is_power_of_two = new_capacity & (new_capacity-1) == 0; + assert(is_power_of_two); + + if (new_capacity <= self.entries.len) { + return; } - // if we get too full (60%), double the capacity - if (self.size * 5 >= self.entries.len * 3) { - const old_entries = self.entries; - try self.initCapacity(self.entries.len * 2); + const old_entries = self.entries; + try self.initCapacity(new_capacity); + self.incrementModificationCount(); + if (old_entries.len > 0) { // dump all of the old elements into the new table for (old_entries) |*old_entry| { if (old_entry.used) { @@ -156,8 +178,13 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 /// Returns the kv pair that was already there. pub fn put(self: *Self, key: K, value: V) !?KV { + try self.autoCapacity(); + return putAssumeCapacity(self, key, value); + } + + pub fn putAssumeCapacity(self: *Self, key: K, value: V) ?KV { + assert(self.count() < self.entries.len); self.incrementModificationCount(); - try self.ensureCapacity(); const put_result = self.internalPut(key); put_result.new_entry.kv.value = value; @@ -175,7 +202,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 return hm.get(key) != null; } - pub fn remove(hm: *Self, key: K) ?*KV { + pub fn remove(hm: *Self, key: K) ?KV { if (hm.entries.len == 0) return null; hm.incrementModificationCount(); const start_index = hm.keyToIndex(key); @@ -189,13 +216,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 if (!eql(entry.kv.key, key)) continue; + const removed_kv = entry.kv; while (roll_over < hm.entries.len) : (roll_over += 1) { const next_index = (start_index + roll_over + 1) % hm.entries.len; const next_entry = &hm.entries[next_index]; if (!next_entry.used or next_entry.distance_from_start_index == 0) { entry.used = false; hm.size -= 1; - return &entry.kv; + return removed_kv; } entry.* = next_entry.*; entry.distance_from_start_index -= 1; @@ -226,6 +254,16 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 return other; } + fn autoCapacity(self: *Self) !void { + if (self.entries.len == 0) { + return self.ensureCapacityExact(16); + } + // if we get too full (60%), double the capacity + if (self.size * 5 >= self.entries.len * 3) { + return self.ensureCapacityExact(self.entries.len * 2); + } + } + fn initCapacity(hm: *Self, capacity: usize) !void { hm.entries = try hm.allocator.alloc(Entry, capacity); hm.size = 0; @@ -371,7 +409,10 @@ test "basic hash map usage" { testing.expect(map.contains(2)); testing.expect(map.get(2).?.value == 22); - _ = map.remove(2); + + const rmv1 = map.remove(2); + testing.expect(rmv1.?.key == 2); + testing.expect(rmv1.?.value == 22); testing.expect(map.remove(2) == null); testing.expect(map.get(2) == null); } @@ -423,6 +464,24 @@ test "iterator hash map" { testing.expect(entry.value == values[0]); } +test "ensure capacity" { + var direct_allocator = std.heap.DirectAllocator.init(); + defer direct_allocator.deinit(); + + var map = AutoHashMap(i32, i32).init(&direct_allocator.allocator); + defer map.deinit(); + + try map.ensureCapacity(20); + const initialCapacity = map.entries.len; + testing.expect(initialCapacity >= 20); + var i : i32 = 0; + while (i < 20) : (i += 1) { + testing.expect(map.putAssumeCapacity(i, i+10) == null); + } + // shouldn't resize from putAssumeCapacity + testing.expect(initialCapacity == map.entries.len); +} + pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) { return struct { fn hash(key: K) u32 { diff --git a/std/heap.zig b/std/heap.zig index dd5cfa4cd7..8e3cccc365 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -34,9 +34,6 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new /// Thread-safe and lock-free. pub const DirectAllocator = struct { allocator: Allocator, - heap_handle: ?HeapHandle, - - const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void; pub fn init() DirectAllocator { return DirectAllocator{ @@ -44,21 +41,15 @@ pub const DirectAllocator = struct { .reallocFn = realloc, .shrinkFn = shrink, }, - .heap_handle = if (builtin.os == Os.windows) null else {}, }; } - pub fn deinit(self: *DirectAllocator) void { - switch (builtin.os) { - Os.windows => if (self.heap_handle) |heap_handle| { - _ = os.windows.HeapDestroy(heap_handle); - }, - else => {}, - } - } + pub fn deinit(self: *DirectAllocator) void {} fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); + if (n == 0) + return (([*]u8)(undefined))[0..0]; switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { @@ -68,39 +59,76 @@ pub const DirectAllocator = struct { if (addr == p.MAP_FAILED) return error.OutOfMemory; if (alloc_size == n) return @intToPtr([*]u8, addr)[0..n]; - const aligned_addr = (addr & ~usize(alignment - 1)) + alignment; - - // We can unmap the unused portions of our mmap, but we must only - // pass munmap bytes that exist outside our allocated pages or it - // will happily eat us too. - - // Since alignment > page_size, we are by definition on a page boundary. - const unused_start = addr; - const unused_len = aligned_addr - 1 - unused_start; - - const err = p.munmap(unused_start, unused_len); - assert(p.getErrno(err) == 0); + const aligned_addr = mem.alignForward(addr, alignment); - // It is impossible that there is an unoccupied page at the top of our - // mmap. + // Unmap the extra bytes that were only requested in order to guarantee + // that the range of memory we were provided had a proper alignment in + // it somewhere. The extra bytes could be at the beginning, or end, or both. + const unused_start_len = aligned_addr - addr; + if (unused_start_len != 0) { + const err = p.munmap(addr, unused_start_len); + assert(p.getErrno(err) == 0); + } + const aligned_end_addr = std.mem.alignForward(aligned_addr + n, os.page_size); + const unused_end_len = addr + alloc_size - aligned_end_addr; + if (unused_end_len != 0) { + const err = p.munmap(aligned_end_addr, unused_end_len); + assert(p.getErrno(err) == 0); + } return @intToPtr([*]u8, aligned_addr)[0..n]; }, - Os.windows => { - const amt = n + alignment + @sizeOf(usize); - const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst); - const heap_handle = optional_heap_handle orelse blk: { - const hh = os.windows.HeapCreate(0, amt, 0) orelse return error.OutOfMemory; - const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh; - _ = os.windows.HeapDestroy(hh); - break :blk other_hh.?; // can't be null because of the cmpxchg - }; - const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory; - const root_addr = @ptrToInt(ptr); - const adjusted_addr = mem.alignForward(root_addr, alignment); - const record_addr = adjusted_addr + n; - @intToPtr(*align(1) usize, record_addr).* = root_addr; - return @intToPtr([*]u8, adjusted_addr)[0..n]; + .windows => { + const w = os.windows; + + // Although officially it's at least aligned to page boundary, + // Windows is known to reserve pages on a 64K boundary. It's + // even more likely that the requested alignment is <= 64K than + // 4K, so we're just allocating blindly and hoping for the best. + // see https://devblogs.microsoft.com/oldnewthing/?p=42223 + const addr = w.VirtualAlloc( + null, + n, + w.MEM_COMMIT | w.MEM_RESERVE, + w.PAGE_READWRITE, + ) orelse return error.OutOfMemory; + + // If the allocation is sufficiently aligned, use it. + if (@ptrToInt(addr) & (alignment - 1) == 0) { + return @ptrCast([*]u8, addr)[0..n]; + } + + // If it wasn't, actually do an explicitely aligned allocation. + if (w.VirtualFree(addr, 0, w.MEM_RELEASE) == 0) unreachable; + const alloc_size = n + alignment; + + const final_addr = while (true) { + // Reserve a range of memory large enough to find a sufficiently + // aligned address. + const reserved_addr = w.VirtualAlloc( + null, + alloc_size, + w.MEM_RESERVE, + w.PAGE_NOACCESS, + ) orelse return error.OutOfMemory; + const aligned_addr = mem.alignForward(@ptrToInt(reserved_addr), alignment); + + // Release the reserved pages (not actually used). + if (w.VirtualFree(reserved_addr, 0, w.MEM_RELEASE) == 0) unreachable; + + // At this point, it is possible that another thread has + // obtained some memory space that will cause the next + // VirtualAlloc call to fail. To handle this, we will retry + // until it succeeds. + if (w.VirtualAlloc( + @intToPtr(*c_void, aligned_addr), + n, + w.MEM_COMMIT | w.MEM_RESERVE, + w.PAGE_READWRITE, + )) |ptr| break ptr; + } else unreachable; // TODO else unreachable should not be necessary + + return @ptrCast([*]u8, final_addr)[0..n]; }, else => @compileError("Unsupported OS"), } @@ -118,13 +146,31 @@ pub const DirectAllocator = struct { } return old_mem[0..new_size]; }, - Os.windows => return realloc(allocator, old_mem, old_align, new_size, new_align) catch { - const old_adjusted_addr = @ptrToInt(old_mem.ptr); - const old_record_addr = old_adjusted_addr + old_mem.len; - const root_addr = @intToPtr(*align(1) usize, old_record_addr).*; - const old_ptr = @intToPtr(*c_void, root_addr); - const new_record_addr = old_record_addr - new_size + old_mem.len; - @intToPtr(*align(1) usize, new_record_addr).* = root_addr; + .windows => { + const w = os.windows; + if (new_size == 0) { + // From the docs: + // "If the dwFreeType parameter is MEM_RELEASE, this parameter + // must be 0 (zero). The function frees the entire region that + // is reserved in the initial allocation call to VirtualAlloc." + // So we can only use MEM_RELEASE when actually releasing the + // whole allocation. + if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable; + } else { + const base_addr = @ptrToInt(old_mem.ptr); + const old_addr_end = base_addr + old_mem.len; + const new_addr_end = base_addr + new_size; + const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size); + if (old_addr_end > new_addr_end_rounded) { + // For shrinking that is not releasing, we will only + // decommit the pages not needed anymore. + if (w.VirtualFree( + @intToPtr(*c_void, new_addr_end_rounded), + old_addr_end - new_addr_end_rounded, + w.MEM_DECOMMIT, + ) == 0) unreachable; + } + } return old_mem[0..new_size]; }, else => @compileError("Unsupported OS"), @@ -138,36 +184,168 @@ pub const DirectAllocator = struct { return shrink(allocator, old_mem, old_align, new_size, new_align); } const result = try alloc(allocator, new_size, new_align); - mem.copy(u8, result, old_mem); - _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len); + if (old_mem.len != 0) { + @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); + _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len); + } return result; }, - Os.windows => { - if (old_mem.len == 0) return alloc(allocator, new_size, new_align); + .windows => { + if (old_mem.len == 0) { + return alloc(allocator, new_size, new_align); + } + + if (new_size <= old_mem.len and new_align <= old_align) { + return shrink(allocator, old_mem, old_align, new_size, new_align); + } + + const w = os.windows; + const base_addr = @ptrToInt(old_mem.ptr); + + if (new_align > old_align and base_addr & (new_align - 1) != 0) { + // Current allocation doesn't satisfy the new alignment. + // For now we'll do a new one no matter what, but maybe + // there is something smarter to do instead. + const result = try alloc(allocator, new_size, new_align); + assert(old_mem.len != 0); + @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); + if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable; - const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); + return result; + } + + const old_addr_end = base_addr + old_mem.len; + const old_addr_end_rounded = mem.alignForward(old_addr_end, os.page_size); + const new_addr_end = base_addr + new_size; + const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size); + if (new_addr_end_rounded == old_addr_end_rounded) { + // The reallocation fits in the already allocated pages. + return @ptrCast([*]u8, old_mem.ptr)[0..new_size]; + } + assert(new_addr_end_rounded > old_addr_end_rounded); + + // We need to commit new pages. + const additional_size = new_addr_end - old_addr_end_rounded; + const realloc_addr = w.VirtualAlloc( + @intToPtr(*c_void, old_addr_end_rounded), + additional_size, + w.MEM_COMMIT | w.MEM_RESERVE, + w.PAGE_READWRITE, + ) orelse { + // Committing new pages at the end of the existing allocation + // failed, we need to try a new one. + const new_alloc_mem = try alloc(allocator, new_size, new_align); + @memcpy(new_alloc_mem.ptr, old_mem.ptr, old_mem.len); + if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable; + + return new_alloc_mem; + }; + + assert(@ptrToInt(realloc_addr) == old_addr_end_rounded); + return @ptrCast([*]u8, old_mem.ptr)[0..new_size]; + }, + else => @compileError("Unsupported OS"), + } + } +}; + +pub const HeapAllocator = switch (builtin.os) { + .windows => struct { + allocator: Allocator, + heap_handle: ?HeapHandle, + + const HeapHandle = os.windows.HANDLE; + + pub fn init() HeapAllocator { + return HeapAllocator{ + .allocator = Allocator{ + .reallocFn = realloc, + .shrinkFn = shrink, + }, + .heap_handle = null, + }; + } + + pub fn deinit(self: *HeapAllocator) void { + if (self.heap_handle) |heap_handle| { + _ = os.windows.HeapDestroy(heap_handle); + } + } + + fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { + const self = @fieldParentPtr(HeapAllocator, "allocator", allocator); + if (n == 0) + return (([*]u8)(undefined))[0..0]; + + const amt = n + alignment + @sizeOf(usize); + const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst); + const heap_handle = optional_heap_handle orelse blk: { + const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0; + const hh = os.windows.HeapCreate(options, amt, 0) orelse return error.OutOfMemory; + const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh; + _ = os.windows.HeapDestroy(hh); + break :blk other_hh.?; // can't be null because of the cmpxchg + }; + const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory; + const root_addr = @ptrToInt(ptr); + const adjusted_addr = mem.alignForward(root_addr, alignment); + const record_addr = adjusted_addr + n; + @intToPtr(*align(1) usize, record_addr).* = root_addr; + return @intToPtr([*]u8, adjusted_addr)[0..n]; + } + + fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + return realloc(allocator, old_mem, old_align, new_size, new_align) catch { const old_adjusted_addr = @ptrToInt(old_mem.ptr); const old_record_addr = old_adjusted_addr + old_mem.len; const root_addr = @intToPtr(*align(1) usize, old_record_addr).*; const old_ptr = @intToPtr(*c_void, root_addr); - const amt = new_size + new_align + @sizeOf(usize); - const new_ptr = os.windows.HeapReAlloc( - self.heap_handle.?, - 0, - old_ptr, - amt, - ) orelse return error.OutOfMemory; - const offset = old_adjusted_addr - root_addr; - const new_root_addr = @ptrToInt(new_ptr); - const new_adjusted_addr = new_root_addr + offset; - assert(new_adjusted_addr % new_align == 0); - const new_record_addr = new_adjusted_addr + new_size; - @intToPtr(*align(1) usize, new_record_addr).* = new_root_addr; - return @intToPtr([*]u8, new_adjusted_addr)[0..new_size]; - }, - else => @compileError("Unsupported OS"), + const new_record_addr = old_record_addr - new_size + old_mem.len; + @intToPtr(*align(1) usize, new_record_addr).* = root_addr; + return old_mem[0..new_size]; + }; } - } + + fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + if (old_mem.len == 0) return alloc(allocator, new_size, new_align); + + const self = @fieldParentPtr(HeapAllocator, "allocator", allocator); + const old_adjusted_addr = @ptrToInt(old_mem.ptr); + const old_record_addr = old_adjusted_addr + old_mem.len; + const root_addr = @intToPtr(*align(1) usize, old_record_addr).*; + const old_ptr = @intToPtr(*c_void, root_addr); + + if (new_size == 0) { + if (os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable; + return old_mem[0..0]; + } + + const amt = new_size + new_align + @sizeOf(usize); + const new_ptr = os.windows.HeapReAlloc( + self.heap_handle.?, + 0, + old_ptr, + amt, + ) orelse return error.OutOfMemory; + const offset = old_adjusted_addr - root_addr; + const new_root_addr = @ptrToInt(new_ptr); + var new_adjusted_addr = new_root_addr + offset; + const offset_is_valid = new_adjusted_addr + new_size + @sizeOf(usize) <= new_root_addr + amt; + const offset_is_aligned = new_adjusted_addr % new_align == 0; + if (!offset_is_valid or !offset_is_aligned) { + // If HeapReAlloc didn't happen to move the memory to the new alignment, + // or the memory starting at the old offset would be outside of the new allocation, + // then we need to copy the memory to a valid aligned address and use that + const new_aligned_addr = mem.alignForward(new_root_addr, new_align); + @memcpy(@intToPtr([*]u8, new_aligned_addr), @intToPtr([*]u8, new_adjusted_addr), std.math.min(old_mem.len, new_size)); + new_adjusted_addr = new_aligned_addr; + } + const new_record_addr = new_adjusted_addr + new_size; + @intToPtr(*align(1) usize, new_record_addr).* = new_root_addr; + return @intToPtr([*]u8, new_adjusted_addr)[0..new_size]; + } + }, + else => @compileError("Unsupported OS"), }; /// This allocator takes an existing allocator, wraps it, and provides an interface @@ -250,7 +428,7 @@ pub const ArenaAllocator = struct { return error.OutOfMemory; } else { const result = try alloc(allocator, new_size, new_align); - mem.copy(u8, result, old_mem); + @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); return result; } } @@ -308,6 +486,103 @@ pub const FixedBufferAllocator = struct { return error.OutOfMemory; } else { const result = try alloc(allocator, new_size, new_align); + @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); + return result; + } + } + + fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + return old_mem[0..new_size]; + } +}; + +// FIXME: Exposed LLVM intrinsics is a bug +// See: https://github.com/ziglang/zig/issues/2291 +extern fn @"llvm.wasm.memory.size.i32"(u32) u32; +extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32; + +pub const wasm_allocator = &wasm_allocator_state.allocator; +var wasm_allocator_state = WasmAllocator{ + .allocator = Allocator{ + .reallocFn = WasmAllocator.realloc, + .shrinkFn = WasmAllocator.shrink, + }, + .start_ptr = undefined, + .num_pages = 0, + .end_index = 0, +}; + +const WasmAllocator = struct { + allocator: Allocator, + start_ptr: [*]u8, + num_pages: usize, + end_index: usize, + + comptime { + if (builtin.arch != .wasm32) { + @compileError("WasmAllocator is only available for wasm32 arch"); + } + } + + fn alloc(allocator: *Allocator, size: usize, alignment: u29) ![]u8 { + const self = @fieldParentPtr(WasmAllocator, "allocator", allocator); + + const addr = @ptrToInt(self.start_ptr) + self.end_index; + const adjusted_addr = mem.alignForward(addr, alignment); + const adjusted_index = self.end_index + (adjusted_addr - addr); + const new_end_index = adjusted_index + size; + + if (new_end_index > self.num_pages * os.page_size) { + const required_memory = new_end_index - (self.num_pages * os.page_size); + + var num_pages: usize = required_memory / os.page_size; + if (required_memory % os.page_size != 0) { + num_pages += 1; + } + + const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, num_pages)); + if (prev_page == -1) { + return error.OutOfMemory; + } + + self.num_pages += num_pages; + } + + const result = self.start_ptr[adjusted_index..new_end_index]; + self.end_index = new_end_index; + + return result; + } + + // Check if memory is the last "item" and is aligned correctly + fn is_last_item(allocator: *Allocator, memory: []u8, alignment: u29) bool { + const self = @fieldParentPtr(WasmAllocator, "allocator", allocator); + return memory.ptr == self.start_ptr + self.end_index - memory.len and mem.alignForward(@ptrToInt(memory.ptr), alignment) == @ptrToInt(memory.ptr); + } + + fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + const self = @fieldParentPtr(WasmAllocator, "allocator", allocator); + + // Initialize start_ptr at the first realloc + if (self.num_pages == 0) { + self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * os.page_size); + } + + if (is_last_item(allocator, old_mem, new_align)) { + const start_index = self.end_index - old_mem.len; + const new_end_index = start_index + new_size; + + if (new_end_index > self.num_pages * os.page_size) { + _ = try alloc(allocator, new_end_index - self.end_index, new_align); + } + const result = self.start_ptr[start_index..new_end_index]; + + self.end_index = new_end_index; + return result; + } else if (new_size <= old_mem.len and new_align <= old_align) { + return error.OutOfMemory; + } else { + const result = try alloc(allocator, new_size, new_align); mem.copy(u8, result, old_mem); return result; } @@ -360,7 +635,7 @@ pub const ThreadSafeFixedBufferAllocator = blk: { return error.OutOfMemory; } else { const result = try alloc(allocator, new_size, new_align); - mem.copy(u8, result, old_mem); + @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); return result; } } @@ -470,6 +745,31 @@ test "DirectAllocator" { try testAllocator(allocator); try testAllocatorAligned(allocator, 16); try testAllocatorLargeAlignment(allocator); + try testAllocatorAlignedShrink(allocator); + + if (builtin.os == .windows) { + // Trying really large alignment. As mentionned in the implementation, + // VirtualAlloc returns 64K aligned addresses. We want to make sure + // DirectAllocator works beyond that, as it's not tested by + // `testAllocatorLargeAlignment`. + const slice = try allocator.alignedAlloc(u8, 1 << 20, 128); + slice[0] = 0x12; + slice[127] = 0x34; + allocator.free(slice); + } +} + +test "HeapAllocator" { + if (builtin.os == .windows) { + var heap_allocator = HeapAllocator.init(); + defer heap_allocator.deinit(); + + const allocator = &heap_allocator.allocator; + try testAllocator(allocator); + try testAllocatorAligned(allocator, 16); + try testAllocatorLargeAlignment(allocator); + try testAllocatorAlignedShrink(allocator); + } } test "ArenaAllocator" { @@ -482,15 +782,17 @@ test "ArenaAllocator" { try testAllocator(&arena_allocator.allocator); try testAllocatorAligned(&arena_allocator.allocator, 16); try testAllocatorLargeAlignment(&arena_allocator.allocator); + try testAllocatorAlignedShrink(&arena_allocator.allocator); } -var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined; +var test_fixed_buffer_allocator_memory: [80000 * @sizeOf(u64)]u8 = undefined; test "FixedBufferAllocator" { var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); try testAllocator(&fixed_buffer_allocator.allocator); try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16); try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator); + try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator); } test "FixedBufferAllocator Reuse memory on realloc" { @@ -528,6 +830,7 @@ test "ThreadSafeFixedBufferAllocator" { try testAllocator(&fixed_buffer_allocator.allocator); try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16); try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator); + try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator); } fn testAllocator(allocator: *mem.Allocator) !void { @@ -610,3 +913,32 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo allocator.free(slice); } + +fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!void { + var debug_buffer: [1000]u8 = undefined; + const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator; + + const alloc_size = os.page_size * 2 + 50; + var slice = try allocator.alignedAlloc(u8, 16, alloc_size); + defer allocator.free(slice); + + var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator); + // On Windows, VirtualAlloc returns addresses aligned to a 64K boundary, + // which is 16 pages, hence the 32. This test may require to increase + // the size of the allocations feeding the `allocator` parameter if they + // fail, because of this high over-alignment we want to have. + while (@ptrToInt(slice.ptr) == mem.alignForward(@ptrToInt(slice.ptr), os.page_size * 32)) { + try stuff_to_free.append(slice); + slice = try allocator.alignedAlloc(u8, 16, alloc_size); + } + while (stuff_to_free.popOrNull()) |item| { + allocator.free(item); + } + slice[0] = 0x12; + slice[60] = 0x34; + + // realloc to a smaller size but with a larger alignment + slice = try allocator.alignedRealloc(slice, os.page_size * 32, alloc_size / 2); + testing.expect(slice[0] == 0x12); + testing.expect(slice[60] == 0x34); +} diff --git a/std/io.zig b/std/io.zig index afbd8198fd..1f363b47b1 100644 --- a/std/io.zig +++ b/std/io.zig @@ -36,6 +36,7 @@ pub fn getStdIn() GetStdIoErrs!File { } pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; +pub const COutStream = @import("io/c_out_stream.zig").COutStream; pub fn InStream(comptime ReadError: type) type { return struct { @@ -194,8 +195,8 @@ pub fn InStream(comptime ReadError: type) type { return mem.readVarInt(ReturnType, bytes, endian); } - pub fn skipBytes(self: *Self, num_bytes: usize) !void { - var i: usize = 0; + pub fn skipBytes(self: *Self, num_bytes: u64) !void { + var i: u64 = 0; while (i < num_bytes) : (i += 1) { _ = try self.readByte(); } @@ -289,7 +290,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim var file = try File.openRead(path); defer file.close(); - const size = try file.getEndPos(); + const size = try math.cast(usize, try file.getEndPos()); const buf = try allocator.alignedAlloc(u8, A, size); errdefer allocator.free(buf); @@ -742,7 +743,7 @@ pub fn CountingOutStream(comptime OutStreamError: type) type { pub const Error = OutStreamError; pub stream: Stream, - pub bytes_written: usize, + pub bytes_written: u64, child_stream: *Stream, pub fn init(child_stream: *Stream) Self { @@ -1089,8 +1090,11 @@ test "io.readLineSliceFrom" { } pub const Packing = enum { - Byte, /// Pack data to byte alignment - Bit, /// Pack data to bit alignment + /// Pack data to byte alignment + Byte, + + /// Pack data to bit alignment + Bit, }; /// Creates a deserializer that deserializes types from any stream. @@ -1111,10 +1115,12 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, pub const Stream = InStream(Error); pub fn init(in_stream: *Stream) Self { - return Self{ .in_stream = switch (packing) { - .Bit => BitInStream(endian, Stream.Error).init(in_stream), - .Byte => in_stream, - } }; + return Self{ + .in_stream = switch (packing) { + .Bit => BitInStream(endian, Stream.Error).init(in_stream), + .Byte => in_stream, + }, + }; } pub fn alignToByte(self: *Self) void { @@ -1281,7 +1287,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, ptr.* = null; return; } - + ptr.* = OC(undefined); //make it non-null so the following .? is guaranteed safe const val_ptr = &ptr.*.?; try self.deserializeInto(val_ptr); @@ -1320,10 +1326,12 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co pub const Stream = OutStream(Error); pub fn init(out_stream: *Stream) Self { - return Self{ .out_stream = switch (packing) { - .Bit => BitOutStream(endian, Stream.Error).init(out_stream), - .Byte => out_stream, - } }; + return Self{ + .out_stream = switch (packing) { + .Bit => BitOutStream(endian, Stream.Error).init(out_stream), + .Byte => out_stream, + }, + }; } /// Flushes any unwritten bits to the stream @@ -1447,7 +1455,6 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co test "import io tests" { comptime { - _ = @import("io_test.zig"); + _ = @import("io/test.zig"); } } - diff --git a/std/io/c_out_stream.zig b/std/io/c_out_stream.zig new file mode 100644 index 0000000000..c66b342f1e --- /dev/null +++ b/std/io/c_out_stream.zig @@ -0,0 +1,48 @@ +const std = @import("../std.zig"); +const OutStream = std.io.OutStream; +const builtin = @import("builtin"); +const posix = std.os.posix; + +/// TODO make std.os.FILE use *FILE when linking libc and this just becomes +/// std.io.FileOutStream because std.os.File.write would do this when linking +/// libc. +pub const COutStream = struct { + pub const Error = std.os.File.WriteError; + pub const Stream = OutStream(Error); + + stream: Stream, + c_file: *std.c.FILE, + + pub fn init(c_file: *std.c.FILE) COutStream { + return COutStream{ + .c_file = c_file, + .stream = Stream{ .writeFn = writeFn }, + }; + } + + fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void { + const self = @fieldParentPtr(COutStream, "stream", out_stream); + const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, self.c_file); + if (amt_written == bytes.len) return; + // TODO errno on windows. should we have a posix layer for windows? + if (builtin.os == .windows) { + return error.InputOutput; + } + const errno = std.c._errno().*; + switch (errno) { + 0 => unreachable, + posix.EINVAL => unreachable, + posix.EFAULT => unreachable, + posix.EAGAIN => unreachable, // this is a blocking API + posix.EBADF => unreachable, // always a race condition + posix.EDESTADDRREQ => unreachable, // connect was never called + posix.EDQUOT => return error.DiskQuota, + posix.EFBIG => return error.FileTooBig, + posix.EIO => return error.InputOutput, + posix.ENOSPC => return error.NoSpaceLeft, + posix.EPERM => return error.AccessDenied, + posix.EPIPE => return error.BrokenPipe, + else => return std.os.unexpectedErrorPosix(@intCast(usize, errno)), + } + } +}; diff --git a/std/io/seekable_stream.zig b/std/io/seekable_stream.zig index 5529e42ff1..baf479891c 100644 --- a/std/io/seekable_stream.zig +++ b/std/io/seekable_stream.zig @@ -7,25 +7,25 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType pub const SeekError = SeekErrorType; pub const GetSeekPosError = GetSeekPosErrorType; - seekToFn: fn (self: *Self, pos: usize) SeekError!void, - seekForwardFn: fn (self: *Self, pos: isize) SeekError!void, + seekToFn: fn (self: *Self, pos: u64) SeekError!void, + seekForwardFn: fn (self: *Self, pos: i64) SeekError!void, - getPosFn: fn (self: *Self) GetSeekPosError!usize, - getEndPosFn: fn (self: *Self) GetSeekPosError!usize, + getPosFn: fn (self: *Self) GetSeekPosError!u64, + getEndPosFn: fn (self: *Self) GetSeekPosError!u64, - pub fn seekTo(self: *Self, pos: usize) SeekError!void { + pub fn seekTo(self: *Self, pos: u64) SeekError!void { return self.seekToFn(self, pos); } - pub fn seekForward(self: *Self, amt: isize) SeekError!void { + pub fn seekForward(self: *Self, amt: i64) SeekError!void { return self.seekForwardFn(self, amt); } - pub fn getEndPos(self: *Self) GetSeekPosError!usize { + pub fn getEndPos(self: *Self) GetSeekPosError!u64 { return self.getEndPosFn(self); } - pub fn getPos(self: *Self) GetSeekPosError!usize { + pub fn getPos(self: *Self) GetSeekPosError!u64 { return self.getPosFn(self); } }; diff --git a/std/io_test.zig b/std/io/test.zig index d6f2264a56..07a3c0e8dd 100644 --- a/std/io_test.zig +++ b/std/io/test.zig @@ -1,4 +1,4 @@ -const std = @import("std.zig"); +const std = @import("../std.zig"); const io = std.io; const meta = std.meta; const trait = std.trait; @@ -589,3 +589,14 @@ test "Deserializer bad data" { try testBadData(.Big, .Bit); try testBadData(.Little, .Bit); } + +test "c out stream" { + if (!builtin.link_libc) return error.SkipZigTest; + + const filename = c"tmp_io_test_file.txt"; + const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile; + defer std.os.deleteFileC(filename) catch {}; + + const out_stream = &io.COutStream.init(out_file).stream; + try out_stream.print("hi: {}\n", i32(123)); +} diff --git a/std/json.zig b/std/json.zig index 551c3a8da7..8d42d1bcf0 100644 --- a/std/json.zig +++ b/std/json.zig @@ -1400,3 +1400,7 @@ test "json.parser.dynamic" { const double = image.Object.get("double").?.value; testing.expect(double.Float == 1.3412); } + +test "import more json tests" { + _ = @import("json/test.zig"); +} diff --git a/std/json/test.zig b/std/json/test.zig new file mode 100644 index 0000000000..7c89dcd123 --- /dev/null +++ b/std/json/test.zig @@ -0,0 +1,1904 @@ +// RFC 8529 conformance tests. +// +// Tests are taken from https://github.com/nst/JSONTestSuite +// Read also http://seriot.ch/parsing_json.php for a good overview. + +const std = @import("../std.zig"); + +fn ok(comptime s: []const u8) void { + std.testing.expect(std.json.validate(s)); +} + +fn err(comptime s: []const u8) void { + std.testing.expect(!std.json.validate(s)); +} + +fn any(comptime s: []const u8) void { + std.testing.expect(true); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Additional tests not part of test JSONTestSuite. + +test "y_trailing_comma_after_empty" { + ok( + \\{"1":[],"2":{},"3":"4"} + ); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +test "y_array_arraysWithSpaces" { + ok( + \\[[] ] + ); +} + +test "y_array_empty" { + ok( + \\[] + ); +} + +test "y_array_empty-string" { + ok( + \\[""] + ); +} + +test "y_array_ending_with_newline" { + ok( + \\["a"] + ); +} + +test "y_array_false" { + ok( + \\[false] + ); +} + +test "y_array_heterogeneous" { + ok( + \\[null, 1, "1", {}] + ); +} + +test "y_array_null" { + ok( + \\[null] + ); +} + +test "y_array_with_1_and_newline" { + ok( + \\[1 + \\] + ); +} + +test "y_array_with_leading_space" { + ok( + \\ [1] + ); +} + +test "y_array_with_several_null" { + ok( + \\[1,null,null,null,2] + ); +} + +test "y_array_with_trailing_space" { + ok("[2] "); +} + +test "y_number_0e+1" { + ok( + \\[0e+1] + ); +} + +test "y_number_0e1" { + ok( + \\[0e1] + ); +} + +test "y_number_after_space" { + ok( + \\[ 4] + ); +} + +test "y_number_double_close_to_zero" { + ok( + \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] + ); +} + +test "y_number_int_with_exp" { + ok( + \\[20e1] + ); +} + +test "y_number" { + ok( + \\[123e65] + ); +} + +test "y_number_minus_zero" { + ok( + \\[-0] + ); +} + +test "y_number_negative_int" { + ok( + \\[-123] + ); +} + +test "y_number_negative_one" { + ok( + \\[-1] + ); +} + +test "y_number_negative_zero" { + ok( + \\[-0] + ); +} + +test "y_number_real_capital_e" { + ok( + \\[1E22] + ); +} + +test "y_number_real_capital_e_neg_exp" { + ok( + \\[1E-2] + ); +} + +test "y_number_real_capital_e_pos_exp" { + ok( + \\[1E+2] + ); +} + +test "y_number_real_exponent" { + ok( + \\[123e45] + ); +} + +test "y_number_real_fraction_exponent" { + ok( + \\[123.456e78] + ); +} + +test "y_number_real_neg_exp" { + ok( + \\[1e-2] + ); +} + +test "y_number_real_pos_exponent" { + ok( + \\[1e+2] + ); +} + +test "y_number_simple_int" { + ok( + \\[123] + ); +} + +test "y_number_simple_real" { + ok( + \\[123.456789] + ); +} + +test "y_object_basic" { + ok( + \\{"asd":"sdf"} + ); +} + +test "y_object_duplicated_key_and_value" { + ok( + \\{"a":"b","a":"b"} + ); +} + +test "y_object_duplicated_key" { + ok( + \\{"a":"b","a":"c"} + ); +} + +test "y_object_empty" { + ok( + \\{} + ); +} + +test "y_object_empty_key" { + ok( + \\{"":0} + ); +} + +test "y_object_escaped_null_in_key" { + ok( + \\{"foo\u0000bar": 42} + ); +} + +test "y_object_extreme_numbers" { + ok( + \\{ "min": -1.0e+28, "max": 1.0e+28 } + ); +} + +test "y_object" { + ok( + \\{"asd":"sdf", "dfg":"fgh"} + ); +} + +test "y_object_long_strings" { + ok( + \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} + ); +} + +test "y_object_simple" { + ok( + \\{"a":[]} + ); +} + +test "y_object_string_unicode" { + ok( + \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } + ); +} + +test "y_object_with_newlines" { + ok( + \\{ + \\"a": "b" + \\} + ); +} + +test "y_string_1_2_3_bytes_UTF-8_sequences" { + ok( + \\["\u0060\u012a\u12AB"] + ); +} + +test "y_string_accepted_surrogate_pair" { + ok( + \\["\uD801\udc37"] + ); +} + +test "y_string_accepted_surrogate_pairs" { + ok( + \\["\ud83d\ude39\ud83d\udc8d"] + ); +} + +test "y_string_allowed_escapes" { + ok( + \\["\"\\\/\b\f\n\r\t"] + ); +} + +test "y_string_backslash_and_u_escaped_zero" { + ok( + \\["\\u0000"] + ); +} + +test "y_string_backslash_doublequotes" { + ok( + \\["\""] + ); +} + +test "y_string_comments" { + ok( + \\["a/*b*/c/*d//e"] + ); +} + +test "y_string_double_escape_a" { + ok( + \\["\\a"] + ); +} + +test "y_string_double_escape_n" { + ok( + \\["\\n"] + ); +} + +test "y_string_escaped_control_character" { + ok( + \\["\u0012"] + ); +} + +test "y_string_escaped_noncharacter" { + ok( + \\["\uFFFF"] + ); +} + +test "y_string_in_array" { + ok( + \\["asd"] + ); +} + +test "y_string_in_array_with_leading_space" { + ok( + \\[ "asd"] + ); +} + +test "y_string_last_surrogates_1_and_2" { + ok( + \\["\uDBFF\uDFFF"] + ); +} + +test "y_string_nbsp_uescaped" { + ok( + \\["new\u00A0line"] + ); +} + +test "y_string_nonCharacterInUTF-8_U+10FFFF" { + ok( + \\[""] + ); +} + +test "y_string_nonCharacterInUTF-8_U+FFFF" { + ok( + \\[""] + ); +} + +test "y_string_null_escape" { + ok( + \\["\u0000"] + ); +} + +test "y_string_one-byte-utf-8" { + ok( + \\["\u002c"] + ); +} + +test "y_string_pi" { + ok( + \\["π"] + ); +} + +test "y_string_reservedCharacterInUTF-8_U+1BFFF" { + ok( + \\[""] + ); +} + +test "y_string_simple_ascii" { + ok( + \\["asd "] + ); +} + +test "y_string_space" { + ok( + \\" " + ); +} + +test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { + ok( + \\["\uD834\uDd1e"] + ); +} + +test "y_string_three-byte-utf-8" { + ok( + \\["\u0821"] + ); +} + +test "y_string_two-byte-utf-8" { + ok( + \\["\u0123"] + ); +} + +test "y_string_u+2028_line_sep" { + ok("[\"\xe2\x80\xa8\"]"); +} + +test "y_string_u+2029_par_sep" { + ok("[\"\xe2\x80\xa9\"]"); +} + +test "y_string_uescaped_newline" { + ok( + \\["new\u000Aline"] + ); +} + +test "y_string_uEscape" { + ok( + \\["\u0061\u30af\u30EA\u30b9"] + ); +} + +test "y_string_unescaped_char_delete" { + ok("[\"\x7f\"]"); +} + +test "y_string_unicode_2" { + ok( + \\["⍂㈴⍂"] + ); +} + +test "y_string_unicodeEscapedBackslash" { + ok( + \\["\u005C"] + ); +} + +test "y_string_unicode_escaped_double_quote" { + ok( + \\["\u0022"] + ); +} + +test "y_string_unicode" { + ok( + \\["\uA66D"] + ); +} + +test "y_string_unicode_U+10FFFE_nonchar" { + ok( + \\["\uDBFF\uDFFE"] + ); +} + +test "y_string_unicode_U+1FFFE_nonchar" { + ok( + \\["\uD83F\uDFFE"] + ); +} + +test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { + ok( + \\["\u200B"] + ); +} + +test "y_string_unicode_U+2064_invisible_plus" { + ok( + \\["\u2064"] + ); +} + +test "y_string_unicode_U+FDD0_nonchar" { + ok( + \\["\uFDD0"] + ); +} + +test "y_string_unicode_U+FFFE_nonchar" { + ok( + \\["\uFFFE"] + ); +} + +test "y_string_utf8" { + ok( + \\["€𝄞"] + ); +} + +test "y_string_with_del_character" { + ok("[\"a\x7fa\"]"); +} + +test "y_structure_lonely_false" { + ok( + \\false + ); +} + +test "y_structure_lonely_int" { + ok( + \\42 + ); +} + +test "y_structure_lonely_negative_real" { + ok( + \\-0.1 + ); +} + +test "y_structure_lonely_null" { + ok( + \\null + ); +} + +test "y_structure_lonely_string" { + ok( + \\"asd" + ); +} + +test "y_structure_lonely_true" { + ok( + \\true + ); +} + +test "y_structure_string_empty" { + ok( + \\"" + ); +} + +test "y_structure_trailing_newline" { + ok( + \\["a"] + ); +} + +test "y_structure_true_in_array" { + ok( + \\[true] + ); +} + +test "y_structure_whitespace_array" { + ok(" [] "); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +test "n_array_1_true_without_comma" { + err( + \\[1 true] + ); +} + +test "n_array_a_invalid_utf8" { + err( + \\[aå] + ); +} + +test "n_array_colon_instead_of_comma" { + err( + \\["": 1] + ); +} + +test "n_array_comma_after_close" { + //err( + // \\[""], + //); +} + +test "n_array_comma_and_number" { + err( + \\[,1] + ); +} + +test "n_array_double_comma" { + err( + \\[1,,2] + ); +} + +test "n_array_double_extra_comma" { + err( + \\["x",,] + ); +} + +test "n_array_extra_close" { + err( + \\["x"]] + ); +} + +test "n_array_extra_comma" { + //err( + // \\["",] + //); +} + +test "n_array_incomplete_invalid_value" { + err( + \\[x + ); +} + +test "n_array_incomplete" { + err( + \\["x" + ); +} + +test "n_array_inner_array_no_comma" { + err( + \\[3[4]] + ); +} + +test "n_array_invalid_utf8" { + err( + \\[ÿ] + ); +} + +test "n_array_items_separated_by_semicolon" { + err( + \\[1:2] + ); +} + +test "n_array_just_comma" { + err( + \\[,] + ); +} + +test "n_array_just_minus" { + err( + \\[-] + ); +} + +test "n_array_missing_value" { + err( + \\[ , ""] + ); +} + +test "n_array_newlines_unclosed" { + err( + \\["a", + \\4 + \\,1, + ); +} + +test "n_array_number_and_comma" { + err( + \\[1,] + ); +} + +test "n_array_number_and_several_commas" { + err( + \\[1,,] + ); +} + +test "n_array_spaces_vertical_tab_formfeed" { + err("[\"\x0aa\"\\f]"); +} + +test "n_array_star_inside" { + err( + \\[*] + ); +} + +test "n_array_unclosed" { + err( + \\["" + ); +} + +test "n_array_unclosed_trailing_comma" { + err( + \\[1, + ); +} + +test "n_array_unclosed_with_new_lines" { + err( + \\[1, + \\1 + \\,1 + ); +} + +test "n_array_unclosed_with_object_inside" { + err( + \\[{} + ); +} + +test "n_incomplete_false" { + err( + \\[fals] + ); +} + +test "n_incomplete_null" { + err( + \\[nul] + ); +} + +test "n_incomplete_true" { + err( + \\[tru] + ); +} + +test "n_multidigit_number_then_00" { + err("123\x00"); +} + +test "n_number_0.1.2" { + err( + \\[0.1.2] + ); +} + +test "n_number_-01" { + err( + \\[-01] + ); +} + +test "n_number_0.3e" { + err( + \\[0.3e] + ); +} + +test "n_number_0.3e+" { + err( + \\[0.3e+] + ); +} + +test "n_number_0_capital_E" { + err( + \\[0E] + ); +} + +test "n_number_0_capital_E+" { + err( + \\[0E+] + ); +} + +test "n_number_0.e1" { + err( + \\[0.e1] + ); +} + +test "n_number_0e" { + err( + \\[0e] + ); +} + +test "n_number_0e+" { + err( + \\[0e+] + ); +} + +test "n_number_1_000" { + err( + \\[1 000.0] + ); +} + +test "n_number_1.0e-" { + err( + \\[1.0e-] + ); +} + +test "n_number_1.0e" { + err( + \\[1.0e] + ); +} + +test "n_number_1.0e+" { + err( + \\[1.0e+] + ); +} + +test "n_number_-1.0." { + err( + \\[-1.0.] + ); +} + +test "n_number_1eE2" { + err( + \\[1eE2] + ); +} + +test "n_number_.-1" { + err( + \\[.-1] + ); +} + +test "n_number_+1" { + err( + \\[+1] + ); +} + +test "n_number_.2e-3" { + err( + \\[.2e-3] + ); +} + +test "n_number_2.e-3" { + err( + \\[2.e-3] + ); +} + +test "n_number_2.e+3" { + err( + \\[2.e+3] + ); +} + +test "n_number_2.e3" { + err( + \\[2.e3] + ); +} + +test "n_number_-2." { + err( + \\[-2.] + ); +} + +test "n_number_9.e+" { + err( + \\[9.e+] + ); +} + +test "n_number_expression" { + err( + \\[1+2] + ); +} + +test "n_number_hex_1_digit" { + err( + \\[0x1] + ); +} + +test "n_number_hex_2_digits" { + err( + \\[0x42] + ); +} + +test "n_number_infinity" { + err( + \\[Infinity] + ); +} + +test "n_number_+Inf" { + err( + \\[+Inf] + ); +} + +test "n_number_Inf" { + err( + \\[Inf] + ); +} + +test "n_number_invalid+-" { + err( + \\[0e+-1] + ); +} + +test "n_number_invalid-negative-real" { + err( + \\[-123.123foo] + ); +} + +test "n_number_invalid-utf-8-in-bigger-int" { + err( + \\[123å] + ); +} + +test "n_number_invalid-utf-8-in-exponent" { + err( + \\[1e1å] + ); +} + +test "n_number_invalid-utf-8-in-int" { + err( + \\[0å] + ); +} + +test "n_number_++" { + err( + \\[++1234] + ); +} + +test "n_number_minus_infinity" { + err( + \\[-Infinity] + ); +} + +test "n_number_minus_sign_with_trailing_garbage" { + err( + \\[-foo] + ); +} + +test "n_number_minus_space_1" { + err( + \\[- 1] + ); +} + +test "n_number_-NaN" { + err( + \\[-NaN] + ); +} + +test "n_number_NaN" { + err( + \\[NaN] + ); +} + +test "n_number_neg_int_starting_with_zero" { + err( + \\[-012] + ); +} + +test "n_number_neg_real_without_int_part" { + err( + \\[-.123] + ); +} + +test "n_number_neg_with_garbage_at_end" { + err( + \\[-1x] + ); +} + +test "n_number_real_garbage_after_e" { + err( + \\[1ea] + ); +} + +test "n_number_real_with_invalid_utf8_after_e" { + err( + \\[1eå] + ); +} + +test "n_number_real_without_fractional_part" { + err( + \\[1.] + ); +} + +test "n_number_starting_with_dot" { + err( + \\[.123] + ); +} + +test "n_number_U+FF11_fullwidth_digit_one" { + err( + \\[ï¼] + ); +} + +test "n_number_with_alpha_char" { + err( + \\[1.8011670033376514H-308] + ); +} + +test "n_number_with_alpha" { + err( + \\[1.2a-3] + ); +} + +test "n_number_with_leading_zero" { + err( + \\[012] + ); +} + +test "n_object_bad_value" { + err( + \\["x", truth] + ); +} + +test "n_object_bracket_key" { + err( + \\{[: "x"} + ); +} + +test "n_object_comma_instead_of_colon" { + err( + \\{"x", null} + ); +} + +test "n_object_double_colon" { + err( + \\{"x"::"b"} + ); +} + +test "n_object_emoji" { + err( + \\{ð¨ð} + ); +} + +test "n_object_garbage_at_end" { + err( + \\{"a":"a" 123} + ); +} + +test "n_object_key_with_single_quotes" { + err( + \\{key: 'value'} + ); +} + +test "n_object_lone_continuation_byte_in_key_and_trailing_comma" { + err( + \\{"¹":"0",} + ); +} + +test "n_object_missing_colon" { + err( + \\{"a" b} + ); +} + +test "n_object_missing_key" { + err( + \\{:"b"} + ); +} + +test "n_object_missing_semicolon" { + err( + \\{"a" "b"} + ); +} + +test "n_object_missing_value" { + err( + \\{"a": + ); +} + +test "n_object_no-colon" { + err( + \\{"a" + ); +} + +test "n_object_non_string_key_but_huge_number_instead" { + err( + \\{9999E9999:1} + ); +} + +test "n_object_non_string_key" { + err( + \\{1:1} + ); +} + +test "n_object_repeated_null_null" { + err( + \\{null:null,null:null} + ); +} + +test "n_object_several_trailing_commas" { + err( + \\{"id":0,,,,,} + ); +} + +test "n_object_single_quote" { + err( + \\{'a':0} + ); +} + +test "n_object_trailing_comma" { + err( + \\{"id":0,} + ); +} + +test "n_object_trailing_comment" { + err( + \\{"a":"b"}/**/ + ); +} + +test "n_object_trailing_comment_open" { + err( + \\{"a":"b"}/**// + ); +} + +test "n_object_trailing_comment_slash_open_incomplete" { + err( + \\{"a":"b"}/ + ); +} + +test "n_object_trailing_comment_slash_open" { + err( + \\{"a":"b"}// + ); +} + +test "n_object_two_commas_in_a_row" { + err( + \\{"a":"b",,"c":"d"} + ); +} + +test "n_object_unquoted_key" { + err( + \\{a: "b"} + ); +} + +test "n_object_unterminated-value" { + err( + \\{"a":"a + ); +} + +test "n_object_with_single_string" { + err( + \\{ "foo" : "bar", "a" } + ); +} + +test "n_object_with_trailing_garbage" { + err( + \\{"a":"b"}# + ); +} + +test "n_single_space" { + err(" "); +} + +test "n_string_1_surrogate_then_escape" { + err( + \\["\uD800\"] + ); +} + +test "n_string_1_surrogate_then_escape_u1" { + err( + \\["\uD800\u1"] + ); +} + +test "n_string_1_surrogate_then_escape_u1x" { + err( + \\["\uD800\u1x"] + ); +} + +test "n_string_1_surrogate_then_escape_u" { + err( + \\["\uD800\u"] + ); +} + +test "n_string_accentuated_char_no_quotes" { + err( + \\[é] + ); +} + +test "n_string_backslash_00" { + err("[\"\x00\"]"); +} + +test "n_string_escaped_backslash_bad" { + err( + \\["\\\"] + ); +} + +test "n_string_escaped_ctrl_char_tab" { + err("\x5b\x22\x5c\x09\x22\x5d"); +} + +test "n_string_escaped_emoji" { + err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]"); +} + +test "n_string_escape_x" { + err( + \\["\x00"] + ); +} + +test "n_string_incomplete_escaped_character" { + err( + \\["\u00A"] + ); +} + +test "n_string_incomplete_escape" { + err( + \\["\"] + ); +} + +test "n_string_incomplete_surrogate_escape_invalid" { + err( + \\["\uD800\uD800\x"] + ); +} + +test "n_string_incomplete_surrogate" { + err( + \\["\uD834\uDd"] + ); +} + +test "n_string_invalid_backslash_esc" { + err( + \\["\a"] + ); +} + +test "n_string_invalid_unicode_escape" { + err( + \\["\uqqqq"] + ); +} + +test "n_string_invalid_utf8_after_escape" { + err("[\"\\\x75\xc3\xa5\"]"); +} + +test "n_string_invalid-utf-8-in-escape" { + err( + \\["\uå"] + ); +} + +test "n_string_leading_uescaped_thinspace" { + err( + \\[\u0020"asd"] + ); +} + +test "n_string_no_quotes_with_bad_escape" { + err( + \\[\n] + ); +} + +test "n_string_single_doublequote" { + err( + \\" + ); +} + +test "n_string_single_quote" { + err( + \\['single quote'] + ); +} + +test "n_string_single_string_no_double_quotes" { + err( + \\abc + ); +} + +test "n_string_start_escape_unclosed" { + err( + \\["\ + ); +} + +test "n_string_unescaped_crtl_char" { + err("[\"a\x00a\"]"); +} + +test "n_string_unescaped_newline" { + err( + \\["new + \\line"] + ); +} + +test "n_string_unescaped_tab" { + err("[\"\t\"]"); +} + +test "n_string_unicode_CapitalU" { + err( + \\"\UA66D" + ); +} + +test "n_string_with_trailing_garbage" { + err( + \\""x + ); +} + +test "n_structure_100000_opening_arrays" { + err("[" ** 100000); +} + +test "n_structure_angle_bracket_." { + err( + \\<.> + ); +} + +test "n_structure_angle_bracket_null" { + err( + \\[<null>] + ); +} + +test "n_structure_array_trailing_garbage" { + err( + \\[1]x + ); +} + +test "n_structure_array_with_extra_array_close" { + err( + \\[1]] + ); +} + +test "n_structure_array_with_unclosed_string" { + err( + \\["asd] + ); +} + +test "n_structure_ascii-unicode-identifier" { + err( + \\aÃ¥ + ); +} + +test "n_structure_capitalized_True" { + err( + \\[True] + ); +} + +test "n_structure_close_unopened_array" { + err( + \\1] + ); +} + +test "n_structure_comma_instead_of_closing_brace" { + err( + \\{"x": true, + ); +} + +test "n_structure_double_array" { + err( + \\[][] + ); +} + +test "n_structure_end_array" { + err( + \\] + ); +} + +test "n_structure_incomplete_UTF8_BOM" { + err( + \\ï»{} + ); +} + +test "n_structure_lone-invalid-utf-8" { + err( + \\å + ); +} + +test "n_structure_lone-open-bracket" { + err( + \\[ + ); +} + +test "n_structure_no_data" { + err( + \\ + ); +} + +test "n_structure_null-byte-outside-string" { + err("[\x00]"); +} + +test "n_structure_number_with_trailing_garbage" { + err( + \\2@ + ); +} + +test "n_structure_object_followed_by_closing_object" { + err( + \\{}} + ); +} + +test "n_structure_object_unclosed_no_value" { + err( + \\{"": + ); +} + +test "n_structure_object_with_comment" { + err( + \\{"a":/*comment*/"b"} + ); +} + +test "n_structure_object_with_trailing_garbage" { + err( + \\{"a": true} "x" + ); +} + +test "n_structure_open_array_apostrophe" { + err( + \\[' + ); +} + +test "n_structure_open_array_comma" { + err( + \\[, + ); +} + +test "n_structure_open_array_object" { + err("[{\"\":" ** 50000); +} + +test "n_structure_open_array_open_object" { + err( + \\[{ + ); +} + +test "n_structure_open_array_open_string" { + err( + \\["a + ); +} + +test "n_structure_open_array_string" { + err( + \\["a" + ); +} + +test "n_structure_open_object_close_array" { + err( + \\{] + ); +} + +test "n_structure_open_object_comma" { + err( + \\{, + ); +} + +test "n_structure_open_object" { + err( + \\{ + ); +} + +test "n_structure_open_object_open_array" { + err( + \\{[ + ); +} + +test "n_structure_open_object_open_string" { + err( + \\{"a + ); +} + +test "n_structure_open_object_string_with_apostrophes" { + err( + \\{'a' + ); +} + +test "n_structure_open_open" { + err( + \\["\{["\{["\{["\{ + ); +} + +test "n_structure_single_eacute" { + err( + \\é + ); +} + +test "n_structure_single_star" { + err( + \\* + ); +} + +test "n_structure_trailing_#" { + err( + \\{"a":"b"}#{} + ); +} + +test "n_structure_U+2060_word_joined" { + err( + \\[â ] + ); +} + +test "n_structure_uescaped_LF_before_string" { + err( + \\[\u000A""] + ); +} + +test "n_structure_unclosed_array" { + err( + \\[1 + ); +} + +test "n_structure_unclosed_array_partial_null" { + err( + \\[ false, nul + ); +} + +test "n_structure_unclosed_array_unfinished_false" { + err( + \\[ true, fals + ); +} + +test "n_structure_unclosed_array_unfinished_true" { + err( + \\[ false, tru + ); +} + +test "n_structure_unclosed_object" { + err( + \\{"asd":"asd" + ); +} + +test "n_structure_unicode-identifier" { + err( + \\Ã¥ + ); +} + +test "n_structure_UTF8_BOM_no_data" { + err( + \\ + ); +} + +test "n_structure_whitespace_formfeed" { + err("[\x0c]"); +} + +test "n_structure_whitespace_U+2060_word_joiner" { + err( + \\[â ] + ); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +test "i_number_double_huge_neg_exp" { + any( + \\[123.456e-789] + ); +} + +test "i_number_huge_exp" { + any( + \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] + ); +} + +test "i_number_neg_int_huge_exp" { + any( + \\[-1e+9999] + ); +} + +test "i_number_pos_double_huge_exp" { + any( + \\[1.5e+9999] + ); +} + +test "i_number_real_neg_overflow" { + any( + \\[-123123e100000] + ); +} + +test "i_number_real_pos_overflow" { + any( + \\[123123e100000] + ); +} + +test "i_number_real_underflow" { + any( + \\[123e-10000000] + ); +} + +test "i_number_too_big_neg_int" { + any( + \\[-123123123123123123123123123123] + ); +} + +test "i_number_too_big_pos_int" { + any( + \\[100000000000000000000] + ); +} + +test "i_number_very_big_negative_int" { + any( + \\[-237462374673276894279832749832423479823246327846] + ); +} + +test "i_object_key_lone_2nd_surrogate" { + any( + \\{"\uDFAA":0} + ); +} + +test "i_string_1st_surrogate_but_2nd_missing" { + any( + \\["\uDADA"] + ); +} + +test "i_string_1st_valid_surrogate_2nd_invalid" { + any( + \\["\uD888\u1234"] + ); +} + +test "i_string_incomplete_surrogate_and_escape_valid" { + any( + \\["\uD800\n"] + ); +} + +test "i_string_incomplete_surrogate_pair" { + any( + \\["\uDd1ea"] + ); +} + +test "i_string_incomplete_surrogates_escape_valid" { + any( + \\["\uD800\uD800\n"] + ); +} + +test "i_string_invalid_lonely_surrogate" { + any( + \\["\ud800"] + ); +} + +test "i_string_invalid_surrogate" { + any( + \\["\ud800abc"] + ); +} + +test "i_string_invalid_utf-8" { + any( + \\["ÿ"] + ); +} + +test "i_string_inverted_surrogates_U+1D11E" { + any( + \\["\uDd1e\uD834"] + ); +} + +test "i_string_iso_latin_1" { + any( + \\["é"] + ); +} + +test "i_string_lone_second_surrogate" { + any( + \\["\uDFAA"] + ); +} + +test "i_string_lone_utf8_continuation_byte" { + any( + \\[""] + ); +} + +test "i_string_not_in_unicode_range" { + any( + \\["ô¿¿¿"] + ); +} + +test "i_string_overlong_sequence_2_bytes" { + any( + \\["À¯"] + ); +} + +test "i_string_overlong_sequence_6_bytes" { + any( + \\["ü¿¿¿¿"] + ); +} + +test "i_string_overlong_sequence_6_bytes_null" { + any( + \\["ü"] + ); +} + +test "i_string_truncated-utf-8" { + any( + \\["àÿ"] + ); +} + +test "i_string_utf16BE_no_BOM" { + any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d"); +} + +test "i_string_utf16LE_no_BOM" { + any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); +} + +test "i_string_UTF-16LE_with_BOM" { + any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); +} + +test "i_string_UTF-8_invalid_sequence" { + any( + \\["æ¥Ñú"] + ); +} + +test "i_string_UTF8_surrogate_U+D800" { + any( + \\["í "] + ); +} + +test "i_structure_500_nested_arrays" { + any(("[" ** 500) ++ ("]" ** 500)); +} + +test "i_structure_UTF-8_BOM_empty_object" { + any( + \\{} + ); +} diff --git a/std/json_test.zig b/std/json_test.zig deleted file mode 100644 index a323e6e979..0000000000 --- a/std/json_test.zig +++ /dev/null @@ -1,1904 +0,0 @@ -// RFC 8529 conformance tests. -// -// Tests are taken from https://github.com/nst/JSONTestSuite -// Read also http://seriot.ch/parsing_json.php for a good overview. - -const std = @import("std.zig"); - -fn ok(comptime s: []const u8) void { - std.testing.expect(std.json.validate(s)); -} - -fn err(comptime s: []const u8) void { - std.testing.expect(!std.json.validate(s)); -} - -fn any(comptime s: []const u8) void { - std.testing.expect(true); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Additional tests not part of test JSONTestSuite. - -test "json.test.y_trailing_comma_after_empty" { - ok( - \\{"1":[],"2":{},"3":"4"} - ); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -test "json.test.y_array_arraysWithSpaces" { - ok( - \\[[] ] - ); -} - -test "json.test.y_array_empty" { - ok( - \\[] - ); -} - -test "json.test.y_array_empty-string" { - ok( - \\[""] - ); -} - -test "json.test.y_array_ending_with_newline" { - ok( - \\["a"] - ); -} - -test "json.test.y_array_false" { - ok( - \\[false] - ); -} - -test "json.test.y_array_heterogeneous" { - ok( - \\[null, 1, "1", {}] - ); -} - -test "json.test.y_array_null" { - ok( - \\[null] - ); -} - -test "json.test.y_array_with_1_and_newline" { - ok( - \\[1 - \\] - ); -} - -test "json.test.y_array_with_leading_space" { - ok( - \\ [1] - ); -} - -test "json.test.y_array_with_several_null" { - ok( - \\[1,null,null,null,2] - ); -} - -test "json.test.y_array_with_trailing_space" { - ok("[2] "); -} - -test "json.test.y_number_0e+1" { - ok( - \\[0e+1] - ); -} - -test "json.test.y_number_0e1" { - ok( - \\[0e1] - ); -} - -test "json.test.y_number_after_space" { - ok( - \\[ 4] - ); -} - -test "json.test.y_number_double_close_to_zero" { - ok( - \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] - ); -} - -test "json.test.y_number_int_with_exp" { - ok( - \\[20e1] - ); -} - -test "json.test.y_number" { - ok( - \\[123e65] - ); -} - -test "json.test.y_number_minus_zero" { - ok( - \\[-0] - ); -} - -test "json.test.y_number_negative_int" { - ok( - \\[-123] - ); -} - -test "json.test.y_number_negative_one" { - ok( - \\[-1] - ); -} - -test "json.test.y_number_negative_zero" { - ok( - \\[-0] - ); -} - -test "json.test.y_number_real_capital_e" { - ok( - \\[1E22] - ); -} - -test "json.test.y_number_real_capital_e_neg_exp" { - ok( - \\[1E-2] - ); -} - -test "json.test.y_number_real_capital_e_pos_exp" { - ok( - \\[1E+2] - ); -} - -test "json.test.y_number_real_exponent" { - ok( - \\[123e45] - ); -} - -test "json.test.y_number_real_fraction_exponent" { - ok( - \\[123.456e78] - ); -} - -test "json.test.y_number_real_neg_exp" { - ok( - \\[1e-2] - ); -} - -test "json.test.y_number_real_pos_exponent" { - ok( - \\[1e+2] - ); -} - -test "json.test.y_number_simple_int" { - ok( - \\[123] - ); -} - -test "json.test.y_number_simple_real" { - ok( - \\[123.456789] - ); -} - -test "json.test.y_object_basic" { - ok( - \\{"asd":"sdf"} - ); -} - -test "json.test.y_object_duplicated_key_and_value" { - ok( - \\{"a":"b","a":"b"} - ); -} - -test "json.test.y_object_duplicated_key" { - ok( - \\{"a":"b","a":"c"} - ); -} - -test "json.test.y_object_empty" { - ok( - \\{} - ); -} - -test "json.test.y_object_empty_key" { - ok( - \\{"":0} - ); -} - -test "json.test.y_object_escaped_null_in_key" { - ok( - \\{"foo\u0000bar": 42} - ); -} - -test "json.test.y_object_extreme_numbers" { - ok( - \\{ "min": -1.0e+28, "max": 1.0e+28 } - ); -} - -test "json.test.y_object" { - ok( - \\{"asd":"sdf", "dfg":"fgh"} - ); -} - -test "json.test.y_object_long_strings" { - ok( - \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} - ); -} - -test "json.test.y_object_simple" { - ok( - \\{"a":[]} - ); -} - -test "json.test.y_object_string_unicode" { - ok( - \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } - ); -} - -test "json.test.y_object_with_newlines" { - ok( - \\{ - \\"a": "b" - \\} - ); -} - -test "json.test.y_string_1_2_3_bytes_UTF-8_sequences" { - ok( - \\["\u0060\u012a\u12AB"] - ); -} - -test "json.test.y_string_accepted_surrogate_pair" { - ok( - \\["\uD801\udc37"] - ); -} - -test "json.test.y_string_accepted_surrogate_pairs" { - ok( - \\["\ud83d\ude39\ud83d\udc8d"] - ); -} - -test "json.test.y_string_allowed_escapes" { - ok( - \\["\"\\\/\b\f\n\r\t"] - ); -} - -test "json.test.y_string_backslash_and_u_escaped_zero" { - ok( - \\["\\u0000"] - ); -} - -test "json.test.y_string_backslash_doublequotes" { - ok( - \\["\""] - ); -} - -test "json.test.y_string_comments" { - ok( - \\["a/*b*/c/*d//e"] - ); -} - -test "json.test.y_string_double_escape_a" { - ok( - \\["\\a"] - ); -} - -test "json.test.y_string_double_escape_n" { - ok( - \\["\\n"] - ); -} - -test "json.test.y_string_escaped_control_character" { - ok( - \\["\u0012"] - ); -} - -test "json.test.y_string_escaped_noncharacter" { - ok( - \\["\uFFFF"] - ); -} - -test "json.test.y_string_in_array" { - ok( - \\["asd"] - ); -} - -test "json.test.y_string_in_array_with_leading_space" { - ok( - \\[ "asd"] - ); -} - -test "json.test.y_string_last_surrogates_1_and_2" { - ok( - \\["\uDBFF\uDFFF"] - ); -} - -test "json.test.y_string_nbsp_uescaped" { - ok( - \\["new\u00A0line"] - ); -} - -test "json.test.y_string_nonCharacterInUTF-8_U+10FFFF" { - ok( - \\[""] - ); -} - -test "json.test.y_string_nonCharacterInUTF-8_U+FFFF" { - ok( - \\[""] - ); -} - -test "json.test.y_string_null_escape" { - ok( - \\["\u0000"] - ); -} - -test "json.test.y_string_one-byte-utf-8" { - ok( - \\["\u002c"] - ); -} - -test "json.test.y_string_pi" { - ok( - \\["π"] - ); -} - -test "json.test.y_string_reservedCharacterInUTF-8_U+1BFFF" { - ok( - \\[""] - ); -} - -test "json.test.y_string_simple_ascii" { - ok( - \\["asd "] - ); -} - -test "json.test.y_string_space" { - ok( - \\" " - ); -} - -test "json.test.y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { - ok( - \\["\uD834\uDd1e"] - ); -} - -test "json.test.y_string_three-byte-utf-8" { - ok( - \\["\u0821"] - ); -} - -test "json.test.y_string_two-byte-utf-8" { - ok( - \\["\u0123"] - ); -} - -test "json.test.y_string_u+2028_line_sep" { - ok("[\"\xe2\x80\xa8\"]"); -} - -test "json.test.y_string_u+2029_par_sep" { - ok("[\"\xe2\x80\xa9\"]"); -} - -test "json.test.y_string_uescaped_newline" { - ok( - \\["new\u000Aline"] - ); -} - -test "json.test.y_string_uEscape" { - ok( - \\["\u0061\u30af\u30EA\u30b9"] - ); -} - -test "json.test.y_string_unescaped_char_delete" { - ok("[\"\x7f\"]"); -} - -test "json.test.y_string_unicode_2" { - ok( - \\["⍂㈴⍂"] - ); -} - -test "json.test.y_string_unicodeEscapedBackslash" { - ok( - \\["\u005C"] - ); -} - -test "json.test.y_string_unicode_escaped_double_quote" { - ok( - \\["\u0022"] - ); -} - -test "json.test.y_string_unicode" { - ok( - \\["\uA66D"] - ); -} - -test "json.test.y_string_unicode_U+10FFFE_nonchar" { - ok( - \\["\uDBFF\uDFFE"] - ); -} - -test "json.test.y_string_unicode_U+1FFFE_nonchar" { - ok( - \\["\uD83F\uDFFE"] - ); -} - -test "json.test.y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { - ok( - \\["\u200B"] - ); -} - -test "json.test.y_string_unicode_U+2064_invisible_plus" { - ok( - \\["\u2064"] - ); -} - -test "json.test.y_string_unicode_U+FDD0_nonchar" { - ok( - \\["\uFDD0"] - ); -} - -test "json.test.y_string_unicode_U+FFFE_nonchar" { - ok( - \\["\uFFFE"] - ); -} - -test "json.test.y_string_utf8" { - ok( - \\["€𝄞"] - ); -} - -test "json.test.y_string_with_del_character" { - ok("[\"a\x7fa\"]"); -} - -test "json.test.y_structure_lonely_false" { - ok( - \\false - ); -} - -test "json.test.y_structure_lonely_int" { - ok( - \\42 - ); -} - -test "json.test.y_structure_lonely_negative_real" { - ok( - \\-0.1 - ); -} - -test "json.test.y_structure_lonely_null" { - ok( - \\null - ); -} - -test "json.test.y_structure_lonely_string" { - ok( - \\"asd" - ); -} - -test "json.test.y_structure_lonely_true" { - ok( - \\true - ); -} - -test "json.test.y_structure_string_empty" { - ok( - \\"" - ); -} - -test "json.test.y_structure_trailing_newline" { - ok( - \\["a"] - ); -} - -test "json.test.y_structure_true_in_array" { - ok( - \\[true] - ); -} - -test "json.test.y_structure_whitespace_array" { - ok(" [] "); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -test "json.test.n_array_1_true_without_comma" { - err( - \\[1 true] - ); -} - -test "json.test.n_array_a_invalid_utf8" { - err( - \\[aå] - ); -} - -test "json.test.n_array_colon_instead_of_comma" { - err( - \\["": 1] - ); -} - -test "json.test.n_array_comma_after_close" { - //err( - // \\[""], - //); -} - -test "json.test.n_array_comma_and_number" { - err( - \\[,1] - ); -} - -test "json.test.n_array_double_comma" { - err( - \\[1,,2] - ); -} - -test "json.test.n_array_double_extra_comma" { - err( - \\["x",,] - ); -} - -test "json.test.n_array_extra_close" { - err( - \\["x"]] - ); -} - -test "json.test.n_array_extra_comma" { - //err( - // \\["",] - //); -} - -test "json.test.n_array_incomplete_invalid_value" { - err( - \\[x - ); -} - -test "json.test.n_array_incomplete" { - err( - \\["x" - ); -} - -test "json.test.n_array_inner_array_no_comma" { - err( - \\[3[4]] - ); -} - -test "json.test.n_array_invalid_utf8" { - err( - \\[ÿ] - ); -} - -test "json.test.n_array_items_separated_by_semicolon" { - err( - \\[1:2] - ); -} - -test "json.test.n_array_just_comma" { - err( - \\[,] - ); -} - -test "json.test.n_array_just_minus" { - err( - \\[-] - ); -} - -test "json.test.n_array_missing_value" { - err( - \\[ , ""] - ); -} - -test "json.test.n_array_newlines_unclosed" { - err( - \\["a", - \\4 - \\,1, - ); -} - -test "json.test.n_array_number_and_comma" { - err( - \\[1,] - ); -} - -test "json.test.n_array_number_and_several_commas" { - err( - \\[1,,] - ); -} - -test "json.test.n_array_spaces_vertical_tab_formfeed" { - err("[\"\x0aa\"\\f]"); -} - -test "json.test.n_array_star_inside" { - err( - \\[*] - ); -} - -test "json.test.n_array_unclosed" { - err( - \\["" - ); -} - -test "json.test.n_array_unclosed_trailing_comma" { - err( - \\[1, - ); -} - -test "json.test.n_array_unclosed_with_new_lines" { - err( - \\[1, - \\1 - \\,1 - ); -} - -test "json.test.n_array_unclosed_with_object_inside" { - err( - \\[{} - ); -} - -test "json.test.n_incomplete_false" { - err( - \\[fals] - ); -} - -test "json.test.n_incomplete_null" { - err( - \\[nul] - ); -} - -test "json.test.n_incomplete_true" { - err( - \\[tru] - ); -} - -test "json.test.n_multidigit_number_then_00" { - err("123\x00"); -} - -test "json.test.n_number_0.1.2" { - err( - \\[0.1.2] - ); -} - -test "json.test.n_number_-01" { - err( - \\[-01] - ); -} - -test "json.test.n_number_0.3e" { - err( - \\[0.3e] - ); -} - -test "json.test.n_number_0.3e+" { - err( - \\[0.3e+] - ); -} - -test "json.test.n_number_0_capital_E" { - err( - \\[0E] - ); -} - -test "json.test.n_number_0_capital_E+" { - err( - \\[0E+] - ); -} - -test "json.test.n_number_0.e1" { - err( - \\[0.e1] - ); -} - -test "json.test.n_number_0e" { - err( - \\[0e] - ); -} - -test "json.test.n_number_0e+" { - err( - \\[0e+] - ); -} - -test "json.test.n_number_1_000" { - err( - \\[1 000.0] - ); -} - -test "json.test.n_number_1.0e-" { - err( - \\[1.0e-] - ); -} - -test "json.test.n_number_1.0e" { - err( - \\[1.0e] - ); -} - -test "json.test.n_number_1.0e+" { - err( - \\[1.0e+] - ); -} - -test "json.test.n_number_-1.0." { - err( - \\[-1.0.] - ); -} - -test "json.test.n_number_1eE2" { - err( - \\[1eE2] - ); -} - -test "json.test.n_number_.-1" { - err( - \\[.-1] - ); -} - -test "json.test.n_number_+1" { - err( - \\[+1] - ); -} - -test "json.test.n_number_.2e-3" { - err( - \\[.2e-3] - ); -} - -test "json.test.n_number_2.e-3" { - err( - \\[2.e-3] - ); -} - -test "json.test.n_number_2.e+3" { - err( - \\[2.e+3] - ); -} - -test "json.test.n_number_2.e3" { - err( - \\[2.e3] - ); -} - -test "json.test.n_number_-2." { - err( - \\[-2.] - ); -} - -test "json.test.n_number_9.e+" { - err( - \\[9.e+] - ); -} - -test "json.test.n_number_expression" { - err( - \\[1+2] - ); -} - -test "json.test.n_number_hex_1_digit" { - err( - \\[0x1] - ); -} - -test "json.test.n_number_hex_2_digits" { - err( - \\[0x42] - ); -} - -test "json.test.n_number_infinity" { - err( - \\[Infinity] - ); -} - -test "json.test.n_number_+Inf" { - err( - \\[+Inf] - ); -} - -test "json.test.n_number_Inf" { - err( - \\[Inf] - ); -} - -test "json.test.n_number_invalid+-" { - err( - \\[0e+-1] - ); -} - -test "json.test.n_number_invalid-negative-real" { - err( - \\[-123.123foo] - ); -} - -test "json.test.n_number_invalid-utf-8-in-bigger-int" { - err( - \\[123å] - ); -} - -test "json.test.n_number_invalid-utf-8-in-exponent" { - err( - \\[1e1å] - ); -} - -test "json.test.n_number_invalid-utf-8-in-int" { - err( - \\[0å] - ); -} - -test "json.test.n_number_++" { - err( - \\[++1234] - ); -} - -test "json.test.n_number_minus_infinity" { - err( - \\[-Infinity] - ); -} - -test "json.test.n_number_minus_sign_with_trailing_garbage" { - err( - \\[-foo] - ); -} - -test "json.test.n_number_minus_space_1" { - err( - \\[- 1] - ); -} - -test "json.test.n_number_-NaN" { - err( - \\[-NaN] - ); -} - -test "json.test.n_number_NaN" { - err( - \\[NaN] - ); -} - -test "json.test.n_number_neg_int_starting_with_zero" { - err( - \\[-012] - ); -} - -test "json.test.n_number_neg_real_without_int_part" { - err( - \\[-.123] - ); -} - -test "json.test.n_number_neg_with_garbage_at_end" { - err( - \\[-1x] - ); -} - -test "json.test.n_number_real_garbage_after_e" { - err( - \\[1ea] - ); -} - -test "json.test.n_number_real_with_invalid_utf8_after_e" { - err( - \\[1eå] - ); -} - -test "json.test.n_number_real_without_fractional_part" { - err( - \\[1.] - ); -} - -test "json.test.n_number_starting_with_dot" { - err( - \\[.123] - ); -} - -test "json.test.n_number_U+FF11_fullwidth_digit_one" { - err( - \\[ï¼] - ); -} - -test "json.test.n_number_with_alpha_char" { - err( - \\[1.8011670033376514H-308] - ); -} - -test "json.test.n_number_with_alpha" { - err( - \\[1.2a-3] - ); -} - -test "json.test.n_number_with_leading_zero" { - err( - \\[012] - ); -} - -test "json.test.n_object_bad_value" { - err( - \\["x", truth] - ); -} - -test "json.test.n_object_bracket_key" { - err( - \\{[: "x"} - ); -} - -test "json.test.n_object_comma_instead_of_colon" { - err( - \\{"x", null} - ); -} - -test "json.test.n_object_double_colon" { - err( - \\{"x"::"b"} - ); -} - -test "json.test.n_object_emoji" { - err( - \\{ð¨ð} - ); -} - -test "json.test.n_object_garbage_at_end" { - err( - \\{"a":"a" 123} - ); -} - -test "json.test.n_object_key_with_single_quotes" { - err( - \\{key: 'value'} - ); -} - -test "json.test.n_object_lone_continuation_byte_in_key_and_trailing_comma" { - err( - \\{"¹":"0",} - ); -} - -test "json.test.n_object_missing_colon" { - err( - \\{"a" b} - ); -} - -test "json.test.n_object_missing_key" { - err( - \\{:"b"} - ); -} - -test "json.test.n_object_missing_semicolon" { - err( - \\{"a" "b"} - ); -} - -test "json.test.n_object_missing_value" { - err( - \\{"a": - ); -} - -test "json.test.n_object_no-colon" { - err( - \\{"a" - ); -} - -test "json.test.n_object_non_string_key_but_huge_number_instead" { - err( - \\{9999E9999:1} - ); -} - -test "json.test.n_object_non_string_key" { - err( - \\{1:1} - ); -} - -test "json.test.n_object_repeated_null_null" { - err( - \\{null:null,null:null} - ); -} - -test "json.test.n_object_several_trailing_commas" { - err( - \\{"id":0,,,,,} - ); -} - -test "json.test.n_object_single_quote" { - err( - \\{'a':0} - ); -} - -test "json.test.n_object_trailing_comma" { - err( - \\{"id":0,} - ); -} - -test "json.test.n_object_trailing_comment" { - err( - \\{"a":"b"}/**/ - ); -} - -test "json.test.n_object_trailing_comment_open" { - err( - \\{"a":"b"}/**// - ); -} - -test "json.test.n_object_trailing_comment_slash_open_incomplete" { - err( - \\{"a":"b"}/ - ); -} - -test "json.test.n_object_trailing_comment_slash_open" { - err( - \\{"a":"b"}// - ); -} - -test "json.test.n_object_two_commas_in_a_row" { - err( - \\{"a":"b",,"c":"d"} - ); -} - -test "json.test.n_object_unquoted_key" { - err( - \\{a: "b"} - ); -} - -test "json.test.n_object_unterminated-value" { - err( - \\{"a":"a - ); -} - -test "json.test.n_object_with_single_string" { - err( - \\{ "foo" : "bar", "a" } - ); -} - -test "json.test.n_object_with_trailing_garbage" { - err( - \\{"a":"b"}# - ); -} - -test "json.test.n_single_space" { - err(" "); -} - -test "json.test.n_string_1_surrogate_then_escape" { - err( - \\["\uD800\"] - ); -} - -test "json.test.n_string_1_surrogate_then_escape_u1" { - err( - \\["\uD800\u1"] - ); -} - -test "json.test.n_string_1_surrogate_then_escape_u1x" { - err( - \\["\uD800\u1x"] - ); -} - -test "json.test.n_string_1_surrogate_then_escape_u" { - err( - \\["\uD800\u"] - ); -} - -test "json.test.n_string_accentuated_char_no_quotes" { - err( - \\[é] - ); -} - -test "json.test.n_string_backslash_00" { - err("[\"\x00\"]"); -} - -test "json.test.n_string_escaped_backslash_bad" { - err( - \\["\\\"] - ); -} - -test "json.test.n_string_escaped_ctrl_char_tab" { - err("\x5b\x22\x5c\x09\x22\x5d"); -} - -test "json.test.n_string_escaped_emoji" { - err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]"); -} - -test "json.test.n_string_escape_x" { - err( - \\["\x00"] - ); -} - -test "json.test.n_string_incomplete_escaped_character" { - err( - \\["\u00A"] - ); -} - -test "json.test.n_string_incomplete_escape" { - err( - \\["\"] - ); -} - -test "json.test.n_string_incomplete_surrogate_escape_invalid" { - err( - \\["\uD800\uD800\x"] - ); -} - -test "json.test.n_string_incomplete_surrogate" { - err( - \\["\uD834\uDd"] - ); -} - -test "json.test.n_string_invalid_backslash_esc" { - err( - \\["\a"] - ); -} - -test "json.test.n_string_invalid_unicode_escape" { - err( - \\["\uqqqq"] - ); -} - -test "json.test.n_string_invalid_utf8_after_escape" { - err("[\"\\\x75\xc3\xa5\"]"); -} - -test "json.test.n_string_invalid-utf-8-in-escape" { - err( - \\["\uå"] - ); -} - -test "json.test.n_string_leading_uescaped_thinspace" { - err( - \\[\u0020"asd"] - ); -} - -test "json.test.n_string_no_quotes_with_bad_escape" { - err( - \\[\n] - ); -} - -test "json.test.n_string_single_doublequote" { - err( - \\" - ); -} - -test "json.test.n_string_single_quote" { - err( - \\['single quote'] - ); -} - -test "json.test.n_string_single_string_no_double_quotes" { - err( - \\abc - ); -} - -test "json.test.n_string_start_escape_unclosed" { - err( - \\["\ - ); -} - -test "json.test.n_string_unescaped_crtl_char" { - err("[\"a\x00a\"]"); -} - -test "json.test.n_string_unescaped_newline" { - err( - \\["new - \\line"] - ); -} - -test "json.test.n_string_unescaped_tab" { - err("[\"\t\"]"); -} - -test "json.test.n_string_unicode_CapitalU" { - err( - \\"\UA66D" - ); -} - -test "json.test.n_string_with_trailing_garbage" { - err( - \\""x - ); -} - -test "json.test.n_structure_100000_opening_arrays" { - err("[" ** 100000); -} - -test "json.test.n_structure_angle_bracket_." { - err( - \\<.> - ); -} - -test "json.test.n_structure_angle_bracket_null" { - err( - \\[<null>] - ); -} - -test "json.test.n_structure_array_trailing_garbage" { - err( - \\[1]x - ); -} - -test "json.test.n_structure_array_with_extra_array_close" { - err( - \\[1]] - ); -} - -test "json.test.n_structure_array_with_unclosed_string" { - err( - \\["asd] - ); -} - -test "json.test.n_structure_ascii-unicode-identifier" { - err( - \\aÃ¥ - ); -} - -test "json.test.n_structure_capitalized_True" { - err( - \\[True] - ); -} - -test "json.test.n_structure_close_unopened_array" { - err( - \\1] - ); -} - -test "json.test.n_structure_comma_instead_of_closing_brace" { - err( - \\{"x": true, - ); -} - -test "json.test.n_structure_double_array" { - err( - \\[][] - ); -} - -test "json.test.n_structure_end_array" { - err( - \\] - ); -} - -test "json.test.n_structure_incomplete_UTF8_BOM" { - err( - \\ï»{} - ); -} - -test "json.test.n_structure_lone-invalid-utf-8" { - err( - \\å - ); -} - -test "json.test.n_structure_lone-open-bracket" { - err( - \\[ - ); -} - -test "json.test.n_structure_no_data" { - err( - \\ - ); -} - -test "json.test.n_structure_null-byte-outside-string" { - err("[\x00]"); -} - -test "json.test.n_structure_number_with_trailing_garbage" { - err( - \\2@ - ); -} - -test "json.test.n_structure_object_followed_by_closing_object" { - err( - \\{}} - ); -} - -test "json.test.n_structure_object_unclosed_no_value" { - err( - \\{"": - ); -} - -test "json.test.n_structure_object_with_comment" { - err( - \\{"a":/*comment*/"b"} - ); -} - -test "json.test.n_structure_object_with_trailing_garbage" { - err( - \\{"a": true} "x" - ); -} - -test "json.test.n_structure_open_array_apostrophe" { - err( - \\[' - ); -} - -test "json.test.n_structure_open_array_comma" { - err( - \\[, - ); -} - -test "json.test.n_structure_open_array_object" { - err("[{\"\":" ** 50000); -} - -test "json.test.n_structure_open_array_open_object" { - err( - \\[{ - ); -} - -test "json.test.n_structure_open_array_open_string" { - err( - \\["a - ); -} - -test "json.test.n_structure_open_array_string" { - err( - \\["a" - ); -} - -test "json.test.n_structure_open_object_close_array" { - err( - \\{] - ); -} - -test "json.test.n_structure_open_object_comma" { - err( - \\{, - ); -} - -test "json.test.n_structure_open_object" { - err( - \\{ - ); -} - -test "json.test.n_structure_open_object_open_array" { - err( - \\{[ - ); -} - -test "json.test.n_structure_open_object_open_string" { - err( - \\{"a - ); -} - -test "json.test.n_structure_open_object_string_with_apostrophes" { - err( - \\{'a' - ); -} - -test "json.test.n_structure_open_open" { - err( - \\["\{["\{["\{["\{ - ); -} - -test "json.test.n_structure_single_eacute" { - err( - \\é - ); -} - -test "json.test.n_structure_single_star" { - err( - \\* - ); -} - -test "json.test.n_structure_trailing_#" { - err( - \\{"a":"b"}#{} - ); -} - -test "json.test.n_structure_U+2060_word_joined" { - err( - \\[â ] - ); -} - -test "json.test.n_structure_uescaped_LF_before_string" { - err( - \\[\u000A""] - ); -} - -test "json.test.n_structure_unclosed_array" { - err( - \\[1 - ); -} - -test "json.test.n_structure_unclosed_array_partial_null" { - err( - \\[ false, nul - ); -} - -test "json.test.n_structure_unclosed_array_unfinished_false" { - err( - \\[ true, fals - ); -} - -test "json.test.n_structure_unclosed_array_unfinished_true" { - err( - \\[ false, tru - ); -} - -test "json.test.n_structure_unclosed_object" { - err( - \\{"asd":"asd" - ); -} - -test "json.test.n_structure_unicode-identifier" { - err( - \\Ã¥ - ); -} - -test "json.test.n_structure_UTF8_BOM_no_data" { - err( - \\ - ); -} - -test "json.test.n_structure_whitespace_formfeed" { - err("[\x0c]"); -} - -test "json.test.n_structure_whitespace_U+2060_word_joiner" { - err( - \\[â ] - ); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -test "json.test.i_number_double_huge_neg_exp" { - any( - \\[123.456e-789] - ); -} - -test "json.test.i_number_huge_exp" { - any( - \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] - ); -} - -test "json.test.i_number_neg_int_huge_exp" { - any( - \\[-1e+9999] - ); -} - -test "json.test.i_number_pos_double_huge_exp" { - any( - \\[1.5e+9999] - ); -} - -test "json.test.i_number_real_neg_overflow" { - any( - \\[-123123e100000] - ); -} - -test "json.test.i_number_real_pos_overflow" { - any( - \\[123123e100000] - ); -} - -test "json.test.i_number_real_underflow" { - any( - \\[123e-10000000] - ); -} - -test "json.test.i_number_too_big_neg_int" { - any( - \\[-123123123123123123123123123123] - ); -} - -test "json.test.i_number_too_big_pos_int" { - any( - \\[100000000000000000000] - ); -} - -test "json.test.i_number_very_big_negative_int" { - any( - \\[-237462374673276894279832749832423479823246327846] - ); -} - -test "json.test.i_object_key_lone_2nd_surrogate" { - any( - \\{"\uDFAA":0} - ); -} - -test "json.test.i_string_1st_surrogate_but_2nd_missing" { - any( - \\["\uDADA"] - ); -} - -test "json.test.i_string_1st_valid_surrogate_2nd_invalid" { - any( - \\["\uD888\u1234"] - ); -} - -test "json.test.i_string_incomplete_surrogate_and_escape_valid" { - any( - \\["\uD800\n"] - ); -} - -test "json.test.i_string_incomplete_surrogate_pair" { - any( - \\["\uDd1ea"] - ); -} - -test "json.test.i_string_incomplete_surrogates_escape_valid" { - any( - \\["\uD800\uD800\n"] - ); -} - -test "json.test.i_string_invalid_lonely_surrogate" { - any( - \\["\ud800"] - ); -} - -test "json.test.i_string_invalid_surrogate" { - any( - \\["\ud800abc"] - ); -} - -test "json.test.i_string_invalid_utf-8" { - any( - \\["ÿ"] - ); -} - -test "json.test.i_string_inverted_surrogates_U+1D11E" { - any( - \\["\uDd1e\uD834"] - ); -} - -test "json.test.i_string_iso_latin_1" { - any( - \\["é"] - ); -} - -test "json.test.i_string_lone_second_surrogate" { - any( - \\["\uDFAA"] - ); -} - -test "json.test.i_string_lone_utf8_continuation_byte" { - any( - \\[""] - ); -} - -test "json.test.i_string_not_in_unicode_range" { - any( - \\["ô¿¿¿"] - ); -} - -test "json.test.i_string_overlong_sequence_2_bytes" { - any( - \\["À¯"] - ); -} - -test "json.test.i_string_overlong_sequence_6_bytes" { - any( - \\["ü¿¿¿¿"] - ); -} - -test "json.test.i_string_overlong_sequence_6_bytes_null" { - any( - \\["ü"] - ); -} - -test "json.test.i_string_truncated-utf-8" { - any( - \\["àÿ"] - ); -} - -test "json.test.i_string_utf16BE_no_BOM" { - any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d"); -} - -test "json.test.i_string_utf16LE_no_BOM" { - any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); -} - -test "json.test.i_string_UTF-16LE_with_BOM" { - any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); -} - -test "json.test.i_string_UTF-8_invalid_sequence" { - any( - \\["æ¥Ñú"] - ); -} - -test "json.test.i_string_UTF8_surrogate_U+D800" { - any( - \\["í "] - ); -} - -test "json.test.i_structure_500_nested_arrays" { - any(("[" ** 500) ++ ("]" ** 500)); -} - -test "json.test.i_structure_UTF-8_BOM_empty_object" { - any( - \\{} - ); -} diff --git a/std/math/acos.zig b/std/math/acos.zig index 763d9d8abd..de07da8fe0 100644 --- a/std/math/acos.zig +++ b/std/math/acos.zig @@ -1,11 +1,17 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - acos(x) = nan if x < -1 or x > 1 +// https://git.musl-libc.org/cgit/musl/tree/src/math/acosf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/acos.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the arc-cosine of x. +/// +/// Special cases: +/// - acos(x) = nan if x < -1 or x > 1 pub fn acos(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/acosh.zig b/std/math/acosh.zig index a2a9926863..503c0433fc 100644 --- a/std/math/acosh.zig +++ b/std/math/acosh.zig @@ -1,13 +1,19 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - acosh(x) = snan if x < 1 -// - acosh(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/acoshf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/acosh.c const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the hyperbolic arc-cosine of x. +/// +/// Special cases: +/// - acosh(x) = snan if x < 1 +/// - acosh(nan) = nan pub fn acosh(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/asin.zig b/std/math/asin.zig index b01a1ac49e..2db9f86ff1 100644 --- a/std/math/asin.zig +++ b/std/math/asin.zig @@ -1,12 +1,18 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - asin(+-0) = +-0 -// - asin(x) = nan if x < -1 or x > 1 +// https://git.musl-libc.org/cgit/musl/tree/src/math/asinf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/asin.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the arc-sin of x. +/// +/// Special Cases: +/// - asin(+-0) = +-0 +/// - asin(x) = nan if x < -1 or x > 1 pub fn asin(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/asinh.zig b/std/math/asinh.zig index cef9bfb23f..0fb51d1b43 100644 --- a/std/math/asinh.zig +++ b/std/math/asinh.zig @@ -1,14 +1,20 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - asinh(+-0) = +-0 -// - asinh(+-inf) = +-inf -// - asinh(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/asinhf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/asinh.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns the hyperbolic arc-sin of x. +/// +/// Special Cases: +/// - asinh(+-0) = +-0 +/// - asinh(+-inf) = +-inf +/// - asinh(nan) = nan pub fn asinh(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/atan.zig b/std/math/atan.zig index ba5a11dd10..cc4cad0dd4 100644 --- a/std/math/atan.zig +++ b/std/math/atan.zig @@ -1,12 +1,18 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - atan(+-0) = +-0 -// - atan(+-inf) = +-pi/2 +// https://git.musl-libc.org/cgit/musl/tree/src/math/atanf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/atan.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the arc-tangent of x. +/// +/// Special Cases: +/// - atan(+-0) = +-0 +/// - atan(+-inf) = +-pi/2 pub fn atan(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/atan2.zig b/std/math/atan2.zig index 7f13507402..68e381607d 100644 --- a/std/math/atan2.zig +++ b/std/math/atan2.zig @@ -1,27 +1,33 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// atan2(y, nan) = nan -// atan2(nan, x) = nan -// atan2(+0, x>=0) = +0 -// atan2(-0, x>=0) = -0 -// atan2(+0, x<=-0) = +pi -// atan2(-0, x<=-0) = -pi -// atan2(y>0, 0) = +pi/2 -// atan2(y<0, 0) = -pi/2 -// atan2(+inf, +inf) = +pi/4 -// atan2(-inf, +inf) = -pi/4 -// atan2(+inf, -inf) = 3pi/4 -// atan2(-inf, -inf) = -3pi/4 -// atan2(y, +inf) = 0 -// atan2(y>0, -inf) = +pi -// atan2(y<0, -inf) = -pi -// atan2(+inf, x) = +pi/2 -// atan2(-inf, x) = -pi/2 +// https://git.musl-libc.org/cgit/musl/tree/src/math/atan2f.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/atan2.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the arc-tangent of y/x. +/// +/// Special Cases: +/// - atan2(y, nan) = nan +/// - atan2(nan, x) = nan +/// - atan2(+0, x>=0) = +0 +/// - atan2(-0, x>=0) = -0 +/// - atan2(+0, x<=-0) = +pi +/// - atan2(-0, x<=-0) = -pi +/// - atan2(y>0, 0) = +pi/2 +/// - atan2(y<0, 0) = -pi/2 +/// - atan2(+inf, +inf) = +pi/4 +/// - atan2(-inf, +inf) = -pi/4 +/// - atan2(+inf, -inf) = 3pi/4 +/// - atan2(-inf, -inf) = -3pi/4 +/// - atan2(y, +inf) = 0 +/// - atan2(y>0, -inf) = +pi +/// - atan2(y<0, -inf) = -pi +/// - atan2(+inf, x) = +pi/2 +/// - atan2(-inf, x) = -pi/2 pub fn atan2(comptime T: type, y: T, x: T) T { return switch (T) { f32 => atan2_32(y, x), diff --git a/std/math/atanh.zig b/std/math/atanh.zig index 9056064f5a..8ba29be761 100644 --- a/std/math/atanh.zig +++ b/std/math/atanh.zig @@ -1,14 +1,20 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - atanh(+-1) = +-inf with signal -// - atanh(x) = nan if |x| > 1 with signal -// - atanh(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/atanhf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/atanh.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns the hyperbolic arc-tangent of x. +/// +/// Special Cases: +/// - atanh(+-1) = +-inf with signal +/// - atanh(x) = nan if |x| > 1 with signal +/// - atanh(nan) = nan pub fn atanh(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/big.zig b/std/math/big.zig index 94b6d864e7..44b5ce675f 100644 --- a/std/math/big.zig +++ b/std/math/big.zig @@ -1,5 +1,7 @@ pub use @import("big/int.zig"); +pub use @import("big/rational.zig"); test "math.big" { _ = @import("big/int.zig"); + _ = @import("big/rational.zig"); } diff --git a/std/math/big/int.zig b/std/math/big/int.zig index 8800c2c7a9..beac3c85fe 100644 --- a/std/math/big/int.zig +++ b/std/math/big/int.zig @@ -21,78 +21,160 @@ comptime { debug.assert(Limb.is_signed == false); } +/// An arbitrary-precision big integer. +/// +/// Memory is allocated by an Int as needed to ensure operations never overflow. The range of an +/// Int is bounded only by available memory. pub const Int = struct { - allocator: *Allocator, - positive: bool, - // - little-endian ordered - // - len >= 1 always - // - zero value -> len == 1 with limbs[0] == 0 + const sign_bit: usize = 1 << (usize.bit_count - 1); + + /// Default number of limbs to allocate on creation of an Int. + pub const default_capacity = 4; + + /// Allocator used by the Int when requesting memory. + allocator: ?*Allocator, + + /// Raw digits. These are: + /// + /// * Little-endian ordered + /// * limbs.len >= 1 + /// * Zero is represent as Int.len() == 1 with limbs[0] == 0. + /// + /// Accessing limbs directly should be avoided. limbs: []Limb, - len: usize, - const default_capacity = 4; + /// High bit is the sign bit. If set, Int is negative, else Int is positive. + /// The remaining bits represent the number of limbs used by Int. + metadata: usize, + /// Creates a new Int. default_capacity limbs will be allocated immediately. + /// Int will be zeroed. pub fn init(allocator: *Allocator) !Int { return try Int.initCapacity(allocator, default_capacity); } + /// Creates a new Int. Int will be set to `value`. + /// + /// This is identical to an `init`, followed by a `set`. pub fn initSet(allocator: *Allocator, value: var) !Int { var s = try Int.init(allocator); try s.set(value); return s; } + /// Creates a new Int with a specific capacity. If capacity < default_capacity then the + /// default capacity will be used instead. pub fn initCapacity(allocator: *Allocator, capacity: usize) !Int { return Int{ .allocator = allocator, - .positive = true, + .metadata = 1, .limbs = block: { var limbs = try allocator.alloc(Limb, math.max(default_capacity, capacity)); limbs[0] = 0; break :block limbs; }, - .len = 1, }; } + /// Returns the number of limbs currently in use. + pub fn len(self: Int) usize { + return self.metadata & ~sign_bit; + } + + /// Returns whether an Int is positive. + pub fn isPositive(self: Int) bool { + return self.metadata & sign_bit == 0; + } + + /// Sets the sign of an Int. + pub fn setSign(self: *Int, positive: bool) void { + if (positive) { + self.metadata &= ~sign_bit; + } else { + self.metadata |= sign_bit; + } + } + + /// Sets the length of an Int. + /// + /// If setLen is used, then the Int must be normalized to suit. + pub fn setLen(self: *Int, new_len: usize) void { + self.metadata &= sign_bit; + self.metadata |= new_len; + } + + /// Returns an Int backed by a fixed set of limb values. + /// This is read-only and cannot be used as a result argument. If the Int tries to allocate + /// memory a runtime panic will occur. + pub fn initFixed(limbs: []const Limb) Int { + var self = Int{ + .allocator = null, + .metadata = limbs.len, + // Cast away the const, invalid use to pass as a pointer argument. + .limbs = @intToPtr([*]Limb, @ptrToInt(limbs.ptr))[0..limbs.len], + }; + + self.normalize(limbs.len); + return self; + } + + /// Ensures an Int has enough space allocated for capacity limbs. If the Int does not have + /// sufficient capacity, the exact amount will be allocated. This occurs even if the requested + /// capacity is only greater than the current capacity by one limb. pub fn ensureCapacity(self: *Int, capacity: usize) !void { + self.assertWritable(); if (capacity <= self.limbs.len) { return; } - self.limbs = try self.allocator.realloc(self.limbs, capacity); + self.limbs = try self.allocator.?.realloc(self.limbs, capacity); } + fn assertWritable(self: Int) void { + if (self.allocator == null) { + @panic("provided Int value is read-only but must be writable"); + } + } + + /// Frees all memory associated with an Int. pub fn deinit(self: *Int) void { - self.allocator.free(self.limbs); + self.assertWritable(); + self.allocator.?.free(self.limbs); self.* = undefined; } + /// Clones an Int and returns a new Int with the same value. The new Int is a deep copy and + /// can be modified separately from the original. pub fn clone(other: Int) !Int { + other.assertWritable(); return Int{ .allocator = other.allocator, - .positive = other.positive, + .metadata = other.metadata, .limbs = block: { - var limbs = try other.allocator.alloc(Limb, other.len); - mem.copy(Limb, limbs[0..], other.limbs[0..other.len]); + var limbs = try other.allocator.?.alloc(Limb, other.len()); + mem.copy(Limb, limbs[0..], other.limbs[0..other.len()]); break :block limbs; }, - .len = other.len, }; } + /// Copies the value of an Int to an existing Int so that they both have the same value. + /// Extra memory will be allocated if the receiver does not have enough capacity. pub fn copy(self: *Int, other: Int) !void { - if (self == &other) { + self.assertWritable(); + if (self.limbs.ptr == other.limbs.ptr) { return; } - self.positive = other.positive; - try self.ensureCapacity(other.len); - mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len]); - self.len = other.len; + try self.ensureCapacity(other.len()); + mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len()]); + self.metadata = other.metadata; } + /// Efficiently swap an Int with another. This swaps the limb pointers and a full copy is not + /// performed. The address of the limbs field will not be the same after this function. pub fn swap(self: *Int, other: *Int) void { + self.assertWritable(); mem.swap(Int, self, other); } @@ -103,45 +185,49 @@ pub const Int = struct { debug.warn("\n"); } - pub fn negate(r: *Int) void { - r.positive = !r.positive; + /// Negate the sign of an Int. + pub fn negate(self: *Int) void { + self.metadata ^= sign_bit; } - pub fn abs(r: *Int) void { - r.positive = true; + /// Make an Int positive. + pub fn abs(self: *Int) void { + self.metadata &= ~sign_bit; } - pub fn isOdd(r: Int) bool { - return r.limbs[0] & 1 != 0; + /// Returns true if an Int is odd. + pub fn isOdd(self: Int) bool { + return self.limbs[0] & 1 != 0; } - pub fn isEven(r: Int) bool { - return !r.isOdd(); + /// Returns true if an Int is even. + pub fn isEven(self: Int) bool { + return !self.isOdd(); } - // Returns the number of bits required to represent the absolute value of self. + /// Returns the number of bits required to represent the absolute value an Int. fn bitCountAbs(self: Int) usize { - return (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1])); + return (self.len() - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len() - 1])); } - // Returns the number of bits required to represent the integer in twos-complement form. - // - // If the integer is negative the value returned is the number of bits needed by a signed - // integer to represent the value. If positive the value is the number of bits for an - // unsigned integer. Any unsigned integer will fit in the signed integer with bitcount - // one greater than the returned value. - // - // e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7. + /// Returns the number of bits required to represent the integer in twos-complement form. + /// + /// If the integer is negative the value returned is the number of bits needed by a signed + /// integer to represent the value. If positive the value is the number of bits for an + /// unsigned integer. Any unsigned integer will fit in the signed integer with bitcount + /// one greater than the returned value. + /// + /// e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7. fn bitCountTwosComp(self: Int) usize { var bits = self.bitCountAbs(); // If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos // complement requires one less bit. - if (!self.positive) block: { + if (!self.isPositive()) block: { bits += 1; - if (@popCount(self.limbs[self.len - 1]) == 1) { - for (self.limbs[0 .. self.len - 1]) |limb| { + if (@popCount(self.limbs[self.len() - 1]) == 1) { + for (self.limbs[0 .. self.len() - 1]) |limb| { if (@popCount(limb) != 0) { break :block; } @@ -154,31 +240,34 @@ pub const Int = struct { return bits; } - pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool { + fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool { if (self.eqZero()) { return true; } - if (!is_signed and !self.positive) { + if (!is_signed and !self.isPositive()) { return false; } - const req_bits = self.bitCountTwosComp() + @boolToInt(self.positive and is_signed); + const req_bits = self.bitCountTwosComp() + @boolToInt(self.isPositive() and is_signed); return bit_count >= req_bits; } + /// Returns whether self can fit into an integer of the requested type. pub fn fits(self: Int, comptime T: type) bool { return self.fitsInTwosComp(T.is_signed, T.bit_count); } - // Returns the approximate size of the integer in the given base. Negative values accommodate for - // the minus sign. This is used for determining the number of characters needed to print the - // value. It is inexact and will exceed the given value by 1-2 digits. + /// Returns the approximate size of the integer in the given base. Negative values accommodate for + /// the minus sign. This is used for determining the number of characters needed to print the + /// value. It is inexact and may exceed the given value by ~1-2 bytes. pub fn sizeInBase(self: Int, base: usize) usize { - const bit_count = usize(@boolToInt(!self.positive)) + self.bitCountAbs(); + const bit_count = usize(@boolToInt(!self.isPositive())) + self.bitCountAbs(); return (bit_count / math.log2(base)) + 1; } + /// Sets an Int to value. Value must be an primitive integer type. pub fn set(self: *Int, value: var) Allocator.Error!void { + self.assertWritable(); const T = @typeOf(value); switch (@typeInfo(T)) { @@ -186,19 +275,19 @@ pub const Int = struct { const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T; try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb)); - self.positive = value >= 0; - self.len = 0; + self.metadata = 0; + self.setSign(value >= 0); var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value); if (info.bits <= Limb.bit_count) { self.limbs[0] = Limb(w_value); - self.len = 1; + self.metadata += 1; } else { var i: usize = 0; while (w_value != 0) : (i += 1) { self.limbs[i] = @truncate(Limb, w_value); - self.len += 1; + self.metadata += 1; // TODO: shift == 64 at compile-time fails. Fails on u128 limbs. w_value >>= Limb.bit_count / 2; @@ -212,8 +301,8 @@ pub const Int = struct { const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1; try self.ensureCapacity(req_limbs); - self.positive = value >= 0; - self.len = req_limbs; + self.metadata = req_limbs; + self.setSign(value >= 0); if (w_value <= maxInt(Limb)) { self.limbs[0] = w_value; @@ -240,6 +329,9 @@ pub const Int = struct { TargetTooSmall, }; + /// Convert self to type T. + /// + /// Returns an error if self cannot be narrowed into the requested type without truncation. pub fn to(self: Int, comptime T: type) ConvertError!T { switch (@typeId(T)) { TypeId.Int => { @@ -254,17 +346,17 @@ pub const Int = struct { if (@sizeOf(UT) <= @sizeOf(Limb)) { r = @intCast(UT, self.limbs[0]); } else { - for (self.limbs[0..self.len]) |_, ri| { - const limb = self.limbs[self.len - ri - 1]; + for (self.limbs[0..self.len()]) |_, ri| { + const limb = self.limbs[self.len() - ri - 1]; r <<= Limb.bit_count; r |= limb; } } if (!T.is_signed) { - return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned; + return if (self.isPositive()) @intCast(T, r) else error.NegativeIntoUnsigned; } else { - if (self.positive) { + if (self.isPositive()) { return @intCast(T, r); } else { if (math.cast(T, r)) |ok| { @@ -303,7 +395,15 @@ pub const Int = struct { }; } + /// Set self from the string representation `value`. + /// + /// value must contain only digits <= `base`. Base prefixes are not allowed (e.g. 0x43 should + /// simply be 43). + /// + /// Returns an error if memory could not be allocated or `value` has invalid digits for the + /// requested base. pub fn setString(self: *Int, base: u8, value: []const u8) !void { + self.assertWritable(); if (base < 2 or base > 16) { return error.InvalidBase; } @@ -315,27 +415,22 @@ pub const Int = struct { i += 1; } - // TODO values less than limb size should guarantee non allocating - var base_buffer: [512]u8 = undefined; - const base_al = &std.heap.FixedBufferAllocator.init(base_buffer[0..]).allocator; - const base_ap = try Int.initSet(base_al, base); - - var d_buffer: [512]u8 = undefined; - var d_fba = std.heap.FixedBufferAllocator.init(d_buffer[0..]); - const d_al = &d_fba.allocator; - + const ap_base = Int.initFixed(([]Limb{base})[0..]); try self.set(0); + for (value[i..]) |ch| { const d = try charToDigit(ch, base); - d_fba.end_index = 0; - const d_ap = try Int.initSet(d_al, d); - try self.mul(self.*, base_ap); - try self.add(self.*, d_ap); + const ap_d = Int.initFixed(([]Limb{d})[0..]); + + try self.mul(self.*, ap_base); + try self.add(self.*, ap_d); } - self.positive = positive; + self.setSign(positive); } + /// Converts self to a string in the requested base. Memory is allocated from the provided + /// allocator and not the one present in self. /// TODO make this call format instead of the other way around pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 { if (base < 2 or base > 16) { @@ -355,7 +450,7 @@ pub const Int = struct { if (base & (base - 1) == 0) { const base_shift = math.log2_int(Limb, base); - for (self.limbs[0..self.len]) |limb| { + for (self.limbs[0..self.len()]) |limb| { var shift: usize = 0; while (shift < Limb.bit_count) : (shift += base_shift) { const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & Limb(base - 1)); @@ -382,11 +477,11 @@ pub const Int = struct { } var q = try self.clone(); - q.positive = true; + q.abs(); var r = try Int.init(allocator); var b = try Int.initSet(allocator, limb_base); - while (q.len >= 2) { + while (q.len() >= 2) { try Int.divTrunc(&q, &r, q, b); var r_word = r.limbs[0]; @@ -399,7 +494,7 @@ pub const Int = struct { } { - debug.assert(q.len == 1); + debug.assert(q.len() == 1); var r_word = q.limbs[0]; while (r_word != 0) { @@ -410,7 +505,7 @@ pub const Int = struct { } } - if (!self.positive) { + if (!self.isPositive()) { try digits.append('-'); } @@ -419,7 +514,7 @@ pub const Int = struct { return s; } - /// for the std lib format function + /// To allow `std.fmt.printf` to work with Int. /// TODO make this non-allocating pub fn format( self: Int, @@ -428,22 +523,24 @@ pub const Int = struct { comptime FmtError: type, output: fn (@typeOf(context), []const u8) FmtError!void, ) FmtError!void { + self.assertWritable(); // TODO look at fmt and support other bases - const str = self.toString(self.allocator, 10) catch @panic("TODO make this non allocating"); - defer self.allocator.free(str); + // TODO support read-only fixed integers + const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); + defer self.allocator.?.free(str); return output(context, str); } - // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. + /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. pub fn cmpAbs(a: Int, b: Int) i8 { - if (a.len < b.len) { + if (a.len() < b.len()) { return -1; } - if (a.len > b.len) { + if (a.len() > b.len()) { return 1; } - var i: usize = a.len - 1; + var i: usize = a.len() - 1; while (i != 0) : (i -= 1) { if (a.limbs[i] != b.limbs[i]) { break; @@ -459,53 +556,37 @@ pub const Int = struct { } } - // returns -1, 0, 1 if a < b, a == b or a > b respectively. + /// Returns -1, 0, 1 if a < b, a == b or a > b respectively. pub fn cmp(a: Int, b: Int) i8 { - if (a.positive != b.positive) { - return if (a.positive) i8(1) else -1; + if (a.isPositive() != b.isPositive()) { + return if (a.isPositive()) i8(1) else -1; } else { const r = cmpAbs(a, b); - return if (a.positive) r else -r; + return if (a.isPositive()) r else -r; } } - // if a == 0 + /// Returns true if a == 0. pub fn eqZero(a: Int) bool { - return a.len == 1 and a.limbs[0] == 0; + return a.len() == 1 and a.limbs[0] == 0; } - // if |a| == |b| + /// Returns true if |a| == |b|. pub fn eqAbs(a: Int, b: Int) bool { return cmpAbs(a, b) == 0; } - // if a == b + /// Returns true if a == b. pub fn eq(a: Int, b: Int) bool { return cmp(a, b) == 0; } - // Normalize for a possible single carry digit. - // - // [1, 2, 3, 4, 0] -> [1, 2, 3, 4] - // [1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5] - // [0] -> [0] - fn norm1(r: *Int, length: usize) void { - debug.assert(length > 0); - debug.assert(length <= r.limbs.len); - - if (r.limbs[length - 1] == 0) { - r.len = if (length > 1) length - 1 else 1; - } else { - r.len = length; - } - } - // Normalize a possible sequence of leading zeros. // // [1, 2, 3, 4, 0] -> [1, 2, 3, 4] // [1, 2, 0, 0, 0] -> [1, 2] // [0, 0, 0, 0, 0] -> [0] - fn normN(r: *Int, length: usize) void { + fn normalize(r: *Int, length: usize) void { debug.assert(length > 0); debug.assert(length <= r.limbs.len); @@ -517,11 +598,25 @@ pub const Int = struct { } // Handle zero - r.len = if (j != 0) j else 1; + r.setLen(if (j != 0) j else 1); } - // r = a + b + // Cannot be used as a result argument to any function. + fn readOnlyPositive(a: Int) Int { + return Int{ + .allocator = null, + .metadata = a.len(), + .limbs = a.limbs, + }; + } + + /// r = a + b + /// + /// r, a and b may be aliases. + /// + /// Returns an error if memory could not be allocated. pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void { + r.assertWritable(); if (a.eqZero()) { try r.copy(b); return; @@ -530,38 +625,26 @@ pub const Int = struct { return; } - if (a.positive != b.positive) { - if (a.positive) { + if (a.isPositive() != b.isPositive()) { + if (a.isPositive()) { // (a) + (-b) => a - b - const bp = Int{ - .allocator = undefined, - .positive = true, - .limbs = b.limbs, - .len = b.len, - }; - try r.sub(a, bp); + try r.sub(a, readOnlyPositive(b)); } else { // (-a) + (b) => b - a - const ap = Int{ - .allocator = undefined, - .positive = true, - .limbs = a.limbs, - .len = a.len, - }; - try r.sub(b, ap); + try r.sub(b, readOnlyPositive(a)); } } else { - if (a.len >= b.len) { - try r.ensureCapacity(a.len + 1); - lladd(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]); - r.norm1(a.len + 1); + if (a.len() >= b.len()) { + try r.ensureCapacity(a.len() + 1); + lladd(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); + r.normalize(a.len() + 1); } else { - try r.ensureCapacity(b.len + 1); - lladd(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]); - r.norm1(b.len + 1); + try r.ensureCapacity(b.len() + 1); + lladd(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); + r.normalize(b.len() + 1); } - r.positive = a.positive; + r.setSign(a.isPositive()); } } @@ -589,55 +672,48 @@ pub const Int = struct { r[i] = carry; } - // r = a - b + /// r = a - b + /// + /// r, a and b may be aliases. + /// + /// Returns an error if memory could not be allocated. pub fn sub(r: *Int, a: Int, b: Int) !void { - if (a.positive != b.positive) { - if (a.positive) { + r.assertWritable(); + if (a.isPositive() != b.isPositive()) { + if (a.isPositive()) { // (a) - (-b) => a + b - const bp = Int{ - .allocator = undefined, - .positive = true, - .limbs = b.limbs, - .len = b.len, - }; - try r.add(a, bp); + try r.add(a, readOnlyPositive(b)); } else { // (-a) - (b) => -(a + b) - const ap = Int{ - .allocator = undefined, - .positive = true, - .limbs = a.limbs, - .len = a.len, - }; - try r.add(ap, b); - r.positive = false; + try r.add(readOnlyPositive(a), b); + r.setSign(false); } } else { - if (a.positive) { + if (a.isPositive()) { // (a) - (b) => a - b if (a.cmp(b) >= 0) { - try r.ensureCapacity(a.len + 1); - llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]); - r.normN(a.len); - r.positive = true; + try r.ensureCapacity(a.len() + 1); + llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); + r.normalize(a.len()); + r.setSign(true); } else { - try r.ensureCapacity(b.len + 1); - llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]); - r.normN(b.len); - r.positive = false; + try r.ensureCapacity(b.len() + 1); + llsub(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); + r.normalize(b.len()); + r.setSign(false); } } else { // (-a) - (-b) => -(a - b) if (a.cmp(b) < 0) { - try r.ensureCapacity(a.len + 1); - llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]); - r.normN(a.len); - r.positive = false; + try r.ensureCapacity(a.len() + 1); + llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); + r.normalize(a.len()); + r.setSign(false); } else { - try r.ensureCapacity(b.len + 1); - llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]); - r.normN(b.len); - r.positive = true; + try r.ensureCapacity(b.len() + 1); + llsub(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); + r.normalize(b.len()); + r.setSign(true); } } } @@ -667,16 +743,20 @@ pub const Int = struct { debug.assert(borrow == 0); } - // rma = a * b - // - // For greatest efficiency, ensure rma does not alias a or b. + /// rma = a * b + /// + /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. + /// + /// Returns an error if memory could not be allocated. pub fn mul(rma: *Int, a: Int, b: Int) !void { + rma.assertWritable(); + var r = rma; var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr; var sr: Int = undefined; if (aliased) { - sr = try Int.initCapacity(rma.allocator, a.len + b.len); + sr = try Int.initCapacity(rma.allocator.?, a.len() + b.len()); r = &sr; aliased = true; } @@ -685,16 +765,16 @@ pub const Int = struct { r.deinit(); }; - try r.ensureCapacity(a.len + b.len); + try r.ensureCapacity(a.len() + b.len()); - if (a.len >= b.len) { - llmul(r.limbs, a.limbs[0..a.len], b.limbs[0..b.len]); + if (a.len() >= b.len()) { + llmul(r.limbs, a.limbs[0..a.len()], b.limbs[0..b.len()]); } else { - llmul(r.limbs, b.limbs[0..b.len], a.limbs[0..a.len]); + llmul(r.limbs, b.limbs[0..b.len()], a.limbs[0..a.len()]); } - r.positive = a.positive == b.positive; - r.normN(a.len + b.len); + r.normalize(a.len() + b.len()); + r.setSign(a.isPositive() == b.isPositive()); } // a + b * c + *carry, sets carry to the overflow bits @@ -740,29 +820,34 @@ pub const Int = struct { } } + /// q = a / b (rem r) + /// + /// a / b are floored (rounded towards 0). pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void { try div(q, r, a, b); // Trunc -> Floor. - if (!q.positive) { - // TODO values less than limb size should guarantee non allocating - var one_buffer: [512]u8 = undefined; - const one_al = &std.heap.FixedBufferAllocator.init(one_buffer[0..]).allocator; - const one_ap = try Int.initSet(one_al, 1); - - try q.sub(q.*, one_ap); - try r.add(q.*, one_ap); + if (!q.isPositive()) { + const one = Int.initFixed(([]Limb{1})[0..]); + try q.sub(q.*, one); + try r.add(q.*, one); } - r.positive = b.positive; + r.setSign(b.isPositive()); } + /// q = a / b (rem r) + /// + /// a / b are truncated (rounded towards -inf). pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void { try div(q, r, a, b); - r.positive = a.positive; + r.setSign(a.isPositive()); } // Truncates by default. fn div(quo: *Int, rem: *Int, a: Int, b: Int) !void { + quo.assertWritable(); + rem.assertWritable(); + if (b.eqZero()) { @panic("division by zero"); } @@ -773,36 +858,67 @@ pub const Int = struct { if (a.cmpAbs(b) < 0) { // quo may alias a so handle rem first try rem.copy(a); - rem.positive = a.positive == b.positive; + rem.setSign(a.isPositive() == b.isPositive()); - quo.positive = true; - quo.len = 1; + quo.metadata = 1; quo.limbs[0] = 0; return; } - if (b.len == 1) { - try quo.ensureCapacity(a.len); + // Handle trailing zero-words of divisor/dividend. These are not handled in the following + // algorithms. + const a_zero_limb_count = blk: { + var i: usize = 0; + while (i < a.len()) : (i += 1) { + if (a.limbs[i] != 0) break; + } + break :blk i; + }; + const b_zero_limb_count = blk: { + var i: usize = 0; + while (i < b.len()) : (i += 1) { + if (b.limbs[i] != 0) break; + } + break :blk i; + }; - lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[0..a.len], b.limbs[0]); - quo.norm1(a.len); - quo.positive = a.positive == b.positive; + const ab_zero_limb_count = std.math.min(a_zero_limb_count, b_zero_limb_count); - rem.len = 1; - rem.positive = true; + if (b.len() - ab_zero_limb_count == 1) { + try quo.ensureCapacity(a.len()); + + lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[ab_zero_limb_count..a.len()], b.limbs[b.len() - 1]); + quo.normalize(a.len() - ab_zero_limb_count); + quo.setSign(a.isPositive() == b.isPositive()); + + rem.metadata = 1; } else { // x and y are modified during division - var x = try a.clone(); + var x = try Int.initCapacity(quo.allocator.?, a.len()); defer x.deinit(); + try x.copy(a); - var y = try b.clone(); + var y = try Int.initCapacity(quo.allocator.?, b.len()); defer y.deinit(); + try y.copy(b); // x may grow one limb during normalization - try quo.ensureCapacity(a.len + y.len); - try divN(quo.allocator, quo, rem, &x, &y); + try quo.ensureCapacity(a.len() + y.len()); + + // Shrink x, y such that the trailing zero limbs shared between are removed. + if (ab_zero_limb_count != 0) { + std.mem.copy(Limb, x.limbs[0..], x.limbs[ab_zero_limb_count..]); + std.mem.copy(Limb, y.limbs[0..], y.limbs[ab_zero_limb_count..]); + x.metadata -= ab_zero_limb_count; + y.metadata -= ab_zero_limb_count; + } - quo.positive = a.positive == b.positive; + try divN(quo.allocator.?, quo, rem, &x, &y); + quo.setSign(a.isPositive() == b.isPositive()); + } + + if (ab_zero_limb_count != 0) { + try rem.shiftLeft(rem.*, ab_zero_limb_count * Limb.bit_count); } } @@ -837,25 +953,28 @@ pub const Int = struct { // // x = qy + r where 0 <= r < y fn divN(allocator: *Allocator, q: *Int, r: *Int, x: *Int, y: *Int) !void { - debug.assert(y.len >= 2); - debug.assert(x.len >= y.len); - debug.assert(q.limbs.len >= x.len + y.len - 1); + debug.assert(y.len() >= 2); + debug.assert(x.len() >= y.len()); + debug.assert(q.limbs.len >= x.len() + y.len() - 1); debug.assert(default_capacity >= 3); // see 3.2 var tmp = try Int.init(allocator); defer tmp.deinit(); - // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set) - const norm_shift = @clz(y.limbs[y.len - 1]); + // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set) and even + var norm_shift = @clz(y.limbs[y.len() - 1]); + if (norm_shift == 0 and y.isOdd()) { + norm_shift = Limb.bit_count; + } try x.shiftLeft(x.*, norm_shift); try y.shiftLeft(y.*, norm_shift); - const n = x.len - 1; - const t = y.len - 1; + const n = x.len() - 1; + const t = y.len() - 1; // 1. - q.len = n - t + 1; - mem.set(Limb, q.limbs[0..q.len], 0); + q.metadata = n - t + 1; + mem.set(Limb, q.limbs[0..q.len()], 0); // 2. try tmp.shiftLeft(y.*, Limb.bit_count * (n - t)); @@ -880,7 +999,7 @@ pub const Int = struct { tmp.limbs[0] = if (i >= 2) x.limbs[i - 2] else 0; tmp.limbs[1] = if (i >= 1) x.limbs[i - 1] else 0; tmp.limbs[2] = x.limbs[i]; - tmp.normN(3); + tmp.normalize(3); while (true) { // 2x1 limb multiplication unrolled against single-limb q[i-t-1] @@ -888,7 +1007,7 @@ pub const Int = struct { r.limbs[0] = addMulLimbWithCarry(0, if (t >= 1) y.limbs[t - 1] else 0, q.limbs[i - t - 1], &carry); r.limbs[1] = addMulLimbWithCarry(0, y.limbs[t], q.limbs[i - t - 1], &carry); r.limbs[2] = carry; - r.normN(3); + r.normalize(3); if (r.cmpAbs(tmp) <= 0) { break; @@ -903,7 +1022,7 @@ pub const Int = struct { try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1)); try x.sub(x.*, tmp); - if (!x.positive) { + if (!x.isPositive()) { try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1)); try x.add(x.*, tmp); q.limbs[i - t - 1] -= 1; @@ -911,18 +1030,20 @@ pub const Int = struct { } // Denormalize - q.normN(q.len); + q.normalize(q.len()); try r.shiftRight(x.*, norm_shift); - r.normN(r.len); + r.normalize(r.len()); } - // r = a << shift, in other words, r = a * 2^shift + /// r = a << shift, in other words, r = a * 2^shift pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void { - try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1); - llshl(r.limbs[0..], a.limbs[0..a.len], shift); - r.norm1(a.len + (shift / Limb.bit_count) + 1); - r.positive = a.positive; + r.assertWritable(); + + try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1); + llshl(r.limbs[0..], a.limbs[0..a.len()], shift); + r.normalize(a.len() + (shift / Limb.bit_count) + 1); + r.setSign(a.isPositive()); } fn llshl(r: []Limb, a: []const Limb, shift: usize) void { @@ -948,19 +1069,20 @@ pub const Int = struct { mem.set(Limb, r[0 .. limb_shift - 1], 0); } - // r = a >> shift + /// r = a >> shift pub fn shiftRight(r: *Int, a: Int, shift: usize) !void { - if (a.len <= shift / Limb.bit_count) { - r.len = 1; + r.assertWritable(); + + if (a.len() <= shift / Limb.bit_count) { + r.metadata = 1; r.limbs[0] = 0; - r.positive = true; return; } - try r.ensureCapacity(a.len - (shift / Limb.bit_count)); - const r_len = llshr(r.limbs[0..], a.limbs[0..a.len], shift); - r.len = a.len - (shift / Limb.bit_count); - r.positive = a.positive; + try r.ensureCapacity(a.len() - (shift / Limb.bit_count)); + const r_len = llshr(r.limbs[0..], a.limbs[0..a.len()], shift); + r.metadata = a.len() - (shift / Limb.bit_count); + r.setSign(a.isPositive()); } fn llshr(r: []Limb, a: []const Limb, shift: usize) void { @@ -983,16 +1105,20 @@ pub const Int = struct { } } - // r = a | b + /// r = a | b + /// + /// a and b are zero-extended to the longer of a or b. pub fn bitOr(r: *Int, a: Int, b: Int) !void { - if (a.len > b.len) { - try r.ensureCapacity(a.len); - llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]); - r.len = a.len; + r.assertWritable(); + + if (a.len() > b.len()) { + try r.ensureCapacity(a.len()); + llor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); + r.setLen(a.len()); } else { - try r.ensureCapacity(b.len); - llor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]); - r.len = b.len; + try r.ensureCapacity(b.len()); + llor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); + r.setLen(b.len()); } } @@ -1010,16 +1136,18 @@ pub const Int = struct { } } - // r = a & b + /// r = a & b pub fn bitAnd(r: *Int, a: Int, b: Int) !void { - if (a.len > b.len) { - try r.ensureCapacity(b.len); - lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]); - r.normN(b.len); + r.assertWritable(); + + if (a.len() > b.len()) { + try r.ensureCapacity(b.len()); + lland(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); + r.normalize(b.len()); } else { - try r.ensureCapacity(a.len); - lland(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]); - r.normN(a.len); + try r.ensureCapacity(a.len()); + lland(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); + r.normalize(a.len()); } } @@ -1034,16 +1162,18 @@ pub const Int = struct { } } - // r = a ^ b + /// r = a ^ b pub fn bitXor(r: *Int, a: Int, b: Int) !void { - if (a.len > b.len) { - try r.ensureCapacity(a.len); - llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]); - r.normN(a.len); + r.assertWritable(); + + if (a.len() > b.len()) { + try r.ensureCapacity(a.len()); + llxor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); + r.normalize(a.len()); } else { - try r.ensureCapacity(b.len); - llxor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]); - r.normN(b.len); + try r.ensureCapacity(b.len()); + llxor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); + r.normalize(b.len()); } } @@ -1067,7 +1197,9 @@ pub const Int = struct { // They will still run on larger than this and should pass, but the multi-limb code-paths // may be untested in some cases. -const al = debug.global_allocator; +var buffer: [64 * 8192]u8 = undefined; +var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); +const al = &fixed.allocator; test "big.int comptime_int set" { comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab; @@ -1088,14 +1220,14 @@ test "big.int comptime_int set negative" { var a = try Int.initSet(al, -10); testing.expect(a.limbs[0] == 10); - testing.expect(a.positive == false); + testing.expect(a.isPositive() == false); } test "big.int int set unaligned small" { var a = try Int.initSet(al, u7(45)); testing.expect(a.limbs[0] == 45); - testing.expect(a.positive == true); + testing.expect(a.isPositive() == true); } test "big.int comptime_int to" { @@ -1116,7 +1248,7 @@ test "big.int to target too small error" { testing.expectError(error.TargetTooSmall, a.to(u8)); } -test "big.int norm1" { +test "big.int normalize" { var a = try Int.init(al); try a.ensureCapacity(8); @@ -1124,26 +1256,26 @@ test "big.int norm1" { a.limbs[1] = 2; a.limbs[2] = 3; a.limbs[3] = 0; - a.norm1(4); - testing.expect(a.len == 3); + a.normalize(4); + testing.expect(a.len() == 3); a.limbs[0] = 1; a.limbs[1] = 2; a.limbs[2] = 3; - a.norm1(3); - testing.expect(a.len == 3); + a.normalize(3); + testing.expect(a.len() == 3); a.limbs[0] = 0; a.limbs[1] = 0; - a.norm1(2); - testing.expect(a.len == 1); + a.normalize(2); + testing.expect(a.len() == 1); a.limbs[0] = 0; - a.norm1(1); - testing.expect(a.len == 1); + a.normalize(1); + testing.expect(a.len() == 1); } -test "big.int normN" { +test "big.int normalize multi" { var a = try Int.init(al); try a.ensureCapacity(8); @@ -1151,25 +1283,25 @@ test "big.int normN" { a.limbs[1] = 2; a.limbs[2] = 0; a.limbs[3] = 0; - a.normN(4); - testing.expect(a.len == 2); + a.normalize(4); + testing.expect(a.len() == 2); a.limbs[0] = 1; a.limbs[1] = 2; a.limbs[2] = 3; - a.normN(3); - testing.expect(a.len == 3); + a.normalize(3); + testing.expect(a.len() == 3); a.limbs[0] = 0; a.limbs[1] = 0; a.limbs[2] = 0; a.limbs[3] = 0; - a.normN(4); - testing.expect(a.len == 1); + a.normalize(4); + testing.expect(a.len() == 1); a.limbs[0] = 0; - a.normN(1); - testing.expect(a.len == 1); + a.normalize(1); + testing.expect(a.len() == 1); } test "big.int parity" { @@ -1204,7 +1336,7 @@ test "big.int bitcount + sizeInBase" { try a.shiftLeft(a, 5000); testing.expect(a.bitCountAbs() == 5032); testing.expect(a.sizeInBase(2) >= 5032); - a.positive = false; + a.setSign(false); testing.expect(a.bitCountAbs() == 5032); testing.expect(a.sizeInBase(2) >= 5033); @@ -1216,10 +1348,8 @@ test "big.int bitcount/to" { try a.set(0); testing.expect(a.bitCountTwosComp() == 0); - // TODO: stack smashing - // testing.expect((try a.to(u0)) == 0); - // TODO: sigsegv - // testing.expect((try a.to(i0)) == 0); + testing.expect((try a.to(u0)) == 0); + testing.expect((try a.to(i0)) == 0); try a.set(-1); testing.expect(a.bitCountTwosComp() == 1); @@ -1980,6 +2110,98 @@ test "big.int div multi-multi (3.1/3.3 branch)" { testing.expect((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282); } +test "big.int div multi-single zero-limb trailing" { + var a = try Int.initSet(al, 0x60000000000000000000000000000000000000000000000000000000000000000); + var b = try Int.initSet(al, 0x10000000000000000); + + var q = try Int.init(al); + var r = try Int.init(al); + try Int.divTrunc(&q, &r, a, b); + + var expected = try Int.initSet(al, 0x6000000000000000000000000000000000000000000000000); + testing.expect(q.eq(expected)); + testing.expect(r.eqZero()); +} + +test "big.int div multi-multi zero-limb trailing (with rem)" { + var a = try Int.initSet(al, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); + var b = try Int.initSet(al, 0x8666666655555555444444443333333300000000000000000000000000000000); + + var q = try Int.init(al); + var r = try Int.init(al); + try Int.divTrunc(&q, &r, a, b); + + testing.expect((try q.to(u128)) == 0x10000000000000000); + + const rs = try r.toString(al, 16); + testing.expect(std.mem.eql(u8, rs, "4444444344444443111111111111111100000000000000000000000000000000")); +} + +test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count > divisor zero-limb count" { + var a = try Int.initSet(al, 0x8666666655555555888888877777777611111111111111110000000000000000); + var b = try Int.initSet(al, 0x8666666655555555444444443333333300000000000000000000000000000000); + + var q = try Int.init(al); + var r = try Int.init(al); + try Int.divTrunc(&q, &r, a, b); + + testing.expect((try q.to(u128)) == 0x1); + + const rs = try r.toString(al, 16); + testing.expect(std.mem.eql(u8, rs, "444444434444444311111111111111110000000000000000")); +} + +test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count < divisor zero-limb count" { + var a = try Int.initSet(al, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); + var b = try Int.initSet(al, 0x866666665555555544444444333333330000000000000000); + + var q = try Int.init(al); + var r = try Int.init(al); + try Int.divTrunc(&q, &r, a, b); + + const qs = try q.toString(al, 16); + testing.expect(std.mem.eql(u8, qs, "10000000000000000820820803105186f")); + + const rs = try r.toString(al, 16); + testing.expect(std.mem.eql(u8, rs, "4e11f2baa5896a321d463b543d0104e30000000000000000")); +} + +test "big.int div multi-multi fuzz case #1" { + var a = try Int.init(al); + var b = try Int.init(al); + + try a.setString(16, "ffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + try b.setString(16, "3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffc000000000000000000000000000000007fffffffffff"); + + var q = try Int.init(al); + var r = try Int.init(al); + try Int.divTrunc(&q, &r, a, b); + + const qs = try q.toString(al, 16); + testing.expect(std.mem.eql(u8, qs, "3ffffffffffffffffffffffffffff0000000000000000000000000000000000001ffffffffffffffffffffffffffff7fffffffe000000000000000000000000000180000000000000000000003fffffbfffffffdfffffffffffffeffff800000100101000000100000000020003fffffdfbfffffe3ffffffffffffeffff7fffc00800a100000017ffe000002000400007efbfff7fe9f00000037ffff3fff7fffa004006100000009ffe00000190038200bf7d2ff7fefe80400060000f7d7f8fbf9401fe38e0403ffc0bdffffa51102c300d7be5ef9df4e5060007b0127ad3fa69f97d0f820b6605ff617ddf7f32ad7a05c0d03f2e7bc78a6000e087a8bbcdc59e07a5a079128a7861f553ddebed7e8e56701756f9ead39b48cd1b0831889ea6ec1fddf643d0565b075ff07e6caea4e2854ec9227fd635ed60a2f5eef2893052ffd54718fa08604acbf6a15e78a467c4a3c53c0278af06c4416573f925491b195e8fd79302cb1aaf7caf4ecfc9aec1254cc969786363ac729f914c6ddcc26738d6b0facd54eba026580aba2eb6482a088b0d224a8852420b91ec1")); + + const rs = try r.toString(al, 16); + testing.expect(std.mem.eql(u8, rs, "310d1d4c414426b4836c2635bad1df3a424e50cbdd167ffccb4dfff57d36b4aae0d6ca0910698220171a0f3373c1060a046c2812f0027e321f72979daa5e7973214170d49e885de0c0ecc167837d44502430674a82522e5df6a0759548052420b91ec1")); +} + +test "big.int div multi-multi fuzz case #2" { + var a = try Int.init(al); + var b = try Int.init(al); + + try a.setString(16, "3ffffffffe00000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000001fffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffc000000000000000000000000000000000000000000000000000000000000000"); + try b.setString(16, "ffc0000000000000000000000000000000000000000000000000"); + + var q = try Int.init(al); + var r = try Int.init(al); + try Int.divTrunc(&q, &r, a, b); + + const qs = try q.toString(al, 16); + testing.expect(std.mem.eql(u8, qs, "40100400fe3f8fe3f8fe3f8fe3f8fe3f8fe4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f91e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4992649926499264991e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4792e4b92e4b92e4b92e4b92a4a92a4a92a4")); + + const rs = try r.toString(al, 16); + testing.expect(std.mem.eql(u8, rs, "a900000000000000000000000000000000000000000000000000")); +} + test "big.int shift-right single" { var a = try Int.initSet(al, 0xffff0000); try a.shiftRight(a, 16); diff --git a/std/math/big/rational.zig b/std/math/big/rational.zig new file mode 100644 index 0000000000..58a5e3ac76 --- /dev/null +++ b/std/math/big/rational.zig @@ -0,0 +1,938 @@ +const std = @import("../../std.zig"); +const builtin = @import("builtin"); +const debug = std.debug; +const math = std.math; +const mem = std.mem; +const testing = std.testing; +const Allocator = mem.Allocator; +const ArrayList = std.ArrayList; + +const TypeId = builtin.TypeId; + +const bn = @import("int.zig"); +const Limb = bn.Limb; +const DoubleLimb = bn.DoubleLimb; +const Int = bn.Int; + +/// An arbitrary-precision rational number. +/// +/// Memory is allocated as needed for operations to ensure full precision is kept. The precision +/// of a Rational is only bounded by memory. +/// +/// Rational's are always normalized. That is, for a Rational r = p/q where p and q are integers, +/// gcd(p, q) = 1 always. +pub const Rational = struct { + /// Numerator. Determines the sign of the Rational. + p: Int, + + /// Denominator. Sign is ignored. + q: Int, + + /// Create a new Rational. A small amount of memory will be allocated on initialization. + /// This will be 2 * Int.default_capacity. + pub fn init(a: *Allocator) !Rational { + return Rational{ + .p = try Int.init(a), + .q = try Int.initSet(a, 1), + }; + } + + /// Frees all memory associated with a Rational. + pub fn deinit(self: *Rational) void { + self.p.deinit(); + self.q.deinit(); + } + + /// Set a Rational from a primitive integer type. + pub fn setInt(self: *Rational, a: var) !void { + try self.p.set(a); + try self.q.set(1); + } + + /// Set a Rational from a string of the form `A/B` where A and B are base-10 integers. + pub fn setFloatString(self: *Rational, str: []const u8) !void { + // TODO: Accept a/b fractions and exponent form + if (str.len == 0) { + return error.InvalidFloatString; + } + + const State = enum { + Integer, + Fractional, + }; + + var state = State.Integer; + var point: ?usize = null; + + var start: usize = 0; + if (str[0] == '-') { + start += 1; + } + + for (str) |c, i| { + switch (state) { + State.Integer => { + switch (c) { + '.' => { + state = State.Fractional; + point = i; + }, + '0'...'9' => { + // okay + }, + else => { + return error.InvalidFloatString; + }, + } + }, + State.Fractional => { + switch (c) { + '0'...'9' => { + // okay + }, + else => { + return error.InvalidFloatString; + }, + } + }, + } + } + + // TODO: batch the multiplies by 10 + if (point) |i| { + try self.p.setString(10, str[0..i]); + + const base = Int.initFixed(([]Limb{10})[0..]); + + var j: usize = start; + while (j < str.len - i - 1) : (j += 1) { + try self.p.mul(self.p, base); + } + + try self.q.setString(10, str[i + 1 ..]); + try self.p.add(self.p, self.q); + + try self.q.set(1); + var k: usize = i + 1; + while (k < str.len) : (k += 1) { + try self.q.mul(self.q, base); + } + + try self.reduce(); + } else { + try self.p.setString(10, str[0..]); + try self.q.set(1); + } + } + + /// Set a Rational from a floating-point value. The rational will have enough precision to + /// completely represent the provided float. + pub fn setFloat(self: *Rational, comptime T: type, f: T) !void { + // Translated from golang.go/src/math/big/rat.go. + debug.assert(@typeId(T) == builtin.TypeId.Float); + + const UnsignedIntType = @IntType(false, T.bit_count); + const f_bits = @bitCast(UnsignedIntType, f); + + const exponent_bits = math.floatExponentBits(T); + const exponent_bias = (1 << (exponent_bits - 1)) - 1; + const mantissa_bits = math.floatMantissaBits(T); + + const exponent_mask = (1 << exponent_bits) - 1; + const mantissa_mask = (1 << mantissa_bits) - 1; + + var exponent = @intCast(i16, (f_bits >> mantissa_bits) & exponent_mask); + var mantissa = f_bits & mantissa_mask; + + switch (exponent) { + exponent_mask => { + return error.NonFiniteFloat; + }, + 0 => { + // denormal + exponent -= exponent_bias - 1; + }, + else => { + // normal + mantissa |= 1 << mantissa_bits; + exponent -= exponent_bias; + }, + } + + var shift: i16 = mantissa_bits - exponent; + + // factor out powers of two early from rational + while (mantissa & 1 == 0 and shift > 0) { + mantissa >>= 1; + shift -= 1; + } + + try self.p.set(mantissa); + self.p.setSign(f >= 0); + + try self.q.set(1); + if (shift >= 0) { + try self.q.shiftLeft(self.q, @intCast(usize, shift)); + } else { + try self.p.shiftLeft(self.p, @intCast(usize, -shift)); + } + + try self.reduce(); + } + + /// Return a floating-point value that is the closest value to a Rational. + /// + /// The result may not be exact if the Rational is too precise or too large for the + /// target type. + pub fn toFloat(self: Rational, comptime T: type) !T { + // Translated from golang.go/src/math/big/rat.go. + // TODO: Indicate whether the result is not exact. + debug.assert(@typeId(T) == builtin.TypeId.Float); + + const fsize = T.bit_count; + const BitReprType = @IntType(false, T.bit_count); + + const msize = math.floatMantissaBits(T); + const msize1 = msize + 1; + const msize2 = msize1 + 1; + + const esize = math.floatExponentBits(T); + const ebias = (1 << (esize - 1)) - 1; + const emin = 1 - ebias; + const emax = ebias; + + if (self.p.eqZero()) { + return 0; + } + + // 1. left-shift a or sub so that a/b is in [1 << msize1, 1 << (msize2 + 1)] + var exp = @intCast(isize, self.p.bitCountTwosComp()) - @intCast(isize, self.q.bitCountTwosComp()); + + var a2 = try self.p.clone(); + defer a2.deinit(); + + var b2 = try self.q.clone(); + defer b2.deinit(); + + const shift = msize2 - exp; + if (shift >= 0) { + try a2.shiftLeft(a2, @intCast(usize, shift)); + } else { + try b2.shiftLeft(b2, @intCast(usize, -shift)); + } + + // 2. compute quotient and remainder + var q = try Int.init(self.p.allocator.?); + defer q.deinit(); + + // unused + var r = try Int.init(self.p.allocator.?); + defer r.deinit(); + + try Int.divTrunc(&q, &r, a2, b2); + + var mantissa = extractLowBits(q, BitReprType); + var have_rem = r.len() > 0; + + // 3. q didn't fit in msize2 bits, redo division b2 << 1 + if (mantissa >> msize2 == 1) { + if (mantissa & 1 == 1) { + have_rem = true; + } + mantissa >>= 1; + exp += 1; + } + if (mantissa >> msize1 != 1) { + // NOTE: This can be hit if the limb size is small (u8/16). + @panic("unexpected bits in result"); + } + + // 4. Rounding + if (emin - msize <= exp and exp <= emin) { + // denormal + const shift1 = @intCast(math.Log2Int(BitReprType), emin - (exp - 1)); + const lost_bits = mantissa & ((@intCast(BitReprType, 1) << shift1) - 1); + have_rem = have_rem or lost_bits != 0; + mantissa >>= shift1; + exp = 2 - ebias; + } + + // round q using round-half-to-even + var exact = !have_rem; + if (mantissa & 1 != 0) { + exact = false; + if (have_rem or (mantissa & 2 != 0)) { + mantissa += 1; + if (mantissa >= 1 << msize2) { + // 11...1 => 100...0 + mantissa >>= 1; + exp += 1; + } + } + } + mantissa >>= 1; + + const f = math.scalbn(@intToFloat(T, mantissa), @intCast(i32, exp - msize1)); + if (math.isInf(f)) { + exact = false; + } + + return if (self.p.isPositive()) f else -f; + } + + /// Set a rational from an integer ratio. + pub fn setRatio(self: *Rational, p: var, q: var) !void { + try self.p.set(p); + try self.q.set(q); + + self.p.setSign(@boolToInt(self.p.isPositive()) ^ @boolToInt(self.q.isPositive()) == 0); + self.q.setSign(true); + + try self.reduce(); + + if (self.q.eqZero()) { + @panic("cannot set rational with denominator = 0"); + } + } + + /// Set a Rational directly from an Int. + pub fn copyInt(self: *Rational, a: Int) !void { + try self.p.copy(a); + try self.q.set(1); + } + + /// Set a Rational directly from a ratio of two Int's. + pub fn copyRatio(self: *Rational, a: Int, b: Int) !void { + try self.p.copy(a); + try self.q.copy(b); + + self.p.setSign(@boolToInt(self.p.isPositive()) ^ @boolToInt(self.q.isPositive()) == 0); + self.q.setSign(true); + + try self.reduce(); + } + + /// Make a Rational positive. + pub fn abs(r: *Rational) void { + r.p.abs(); + } + + /// Negate the sign of a Rational. + pub fn negate(r: *Rational) void { + r.p.negate(); + } + + /// Efficiently swap a Rational with another. This swaps the limb pointers and a full copy is not + /// performed. The address of the limbs field will not be the same after this function. + pub fn swap(r: *Rational, other: *Rational) void { + r.p.swap(&other.p); + r.q.swap(&other.q); + } + + /// Returns -1, 0, 1 if a < b, a == b or a > b respectively. + pub fn cmp(a: Rational, b: Rational) !i8 { + return cmpInternal(a, b, true); + } + + /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. + pub fn cmpAbs(a: Rational, b: Rational) !i8 { + return cmpInternal(a, b, false); + } + + // p/q > x/y iff p*y > x*q + fn cmpInternal(a: Rational, b: Rational, is_abs: bool) !i8 { + // TODO: Would a div compare algorithm of sorts be viable and quicker? Can we avoid + // the memory allocations here? + var q = try Int.init(a.p.allocator.?); + defer q.deinit(); + + var p = try Int.init(b.p.allocator.?); + defer p.deinit(); + + try q.mul(a.p, b.q); + try p.mul(b.p, a.q); + + return if (is_abs) q.cmpAbs(p) else q.cmp(p); + } + + /// rma = a + b. + /// + /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. + /// + /// Returns an error if memory could not be allocated. + pub fn add(rma: *Rational, a: Rational, b: Rational) !void { + var r = rma; + var aliased = rma.p.limbs.ptr == a.p.limbs.ptr or rma.p.limbs.ptr == b.p.limbs.ptr; + + var sr: Rational = undefined; + if (aliased) { + sr = try Rational.init(rma.p.allocator.?); + r = &sr; + aliased = true; + } + defer if (aliased) { + rma.swap(r); + r.deinit(); + }; + + try r.p.mul(a.p, b.q); + try r.q.mul(b.p, a.q); + try r.p.add(r.p, r.q); + + try r.q.mul(a.q, b.q); + try r.reduce(); + } + + /// rma = a - b. + /// + /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. + /// + /// Returns an error if memory could not be allocated. + pub fn sub(rma: *Rational, a: Rational, b: Rational) !void { + var r = rma; + var aliased = rma.p.limbs.ptr == a.p.limbs.ptr or rma.p.limbs.ptr == b.p.limbs.ptr; + + var sr: Rational = undefined; + if (aliased) { + sr = try Rational.init(rma.p.allocator.?); + r = &sr; + aliased = true; + } + defer if (aliased) { + rma.swap(r); + r.deinit(); + }; + + try r.p.mul(a.p, b.q); + try r.q.mul(b.p, a.q); + try r.p.sub(r.p, r.q); + + try r.q.mul(a.q, b.q); + try r.reduce(); + } + + /// rma = a * b. + /// + /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. + /// + /// Returns an error if memory could not be allocated. + pub fn mul(r: *Rational, a: Rational, b: Rational) !void { + try r.p.mul(a.p, b.p); + try r.q.mul(a.q, b.q); + try r.reduce(); + } + + /// rma = a / b. + /// + /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. + /// + /// Returns an error if memory could not be allocated. + pub fn div(r: *Rational, a: Rational, b: Rational) !void { + if (b.p.eqZero()) { + @panic("division by zero"); + } + + try r.p.mul(a.p, b.q); + try r.q.mul(b.p, a.q); + try r.reduce(); + } + + /// Invert the numerator and denominator fields of a Rational. p/q => q/p. + pub fn invert(r: *Rational) void { + Int.swap(&r.p, &r.q); + } + + // reduce r/q such that gcd(r, q) = 1 + fn reduce(r: *Rational) !void { + var a = try Int.init(r.p.allocator.?); + defer a.deinit(); + + const sign = r.p.isPositive(); + r.p.abs(); + try gcd(&a, r.p, r.q); + r.p.setSign(sign); + + const one = Int.initFixed(([]Limb{1})[0..]); + if (a.cmp(one) != 0) { + var unused = try Int.init(r.p.allocator.?); + defer unused.deinit(); + + // TODO: divexact would be useful here + // TODO: don't copy r.q for div + try Int.divTrunc(&r.p, &unused, r.p, a); + try Int.divTrunc(&r.q, &unused, r.q, a); + } + } +}; + +const SignedDoubleLimb = @IntType(true, DoubleLimb.bit_count); + +fn gcd(rma: *Int, x: Int, y: Int) !void { + rma.assertWritable(); + var r = rma; + var aliased = rma.limbs.ptr == x.limbs.ptr or rma.limbs.ptr == y.limbs.ptr; + + var sr: Int = undefined; + if (aliased) { + sr = try Int.initCapacity(rma.allocator.?, math.max(x.len(), y.len())); + r = &sr; + aliased = true; + } + defer if (aliased) { + rma.swap(r); + r.deinit(); + }; + + try gcdLehmer(r, x, y); +} + +// Storage must live for the lifetime of the returned value +fn FixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Int { + std.debug.assert(storage.len >= 2); + + var A_is_positive = A >= 0; + const Au = @intCast(DoubleLimb, if (A < 0) -A else A); + storage[0] = @truncate(Limb, Au); + storage[1] = @truncate(Limb, Au >> Limb.bit_count); + var Ap = Int.initFixed(storage[0..2]); + Ap.setSign(A_is_positive); + return Ap; +} + +fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void { + var x = try xa.clone(); + x.abs(); + defer x.deinit(); + + var y = try ya.clone(); + y.abs(); + defer y.deinit(); + + if (x.cmp(y) < 0) { + x.swap(&y); + } + + var T = try Int.init(r.allocator.?); + defer T.deinit(); + + while (y.len() > 1) { + debug.assert(x.isPositive() and y.isPositive()); + debug.assert(x.len() >= y.len()); + + var xh: SignedDoubleLimb = x.limbs[x.len() - 1]; + var yh: SignedDoubleLimb = if (x.len() > y.len()) 0 else y.limbs[x.len() - 1]; + + var A: SignedDoubleLimb = 1; + var B: SignedDoubleLimb = 0; + var C: SignedDoubleLimb = 0; + var D: SignedDoubleLimb = 1; + + while (yh + C != 0 and yh + D != 0) { + const q = @divFloor(xh + A, yh + C); + const qp = @divFloor(xh + B, yh + D); + if (q != qp) { + break; + } + + var t = A - q * C; + A = C; + C = t; + t = B - q * D; + B = D; + D = t; + + t = xh - q * yh; + xh = yh; + yh = t; + } + + if (B == 0) { + // T = x % y, r is unused + try Int.divTrunc(r, &T, x, y); + debug.assert(T.isPositive()); + + x.swap(&y); + y.swap(&T); + } else { + var storage: [8]Limb = undefined; + const Ap = FixedIntFromSignedDoubleLimb(A, storage[0..2]); + const Bp = FixedIntFromSignedDoubleLimb(B, storage[2..4]); + const Cp = FixedIntFromSignedDoubleLimb(C, storage[4..6]); + const Dp = FixedIntFromSignedDoubleLimb(D, storage[6..8]); + + // T = Ax + By + try r.mul(x, Ap); + try T.mul(y, Bp); + try T.add(r.*, T); + + // u = Cx + Dy, r as u + try x.mul(x, Cp); + try r.mul(y, Dp); + try r.add(x, r.*); + + x.swap(&T); + y.swap(r); + } + } + + // euclidean algorithm + debug.assert(x.cmp(y) >= 0); + + while (!y.eqZero()) { + try Int.divTrunc(&T, r, x, y); + x.swap(&y); + y.swap(r); + } + + r.swap(&x); +} + +var buffer: [64 * 8192]u8 = undefined; +var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); +var al = &fixed.allocator; + +test "big.rational gcd non-one small" { + var a = try Int.initSet(al, 17); + var b = try Int.initSet(al, 97); + var r = try Int.init(al); + + try gcd(&r, a, b); + + testing.expect((try r.to(u32)) == 1); +} + +test "big.rational gcd non-one small" { + var a = try Int.initSet(al, 4864); + var b = try Int.initSet(al, 3458); + var r = try Int.init(al); + + try gcd(&r, a, b); + + testing.expect((try r.to(u32)) == 38); +} + +test "big.rational gcd non-one large" { + var a = try Int.initSet(al, 0xffffffffffffffff); + var b = try Int.initSet(al, 0xffffffffffffffff7777); + var r = try Int.init(al); + + try gcd(&r, a, b); + + testing.expect((try r.to(u32)) == 4369); +} + +test "big.rational gcd large multi-limb result" { + var a = try Int.initSet(al, 0x12345678123456781234567812345678123456781234567812345678); + var b = try Int.initSet(al, 0x12345671234567123456712345671234567123456712345671234567); + var r = try Int.init(al); + + try gcd(&r, a, b); + + testing.expect((try r.to(u256)) == 0xf000000ff00000fff0000ffff000fffff00ffffff1); +} + +test "big.rational gcd one large" { + var a = try Int.initSet(al, 1897056385327307); + var b = try Int.initSet(al, 2251799813685248); + var r = try Int.init(al); + + try gcd(&r, a, b); + + testing.expect((try r.to(u64)) == 1); +} + +fn extractLowBits(a: Int, comptime T: type) T { + testing.expect(@typeId(T) == builtin.TypeId.Int); + + if (T.bit_count <= Limb.bit_count) { + return @truncate(T, a.limbs[0]); + } else { + var r: T = 0; + comptime var i: usize = 0; + + // Remainder is always 0 since if T.bit_count >= Limb.bit_count -> Limb | T and both + // are powers of two. + inline while (i < T.bit_count / Limb.bit_count) : (i += 1) { + r |= math.shl(T, a.limbs[i], i * Limb.bit_count); + } + + return r; + } +} + +test "big.rational extractLowBits" { + var a = try Int.initSet(al, 0x11112222333344441234567887654321); + + const a1 = extractLowBits(a, u8); + testing.expect(a1 == 0x21); + + const a2 = extractLowBits(a, u16); + testing.expect(a2 == 0x4321); + + const a3 = extractLowBits(a, u32); + testing.expect(a3 == 0x87654321); + + const a4 = extractLowBits(a, u64); + testing.expect(a4 == 0x1234567887654321); + + const a5 = extractLowBits(a, u128); + testing.expect(a5 == 0x11112222333344441234567887654321); +} + +test "big.rational set" { + var a = try Rational.init(al); + + try a.setInt(5); + testing.expect((try a.p.to(u32)) == 5); + testing.expect((try a.q.to(u32)) == 1); + + try a.setRatio(7, 3); + testing.expect((try a.p.to(u32)) == 7); + testing.expect((try a.q.to(u32)) == 3); + + try a.setRatio(9, 3); + testing.expect((try a.p.to(i32)) == 3); + testing.expect((try a.q.to(i32)) == 1); + + try a.setRatio(-9, 3); + testing.expect((try a.p.to(i32)) == -3); + testing.expect((try a.q.to(i32)) == 1); + + try a.setRatio(9, -3); + testing.expect((try a.p.to(i32)) == -3); + testing.expect((try a.q.to(i32)) == 1); + + try a.setRatio(-9, -3); + testing.expect((try a.p.to(i32)) == 3); + testing.expect((try a.q.to(i32)) == 1); +} + +test "big.rational setFloat" { + var a = try Rational.init(al); + + try a.setFloat(f64, 2.5); + testing.expect((try a.p.to(i32)) == 5); + testing.expect((try a.q.to(i32)) == 2); + + try a.setFloat(f32, -2.5); + testing.expect((try a.p.to(i32)) == -5); + testing.expect((try a.q.to(i32)) == 2); + + try a.setFloat(f32, 3.141593); + + // = 3.14159297943115234375 + testing.expect((try a.p.to(u32)) == 3294199); + testing.expect((try a.q.to(u32)) == 1048576); + + try a.setFloat(f64, 72.141593120712409172417410926841290461290467124); + + // = 72.1415931207124145885245525278151035308837890625 + testing.expect((try a.p.to(u128)) == 5076513310880537); + testing.expect((try a.q.to(u128)) == 70368744177664); +} + +test "big.rational setFloatString" { + var a = try Rational.init(al); + + try a.setFloatString("72.14159312071241458852455252781510353"); + + // = 72.1415931207124145885245525278151035308837890625 + testing.expect((try a.p.to(u128)) == 7214159312071241458852455252781510353); + testing.expect((try a.q.to(u128)) == 100000000000000000000000000000000000); +} + +test "big.rational toFloat" { + var a = try Rational.init(al); + + // = 3.14159297943115234375 + try a.setRatio(3294199, 1048576); + testing.expect((try a.toFloat(f64)) == 3.14159297943115234375); + + // = 72.1415931207124145885245525278151035308837890625 + try a.setRatio(5076513310880537, 70368744177664); + testing.expect((try a.toFloat(f64)) == 72.141593120712409172417410926841290461290467124); +} + +test "big.rational set/to Float round-trip" { + var a = try Rational.init(al); + var prng = std.rand.DefaultPrng.init(0x5EED); + var i: usize = 0; + while (i < 512) : (i += 1) { + const r = prng.random.float(f64); + try a.setFloat(f64, r); + testing.expect((try a.toFloat(f64)) == r); + } +} + +test "big.rational copy" { + var a = try Rational.init(al); + + const b = try Int.initSet(al, 5); + + try a.copyInt(b); + testing.expect((try a.p.to(u32)) == 5); + testing.expect((try a.q.to(u32)) == 1); + + const c = try Int.initSet(al, 7); + const d = try Int.initSet(al, 3); + + try a.copyRatio(c, d); + testing.expect((try a.p.to(u32)) == 7); + testing.expect((try a.q.to(u32)) == 3); + + const e = try Int.initSet(al, 9); + const f = try Int.initSet(al, 3); + + try a.copyRatio(e, f); + testing.expect((try a.p.to(u32)) == 3); + testing.expect((try a.q.to(u32)) == 1); +} + +test "big.rational negate" { + var a = try Rational.init(al); + + try a.setInt(-50); + testing.expect((try a.p.to(i32)) == -50); + testing.expect((try a.q.to(i32)) == 1); + + a.negate(); + testing.expect((try a.p.to(i32)) == 50); + testing.expect((try a.q.to(i32)) == 1); + + a.negate(); + testing.expect((try a.p.to(i32)) == -50); + testing.expect((try a.q.to(i32)) == 1); +} + +test "big.rational abs" { + var a = try Rational.init(al); + + try a.setInt(-50); + testing.expect((try a.p.to(i32)) == -50); + testing.expect((try a.q.to(i32)) == 1); + + a.abs(); + testing.expect((try a.p.to(i32)) == 50); + testing.expect((try a.q.to(i32)) == 1); + + a.abs(); + testing.expect((try a.p.to(i32)) == 50); + testing.expect((try a.q.to(i32)) == 1); +} + +test "big.rational swap" { + var a = try Rational.init(al); + var b = try Rational.init(al); + + try a.setRatio(50, 23); + try b.setRatio(17, 3); + + testing.expect((try a.p.to(u32)) == 50); + testing.expect((try a.q.to(u32)) == 23); + + testing.expect((try b.p.to(u32)) == 17); + testing.expect((try b.q.to(u32)) == 3); + + a.swap(&b); + + testing.expect((try a.p.to(u32)) == 17); + testing.expect((try a.q.to(u32)) == 3); + + testing.expect((try b.p.to(u32)) == 50); + testing.expect((try b.q.to(u32)) == 23); +} + +test "big.rational cmp" { + var a = try Rational.init(al); + var b = try Rational.init(al); + + try a.setRatio(500, 231); + try b.setRatio(18903, 8584); + testing.expect((try a.cmp(b)) < 0); + + try a.setRatio(890, 10); + try b.setRatio(89, 1); + testing.expect((try a.cmp(b)) == 0); +} + +test "big.rational add single-limb" { + var a = try Rational.init(al); + var b = try Rational.init(al); + + try a.setRatio(500, 231); + try b.setRatio(18903, 8584); + testing.expect((try a.cmp(b)) < 0); + + try a.setRatio(890, 10); + try b.setRatio(89, 1); + testing.expect((try a.cmp(b)) == 0); +} + +test "big.rational add" { + var a = try Rational.init(al); + var b = try Rational.init(al); + var r = try Rational.init(al); + + try a.setRatio(78923, 23341); + try b.setRatio(123097, 12441414); + try a.add(a, b); + + try r.setRatio(984786924199, 290395044174); + testing.expect((try a.cmp(r)) == 0); +} + +test "big.rational sub" { + var a = try Rational.init(al); + var b = try Rational.init(al); + var r = try Rational.init(al); + + try a.setRatio(78923, 23341); + try b.setRatio(123097, 12441414); + try a.sub(a, b); + + try r.setRatio(979040510045, 290395044174); + testing.expect((try a.cmp(r)) == 0); +} + +test "big.rational mul" { + var a = try Rational.init(al); + var b = try Rational.init(al); + var r = try Rational.init(al); + + try a.setRatio(78923, 23341); + try b.setRatio(123097, 12441414); + try a.mul(a, b); + + try r.setRatio(571481443, 17082061422); + testing.expect((try a.cmp(r)) == 0); +} + +test "big.rational div" { + var a = try Rational.init(al); + var b = try Rational.init(al); + var r = try Rational.init(al); + + try a.setRatio(78923, 23341); + try b.setRatio(123097, 12441414); + try a.div(a, b); + + try r.setRatio(75531824394, 221015929); + testing.expect((try a.cmp(r)) == 0); +} + +test "big.rational div" { + var a = try Rational.init(al); + var r = try Rational.init(al); + + try a.setRatio(78923, 23341); + a.invert(); + + try r.setRatio(23341, 78923); + testing.expect((try a.cmp(r)) == 0); + + try a.setRatio(-78923, 23341); + a.invert(); + + try r.setRatio(-23341, 78923); + testing.expect((try a.cmp(r)) == 0); +} diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig index 9497255269..5241e31323 100644 --- a/std/math/cbrt.zig +++ b/std/math/cbrt.zig @@ -1,13 +1,19 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - cbrt(+-0) = +-0 -// - cbrt(+-inf) = +-inf -// - cbrt(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/cbrtf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/cbrt.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the cube root of x. +/// +/// Special Cases: +/// - cbrt(+-0) = +-0 +/// - cbrt(+-inf) = +-inf +/// - cbrt(nan) = nan pub fn cbrt(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/ceil.zig b/std/math/ceil.zig index da83e0ec59..5f86093a6d 100644 --- a/std/math/ceil.zig +++ b/std/math/ceil.zig @@ -1,14 +1,20 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - ceil(+-0) = +-0 -// - ceil(+-inf) = +-inf -// - ceil(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the least integer value greater than of equal to x. +/// +/// Special Cases: +/// - ceil(+-0) = +-0 +/// - ceil(+-inf) = +-inf +/// - ceil(nan) = nan pub fn ceil(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/complex.zig b/std/math/complex.zig index cc0573b227..e5574f9cee 100644 --- a/std/math/complex.zig +++ b/std/math/complex.zig @@ -23,13 +23,18 @@ pub const sqrt = @import("complex/sqrt.zig").sqrt; pub const tanh = @import("complex/tanh.zig").tanh; pub const tan = @import("complex/tan.zig").tan; +/// A complex number consisting of a real an imaginary part. T must be a floating-point value. pub fn Complex(comptime T: type) type { return struct { const Self = @This(); + /// Real part. re: T, + + /// Imaginary part. im: T, + /// Create a new Complex number from the given real and imaginary parts. pub fn new(re: T, im: T) Self { return Self{ .re = re, @@ -37,6 +42,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the sum of two complex numbers. pub fn add(self: Self, other: Self) Self { return Self{ .re = self.re + other.re, @@ -44,6 +50,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the subtraction of two complex numbers. pub fn sub(self: Self, other: Self) Self { return Self{ .re = self.re - other.re, @@ -51,6 +58,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the product of two complex numbers. pub fn mul(self: Self, other: Self) Self { return Self{ .re = self.re * other.re - self.im * other.im, @@ -58,6 +66,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the quotient of two complex numbers. pub fn div(self: Self, other: Self) Self { const re_num = self.re * other.re + self.im * other.im; const im_num = self.im * other.re - self.re * other.im; @@ -69,6 +78,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the complex conjugate of a number. pub fn conjugate(self: Self) Self { return Self{ .re = self.re, @@ -76,6 +86,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the reciprocal of a complex number. pub fn reciprocal(self: Self) Self { const m = self.re * self.re + self.im * self.im; return Self{ @@ -84,6 +95,7 @@ pub fn Complex(comptime T: type) type { }; } + /// Returns the magnitude of a complex number. pub fn magnitude(self: Self) T { return math.sqrt(self.re * self.re + self.im * self.im); } diff --git a/std/math/complex/abs.zig b/std/math/complex/abs.zig index e1368d6ef6..8105f57218 100644 --- a/std/math/complex/abs.zig +++ b/std/math/complex/abs.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the absolute value (modulus) of z. pub fn abs(z: var) @typeOf(z.re) { const T = @typeOf(z.re); return math.hypot(T, z.re, z.im); diff --git a/std/math/complex/acos.zig b/std/math/complex/acos.zig index 8aed26a71b..f3526cc9ff 100644 --- a/std/math/complex/acos.zig +++ b/std/math/complex/acos.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the arc-cosine of z. pub fn acos(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const q = cmath.asin(z); diff --git a/std/math/complex/acosh.zig b/std/math/complex/acosh.zig index e72bf431fe..6f0fd2e36c 100644 --- a/std/math/complex/acosh.zig +++ b/std/math/complex/acosh.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the hyperbolic arc-cosine of z. pub fn acosh(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const q = cmath.acos(z); diff --git a/std/math/complex/arg.zig b/std/math/complex/arg.zig index 0a2441d1fd..d0c9588b8d 100644 --- a/std/math/complex/arg.zig +++ b/std/math/complex/arg.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the angular component (in radians) of z. pub fn arg(z: var) @typeOf(z.re) { const T = @typeOf(z.re); return math.atan2(T, z.im, z.re); diff --git a/std/math/complex/asin.zig b/std/math/complex/asin.zig index 6be775d748..76f94a286c 100644 --- a/std/math/complex/asin.zig +++ b/std/math/complex/asin.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +// Returns the arc-sine of z. pub fn asin(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const x = z.re; diff --git a/std/math/complex/asinh.zig b/std/math/complex/asinh.zig index 8e09036750..da065aad01 100644 --- a/std/math/complex/asinh.zig +++ b/std/math/complex/asinh.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the hyperbolic arc-sine of z. pub fn asinh(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const q = Complex(T).new(-z.im, z.re); diff --git a/std/math/complex/atan.zig b/std/math/complex/atan.zig index 6b83adbd97..89bc8dfaf0 100644 --- a/std/math/complex/atan.zig +++ b/std/math/complex/atan.zig @@ -1,9 +1,16 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/catanf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/catan.c + const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the arc-tangent of z. pub fn atan(z: var) @typeOf(z) { const T = @typeOf(z.re); return switch (T) { diff --git a/std/math/complex/atanh.zig b/std/math/complex/atanh.zig index 8edfb6e78e..225e7c61de 100644 --- a/std/math/complex/atanh.zig +++ b/std/math/complex/atanh.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the hyperbolic arc-tangent of z. pub fn atanh(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const q = Complex(T).new(-z.im, z.re); diff --git a/std/math/complex/conj.zig b/std/math/complex/conj.zig index 7a42d365ea..bd71ca3c06 100644 --- a/std/math/complex/conj.zig +++ b/std/math/complex/conj.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the complex conjugate of z. pub fn conj(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); return Complex(T).new(z.re, -z.im); diff --git a/std/math/complex/cos.zig b/std/math/complex/cos.zig index 71f9603c75..332009ffe5 100644 --- a/std/math/complex/cos.zig +++ b/std/math/complex/cos.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the cosine of z. pub fn cos(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const p = Complex(T).new(-z.im, z.re); diff --git a/std/math/complex/cosh.zig b/std/math/complex/cosh.zig index 9806e41170..be7bfde963 100644 --- a/std/math/complex/cosh.zig +++ b/std/math/complex/cosh.zig @@ -1,3 +1,9 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/ccoshf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/ccosh.c + const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; @@ -6,6 +12,7 @@ const Complex = cmath.Complex; const ldexp_cexp = @import("ldexp.zig").ldexp_cexp; +/// Returns the hyperbolic arc-cosine of z. pub fn cosh(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); return switch (T) { diff --git a/std/math/complex/exp.zig b/std/math/complex/exp.zig index c74ac2fc08..9b686bebc3 100644 --- a/std/math/complex/exp.zig +++ b/std/math/complex/exp.zig @@ -1,3 +1,9 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/cexpf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/cexp.c + const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; @@ -6,6 +12,7 @@ const Complex = cmath.Complex; const ldexp_cexp = @import("ldexp.zig").ldexp_cexp; +/// Returns e raised to the power of z (e^z). pub fn exp(z: var) @typeOf(z) { const T = @typeOf(z.re); diff --git a/std/math/complex/ldexp.zig b/std/math/complex/ldexp.zig index 6b4306bf77..d6f810793f 100644 --- a/std/math/complex/ldexp.zig +++ b/std/math/complex/ldexp.zig @@ -1,9 +1,16 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/__cexpf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/__cexp.c + const std = @import("../../std.zig"); const debug = std.debug; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns exp(z) scaled to avoid overflow. pub fn ldexp_cexp(z: var, expt: i32) @typeOf(z) { const T = @typeOf(z.re); diff --git a/std/math/complex/log.zig b/std/math/complex/log.zig index 2b43a6970f..762b4fde9a 100644 --- a/std/math/complex/log.zig +++ b/std/math/complex/log.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the natural logarithm of z. pub fn log(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const r = cmath.abs(z); diff --git a/std/math/complex/pow.zig b/std/math/complex/pow.zig index 9174bb3626..a2480453fc 100644 --- a/std/math/complex/pow.zig +++ b/std/math/complex/pow.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns z raised to the complex power of c. pub fn pow(comptime T: type, z: T, c: T) T { const p = cmath.log(z); const q = c.mul(p); diff --git a/std/math/complex/proj.zig b/std/math/complex/proj.zig index aadcff6ff6..c8f2d9fc6d 100644 --- a/std/math/complex/proj.zig +++ b/std/math/complex/proj.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the projection of z onto the riemann sphere. pub fn proj(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); diff --git a/std/math/complex/sin.zig b/std/math/complex/sin.zig index 049631f31e..9ddc3a7a80 100644 --- a/std/math/complex/sin.zig +++ b/std/math/complex/sin.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the sine of z. pub fn sin(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const p = Complex(T).new(-z.im, z.re); diff --git a/std/math/complex/sinh.zig b/std/math/complex/sinh.zig index 0b656e5354..6286d8447f 100644 --- a/std/math/complex/sinh.zig +++ b/std/math/complex/sinh.zig @@ -1,3 +1,9 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/csinhf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/csinh.c + const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; @@ -6,6 +12,7 @@ const Complex = cmath.Complex; const ldexp_cexp = @import("ldexp.zig").ldexp_cexp; +/// Returns the hyperbolic sine of z. pub fn sinh(z: var) @typeOf(z) { const T = @typeOf(z.re); return switch (T) { diff --git a/std/math/complex/sqrt.zig b/std/math/complex/sqrt.zig index e935d0b238..36f4c28e29 100644 --- a/std/math/complex/sqrt.zig +++ b/std/math/complex/sqrt.zig @@ -1,9 +1,17 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/csqrtf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/csqrt.c + const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the square root of z. The real and imaginary parts of the result have the same sign +/// as the imaginary part of z. pub fn sqrt(z: var) @typeOf(z) { const T = @typeOf(z.re); diff --git a/std/math/complex/tan.zig b/std/math/complex/tan.zig index 45e2873eb6..398b8295ca 100644 --- a/std/math/complex/tan.zig +++ b/std/math/complex/tan.zig @@ -4,6 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the tanget of z. pub fn tan(z: var) Complex(@typeOf(z.re)) { const T = @typeOf(z.re); const q = Complex(T).new(-z.im, z.re); diff --git a/std/math/complex/tanh.zig b/std/math/complex/tanh.zig index de905ee3f6..5c14ec66f2 100644 --- a/std/math/complex/tanh.zig +++ b/std/math/complex/tanh.zig @@ -1,9 +1,16 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/complex/ctanhf.c +// https://git.musl-libc.org/cgit/musl/tree/src/complex/ctanh.c + const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; +/// Returns the hyperbolic tangent of z. pub fn tanh(z: var) @typeOf(z) { const T = @typeOf(z.re); return switch (T) { diff --git a/std/math/copysign.zig b/std/math/copysign.zig index ff8140b3ab..e4d90c395e 100644 --- a/std/math/copysign.zig +++ b/std/math/copysign.zig @@ -1,8 +1,15 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/math/copysignf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/copysign.c + const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns a value with the magnitude of x and the sign of y. pub fn copysign(comptime T: type, x: T, y: T) T { return switch (T) { f16 => copysign16(x, y), diff --git a/std/math/cos.zig b/std/math/cos.zig index 9479482894..dc4aff59d6 100644 --- a/std/math/cos.zig +++ b/std/math/cos.zig @@ -1,18 +1,23 @@ -// Special Cases: +// Ported from go, which is licensed under a BSD-3 license. +// https://golang.org/LICENSE // -// - cos(+-inf) = nan -// - cos(nan) = nan +// https://golang.org/src/math/sin.go const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the cosine of the radian value x. +/// +/// Special Cases: +/// - cos(+-inf) = nan +/// - cos(nan) = nan pub fn cos(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { - f32 => cos32(x), - f64 => cos64(x), + f32 => cos_(f32, x), + f64 => cos_(f64, x), else => @compileError("cos not implemented for " ++ @typeName(T)), }; } @@ -33,78 +38,24 @@ const C3 = 2.48015872888517045348E-5; const C4 = -1.38888888888730564116E-3; const C5 = 4.16666666666665929218E-2; -// NOTE: This is taken from the go stdlib. The musl implementation is much more complex. -// -// This may have slight differences on some edge cases and may need to replaced if so. -fn cos32(x_: f32) f32 { - const pi4a = 7.85398125648498535156e-1; - const pi4b = 3.77489470793079817668E-8; - const pi4c = 2.69515142907905952645E-15; - const m4pi = 1.273239544735162542821171882678754627704620361328125; - - var x = x_; - if (math.isNan(x) or math.isInf(x)) { - return math.nan(f32); - } - - var sign = false; - if (x < 0) { - x = -x; - } - - var y = math.floor(x * m4pi); - var j = @floatToInt(i64, y); +const pi4a = 7.85398125648498535156e-1; +const pi4b = 3.77489470793079817668E-8; +const pi4c = 2.69515142907905952645E-15; +const m4pi = 1.273239544735162542821171882678754627704620361328125; - if (j & 1 == 1) { - j += 1; - y += 1; - } - - j &= 7; - if (j > 3) { - j -= 4; - sign = !sign; - } - if (j > 1) { - sign = !sign; - } - - const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; - const w = z * z; - - const r = r: { - if (j == 1 or j == 2) { - break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); - } else { - break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); - } - }; - - if (sign) { - return -r; - } else { - return r; - } -} - -fn cos64(x_: f64) f64 { - const pi4a = 7.85398125648498535156e-1; - const pi4b = 3.77489470793079817668E-8; - const pi4c = 2.69515142907905952645E-15; - const m4pi = 1.273239544735162542821171882678754627704620361328125; +fn cos_(comptime T: type, x_: T) T { + const I = @IntType(true, T.bit_count); var x = x_; if (math.isNan(x) or math.isInf(x)) { - return math.nan(f64); + return math.nan(T); } var sign = false; - if (x < 0) { - x = -x; - } + x = math.fabs(x); var y = math.floor(x * m4pi); - var j = @floatToInt(i64, y); + var j = @floatToInt(I, y); if (j & 1 == 1) { j += 1; @@ -123,56 +74,51 @@ fn cos64(x_: f64) f64 { const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; const w = z * z; - const r = r: { - if (j == 1 or j == 2) { - break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); - } else { - break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); - } - }; + const r = if (j == 1 or j == 2) + z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))) + else + 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); - if (sign) { - return -r; - } else { - return r; - } + return if (sign) -r else r; } test "math.cos" { - expect(cos(f32(0.0)) == cos32(0.0)); - expect(cos(f64(0.0)) == cos64(0.0)); + expect(cos(f32(0.0)) == cos_(f32, 0.0)); + expect(cos(f64(0.0)) == cos_(f64, 0.0)); } test "math.cos32" { const epsilon = 0.000001; - expect(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); - expect(math.approxEq(f32, cos32(0.2), 0.980067, epsilon)); - expect(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon)); - expect(math.approxEq(f32, cos32(1.5), 0.070737, epsilon)); - expect(math.approxEq(f32, cos32(37.45), 0.969132, epsilon)); - expect(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); + expect(math.approxEq(f32, cos_(f32, 0.0), 1.0, epsilon)); + expect(math.approxEq(f32, cos_(f32, 0.2), 0.980067, epsilon)); + expect(math.approxEq(f32, cos_(f32, 0.8923), 0.627623, epsilon)); + expect(math.approxEq(f32, cos_(f32, 1.5), 0.070737, epsilon)); + expect(math.approxEq(f32, cos_(f32, -1.5), 0.070737, epsilon)); + expect(math.approxEq(f32, cos_(f32, 37.45), 0.969132, epsilon)); + expect(math.approxEq(f32, cos_(f32, 89.123), 0.400798, epsilon)); } test "math.cos64" { const epsilon = 0.000001; - expect(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); - expect(math.approxEq(f64, cos64(0.2), 0.980067, epsilon)); - expect(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon)); - expect(math.approxEq(f64, cos64(1.5), 0.070737, epsilon)); - expect(math.approxEq(f64, cos64(37.45), 0.969132, epsilon)); - expect(math.approxEq(f64, cos64(89.123), 0.40080, epsilon)); + expect(math.approxEq(f64, cos_(f64, 0.0), 1.0, epsilon)); + expect(math.approxEq(f64, cos_(f64, 0.2), 0.980067, epsilon)); + expect(math.approxEq(f64, cos_(f64, 0.8923), 0.627623, epsilon)); + expect(math.approxEq(f64, cos_(f64, 1.5), 0.070737, epsilon)); + expect(math.approxEq(f64, cos_(f64, -1.5), 0.070737, epsilon)); + expect(math.approxEq(f64, cos_(f64, 37.45), 0.969132, epsilon)); + expect(math.approxEq(f64, cos_(f64, 89.123), 0.40080, epsilon)); } test "math.cos32.special" { - expect(math.isNan(cos32(math.inf(f32)))); - expect(math.isNan(cos32(-math.inf(f32)))); - expect(math.isNan(cos32(math.nan(f32)))); + expect(math.isNan(cos_(f32, math.inf(f32)))); + expect(math.isNan(cos_(f32, -math.inf(f32)))); + expect(math.isNan(cos_(f32, math.nan(f32)))); } test "math.cos64.special" { - expect(math.isNan(cos64(math.inf(f64)))); - expect(math.isNan(cos64(-math.inf(f64)))); - expect(math.isNan(cos64(math.nan(f64)))); + expect(math.isNan(cos_(f64, math.inf(f64)))); + expect(math.isNan(cos_(f64, -math.inf(f64)))); + expect(math.isNan(cos_(f64, math.nan(f64)))); } diff --git a/std/math/cosh.zig b/std/math/cosh.zig index eb3082e5fa..75c5c15ec1 100644 --- a/std/math/cosh.zig +++ b/std/math/cosh.zig @@ -1,8 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - cosh(+-0) = 1 -// - cosh(+-inf) = +inf -// - cosh(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/coshf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/cosh.c const builtin = @import("builtin"); const std = @import("../std.zig"); @@ -11,6 +11,12 @@ const expo2 = @import("expo2.zig").expo2; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns the hyperbolic cosine of x. +/// +/// Special Cases: +/// - cosh(+-0) = 1 +/// - cosh(+-inf) = +inf +/// - cosh(nan) = nan pub fn cosh(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/exp.zig b/std/math/exp.zig index aabccffd0b..ad058646a4 100644 --- a/std/math/exp.zig +++ b/std/math/exp.zig @@ -1,13 +1,19 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - exp(+inf) = +inf -// - exp(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/expf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c const std = @import("../std.zig"); const math = std.math; const assert = std.debug.assert; const builtin = @import("builtin"); +/// Returns e raised to the power of x (e^x). +/// +/// Special Cases: +/// - exp(+inf) = +inf +/// - exp(nan) = nan pub fn exp(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/exp2.zig b/std/math/exp2.zig index 392d45bf68..07a39576b1 100644 --- a/std/math/exp2.zig +++ b/std/math/exp2.zig @@ -1,12 +1,18 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - exp2(+inf) = +inf -// - exp2(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/exp2f.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns 2 raised to the power of x (2^x). +/// +/// Special Cases: +/// - exp2(+inf) = +inf +/// - exp2(nan) = nan pub fn exp2(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/expm1.zig b/std/math/expm1.zig index b83cc3e82e..5e347f86f6 100644 --- a/std/math/expm1.zig +++ b/std/math/expm1.zig @@ -1,14 +1,23 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - expm1(+inf) = +inf -// - expm1(-inf) = -1 -// - expm1(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/expmf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/expm.c + +// TODO: Updated recently. const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns e raised to the power of x, minus 1 (e^x - 1). This is more accurate than exp(e, x) - 1 +/// when x is near 0. +/// +/// Special Cases: +/// - expm1(+inf) = +inf +/// - expm1(-inf) = -1 +/// - expm1(nan) = nan pub fn expm1(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/expo2.zig b/std/math/expo2.zig index 57e2bf34c9..c00098a5a7 100644 --- a/std/math/expo2.zig +++ b/std/math/expo2.zig @@ -1,5 +1,12 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/math/__expo2f.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/__expo2.c + const math = @import("../math.zig"); +/// Returns exp(x) / 2 for x >= log(maxFloat(T)). pub fn expo2(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/fabs.zig b/std/math/fabs.zig index e30f788ae7..6469f38835 100644 --- a/std/math/fabs.zig +++ b/std/math/fabs.zig @@ -1,13 +1,19 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - fabs(+-inf) = +inf -// - fabs(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/fabsf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/fabs.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns the absolute value of x. +/// +/// Special Cases: +/// - fabs(+-inf) = +inf +/// - fabs(nan) = nan pub fn fabs(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/floor.zig b/std/math/floor.zig index ab45a8fee7..e5ff2b1fc1 100644 --- a/std/math/floor.zig +++ b/std/math/floor.zig @@ -1,14 +1,20 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - floor(+-0) = +-0 -// - floor(+-inf) = +-inf -// - floor(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c const builtin = @import("builtin"); const expect = std.testing.expect; const std = @import("../std.zig"); const math = std.math; +/// Returns the greatest integer value less than or equal to x. +/// +/// Special Cases: +/// - floor(+-0) = +-0 +/// - floor(+-inf) = +-inf +/// - floor(nan) = nan pub fn floor(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/fma.zig b/std/math/fma.zig index a317bc96de..19c306fa2a 100644 --- a/std/math/fma.zig +++ b/std/math/fma.zig @@ -1,7 +1,14 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c + const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns x * y + z with a single rounding error. pub fn fma(comptime T: type, x: T, y: T, z: T) T { return switch (T) { f32 => fma32(x, y, z), @@ -16,7 +23,7 @@ fn fma32(x: f32, y: f32, z: f32) f32 { const u = @bitCast(u64, xy_z); const e = (u >> 52) & 0x7FF; - if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) { + if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or (xy_z - xy == z and xy_z - z == xy)) { return @floatCast(f32, xy_z); } else { // TODO: Handle inexact case with double-rounding @@ -24,6 +31,7 @@ fn fma32(x: f32, y: f32, z: f32) f32 { } } +// NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately. fn fma64(x: f64, y: f64, z: f64) f64 { if (!math.isFinite(x) or !math.isFinite(y)) { return x * y + z; diff --git a/std/math/frexp.zig b/std/math/frexp.zig index 35eec315d9..2759cd6492 100644 --- a/std/math/frexp.zig +++ b/std/math/frexp.zig @@ -1,8 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - frexp(+-0) = +-0, 0 -// - frexp(+-inf) = +-inf, 0 -// - frexp(nan) = nan, undefined +// https://git.musl-libc.org/cgit/musl/tree/src/math/frexpf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/frexp.c const std = @import("../std.zig"); const math = std.math; @@ -17,6 +17,13 @@ fn frexp_result(comptime T: type) type { pub const frexp32_result = frexp_result(f32); pub const frexp64_result = frexp_result(f64); +/// Breaks x into a normalized fraction and an integral power of two. +/// f == frac * 2^exp, with |frac| in the interval [0.5, 1). +/// +/// Special Cases: +/// - frexp(+-0) = +-0, 0 +/// - frexp(+-inf) = +-inf, 0 +/// - frexp(nan) = nan, undefined pub fn frexp(x: var) frexp_result(@typeOf(x)) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/hypot.zig b/std/math/hypot.zig index fddbe7c068..c15da1495e 100644 --- a/std/math/hypot.zig +++ b/std/math/hypot.zig @@ -1,15 +1,21 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - hypot(+-inf, y) = +inf -// - hypot(x, +-inf) = +inf -// - hypot(nan, y) = nan -// - hypot(x, nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/hypotf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/hypot.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns sqrt(x * x + y * y), avoiding unncessary overflow and underflow. +/// +/// Special Cases: +/// - hypot(+-inf, y) = +inf +/// - hypot(x, +-inf) = +inf +/// - hypot(nan, y) = nan +/// - hypot(x, nan) = nan pub fn hypot(comptime T: type, x: T, y: T) T { return switch (T) { f32 => hypot32(x, y), diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig index 2dfd42a62c..fe4158a6dd 100644 --- a/std/math/ilogb.zig +++ b/std/math/ilogb.zig @@ -1,8 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - ilogb(+-inf) = maxInt(i32) -// - ilogb(0) = maxInt(i32) -// - ilogb(nan) = maxInt(i32) +// https://git.musl-libc.org/cgit/musl/tree/src/math/ilogbf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/ilogb.c const std = @import("../std.zig"); const math = std.math; @@ -10,6 +10,12 @@ const expect = std.testing.expect; const maxInt = std.math.maxInt; const minInt = std.math.minInt; +/// Returns the binary exponent of x as an integer. +/// +/// Special Cases: +/// - ilogb(+-inf) = maxInt(i32) +/// - ilogb(0) = maxInt(i32) +/// - ilogb(nan) = maxInt(i32) pub fn ilogb(x: var) i32 { const T = @typeOf(x); return switch (T) { diff --git a/std/math/inf.zig b/std/math/inf.zig index e1bfbb197a..86ff245533 100644 --- a/std/math/inf.zig +++ b/std/math/inf.zig @@ -1,6 +1,7 @@ const std = @import("../std.zig"); const math = std.math; +/// Returns value inf for the type T. pub fn inf(comptime T: type) T { return switch (T) { f16 => math.inf_f16, diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig index ee8a5ff590..99eba668f9 100644 --- a/std/math/isfinite.zig +++ b/std/math/isfinite.zig @@ -3,6 +3,7 @@ const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns whether x is a finite value. pub fn isFinite(x: var) bool { const T = @typeOf(x); switch (T) { diff --git a/std/math/isinf.zig b/std/math/isinf.zig index 1b1759bd36..37934f4cf4 100644 --- a/std/math/isinf.zig +++ b/std/math/isinf.zig @@ -3,6 +3,7 @@ const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns whether x is an infinity, ignoring sign. pub fn isInf(x: var) bool { const T = @typeOf(x); switch (T) { @@ -28,6 +29,7 @@ pub fn isInf(x: var) bool { } } +/// Returns whether x is an infinity with a positive sign. pub fn isPositiveInf(x: var) bool { const T = @typeOf(x); switch (T) { @@ -49,6 +51,7 @@ pub fn isPositiveInf(x: var) bool { } } +/// Returns whether x is an infinity with a negative sign. pub fn isNegativeInf(x: var) bool { const T = @typeOf(x); switch (T) { diff --git a/std/math/isnan.zig b/std/math/isnan.zig index 9e541bf0a2..cf8cd2e1c2 100644 --- a/std/math/isnan.zig +++ b/std/math/isnan.zig @@ -3,13 +3,15 @@ const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns whether x is a nan. pub fn isNan(x: var) bool { return x != x; } -/// Note: A signalling nan is identical to a standard nan right now but may have a different bit -/// representation in the future when required. +/// Returns whether x is a signalling nan. pub fn isSignalNan(x: var) bool { + // Note: A signalling nan is identical to a standard nan right now but may have a different bit + // representation in the future when required. return isNan(x); } diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig index cddcada1d3..f8611ef805 100644 --- a/std/math/isnormal.zig +++ b/std/math/isnormal.zig @@ -3,6 +3,7 @@ const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +// Returns whether x has a normalized representation (i.e. integer part of mantissa is 1). pub fn isNormal(x: var) bool { const T = @typeOf(x); switch (T) { diff --git a/std/math/ln.zig b/std/math/ln.zig index 82b212f00f..c5d4c9ff25 100644 --- a/std/math/ln.zig +++ b/std/math/ln.zig @@ -1,9 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - ln(+inf) = +inf -// - ln(0) = -inf -// - ln(x) = nan if x < 0 -// - ln(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/lnf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c const std = @import("../std.zig"); const math = std.math; @@ -11,6 +10,13 @@ const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; +/// Returns the natural logarithm of x. +/// +/// Special Cases: +/// - ln(+inf) = +inf +/// - ln(0) = -inf +/// - ln(x) = nan if x < 0 +/// - ln(nan) = nan pub fn ln(x: var) @typeOf(x) { const T = @typeOf(x); switch (@typeId(T)) { diff --git a/std/math/log.zig b/std/math/log.zig index 100dc2fb7f..77f3639fd2 100644 --- a/std/math/log.zig +++ b/std/math/log.zig @@ -1,9 +1,16 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/math/logf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/log.c + const std = @import("../std.zig"); const math = std.math; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const expect = std.testing.expect; +/// Returns the logarithm of x for the provided base. pub fn log(comptime T: type, base: T, x: T) T { if (base == 2) { return math.log2(x); diff --git a/std/math/log10.zig b/std/math/log10.zig index 7311778ddd..9b0bc3ac52 100644 --- a/std/math/log10.zig +++ b/std/math/log10.zig @@ -1,9 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - log10(+inf) = +inf -// - log10(0) = -inf -// - log10(x) = nan if x < 0 -// - log10(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/log10f.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c const std = @import("../std.zig"); const math = std.math; @@ -12,6 +11,13 @@ const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; +/// Returns the base-10 logarithm of x. +/// +/// Special Cases: +/// - log10(+inf) = +inf +/// - log10(0) = -inf +/// - log10(x) = nan if x < 0 +/// - log10(nan) = nan pub fn log10(x: var) @typeOf(x) { const T = @typeOf(x); switch (@typeId(T)) { diff --git a/std/math/log1p.zig b/std/math/log1p.zig index c9be1132be..bae6deb536 100644 --- a/std/math/log1p.zig +++ b/std/math/log1p.zig @@ -1,16 +1,22 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - log1p(+inf) = +inf -// - log1p(+-0) = +-0 -// - log1p(-1) = -inf -// - log1p(x) = nan if x < -1 -// - log1p(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/log1pf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/log1p.c const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the natural logarithm of 1 + x with greater accuracy when x is near zero. +/// +/// Special Cases: +/// - log1p(+inf) = +inf +/// - log1p(+-0) = +-0 +/// - log1p(-1) = -inf +/// - log1p(x) = nan if x < -1 +/// - log1p(nan) = nan pub fn log1p(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/log2.zig b/std/math/log2.zig index e2dbf4105a..88450a7ffd 100644 --- a/std/math/log2.zig +++ b/std/math/log2.zig @@ -1,9 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - log2(+inf) = +inf -// - log2(0) = -inf -// - log2(x) = nan if x < 0 -// - log2(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/log2f.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c const std = @import("../std.zig"); const math = std.math; @@ -12,6 +11,13 @@ const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; +/// Returns the base-2 logarithm of x. +/// +/// Special Cases: +/// - log2(+inf) = +inf +/// - log2(0) = -inf +/// - log2(x) = nan if x < 0 +/// - log2(nan) = nan pub fn log2(x: var) @typeOf(x) { const T = @typeOf(x); switch (@typeId(T)) { diff --git a/std/math/modf.zig b/std/math/modf.zig index e5a4964e63..92194d4c75 100644 --- a/std/math/modf.zig +++ b/std/math/modf.zig @@ -1,7 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - modf(+-inf) = +-inf, nan -// - modf(nan) = nan, nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/modff.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/modf.c const std = @import("../std.zig"); const math = std.math; @@ -17,6 +18,12 @@ fn modf_result(comptime T: type) type { pub const modf32_result = modf_result(f32); pub const modf64_result = modf_result(f64); +/// Returns the integer and fractional floating-point numbers that sum to x. The sign of each +/// result is the same as the sign of x. +/// +/// Special Cases: +/// - modf(+-inf) = +-inf, nan +/// - modf(nan) = nan, nan pub fn modf(x: var) modf_result(@typeOf(x)) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/nan.zig b/std/math/nan.zig index 1a11a141d5..5a01a5b3bd 100644 --- a/std/math/nan.zig +++ b/std/math/nan.zig @@ -1,5 +1,6 @@ const math = @import("../math.zig"); +/// Returns the nan representation for type T. pub fn nan(comptime T: type) T { return switch (T) { f16 => math.nan_f16, @@ -10,9 +11,10 @@ pub fn nan(comptime T: type) T { }; } -// Note: A signalling nan is identical to a standard right now by may have a different bit -// representation in the future when required. +/// Returns the signalling nan representation for type T. pub fn snan(comptime T: type) T { + // Note: A signalling nan is identical to a standard right now by may have a different bit + // representation in the future when required. return switch (T) { f16 => @bitCast(f16, math.nan_u16), f32 => @bitCast(f32, math.nan_u32), diff --git a/std/math/pow.zig b/std/math/pow.zig index 81bb2d95d5..18c9f80634 100644 --- a/std/math/pow.zig +++ b/std/math/pow.zig @@ -1,32 +1,36 @@ -// Special Cases: +// Ported from go, which is licensed under a BSD-3 license. +// https://golang.org/LICENSE // -// pow(x, +-0) = 1 for any x -// pow(1, y) = 1 for any y -// pow(x, 1) = x for any x -// pow(nan, y) = nan -// pow(x, nan) = nan -// pow(+-0, y) = +-inf for y an odd integer < 0 -// pow(+-0, -inf) = +inf -// pow(+-0, +inf) = +0 -// pow(+-0, y) = +inf for finite y < 0 and not an odd integer -// pow(+-0, y) = +-0 for y an odd integer > 0 -// pow(+-0, y) = +0 for finite y > 0 and not an odd integer -// pow(-1, +-inf) = 1 -// pow(x, +inf) = +inf for |x| > 1 -// pow(x, -inf) = +0 for |x| > 1 -// pow(x, +inf) = +0 for |x| < 1 -// pow(x, -inf) = +inf for |x| < 1 -// pow(+inf, y) = +inf for y > 0 -// pow(+inf, y) = +0 for y < 0 -// pow(-inf, y) = pow(-0, -y) -// pow(x, y) = nan for finite x < 0 and finite non-integer y +// https://golang.org/src/math/pow.go const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; -// This implementation is taken from the go stlib, musl is a bit more complex. +/// Returns x raised to the power of y (x^y). +/// +/// Special Cases: +/// - pow(x, +-0) = 1 for any x +/// - pow(1, y) = 1 for any y +/// - pow(x, 1) = x for any x +/// - pow(nan, y) = nan +/// - pow(x, nan) = nan +/// - pow(+-0, y) = +-inf for y an odd integer < 0 +/// - pow(+-0, -inf) = +inf +/// - pow(+-0, +inf) = +0 +/// - pow(+-0, y) = +inf for finite y < 0 and not an odd integer +/// - pow(+-0, y) = +-0 for y an odd integer > 0 +/// - pow(+-0, y) = +0 for finite y > 0 and not an odd integer +/// - pow(-1, +-inf) = 1 +/// - pow(x, +inf) = +inf for |x| > 1 +/// - pow(x, -inf) = +0 for |x| > 1 +/// - pow(x, +inf) = +0 for |x| < 1 +/// - pow(x, -inf) = +inf for |x| < 1 +/// - pow(+inf, y) = +inf for y > 0 +/// - pow(+inf, y) = +0 for y < 0 +/// - pow(-inf, y) = pow(-0, -y) +/// - pow(x, y) = nan for finite x < 0 and finite non-integer y pub fn pow(comptime T: type, x: T, y: T) T { if (@typeInfo(T) == builtin.TypeId.Int) { return math.powi(T, x, y) catch unreachable; @@ -53,15 +57,6 @@ pub fn pow(comptime T: type, x: T, y: T) T { return x; } - // special case sqrt - if (y == 0.5) { - return math.sqrt(x); - } - - if (y == -0.5) { - return 1 / math.sqrt(x); - } - if (x == 0) { if (y < 0) { // pow(+-0, y) = +- 0 for y an odd integer @@ -112,14 +107,16 @@ pub fn pow(comptime T: type, x: T, y: T) T { } } - var ay = y; - var flip = false; - if (ay < 0) { - ay = -ay; - flip = true; + // special case sqrt + if (y == 0.5) { + return math.sqrt(x); + } + + if (y == -0.5) { + return 1 / math.sqrt(x); } - const r1 = math.modf(ay); + const r1 = math.modf(math.fabs(y)); var yi = r1.ipart; var yf = r1.fpart; @@ -148,8 +145,18 @@ pub fn pow(comptime T: type, x: T, y: T) T { var xe = r2.exponent; var x1 = r2.significand; - var i = @floatToInt(i32, yi); + var i = @floatToInt(@IntType(true, T.bit_count), yi); while (i != 0) : (i >>= 1) { + const overflow_shift = math.floatExponentBits(T) + 1; + if (xe < -(1 << overflow_shift) or (1 << overflow_shift) < xe) { + // catch xe before it overflows the left shift below + // Since i != 0 it has at least one bit still set, so ae will accumulate xe + // on at least one more iteration, ae += xe is a lower bound on ae + // the lower bound on ae exceeds the size of a float exp + // so the final call to Ldexp will produce under/overflow (0/Inf) + ae += xe; + break; + } if (i & 1 == 1) { a1 *= x1; ae += xe; @@ -163,7 +170,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { } // a *= a1 * 2^ae - if (flip) { + if (y < 0) { a1 = 1 / a1; ae = -ae; } @@ -202,6 +209,9 @@ test "math.pow.special" { expect(pow(f32, 45, 1.0) == 45); expect(pow(f32, -45, 1.0) == -45); expect(math.isNan(pow(f32, math.nan(f32), 5.0))); + expect(math.isPositiveInf(pow(f32, -math.inf(f32), 0.5))); + expect(math.isPositiveInf(pow(f32, -0, -0.5))); + expect(pow(f32, -0, 0.5) == 0); expect(math.isNan(pow(f32, 5.0, math.nan(f32)))); expect(math.isPositiveInf(pow(f32, 0.0, -1.0))); //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? @@ -232,3 +242,11 @@ test "math.pow.special" { expect(math.isNan(pow(f32, -1.0, 1.2))); expect(math.isNan(pow(f32, -12.4, 78.5))); } + +test "math.pow.overflow" { + expect(math.isPositiveInf(pow(f64, 2, 1 << 32))); + expect(pow(f64, 2, -(1 << 32)) == 0); + expect(math.isNegativeInf(pow(f64, -2, (1 << 32) + 1))); + expect(pow(f64, 0.5, 1 << 45) == 0); + expect(math.isPositiveInf(pow(f64, 0.5, -(1 << 45)))); +} diff --git a/std/math/powi.zig b/std/math/powi.zig index b7212efcbf..d80700e5cd 100644 --- a/std/math/powi.zig +++ b/std/math/powi.zig @@ -1,12 +1,7 @@ -// Special Cases: +// Based on Rust, which is licensed under the MIT license. +// https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/LICENSE-MIT // -// powi(x, +-0) = 1 for any x -// powi(0, y) = 0 for any y -// powi(1, y) = 1 for any y -// powi(-1, y) = -1 for for y an odd integer -// powi(-1, y) = 1 for for y an even integer -// powi(x, y) = Overflow for for y >= @sizeOf(x) - 1 y > 0 -// powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 0 +// https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/src/libcore/num/mod.rs#L3423 const builtin = @import("builtin"); const std = @import("../std.zig"); @@ -14,7 +9,16 @@ const math = std.math; const assert = std.debug.assert; const testing = std.testing; -// This implementation is based on that from the rust stlib +/// Returns the power of x raised by the integer y (x^y). +/// +/// Special Cases: +/// - powi(x, +-0) = 1 for any x +/// - powi(0, y) = 0 for any y +/// - powi(1, y) = 1 for any y +/// - powi(-1, y) = -1 for y an odd integer +/// - powi(-1, y) = 1 for y an even integer +/// - powi(x, y) = Overflow for y >= @sizeOf(x) - 1 or y > 0 +/// - powi(x, y) = Underflow for y > @sizeOf(x) - 1 or y < 0 pub fn powi(comptime T: type, x: T, y: T) (error{ Overflow, Underflow, diff --git a/std/math/round.zig b/std/math/round.zig index 39ff56ca79..0b80a46ce5 100644 --- a/std/math/round.zig +++ b/std/math/round.zig @@ -1,14 +1,20 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - round(+-0) = +-0 -// - round(+-inf) = +-inf -// - round(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/round.c const builtin = @import("builtin"); const expect = std.testing.expect; const std = @import("../std.zig"); const math = std.math; +/// Returns x rounded to the nearest integer, rounding half away from zero. +/// +/// Special Cases: +/// - round(+-0) = +-0 +/// - round(+-inf) = +-inf +/// - round(nan) = nan pub fn round(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig index d1338f5acb..d5716d621c 100644 --- a/std/math/scalbn.zig +++ b/std/math/scalbn.zig @@ -1,7 +1,14 @@ +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +// +// https://git.musl-libc.org/cgit/musl/tree/src/math/scalbnf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/scalbn.c + const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns x * 2^n. pub fn scalbn(x: var, n: i32) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/signbit.zig b/std/math/signbit.zig index 9727152b07..e5c5909292 100644 --- a/std/math/signbit.zig +++ b/std/math/signbit.zig @@ -2,6 +2,7 @@ const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns whether x is negative or negative 0. pub fn signbit(x: var) bool { const T = @typeOf(x); return switch (T) { diff --git a/std/math/sin.zig b/std/math/sin.zig index e25b8a292b..f21db4054e 100644 --- a/std/math/sin.zig +++ b/std/math/sin.zig @@ -1,19 +1,24 @@ -// Special Cases: +// Ported from go, which is licensed under a BSD-3 license. +// https://golang.org/LICENSE // -// - sin(+-0) = +-0 -// - sin(+-inf) = nan -// - sin(nan) = nan +// https://golang.org/src/math/sin.go const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the sine of the radian value x. +/// +/// Special Cases: +/// - sin(+-0) = +-0 +/// - sin(+-inf) = nan +/// - sin(nan) = nan pub fn sin(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { - f32 => sin32(x), - f64 => sin64(x), + f32 => sin_(T, x), + f64 => sin_(T, x), else => @compileError("sin not implemented for " ++ @typeName(T)), }; } @@ -34,83 +39,27 @@ const C3 = 2.48015872888517045348E-5; const C4 = -1.38888888888730564116E-3; const C5 = 4.16666666666665929218E-2; -// NOTE: This is taken from the go stdlib. The musl implementation is much more complex. -// -// This may have slight differences on some edge cases and may need to replaced if so. -fn sin32(x_: f32) f32 { - const pi4a = 7.85398125648498535156e-1; - const pi4b = 3.77489470793079817668E-8; - const pi4c = 2.69515142907905952645E-15; - const m4pi = 1.273239544735162542821171882678754627704620361328125; - - var x = x_; - if (x == 0 or math.isNan(x)) { - return x; - } - if (math.isInf(x)) { - return math.nan(f32); - } - - var sign = false; - if (x < 0) { - x = -x; - sign = true; - } - - var y = math.floor(x * m4pi); - var j = @floatToInt(i64, y); - - if (j & 1 == 1) { - j += 1; - y += 1; - } +const pi4a = 7.85398125648498535156e-1; +const pi4b = 3.77489470793079817668E-8; +const pi4c = 2.69515142907905952645E-15; +const m4pi = 1.273239544735162542821171882678754627704620361328125; - j &= 7; - if (j > 3) { - j -= 4; - sign = !sign; - } - - const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; - const w = z * z; - - const r = r: { - if (j == 1 or j == 2) { - break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); - } else { - break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); - } - }; - - if (sign) { - return -r; - } else { - return r; - } -} - -fn sin64(x_: f64) f64 { - const pi4a = 7.85398125648498535156e-1; - const pi4b = 3.77489470793079817668E-8; - const pi4c = 2.69515142907905952645E-15; - const m4pi = 1.273239544735162542821171882678754627704620361328125; +fn sin_(comptime T: type, x_: T) T { + const I = @IntType(true, T.bit_count); var x = x_; if (x == 0 or math.isNan(x)) { return x; } if (math.isInf(x)) { - return math.nan(f64); + return math.nan(T); } - var sign = false; - if (x < 0) { - x = -x; - sign = true; - } + var sign = x < 0; + x = math.fabs(x); var y = math.floor(x * m4pi); - var j = @floatToInt(i64, y); + var j = @floatToInt(I, y); if (j & 1 == 1) { j += 1; @@ -126,61 +75,56 @@ fn sin64(x_: f64) f64 { const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; const w = z * z; - const r = r: { - if (j == 1 or j == 2) { - break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); - } else { - break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); - } - }; + const r = if (j == 1 or j == 2) + 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))) + else + z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); - if (sign) { - return -r; - } else { - return r; - } + return if (sign) -r else r; } test "math.sin" { - expect(sin(f32(0.0)) == sin32(0.0)); - expect(sin(f64(0.0)) == sin64(0.0)); + expect(sin(f32(0.0)) == sin_(f32, 0.0)); + expect(sin(f64(0.0)) == sin_(f64, 0.0)); expect(comptime (math.sin(f64(2))) == math.sin(f64(2))); } test "math.sin32" { const epsilon = 0.000001; - expect(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); - expect(math.approxEq(f32, sin32(0.2), 0.198669, epsilon)); - expect(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon)); - expect(math.approxEq(f32, sin32(1.5), 0.997495, epsilon)); - expect(math.approxEq(f32, sin32(37.45), -0.246544, epsilon)); - expect(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); + expect(math.approxEq(f32, sin_(f32, 0.0), 0.0, epsilon)); + expect(math.approxEq(f32, sin_(f32, 0.2), 0.198669, epsilon)); + expect(math.approxEq(f32, sin_(f32, 0.8923), 0.778517, epsilon)); + expect(math.approxEq(f32, sin_(f32, 1.5), 0.997495, epsilon)); + expect(math.approxEq(f32, sin_(f32, -1.5), -0.997495, epsilon)); + expect(math.approxEq(f32, sin_(f32, 37.45), -0.246544, epsilon)); + expect(math.approxEq(f32, sin_(f32, 89.123), 0.916166, epsilon)); } test "math.sin64" { const epsilon = 0.000001; - expect(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); - expect(math.approxEq(f64, sin64(0.2), 0.198669, epsilon)); - expect(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon)); - expect(math.approxEq(f64, sin64(1.5), 0.997495, epsilon)); - expect(math.approxEq(f64, sin64(37.45), -0.246543, epsilon)); - expect(math.approxEq(f64, sin64(89.123), 0.916166, epsilon)); + expect(math.approxEq(f64, sin_(f64, 0.0), 0.0, epsilon)); + expect(math.approxEq(f64, sin_(f64, 0.2), 0.198669, epsilon)); + expect(math.approxEq(f64, sin_(f64, 0.8923), 0.778517, epsilon)); + expect(math.approxEq(f64, sin_(f64, 1.5), 0.997495, epsilon)); + expect(math.approxEq(f64, sin_(f64, -1.5), -0.997495, epsilon)); + expect(math.approxEq(f64, sin_(f64, 37.45), -0.246543, epsilon)); + expect(math.approxEq(f64, sin_(f64, 89.123), 0.916166, epsilon)); } test "math.sin32.special" { - expect(sin32(0.0) == 0.0); - expect(sin32(-0.0) == -0.0); - expect(math.isNan(sin32(math.inf(f32)))); - expect(math.isNan(sin32(-math.inf(f32)))); - expect(math.isNan(sin32(math.nan(f32)))); + expect(sin_(f32, 0.0) == 0.0); + expect(sin_(f32, -0.0) == -0.0); + expect(math.isNan(sin_(f32, math.inf(f32)))); + expect(math.isNan(sin_(f32, -math.inf(f32)))); + expect(math.isNan(sin_(f32, math.nan(f32)))); } test "math.sin64.special" { - expect(sin64(0.0) == 0.0); - expect(sin64(-0.0) == -0.0); - expect(math.isNan(sin64(math.inf(f64)))); - expect(math.isNan(sin64(-math.inf(f64)))); - expect(math.isNan(sin64(math.nan(f64)))); + expect(sin_(f64, 0.0) == 0.0); + expect(sin_(f64, -0.0) == -0.0); + expect(math.isNan(sin_(f64, math.inf(f64)))); + expect(math.isNan(sin_(f64, -math.inf(f64)))); + expect(math.isNan(sin_(f64, math.nan(f64)))); } diff --git a/std/math/sinh.zig b/std/math/sinh.zig index cf4363c4a9..73ee65ea6f 100644 --- a/std/math/sinh.zig +++ b/std/math/sinh.zig @@ -1,8 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - sinh(+-0) = +-0 -// - sinh(+-inf) = +-inf -// - sinh(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/sinhf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/sinh.c const builtin = @import("builtin"); const std = @import("../std.zig"); @@ -11,6 +11,12 @@ const expect = std.testing.expect; const expo2 = @import("expo2.zig").expo2; const maxInt = std.math.maxInt; +/// Returns the hyperbolic sine of x. +/// +/// Special Cases: +/// - sinh(+-0) = +-0 +/// - sinh(+-inf) = +-inf +/// - sinh(nan) = nan pub fn sinh(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig index 9062f598a1..30af5915d4 100644 --- a/std/math/sqrt.zig +++ b/std/math/sqrt.zig @@ -1,10 +1,3 @@ -// Special Cases: -// -// - sqrt(+inf) = +inf -// - sqrt(+-0) = +-0 -// - sqrt(x) = nan if x < 0 -// - sqrt(nan) = nan - const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; @@ -12,6 +5,13 @@ const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; +/// Returns the square root of x. +/// +/// Special Cases: +/// - sqrt(+inf) = +inf +/// - sqrt(+-0) = +-0 +/// - sqrt(x) = nan if x < 0 +/// - sqrt(nan) = nan pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typeOf(x).bit_count / 2) else @typeOf(x)) { const T = @typeOf(x); switch (@typeId(T)) { diff --git a/std/math/tan.zig b/std/math/tan.zig index fc11ebdef7..e8259ee7ad 100644 --- a/std/math/tan.zig +++ b/std/math/tan.zig @@ -1,19 +1,24 @@ -// Special Cases: +// Ported from go, which is licensed under a BSD-3 license. +// https://golang.org/LICENSE // -// - tan(+-0) = +-0 -// - tan(+-inf) = nan -// - tan(nan) = nan +// https://golang.org/src/math/tan.go const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; +/// Returns the tangent of the radian value x. +/// +/// Special Cases: +/// - tan(+-0) = +-0 +/// - tan(+-inf) = nan +/// - tan(nan) = nan pub fn tan(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { - f32 => tan32(x), - f64 => tan64(x), + f32 => tan_(f32, x), + f64 => tan_(f64, x), else => @compileError("tan not implemented for " ++ @typeName(T)), }; } @@ -27,80 +32,27 @@ const Tq2 = -1.32089234440210967447E6; const Tq3 = 2.50083801823357915839E7; const Tq4 = -5.38695755929454629881E7; -// NOTE: This is taken from the go stdlib. The musl implementation is much more complex. -// -// This may have slight differences on some edge cases and may need to replaced if so. -fn tan32(x_: f32) f32 { - const pi4a = 7.85398125648498535156e-1; - const pi4b = 3.77489470793079817668E-8; - const pi4c = 2.69515142907905952645E-15; - const m4pi = 1.273239544735162542821171882678754627704620361328125; - - var x = x_; - if (x == 0 or math.isNan(x)) { - return x; - } - if (math.isInf(x)) { - return math.nan(f32); - } - - var sign = false; - if (x < 0) { - x = -x; - sign = true; - } - - var y = math.floor(x * m4pi); - var j = @floatToInt(i64, y); - - if (j & 1 == 1) { - j += 1; - y += 1; - } - - const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; - const w = z * z; - - var r = r: { - if (w > 1e-14) { - break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)); - } else { - break :r z; - } - }; - - if (j & 2 == 2) { - r = -1 / r; - } - if (sign) { - r = -r; - } - - return r; -} +const pi4a = 7.85398125648498535156e-1; +const pi4b = 3.77489470793079817668E-8; +const pi4c = 2.69515142907905952645E-15; +const m4pi = 1.273239544735162542821171882678754627704620361328125; -fn tan64(x_: f64) f64 { - const pi4a = 7.85398125648498535156e-1; - const pi4b = 3.77489470793079817668E-8; - const pi4c = 2.69515142907905952645E-15; - const m4pi = 1.273239544735162542821171882678754627704620361328125; +fn tan_(comptime T: type, x_: T) T { + const I = @IntType(true, T.bit_count); var x = x_; if (x == 0 or math.isNan(x)) { return x; } if (math.isInf(x)) { - return math.nan(f64); + return math.nan(T); } - var sign = false; - if (x < 0) { - x = -x; - sign = true; - } + var sign = x < 0; + x = math.fabs(x); var y = math.floor(x * m4pi); - var j = @floatToInt(i64, y); + var j = @floatToInt(I, y); if (j & 1 == 1) { j += 1; @@ -110,63 +62,57 @@ fn tan64(x_: f64) f64 { const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; const w = z * z; - var r = r: { - if (w > 1e-14) { - break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)); - } else { - break :r z; - } - }; + var r = if (w > 1e-14) + z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)) + else + z; if (j & 2 == 2) { r = -1 / r; } - if (sign) { - r = -r; - } - return r; + return if (sign) -r else r; } test "math.tan" { - expect(tan(f32(0.0)) == tan32(0.0)); - expect(tan(f64(0.0)) == tan64(0.0)); + expect(tan(f32(0.0)) == tan_(f32, 0.0)); + expect(tan(f64(0.0)) == tan_(f64, 0.0)); } test "math.tan32" { const epsilon = 0.000001; - expect(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); - expect(math.approxEq(f32, tan32(0.2), 0.202710, epsilon)); - expect(math.approxEq(f32, tan32(0.8923), 1.240422, epsilon)); - expect(math.approxEq(f32, tan32(1.5), 14.101420, epsilon)); - expect(math.approxEq(f32, tan32(37.45), -0.254397, epsilon)); - expect(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); + expect(math.approxEq(f32, tan_(f32, 0.0), 0.0, epsilon)); + expect(math.approxEq(f32, tan_(f32, 0.2), 0.202710, epsilon)); + expect(math.approxEq(f32, tan_(f32, 0.8923), 1.240422, epsilon)); + expect(math.approxEq(f32, tan_(f32, 1.5), 14.101420, epsilon)); + expect(math.approxEq(f32, tan_(f32, 37.45), -0.254397, epsilon)); + expect(math.approxEq(f32, tan_(f32, 89.123), 2.285852, epsilon)); } test "math.tan64" { const epsilon = 0.000001; - expect(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); - expect(math.approxEq(f64, tan64(0.2), 0.202710, epsilon)); - expect(math.approxEq(f64, tan64(0.8923), 1.240422, epsilon)); - expect(math.approxEq(f64, tan64(1.5), 14.101420, epsilon)); - expect(math.approxEq(f64, tan64(37.45), -0.254397, epsilon)); - expect(math.approxEq(f64, tan64(89.123), 2.2858376, epsilon)); + expect(math.approxEq(f64, tan_(f64, 0.0), 0.0, epsilon)); + expect(math.approxEq(f64, tan_(f64, 0.2), 0.202710, epsilon)); + expect(math.approxEq(f64, tan_(f64, 0.8923), 1.240422, epsilon)); + expect(math.approxEq(f64, tan_(f64, 1.5), 14.101420, epsilon)); + expect(math.approxEq(f64, tan_(f64, 37.45), -0.254397, epsilon)); + expect(math.approxEq(f64, tan_(f64, 89.123), 2.2858376, epsilon)); } test "math.tan32.special" { - expect(tan32(0.0) == 0.0); - expect(tan32(-0.0) == -0.0); - expect(math.isNan(tan32(math.inf(f32)))); - expect(math.isNan(tan32(-math.inf(f32)))); - expect(math.isNan(tan32(math.nan(f32)))); + expect(tan_(f32, 0.0) == 0.0); + expect(tan_(f32, -0.0) == -0.0); + expect(math.isNan(tan_(f32, math.inf(f32)))); + expect(math.isNan(tan_(f32, -math.inf(f32)))); + expect(math.isNan(tan_(f32, math.nan(f32)))); } test "math.tan64.special" { - expect(tan64(0.0) == 0.0); - expect(tan64(-0.0) == -0.0); - expect(math.isNan(tan64(math.inf(f64)))); - expect(math.isNan(tan64(-math.inf(f64)))); - expect(math.isNan(tan64(math.nan(f64)))); + expect(tan_(f64, 0.0) == 0.0); + expect(tan_(f64, -0.0) == -0.0); + expect(math.isNan(tan_(f64, math.inf(f64)))); + expect(math.isNan(tan_(f64, -math.inf(f64)))); + expect(math.isNan(tan_(f64, math.nan(f64)))); } diff --git a/std/math/tanh.zig b/std/math/tanh.zig index f88ecfdc9c..48d26d091e 100644 --- a/std/math/tanh.zig +++ b/std/math/tanh.zig @@ -1,8 +1,8 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - sinh(+-0) = +-0 -// - sinh(+-inf) = +-1 -// - sinh(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/tanhf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/tanh.c const builtin = @import("builtin"); const std = @import("../std.zig"); @@ -11,6 +11,12 @@ const expect = std.testing.expect; const expo2 = @import("expo2.zig").expo2; const maxInt = std.math.maxInt; +/// Returns the hyperbolic tangent of x. +/// +/// Special Cases: +/// - sinh(+-0) = +-0 +/// - sinh(+-inf) = +-1 +/// - sinh(nan) = nan pub fn tanh(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/math/trunc.zig b/std/math/trunc.zig index 9449d0e7eb..219bcd4914 100644 --- a/std/math/trunc.zig +++ b/std/math/trunc.zig @@ -1,14 +1,20 @@ -// Special Cases: +// Ported from musl, which is licensed under the MIT license: +// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // -// - trunc(+-0) = +-0 -// - trunc(+-inf) = +-inf -// - trunc(nan) = nan +// https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c +// https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +/// Returns the integer value of x. +/// +/// Special Cases: +/// - trunc(+-0) = +-0 +/// - trunc(+-inf) = +-inf +/// - trunc(nan) = nan pub fn trunc(x: var) @typeOf(x) { const T = @typeOf(x); return switch (T) { diff --git a/std/mem.zig b/std/mem.zig index 9bf68698c9..2407b56f07 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -34,39 +34,39 @@ pub const Allocator = struct { /// The returned slice must have its pointer aligned at least to `new_alignment` bytes. reallocFn: fn ( self: *Allocator, - // Guaranteed to be the same as what was returned from most recent call to - // `reallocFn` or `shrinkFn`. - // If `old_mem.len == 0` then this is a new allocation and `new_byte_count` - // is guaranteed to be >= 1. + /// Guaranteed to be the same as what was returned from most recent call to + /// `reallocFn` or `shrinkFn`. + /// If `old_mem.len == 0` then this is a new allocation and `new_byte_count` + /// is guaranteed to be >= 1. old_mem: []u8, - // If `old_mem.len == 0` then this is `undefined`, otherwise: - // Guaranteed to be the same as what was returned from most recent call to - // `reallocFn` or `shrinkFn`. - // Guaranteed to be >= 1. - // Guaranteed to be a power of 2. + /// If `old_mem.len == 0` then this is `undefined`, otherwise: + /// Guaranteed to be the same as what was returned from most recent call to + /// `reallocFn` or `shrinkFn`. + /// Guaranteed to be >= 1. + /// Guaranteed to be a power of 2. old_alignment: u29, - // If `new_byte_count` is 0 then this is a free and it is guaranteed that - // `old_mem.len != 0`. + /// If `new_byte_count` is 0 then this is a free and it is guaranteed that + /// `old_mem.len != 0`. new_byte_count: usize, - // Guaranteed to be >= 1. - // Guaranteed to be a power of 2. - // Returned slice's pointer must have this alignment. + /// Guaranteed to be >= 1. + /// Guaranteed to be a power of 2. + /// Returned slice's pointer must have this alignment. new_alignment: u29, ) Error![]u8, /// This function deallocates memory. It must succeed. shrinkFn: fn ( self: *Allocator, - // Guaranteed to be the same as what was returned from most recent call to - // `reallocFn` or `shrinkFn`. + /// Guaranteed to be the same as what was returned from most recent call to + /// `reallocFn` or `shrinkFn`. old_mem: []u8, - // Guaranteed to be the same as what was returned from most recent call to - // `reallocFn` or `shrinkFn`. + /// Guaranteed to be the same as what was returned from most recent call to + /// `reallocFn` or `shrinkFn`. old_alignment: u29, - // Guaranteed to be less than or equal to `old_mem.len`. + /// Guaranteed to be less than or equal to `old_mem.len`. new_byte_count: usize, - // If `new_byte_count == 0` then this is `undefined`, otherwise: - // Guaranteed to be less than or equal to `old_alignment`. + /// If `new_byte_count == 0` then this is `undefined`, otherwise: + /// Guaranteed to be less than or equal to `old_alignment`. new_alignment: u29, ) []u8, @@ -104,10 +104,7 @@ pub const Allocator = struct { const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, alignment); assert(byte_slice.len == byte_count); - // This loop gets optimized out in ReleaseFast mode - for (byte_slice) |*byte| { - byte.* = undefined; - } + @memset(byte_slice.ptr, undefined, byte_slice.len); return @bytesToSlice(T, @alignCast(alignment, byte_slice)); } @@ -153,10 +150,7 @@ pub const Allocator = struct { const byte_slice = try self.reallocFn(self, old_byte_slice, Slice.alignment, byte_count, new_alignment); assert(byte_slice.len == byte_count); if (new_n > old_mem.len) { - // This loop gets optimized out in ReleaseFast mode - for (byte_slice[old_byte_slice.len..]) |*byte| { - byte.* = undefined; - } + @memset(byte_slice.ptr + old_byte_slice.len, undefined, byte_slice.len - old_byte_slice.len); } return @bytesToSlice(T, @alignCast(new_alignment, byte_slice)); } diff --git a/std/os.zig b/std/os.zig index d641cf29c9..fe97c1aa61 100644 --- a/std/os.zig +++ b/std/os.zig @@ -23,6 +23,7 @@ test "std.os" { _ = @import("os/time.zig"); _ = @import("os/windows.zig"); _ = @import("os/uefi.zig"); + _ = @import("os/wasi.zig"); _ = @import("os/get_app_data_dir.zig"); } @@ -33,6 +34,7 @@ pub const freebsd = @import("os/freebsd.zig"); pub const netbsd = @import("os/netbsd.zig"); pub const zen = @import("os/zen.zig"); pub const uefi = @import("os/uefi.zig"); +pub const wasi = @import("os/wasi.zig"); pub const posix = switch (builtin.os) { Os.linux => linux, @@ -40,6 +42,7 @@ pub const posix = switch (builtin.os) { Os.freebsd => freebsd, Os.netbsd => netbsd, Os.zen => zen, + Os.wasi => wasi, else => @compileError("Unsupported OS"), }; @@ -50,7 +53,11 @@ pub const path = @import("os/path.zig"); pub const File = @import("os/file.zig").File; pub const time = @import("os/time.zig"); -pub const page_size = 4 * 1024; +pub const page_size = switch (builtin.arch) { + .wasm32, .wasm64 => 64 * 1024, + else => 4 * 1024, +}; + pub const MAX_PATH_BYTES = switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. @@ -139,6 +146,12 @@ pub fn getRandomBytes(buf: []u8) !void { }; } }, + Os.wasi => { + const random_get_result = os.wasi.random_get(buf.ptr, buf.len); + if (random_get_result != os.wasi.ESUCCESS) { + return error.Unknown; + } + }, Os.zen => { const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 }; var i: usize = 0; @@ -198,6 +211,12 @@ pub fn abort() noreturn { } windows.ExitProcess(3); }, + Os.wasi => { + _ = wasi.proc_raise(wasi.SIGABRT); + // TODO: Is SIGKILL even necessary? + _ = wasi.proc_raise(wasi.SIGKILL); + while (true) {} + }, Os.uefi => { // TODO there's gotta be a better thing to do here than loop forever while (true) {} @@ -226,6 +245,9 @@ pub fn exit(status: u8) noreturn { Os.windows => { windows.ExitProcess(status); }, + Os.wasi => { + wasi.proc_exit(status); + }, else => @compileError("Unsupported OS"), } } @@ -749,6 +771,37 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { try result.setMove(key, value); } + } else if (builtin.os == Os.wasi) { + var environ_count: usize = undefined; + var environ_buf_size: usize = undefined; + + const environ_sizes_get_ret = std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size); + if (environ_sizes_get_ret != os.wasi.ESUCCESS) { + return unexpectedErrorPosix(environ_sizes_get_ret); + } + + // TODO: Verify that the documentation is incorrect + // https://github.com/WebAssembly/WASI/issues/27 + var environ = try allocator.alloc(?[*]u8, environ_count + 1); + defer allocator.free(environ); + var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size); + defer allocator.free(environ_buf); + + const environ_get_ret = std.os.wasi.environ_get(environ.ptr, environ_buf.ptr); + if (environ_get_ret != os.wasi.ESUCCESS) { + return unexpectedErrorPosix(environ_get_ret); + } + + for (environ) |env| { + if (env) |ptr| { + const pair = mem.toSlice(u8, ptr); + var parts = mem.separate(pair, "="); + const key = parts.next().?; + const value = parts.next().?; + try result.set(key, value); + } + } + return result; } else { for (posix_environ_raw) |ptr| { var line_i: usize = 0; @@ -1083,13 +1136,14 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { defer in_file.close(); const mode = try in_file.mode(); + const in_stream = &in_file.inStream().stream; var atomic_file = try AtomicFile.init(dest_path, mode); defer atomic_file.deinit(); var buf: [page_size]u8 = undefined; while (true) { - const amt = try in_file.readFull(buf[0..]); + const amt = try in_stream.readFull(buf[0..]); try atomic_file.file.write(buf[0..amt]); if (amt != buf.len) { return atomic_file.finish(); @@ -2127,6 +2181,11 @@ pub const ArgIterator = struct { inner: InnerType, pub fn init() ArgIterator { + if (builtin.os == Os.wasi) { + // TODO: Figure out a compatible interface accomodating WASI + @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead."); + } + return ArgIterator{ .inner = InnerType.init() }; } @@ -2159,6 +2218,34 @@ pub fn args() ArgIterator { /// Caller must call argsFree on result. pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 { + if (builtin.os == Os.wasi) { + var count: usize = undefined; + var buf_size: usize = undefined; + + const args_sizes_get_ret = os.wasi.args_sizes_get(&count, &buf_size); + if (args_sizes_get_ret != os.wasi.ESUCCESS) { + return unexpectedErrorPosix(args_sizes_get_ret); + } + + var argv = try allocator.alloc([*]u8, count); + defer allocator.free(argv); + + var argv_buf = try allocator.alloc(u8, buf_size); + const args_get_ret = os.wasi.args_get(argv.ptr, argv_buf.ptr); + if (args_get_ret != os.wasi.ESUCCESS) { + return unexpectedErrorPosix(args_get_ret); + } + + var result_slice = try allocator.alloc([]u8, count); + + var i: usize = 0; + while (i < count) : (i += 1) { + result_slice[i] = mem.toSlice(u8, argv[i]); + } + + return result_slice; + } + // TODO refactor to only make 1 allocation. var it = args(); var contents = try Buffer.initSize(allocator, 0); @@ -2196,6 +2283,16 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 { } pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void { + if (builtin.os == Os.wasi) { + const last_item = args_alloc[args_alloc.len - 1]; + const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated + const first_item_ptr = args_alloc[0].ptr; + const len = last_byte_addr - @ptrToInt(first_item_ptr); + allocator.free(first_item_ptr[0..len]); + + return allocator.free(args_alloc); + } + var total_bytes: usize = 0; for (args_alloc) |arg| { total_bytes += @sizeOf([]u8) + arg.len; @@ -3030,9 +3127,6 @@ pub const SpawnThreadError = error{ Unexpected, }; -pub var linux_tls_phdr: ?*std.elf.Phdr = null; -pub var linux_tls_img_src: [*]const u8 = undefined; // defined if linux_tls_phdr is - /// caller must call wait on the returned thread /// fn startFn(@typeOf(context)) T /// where T is u8, noreturn, void, or !void @@ -3142,12 +3236,10 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread } // Finally, the Thread Local Storage, if any. if (!Thread.use_pthreads) { - if (linux_tls_phdr) |tls_phdr| { - l = mem.alignForward(l, tls_phdr.p_align); + if (linux.tls.tls_image) |tls_img| { + l = mem.alignForward(l, @alignOf(usize)); tls_start_offset = l; - l += tls_phdr.p_memsz; - // the fs register address - l += @sizeOf(usize); + l += tls_img.alloc_size; } } break :blk l; @@ -3188,10 +3280,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED; var newtls: usize = undefined; - if (linux_tls_phdr) |tls_phdr| { - @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz); - newtls = mmap_addr + mmap_len - @sizeOf(usize); - @intToPtr(*usize, newtls).* = newtls; + if (linux.tls.tls_image) |tls_img| { + newtls = linux.tls.copyTLS(mmap_addr + tls_start_offset); flags |= posix.CLONE_SETTLS; } const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle); diff --git a/std/os/darwin.zig b/std/os/darwin.zig index 9dc1ce1173..04122100f4 100644 --- a/std/os/darwin.zig +++ b/std/os/darwin.zig @@ -812,7 +812,7 @@ pub fn sigaction(sig: u5, noalias act: *const Sigaction, noalias oact: ?*Sigacti .sa_mask = act.mask, }; var coact: c.Sigaction = undefined; - const result = errnoWrap(c.sigaction(sig, *cact, *coact)); + const result = errnoWrap(c.sigaction(sig, &cact, &coact)); if (result != 0) { return result; } diff --git a/std/os/file.zig b/std/os/file.zig index c9a0e2b696..814e5e318c 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -235,7 +235,7 @@ pub const File = struct { Unexpected, }; - pub fn seekForward(self: File, amount: isize) SeekError!void { + pub fn seekForward(self: File, amount: i64) SeekError!void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); @@ -266,7 +266,7 @@ pub const File = struct { } } - pub fn seekTo(self: File, pos: usize) SeekError!void { + pub fn seekTo(self: File, pos: u64) SeekError!void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { const ipos = try math.cast(isize, pos); @@ -301,13 +301,12 @@ pub const File = struct { } pub const GetSeekPosError = error{ - Overflow, SystemResources, Unseekable, Unexpected, }; - pub fn getPos(self: File) GetSeekPosError!usize { + pub fn getPos(self: File) GetSeekPosError!u64 { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); @@ -324,7 +323,7 @@ pub const File = struct { else => os.unexpectedErrorPosix(err), }; } - return result; + return u64(result); }, Os.windows => { var pos: windows.LARGE_INTEGER = undefined; @@ -336,17 +335,16 @@ pub const File = struct { }; } - assert(pos >= 0); - return math.cast(usize, pos); + return @intCast(u64, pos); }, else => @compileError("unsupported OS"), } } - pub fn getEndPos(self: File) GetSeekPosError!usize { + pub fn getEndPos(self: File) GetSeekPosError!u64 { if (is_posix) { const stat = try os.posixFStat(self.handle); - return @intCast(usize, stat.size); + return @intCast(u64, stat.size); } else if (is_windows) { var file_size: windows.LARGE_INTEGER = undefined; if (windows.GetFileSizeEx(self.handle, &file_size) == 0) { @@ -355,9 +353,7 @@ pub const File = struct { else => os.unexpectedErrorWindows(err), }; } - if (file_size < 0) - return error.Overflow; - return math.cast(usize, @intCast(u64, file_size)); + return @intCast(u64, file_size); } else { @compileError("TODO support getEndPos on this OS"); } @@ -492,22 +488,22 @@ pub const File = struct { pub const Stream = io.SeekableStream(SeekError, GetSeekPosError); - pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void { + pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void { const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); return self.file.seekTo(pos); } - pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void { + pub fn seekForwardFn(seekable_stream: *Stream, amt: i64) SeekError!void { const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); return self.file.seekForward(amt); } - pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize { + pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!u64 { const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); return self.file.getEndPos(); } - pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize { + pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!u64 { const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); return self.file.getPos(); } diff --git a/std/os/linux.zig b/std/os/linux.zig index e7f822185b..1e121b81c8 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -2,7 +2,10 @@ const std = @import("../std.zig"); const assert = std.debug.assert; const builtin = @import("builtin"); const maxInt = std.math.maxInt; +const elf = std.elf; +pub const tls = @import("linux/tls.zig"); const vdso = @import("linux/vdso.zig"); +const dl = @import("../dynamic_library.zig"); pub use switch (builtin.arch) { builtin.Arch.x86_64 => @import("linux/x86_64.zig"), builtin.Arch.i386 => @import("linux/i386.zig"), @@ -12,6 +15,7 @@ pub use switch (builtin.arch) { pub use @import("linux/errno.zig"); pub const PATH_MAX = 4096; +pub const IOV_MAX = 1024; pub const STDIN_FILENO = 0; pub const STDOUT_FILENO = 1; @@ -955,10 +959,13 @@ pub fn waitpid(pid: i32, status: *i32, options: i32) usize { return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); } +var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); + pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { if (VDSO_CGT_SYM.len != 0) { - const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered); - if (@ptrToInt(f) != 0) { + const ptr = @atomicLoad(?*const c_void, &vdso_clock_gettime, .Unordered); + if (ptr) |fn_ptr| { + const f = @ptrCast(@typeOf(clock_gettime), fn_ptr); const rc = f(clk_id, tp); switch (rc) { 0, @bitCast(usize, isize(-EINVAL)) => return rc, @@ -968,13 +975,18 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { } return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); } -var vdso_clock_gettime = init_vdso_clock_gettime; + extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize { - const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM); - var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr); - _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic); - if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS)); - return f(clk, ts); + const ptr = @intToPtr(?*const c_void, vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM)); + // Note that we may not have a VDSO at all, update the stub address anyway + // so that clock_gettime will fall back on the good old (and slow) syscall + _ = @cmpxchgStrong(?*const c_void, &vdso_clock_gettime, &init_vdso_clock_gettime, ptr, .Monotonic, .Monotonic); + // Call into the VDSO if available + if (ptr) |fn_ptr| { + const f = @ptrCast(@typeOf(clock_gettime), fn_ptr); + return f(clk, ts); + } + return @bitCast(usize, isize(-ENOSYS)); } pub fn clock_getres(clk_id: i32, tp: *timespec) usize { @@ -1100,8 +1112,8 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti const NSIG = 65; const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{maxInt(usize)}; -const app_mask = []usize{0xfffffffc7fffffff}; +const all_mask = []u32{ 0xffffffff, 0xffffffff }; +const app_mask = []u32{ 0xfffffffc, 0x7fffffff }; const k_sigaction = extern struct { handler: extern fn (i32) void, @@ -1193,6 +1205,16 @@ pub const iovec_const = extern struct { iov_len: usize, }; +pub const mmsghdr = extern struct { + msg_hdr: msghdr, + msg_len: u32, +}; + +pub const mmsghdr_const = extern struct { + msg_hdr: msghdr_const, + msg_len: u32, +}; + pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); } @@ -1213,10 +1235,50 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); } -pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize { +pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); } +pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize { + if (@typeInfo(usize).Int.bits > @typeInfo(@typeOf(mmsghdr(undefined).msg_len)).Int.bits) { + // workaround kernel brokenness: + // if adding up all iov_len overflows a i32 then split into multiple calls + // see https://www.openwall.com/lists/musl/2014/06/07/5 + const kvlen = if (vlen > IOV_MAX) IOV_MAX else vlen; // matches kernel + var next_unsent: usize = 0; + for (msgvec[0..kvlen]) |*msg, i| { + var size: i32 = 0; + const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned + for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov, j| { + if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) { + // batch-send all messages up to the current message + if (next_unsent < i) { + const batch_size = i - next_unsent; + const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags); + if (getErrno(r) != 0) return next_unsent; + if (r < batch_size) return next_unsent + r; + } + // send current message as own packet + const r = sendmsg(fd, &msg.msg_hdr, flags); + if (getErrno(r) != 0) return r; + // Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe. + msg.msg_len = @intCast(u32, r); + next_unsent = i + 1; + break; + } + } + } + if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG_EOR) + const batch_size = kvlen - next_unsent; + const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags); + if (getErrno(r) != 0) return r; + return next_unsent + r; + } + return kvlen; + } + return syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(msgvec), vlen, flags); +} + pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len); } @@ -1339,17 +1401,25 @@ pub fn sched_getaffinity(pid: i32, set: []usize) usize { return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr)); } -pub const epoll_data = packed union { +pub const epoll_data = extern union { ptr: usize, fd: i32, @"u32": u32, @"u64": u64, }; -pub const epoll_event = packed struct { - events: u32, - data: epoll_data, -}; +// On x86_64 the structure is packed so that it matches the definition of its +// 32bit counterpart +pub const epoll_event = if (builtin.arch != .x86_64) + extern struct { + events: u32, + data: epoll_data, + } +else + packed struct { + events: u32, + data: epoll_data, + }; pub fn epoll_create() usize { return epoll_create1(0); @@ -1534,6 +1604,70 @@ pub const dirent64 = extern struct { d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173 }; +pub const dl_phdr_info = extern struct { + dlpi_addr: usize, + dlpi_name: ?[*]const u8, + dlpi_phdr: [*]elf.Phdr, + dlpi_phnum: u16, +}; + +// XXX: This should be weak +extern const __ehdr_start: elf.Ehdr = undefined; + +pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { + if (builtin.link_libc) { + return std.c.dl_iterate_phdr(@ptrCast(std.c.dl_iterate_phdr_callback, callback), @ptrCast(?*c_void, data)); + } + + const elf_base = @ptrToInt(&__ehdr_start); + const n_phdr = __ehdr_start.e_phnum; + const phdrs = (@intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff))[0..n_phdr]; + + var it = dl.linkmap_iterator(phdrs) catch return 0; + + // The executable has no dynamic link segment, create a single entry for + // the whole ELF image + if (it.end()) { + var info = dl_phdr_info{ + .dlpi_addr = elf_base, + .dlpi_name = c"/proc/self/exe", + .dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff), + .dlpi_phnum = __ehdr_start.e_phnum, + }; + + return callback(&info, @sizeOf(dl_phdr_info), data); + } + + // Last return value from the callback function + var last_r: isize = 0; + while (it.next()) |entry| { + var dlpi_phdr: usize = undefined; + var dlpi_phnum: u16 = undefined; + + if (entry.l_addr != 0) { + const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr); + dlpi_phdr = entry.l_addr + elf_header.e_phoff; + dlpi_phnum = elf_header.e_phnum; + } else { + // This is the running ELF image + dlpi_phdr = elf_base + __ehdr_start.e_phoff; + dlpi_phnum = __ehdr_start.e_phnum; + } + + var info = dl_phdr_info{ + .dlpi_addr = entry.l_addr, + .dlpi_name = entry.l_name, + .dlpi_phdr = @intToPtr([*]elf.Phdr, dlpi_phdr), + .dlpi_phnum = dlpi_phnum, + }; + + last_r = callback(&info, @sizeOf(dl_phdr_info), data); + if (last_r != 0) break; + } + + return last_r; +} + test "import" { if (builtin.os == builtin.Os.linux) { _ = @import("linux/test.zig"); diff --git a/std/os/linux/arm64.zig b/std/os/linux/arm64.zig index ac2c18ee5f..4ae55765fb 100644 --- a/std/os/linux/arm64.zig +++ b/std/os/linux/arm64.zig @@ -2,6 +2,7 @@ const std = @import("../../std.zig"); const linux = std.os.linux; const socklen_t = linux.socklen_t; const iovec = linux.iovec; +const iovec_const = linux.iovec_const; pub const SYS_io_setup = 0; pub const SYS_io_destroy = 1; @@ -415,12 +416,24 @@ pub fn syscall6( pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; pub const msghdr = extern struct { - msg_name: *u8, + msg_name: ?*sockaddr, msg_namelen: socklen_t, - msg_iov: *iovec, + msg_iov: [*]iovec, msg_iovlen: i32, __pad1: i32, - msg_control: *u8, + msg_control: ?*c_void, + msg_controllen: socklen_t, + __pad2: socklen_t, + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + msg_name: ?*const sockaddr, + msg_namelen: socklen_t, + msg_iov: [*]iovec_const, + msg_iovlen: i32, + __pad1: i32, + msg_control: ?*c_void, msg_controllen: socklen_t, __pad2: socklen_t, msg_flags: i32, diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig index 286748b70c..1949d00298 100644 --- a/std/os/linux/test.zig +++ b/std/os/linux/test.zig @@ -1,6 +1,8 @@ const std = @import("../../std.zig"); const builtin = @import("builtin"); const linux = std.os.linux; +const mem = std.mem; +const elf = std.elf; const expect = std.testing.expect; test "getpid" { @@ -42,3 +44,42 @@ test "timer" { // TODO implicit cast from *[N]T to [*]T err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); } + +export fn iter_fn(info: *linux.dl_phdr_info, size: usize, data: ?*usize) i32 { + var counter = data.?; + // Count how many libraries are loaded + counter.* += usize(1); + + // The image should contain at least a PT_LOAD segment + if (info.dlpi_phnum < 1) return -1; + + // Quick & dirty validation of the phdr pointers, make sure we're not + // pointing to some random gibberish + var i: usize = 0; + var found_load = false; + while (i < info.dlpi_phnum) : (i += 1) { + const phdr = info.dlpi_phdr[i]; + + if (phdr.p_type != elf.PT_LOAD) continue; + + // Find the ELF header + const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset); + // Validate the magic + if (!mem.eql(u8, elf_header.e_ident[0..], "\x7fELF")) return -1; + // Consistency check + if (elf_header.e_phnum != info.dlpi_phnum) return -1; + + found_load = true; + break; + } + + if (!found_load) return -1; + + return 42; +} + +test "dl_iterate_phdr" { + var counter: usize = 0; + expect(linux.dl_iterate_phdr(usize, iter_fn, &counter) != 0); + expect(counter != 0); +} diff --git a/std/os/linux/tls.zig b/std/os/linux/tls.zig new file mode 100644 index 0000000000..9c8d816f05 --- /dev/null +++ b/std/os/linux/tls.zig @@ -0,0 +1,247 @@ +const std = @import("std"); +const mem = std.mem; +const posix = std.os.posix; +const elf = std.elf; +const builtin = @import("builtin"); +const assert = std.debug.assert; + +// This file implements the two TLS variants [1] used by ELF-based systems. +// +// The variant I has the following layout in memory: +// ------------------------------------------------------- +// | DTV | Zig | DTV | Alignment | TLS | +// | storage | thread data | pointer | | block | +// ------------------------^------------------------------ +// `-- The thread pointer register points here +// +// In this case we allocate additional space for our control structure that's +// placed _before_ the DTV pointer together with the DTV. +// +// NOTE: Some systems such as power64 or mips use this variant with a twist: the +// alignment is not present and the tp and DTV addresses are offset by a +// constant. +// +// On the other hand the variant II has the following layout in memory: +// --------------------------------------- +// | TLS | TCB | Zig | DTV | +// | block | | thread data | storage | +// --------^------------------------------ +// `-- The thread pointer register points here +// +// The structure of the TCB is not defined by the ABI so we reserve enough space +// for a single pointer as some architectures such as i386 and x86_64 need a +// pointer to the TCB block itself at the address pointed by the tp. +// +// In this case the control structure and DTV are placed one after another right +// after the TLS block data. +// +// At the moment the DTV is very simple since we only support static TLS, all we +// need is a two word vector to hold the number of entries (1) and the address +// of the first TLS block. +// +// [1] https://www.akkadia.org/drepper/tls.pdf + +const TLSVariant = enum { + VariantI, + VariantII, +}; + +const tls_variant = switch (builtin.arch) { + .arm, .armeb, .aarch64, .aarch64_be => TLSVariant.VariantI, + .x86_64, .i386 => TLSVariant.VariantII, + else => @compileError("undefined tls_variant for this architecture"), +}; + +// Controls how many bytes are reserved for the Thread Control Block +const tls_tcb_size = switch (builtin.arch) { + // ARM EABI mandates enough space for two pointers: the first one points to + // the DTV while the second one is unspecified but reserved + .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), + .i386, .x86_64 => @sizeOf(usize), + else => 0, +}; + +// Controls if the TCB should be aligned according to the TLS segment p_align +const tls_tcb_align_size = switch (builtin.arch) { + .arm, .armeb, .aarch64, .aarch64_be => true, + else => false, +}; + +// Check if the architecture-specific parameters look correct +comptime { + if (tls_tcb_align_size and tls_variant != TLSVariant.VariantI) { + @compileError("tls_tcb_align_size is only meaningful for variant I TLS"); + } +} + +// Some architectures add some offset to the tp and dtv addresses in order to +// make the generated code more efficient + +const tls_tp_offset = switch (builtin.arch) { + else => 0, +}; + +const tls_dtv_offset = switch (builtin.arch) { + else => 0, +}; + +// Per-thread storage for Zig's use +const CustomData = packed struct { +}; + +// Dynamic Thread Vector +const DTV = packed struct { + entries: usize, + tls_block: [1]usize, +}; + +// Holds all the information about the process TLS image +const TLSImage = struct { + data_src: []u8, + alloc_size: usize, + tcb_offset: usize, + dtv_offset: usize, + data_offset: usize, +}; + +pub var tls_image: ?TLSImage = null; + +pub fn setThreadPointer(addr: usize) void { + switch (builtin.arch) { + .x86_64 => { + const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, + std.os.linux.ARCH_SET_FS, addr); + assert(rc == 0); + }, + .aarch64 => { + asm volatile ( + \\ msr tpidr_el0, %[addr] + : : [addr] "r" (addr) + ); + }, + else => @compileError("Unsupported architecture"), + } +} + +pub fn initTLS() void { + var tls_phdr: ?*elf.Phdr = null; + var img_base: usize = 0; + + const auxv = std.os.linux_elf_aux_maybe.?; + var at_phent: usize = undefined; + var at_phnum: usize = undefined; + var at_phdr: usize = undefined; + + var i: usize = 0; + while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { + switch (auxv[i].a_type) { + elf.AT_PHENT => at_phent = auxv[i].a_un.a_val, + elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, + elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, + else => continue, + } + } + + // Sanity check + assert(at_phent == @sizeOf(elf.Phdr)); + + // Search the TLS section + const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum]; + + for (phdrs) |*phdr| { + switch (phdr.p_type) { + elf.PT_PHDR => img_base = at_phdr - phdr.p_vaddr, + elf.PT_TLS => tls_phdr = phdr, + else => continue, + } + } + + if (tls_phdr) |phdr| { + // Offsets into the allocated TLS area + var tcb_offset: usize = undefined; + var dtv_offset: usize = undefined; + var data_offset: usize = undefined; + var thread_data_offset: usize = undefined; + // Compute the total size of the ABI-specific data plus our own control + // structures + const alloc_size = switch (tls_variant) { + .VariantI => blk: { + var l: usize = 0; + dtv_offset = l; + l += @sizeOf(DTV); + thread_data_offset = l; + l += @sizeOf(CustomData); + l = mem.alignForward(l, phdr.p_align); + tcb_offset = l; + if (tls_tcb_align_size) { + l += mem.alignForward(tls_tcb_size, phdr.p_align); + } else { + l += tls_tcb_size; + } + data_offset = l; + l += phdr.p_memsz; + break :blk l; + }, + .VariantII => blk: { + var l: usize = 0; + data_offset = l; + l += phdr.p_memsz; + l = mem.alignForward(l, phdr.p_align); + tcb_offset = l; + l += tls_tcb_size; + thread_data_offset = l; + l += @sizeOf(CustomData); + dtv_offset = l; + l += @sizeOf(DTV); + break :blk l; + } + }; + + tls_image = TLSImage{ + .data_src = @intToPtr([*]u8, phdr.p_vaddr + img_base)[0..phdr.p_filesz], + .alloc_size = alloc_size, + .tcb_offset = tcb_offset, + .dtv_offset = dtv_offset, + .data_offset = data_offset, + }; + } +} + +pub fn copyTLS(addr: usize) usize { + const tls_img = tls_image.?; + + // Be paranoid, clear the area we're going to use + @memset(@intToPtr([*]u8, addr), 0, tls_img.alloc_size); + // Prepare the DTV + const dtv = @intToPtr(*DTV, addr + tls_img.dtv_offset); + dtv.entries = 1; + dtv.tls_block[0] = addr + tls_img.data_offset + tls_dtv_offset; + // Set-up the TCB + const tcb_ptr = @intToPtr(*usize, addr + tls_img.tcb_offset); + if (tls_variant == TLSVariant.VariantI) { + tcb_ptr.* = addr + tls_img.dtv_offset; + } else { + tcb_ptr.* = addr + tls_img.tcb_offset; + } + // Copy the data + @memcpy(@intToPtr([*]u8, addr + tls_img.data_offset), tls_img.data_src.ptr, tls_img.data_src.len); + + // Return the corrected (if needed) value for the tp register + return addr + tls_img.tcb_offset + tls_tp_offset; +} + +var main_thread_tls_buffer: [256]u8 align(32) = undefined; + +pub fn allocateTLS(size: usize) usize { + // Small TLS allocation, use our local buffer + if (size < main_thread_tls_buffer.len) { + return @ptrToInt(&main_thread_tls_buffer); + } + + const addr = posix.mmap(null, size, posix.PROT_READ | posix.PROT_WRITE, + posix.MAP_PRIVATE | posix.MAP_ANONYMOUS, -1, 0); + + if (posix.getErrno(addr) != 0) @panic("out of memory"); + + return addr; +} diff --git a/std/os/linux/x86_64.zig b/std/os/linux/x86_64.zig index d194cd4003..621783d572 100644 --- a/std/os/linux/x86_64.zig +++ b/std/os/linux/x86_64.zig @@ -1,7 +1,9 @@ const std = @import("../../std.zig"); const linux = std.os.linux; +const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; const iovec = linux.iovec; +const iovec_const = linux.iovec_const; pub const SYS_read = 0; pub const SYS_write = 1; @@ -386,6 +388,11 @@ pub const VDSO_CGT_VER = "LINUX_2.6"; pub const VDSO_GETCPU_SYM = "__vdso_getcpu"; pub const VDSO_GETCPU_VER = "LINUX_2.6"; +pub const ARCH_SET_GS = 0x1001; +pub const ARCH_SET_FS = 0x1002; +pub const ARCH_GET_FS = 0x1003; +pub const ARCH_GET_GS = 0x1004; + pub fn syscall0(number: usize) usize { return asm volatile ("syscall" : [ret] "={rax}" (-> usize) @@ -483,12 +490,24 @@ pub nakedcc fn restore_rt() void { } pub const msghdr = extern struct { - msg_name: *u8, + msg_name: ?*sockaddr, + msg_namelen: socklen_t, + msg_iov: [*]iovec, + msg_iovlen: i32, + __pad1: i32, + msg_control: ?*c_void, + msg_controllen: socklen_t, + __pad2: socklen_t, + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + msg_name: ?*const sockaddr, msg_namelen: socklen_t, - msg_iov: *iovec, + msg_iov: [*]iovec_const, msg_iovlen: i32, __pad1: i32, - msg_control: *u8, + msg_control: ?*c_void, msg_controllen: socklen_t, __pad2: socklen_t, msg_flags: i32, diff --git a/std/os/time.zig b/std/os/time.zig index 66ceedb1b6..abb6412843 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -3,41 +3,44 @@ const builtin = @import("builtin"); const Os = builtin.Os; const debug = std.debug; const testing = std.testing; +const math = std.math; const windows = std.os.windows; const linux = std.os.linux; const darwin = std.os.darwin; +const wasi = std.os.wasi; const posix = std.os.posix; pub const epoch = @import("epoch.zig"); -/// Sleep for the specified duration +/// Spurious wakeups are possible and no precision of timing is guaranteed. pub fn sleep(nanoseconds: u64) void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { const s = nanoseconds / ns_per_s; const ns = nanoseconds % ns_per_s; - posixSleep(@intCast(u63, s), @intCast(u63, ns)); + posixSleep(s, ns); }, Os.windows => { const ns_per_ms = ns_per_s / ms_per_s; const milliseconds = nanoseconds / ns_per_ms; - windows.Sleep(@intCast(windows.DWORD, milliseconds)); + const ms_that_will_fit = std.math.cast(windows.DWORD, milliseconds) catch std.math.maxInt(windows.DWORD); + windows.Sleep(ms_that_will_fit); }, else => @compileError("Unsupported OS"), } } -pub fn posixSleep(seconds: u63, nanoseconds: u63) void { +/// Spurious wakeups are possible and no precision of timing is guaranteed. +pub fn posixSleep(seconds: u64, nanoseconds: u64) void { var req = posix.timespec{ - .tv_sec = seconds, - .tv_nsec = nanoseconds, + .tv_sec = std.math.cast(isize, seconds) catch std.math.maxInt(isize), + .tv_nsec = std.math.cast(isize, nanoseconds) catch std.math.maxInt(isize), }; var rem: posix.timespec = undefined; while (true) { const ret_val = posix.nanosleep(&req, &rem); const err = posix.getErrno(ret_val); - if (err == 0) return; switch (err) { posix.EFAULT => unreachable, posix.EINVAL => { @@ -49,6 +52,7 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) void { req = rem; continue; }, + // This prong handles success as well as unexpected errors. else => return, } } @@ -64,9 +68,21 @@ pub const milliTimestamp = switch (builtin.os) { Os.windows => milliTimestampWindows, Os.linux, Os.freebsd, Os.netbsd => milliTimestampPosix, Os.macosx, Os.ios => milliTimestampDarwin, + Os.wasi => milliTimestampWasi, else => @compileError("Unsupported OS"), }; +fn milliTimestampWasi() u64 { + var ns: wasi.timestamp_t = undefined; + + // TODO: Verify that precision is ignored + const err = wasi.clock_time_get(wasi.CLOCK_REALTIME, 1, &ns); + debug.assert(err == wasi.ESUCCESS); + + const ns_per_ms = 1000; + return @divFloor(ns, ns_per_ms); +} + fn milliTimestampWindows() u64 { //FileTime has a granularity of 100 nanoseconds // and uses the NTFS/Windows epoch diff --git a/std/os/wasi.zig b/std/os/wasi.zig new file mode 100644 index 0000000000..2118db9a2a --- /dev/null +++ b/std/os/wasi.zig @@ -0,0 +1,42 @@ +pub use @import("wasi/core.zig"); + +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +pub fn getErrno(r: usize) usize { + const signed_r = @bitCast(isize, r); + return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0; +} + +pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { + var nwritten: usize = undefined; + + const ciovs = ciovec_t{ + .buf = buf, + .buf_len = count, + }; + + const err = fd_write(@bitCast(fd_t, isize(fd)), &ciovs, 1, &nwritten); + if (err == ESUCCESS) { + return nwritten; + } else { + return @bitCast(usize, -isize(err)); + } +} + +pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { + var nread: usize = undefined; + + const iovs = iovec_t{ + .buf = buf, + .buf_len = nbyte, + }; + + const err = fd_read(@bitCast(fd_t, isize(fd)), &iovs, 1, &nread); + if (err == ESUCCESS) { + return nread; + } else { + return @bitCast(usize, -isize(err)); + } +} diff --git a/std/os/wasi/core.zig b/std/os/wasi/core.zig new file mode 100644 index 0000000000..f2bef73be9 --- /dev/null +++ b/std/os/wasi/core.zig @@ -0,0 +1,374 @@ +// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h +// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md + +pub const advice_t = u8; +pub const ADVICE_NORMAL: advice_t = 0; +pub const ADVICE_SEQUENTIAL: advice_t = 1; +pub const ADVICE_RANDOM: advice_t = 2; +pub const ADVICE_WILLNEED: advice_t = 3; +pub const ADVICE_DONTNEED: advice_t = 4; +pub const ADVICE_NOREUSE: advice_t = 5; + +pub const ciovec_t = extern struct { + buf: [*]const u8, + buf_len: usize, +}; + +pub const clockid_t = u32; +pub const CLOCK_REALTIME: clockid_t = 0; +pub const CLOCK_MONOTONIC: clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3; + +pub const device_t = u64; + +pub const dircookie_t = u64; +pub const DIRCOOKIE_START: dircookie_t = 0; + +pub const dirent_t = extern struct { + d_next: dircookie_t, + d_ino: inode_t, + d_namlen: u32, + d_type: filetype_t, +}; + +pub const errno_t = u16; +pub const ESUCCESS: errno_t = 0; +pub const E2BIG: errno_t = 1; +pub const EACCES: errno_t = 2; +pub const EADDRINUSE: errno_t = 3; +pub const EADDRNOTAVAIL: errno_t = 4; +pub const EAFNOSUPPORT: errno_t = 5; +pub const EAGAIN: errno_t = 6; +pub const EALREADY: errno_t = 7; +pub const EBADF: errno_t = 8; +pub const EBADMSG: errno_t = 9; +pub const EBUSY: errno_t = 10; +pub const ECANCELED: errno_t = 11; +pub const ECHILD: errno_t = 12; +pub const ECONNABORTED: errno_t = 13; +pub const ECONNREFUSED: errno_t = 14; +pub const ECONNRESET: errno_t = 15; +pub const EDEADLK: errno_t = 16; +pub const EDESTADDRREQ: errno_t = 17; +pub const EDOM: errno_t = 18; +pub const EDQUOT: errno_t = 19; +pub const EEXIST: errno_t = 20; +pub const EFAULT: errno_t = 21; +pub const EFBIG: errno_t = 22; +pub const EHOSTUNREACH: errno_t = 23; +pub const EIDRM: errno_t = 24; +pub const EILSEQ: errno_t = 25; +pub const EINPROGRESS: errno_t = 26; +pub const EINTR: errno_t = 27; +pub const EINVAL: errno_t = 28; +pub const EIO: errno_t = 29; +pub const EISCONN: errno_t = 30; +pub const EISDIR: errno_t = 31; +pub const ELOOP: errno_t = 32; +pub const EMFILE: errno_t = 33; +pub const EMLINK: errno_t = 34; +pub const EMSGSIZE: errno_t = 35; +pub const EMULTIHOP: errno_t = 36; +pub const ENAMETOOLONG: errno_t = 37; +pub const ENETDOWN: errno_t = 38; +pub const ENETRESET: errno_t = 39; +pub const ENETUNREACH: errno_t = 40; +pub const ENFILE: errno_t = 41; +pub const ENOBUFS: errno_t = 42; +pub const ENODEV: errno_t = 43; +pub const ENOENT: errno_t = 44; +pub const ENOEXEC: errno_t = 45; +pub const ENOLCK: errno_t = 46; +pub const ENOLINK: errno_t = 47; +pub const ENOMEM: errno_t = 48; +pub const ENOMSG: errno_t = 49; +pub const ENOPROTOOPT: errno_t = 50; +pub const ENOSPC: errno_t = 51; +pub const ENOSYS: errno_t = 52; +pub const ENOTCONN: errno_t = 53; +pub const ENOTDIR: errno_t = 54; +pub const ENOTEMPTY: errno_t = 55; +pub const ENOTRECOVERABLE: errno_t = 56; +pub const ENOTSOCK: errno_t = 57; +pub const ENOTSUP: errno_t = 58; +pub const ENOTTY: errno_t = 59; +pub const ENXIO: errno_t = 60; +pub const EOVERFLOW: errno_t = 61; +pub const EOWNERDEAD: errno_t = 62; +pub const EPERM: errno_t = 63; +pub const EPIPE: errno_t = 64; +pub const EPROTO: errno_t = 65; +pub const EPROTONOSUPPORT: errno_t = 66; +pub const EPROTOTYPE: errno_t = 67; +pub const ERANGE: errno_t = 68; +pub const EROFS: errno_t = 69; +pub const ESPIPE: errno_t = 70; +pub const ESRCH: errno_t = 71; +pub const ESTALE: errno_t = 72; +pub const ETIMEDOUT: errno_t = 73; +pub const ETXTBSY: errno_t = 74; +pub const EXDEV: errno_t = 75; +pub const ENOTCAPABLE: errno_t = 76; + +pub const event_t = extern struct { + userdata: userdata_t, + @"error": errno_t, + @"type": eventtype_t, + u: extern union { + fd_readwrite: extern struct { + nbytes: filesize_t, + flags: eventrwflags_t, + }, + }, +}; + +pub const eventrwflags_t = u16; +pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001; + +pub const eventtype_t = u8; +pub const EVENTTYPE_CLOCK: eventtype_t = 0; +pub const EVENTTYPE_FD_READ: eventtype_t = 1; +pub const EVENTTYPE_FD_WRITE: eventtype_t = 2; + +pub const exitcode_t = u32; + +pub const fd_t = u32; + +pub const fdflags_t = u16; +pub const FDFLAG_APPEND: fdflags_t = 0x0001; +pub const FDFLAG_DSYNC: fdflags_t = 0x0002; +pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004; +pub const FDFLAG_RSYNC: fdflags_t = 0x0008; +pub const FDFLAG_SYNC: fdflags_t = 0x0010; + +const fdstat_t = extern struct { + fs_filetype: filetype_t, + fs_flags: fdflags_t, + fs_rights_base: rights_t, + fs_rights_inheriting: rights_t, +}; + +pub const filedelta_t = i64; + +pub const filesize_t = u64; + +pub const filestat_t = extern struct { + st_dev: device_t, + st_ino: inode_t, + st_filetype: filetype_t, + st_nlink: linkcount_t, + st_size: filesize_t, + st_atim: timestamp_t, + st_mtim: timestamp_t, + st_ctim: timestamp_t, +}; + +pub const filetype_t = u8; +pub const FILETYPE_UNKNOWN: filetype_t = 0; +pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1; +pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2; +pub const FILETYPE_DIRECTORY: filetype_t = 3; +pub const FILETYPE_REGULAR_FILE: filetype_t = 4; +pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5; +pub const FILETYPE_SOCKET_STREAM: filetype_t = 6; +pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7; + +pub const fstflags_t = u16; +pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001; +pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002; +pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004; +pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008; + +pub const inode_t = u64; + +pub const iovec_t = extern struct { + buf: [*]u8, + buf_len: usize, +}; + +pub const linkcount_t = u32; + +pub const lookupflags_t = u32; +pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001; + +pub const oflags_t = u16; +pub const O_CREAT: oflags_t = 0x0001; +pub const O_DIRECTORY: oflags_t = 0x0002; +pub const O_EXCL: oflags_t = 0x0004; +pub const O_TRUNC: oflags_t = 0x0008; + +pub const preopentype_t = u8; +pub const PREOPENTYPE_DIR: preopentype_t = 0; + +pub const prestat_t = extern struct { + pr_type: preopentype_t, + u: extern union { + dir: extern struct { + pr_name_len: usize, + }, + }, +}; + +pub const riflags_t = u16; +pub const SOCK_RECV_PEEK: riflags_t = 0x0001; +pub const SOCK_RECV_WAITALL: riflags_t = 0x0002; + +pub const rights_t = u64; +pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001; +pub const RIGHT_FD_READ: rights_t = 0x0000000000000002; +pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004; +pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008; +pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010; +pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020; +pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040; +pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080; +pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100; +pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200; +pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400; +pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800; +pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000; +pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000; +pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000; +pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000; +pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000; +pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000; +pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000; +pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000; +pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000; +pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000; +pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000; +pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000; +pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000; +pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000; +pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000; +pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000; +pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000; + +pub const roflags_t = u16; +pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001; + +pub const sdflags_t = u8; +pub const SHUT_RD: sdflags_t = 0x01; +pub const SHUT_WR: sdflags_t = 0x02; + +pub const siflags_t = u16; + +pub const signal_t = u8; +pub const SIGHUP: signal_t = 1; +pub const SIGINT: signal_t = 2; +pub const SIGQUIT: signal_t = 3; +pub const SIGILL: signal_t = 4; +pub const SIGTRAP: signal_t = 5; +pub const SIGABRT: signal_t = 6; +pub const SIGBUS: signal_t = 7; +pub const SIGFPE: signal_t = 8; +pub const SIGKILL: signal_t = 9; +pub const SIGUSR1: signal_t = 10; +pub const SIGSEGV: signal_t = 11; +pub const SIGUSR2: signal_t = 12; +pub const SIGPIPE: signal_t = 13; +pub const SIGALRM: signal_t = 14; +pub const SIGTERM: signal_t = 15; +pub const SIGCHLD: signal_t = 16; +pub const SIGCONT: signal_t = 17; +pub const SIGSTOP: signal_t = 18; +pub const SIGTSTP: signal_t = 19; +pub const SIGTTIN: signal_t = 20; +pub const SIGTTOU: signal_t = 21; +pub const SIGURG: signal_t = 22; +pub const SIGXCPU: signal_t = 23; +pub const SIGXFSZ: signal_t = 24; +pub const SIGVTALRM: signal_t = 25; +pub const SIGPROF: signal_t = 26; +pub const SIGWINCH: signal_t = 27; +pub const SIGPOLL: signal_t = 28; +pub const SIGPWR: signal_t = 29; +pub const SIGSYS: signal_t = 30; + +pub const subclockflags_t = u16; +pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001; + +pub const subscription_t = extern struct { + userdata: userdata_t, + @"type": eventtype_t, + u: extern union { + clock: extern struct { + identifier: userdata_t, + clock_id: clockid_t, + timeout: timestamp_t, + precision: timestamp_t, + flags: subclockflags_t, + }, + fd_readwrite: extern struct { + fd: fd_t, + }, + }, +}; + +pub const timestamp_t = u64; + +pub const userdata_t = u64; + +pub const whence_t = u8; +pub const WHENCE_CUR: whence_t = 0; +pub const WHENCE_END: whence_t = 1; +pub const WHENCE_SET: whence_t = 2; + +pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t; +pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; + +pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t; +pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t; + +pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t; +pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t; + +pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t; +pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t; +pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t; +pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t; +pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t; +pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t; +pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, nread: *usize) errno_t; +pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t; +pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t; +pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t; +pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t; +pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t; +pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t; + +pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t; +pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t; +pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t; + +pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; +pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t; +pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t; + +pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t; +pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t; + +pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; +pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t; +pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t; +pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; +pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t; +pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t; +pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; +pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; +pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; +pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; + +pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t; + +pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn; +pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t; + +pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t; + +pub extern "wasi_unstable" fn sched_yield() errno_t; + +pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t; +pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t; +pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t; diff --git a/std/os/windows.zig b/std/os/windows.zig index 96274632ce..e134d87eae 100644 --- a/std/os/windows.zig +++ b/std/os/windows.zig @@ -239,6 +239,37 @@ pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000; pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004; pub const HEAP_NO_SERIALIZE = 0x00000001; +// AllocationType values +pub const MEM_COMMIT = 0x1000; +pub const MEM_RESERVE = 0x2000; +pub const MEM_RESET = 0x80000; +pub const MEM_RESET_UNDO = 0x1000000; +pub const MEM_LARGE_PAGES = 0x20000000; +pub const MEM_PHYSICAL = 0x400000; +pub const MEM_TOP_DOWN = 0x100000; +pub const MEM_WRITE_WATCH = 0x200000; + +// Protect values +pub const PAGE_EXECUTE = 0x10; +pub const PAGE_EXECUTE_READ = 0x20; +pub const PAGE_EXECUTE_READWRITE = 0x40; +pub const PAGE_EXECUTE_WRITECOPY = 0x80; +pub const PAGE_NOACCESS = 0x01; +pub const PAGE_READONLY = 0x02; +pub const PAGE_READWRITE = 0x04; +pub const PAGE_WRITECOPY = 0x08; +pub const PAGE_TARGETS_INVALID = 0x40000000; +pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID +pub const PAGE_GUARD = 0x100; +pub const PAGE_NOCACHE = 0x200; +pub const PAGE_WRITECOMBINE = 0x400; + +// FreeType values +pub const MEM_COALESCE_PLACEHOLDERS = 0x1; +pub const MEM_RESERVE_PLACEHOLDERS = 0x2; +pub const MEM_DECOMMIT = 0x4000; +pub const MEM_RELEASE = 0x8000; + pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD; pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 64a97ca87d..7e99f7eda9 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -116,6 +116,9 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: ?*const c_void) BOOL; +pub extern "kernel32" stdcallcc fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) ?LPVOID; +pub extern "kernel32" stdcallcc fn VirtualFree(lpAddress: ?LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) BOOL; + pub extern "kernel32" stdcallcc fn MoveFileExW( lpExistingFileName: [*]const u16, lpNewFileName: [*]const u16, diff --git a/std/packed_int_array.zig b/std/packed_int_array.zig new file mode 100644 index 0000000000..d4ed68c6ee --- /dev/null +++ b/std/packed_int_array.zig @@ -0,0 +1,649 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const debug = std.debug; +const testing = std.testing; + +pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { + //The general technique employed here is to cast bytes in the array to a container + // integer (having bits % 8 == 0) large enough to contain the number of bits we want, + // then we can retrieve or store the new value with a relative minimum of masking + // and shifting. In this worst case, this means that we'll need an integer that's + // actually 1 byte larger than the minimum required to store the bits, because it + // is possible that the bits start at the end of the first byte, continue through + // zero or more, then end in the beginning of the last. But, if we try to access + // a value in the very last byte of memory with that integer size, that extra byte + // will be out of bounds. Depending on the circumstances of the memory, that might + // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo) + // most of the time, but a smaller container (MinIo) when touching the last byte + // of the memory. + const int_bits = comptime std.meta.bitCount(Int); + + //in the best case, this is the number of bytes we need to touch + // to read or write a value, as bits + const min_io_bits = ((int_bits + 7) / 8) * 8; + + //in the worst case, this is the number of bytes we need to touch + // to read or write a value, as bits + const max_io_bits = switch (int_bits) { + 0 => 0, + 1 => 8, + 2...9 => 16, + 10...65535 => ((int_bits / 8) + 2) * 8, + else => unreachable, + }; + + //we bitcast the desired Int type to an unsigned version of itself + // to avoid issues with shifting signed ints. + const UnInt = @IntType(false, int_bits); + + //The maximum container int type + const MinIo = @IntType(false, min_io_bits); + + //The minimum container int type + const MaxIo = @IntType(false, max_io_bits); + + return struct { + pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int { + if (int_bits == 0) return 0; + + const bit_index = (index * int_bits) + bit_offset; + const max_end_byte = (bit_index + max_io_bits) / 8; + + //Using the larger container size will potentially read out of bounds + if (max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index); + return getBits(bytes, MaxIo, bit_index); + } + + fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int { + const container_bits = comptime std.meta.bitCount(Container); + const Shift = std.math.Log2Int(Container); + + const start_byte = bit_index / 8; + const head_keep_bits = bit_index - (start_byte * 8); + const tail_keep_bits = container_bits - (int_bits + head_keep_bits); + + //read bytes as container + const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]); + var value = value_ptr.*; + + if (endian != builtin.endian) value = @bswap(Container, value); + + switch (endian) { + .Big => { + value <<= @intCast(Shift, head_keep_bits); + value >>= @intCast(Shift, head_keep_bits); + value >>= @intCast(Shift, tail_keep_bits); + }, + .Little => { + value <<= @intCast(Shift, tail_keep_bits); + value >>= @intCast(Shift, tail_keep_bits); + value >>= @intCast(Shift, head_keep_bits); + }, + } + + return @bitCast(Int, @truncate(UnInt, value)); + } + + pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void { + if (int_bits == 0) return; + + const bit_index = (index * int_bits) + bit_offset; + const max_end_byte = (bit_index + max_io_bits) / 8; + + //Using the larger container size will potentially write out of bounds + if (max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int); + setBits(bytes, MaxIo, bit_index, int); + } + + fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void { + const container_bits = comptime std.meta.bitCount(Container); + const Shift = std.math.Log2Int(Container); + + const start_byte = bit_index / 8; + const head_keep_bits = bit_index - (start_byte * 8); + const tail_keep_bits = container_bits - (int_bits + head_keep_bits); + const keep_shift = switch (endian) { + .Big => @intCast(Shift, tail_keep_bits), + .Little => @intCast(Shift, head_keep_bits), + }; + + //position the bits where they need to be in the container + const value = @intCast(Container, @bitCast(UnInt, int)) << keep_shift; + + //read existing bytes + const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]); + var target = target_ptr.*; + + if (endian != builtin.endian) target = @bswap(Container, target); + + //zero the bits we want to replace in the existing bytes + const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift; + const mask = ~inv_mask; + target &= mask; + + //merge the new value + target |= value; + + if (endian != builtin.endian) target = @bswap(Container, target); + + //save it back + target_ptr.* = target; + } + + fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSliceEndian(Int, endian) { + debug.assert(end >= start); + + const length = end - start; + const bit_index = (start * int_bits) + bit_offset; + const start_byte = bit_index / 8; + const end_byte = (bit_index + (length * int_bits) + 7) / 8; + const new_bytes = bytes[start_byte..end_byte]; + + if (length == 0) return PackedIntSliceEndian(Int, endian).init(new_bytes[0..0], 0); + + var new_slice = PackedIntSliceEndian(Int, endian).init(new_bytes, length); + new_slice.bit_offset = @intCast(u3, (bit_index - (start_byte * 8))); + return new_slice; + } + + fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: builtin.Endian, bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian) { + const new_int_bits = comptime std.meta.bitCount(NewInt); + const New = PackedIntSliceEndian(NewInt, new_endian); + + const total_bits = (old_len * int_bits); + const new_int_count = total_bits / new_int_bits; + + debug.assert(total_bits == new_int_count * new_int_bits); + + var new = New.init(bytes, new_int_count); + new.bit_offset = bit_offset; + + return new; + } + }; +} + +///Creates a bit-packed array of integers of type Int. Bits +/// are packed using native endianess and without storing any meta +/// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory. +pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type { + return PackedIntArrayEndian(Int, builtin.endian, int_count); +} + +///Creates a bit-packed array of integers of type Int. Bits +/// are packed using specified endianess and without storing any meta +/// data. +pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian, comptime int_count: usize) type { + const int_bits = comptime std.meta.bitCount(Int); + const total_bits = int_bits * int_count; + const total_bytes = (total_bits + 7) / 8; + + const Io = PackedIntIo(Int, endian); + + return struct { + const Self = @This(); + + bytes: [total_bytes]u8, + + ///Returns the number of elements in the packed array + pub fn len(self: Self) usize { + return int_count; + } + + ///Initialize a packed array using an unpacked array + /// or, more likely, an array literal. + pub fn init(ints: [int_count]Int) Self { + var self = Self(undefined); + for (ints) |int, i| self.set(i, int); + return self; + } + + ///Return the Int stored at index + pub fn get(self: Self, index: usize) Int { + debug.assert(index < int_count); + return Io.get(self.bytes, index, 0); + } + + ///Copy int into the array at index + pub fn set(self: *Self, index: usize, int: Int) void { + debug.assert(index < int_count); + return Io.set(&self.bytes, index, 0, int); + } + + ///Create a PackedIntSlice of the array from given start to given end + pub fn slice(self: *Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) { + debug.assert(start < int_count); + debug.assert(end <= int_count); + return Io.slice(&self.bytes, 0, start, end); + } + + ///Create a PackedIntSlice of the array using NewInt as the bit width integer. + /// NewInt's bit width must fit evenly within the array's Int's total bits. + pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt) { + return self.sliceCastEndian(NewInt, endian); + } + + ///Create a PackedIntSlice of the array using NewInt as the bit width integer + /// and new_endian as the new endianess. NewInt's bit width must fit evenly within + /// the array's Int's total bits. + pub fn sliceCastEndian(self: *Self, comptime NewInt: type, comptime new_endian: builtin.Endian) PackedIntSliceEndian(NewInt, new_endian) { + return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count); + } + }; +} + +///Uses a slice as a bit-packed block of int_count integers of type Int. +/// Bits are packed using native endianess and without storing any meta +/// data. +pub fn PackedIntSlice(comptime Int: type) type { + return PackedIntSliceEndian(Int, builtin.endian); +} + +///Uses a slice as a bit-packed block of int_count integers of type Int. +/// Bits are packed using specified endianess and without storing any meta +/// data. +pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian) type { + const int_bits = comptime std.meta.bitCount(Int); + const Io = PackedIntIo(Int, endian); + + return struct { + const Self = @This(); + + bytes: []u8, + int_count: usize, + bit_offset: u3, + + ///Returns the number of elements in the packed slice + pub fn len(self: Self) usize { + return self.int_count; + } + + ///Calculates the number of bytes required to store a desired count + /// of Ints + pub fn bytesRequired(int_count: usize) usize { + const total_bits = int_bits * int_count; + const total_bytes = (total_bits + 7) / 8; + return total_bytes; + } + + ///Initialize a packed slice using the memory at bytes, with int_count + /// elements. bytes must be large enough to accomodate the requested + /// count. + pub fn init(bytes: []u8, int_count: usize) Self { + debug.assert(bytes.len >= bytesRequired(int_count)); + + return Self{ + .bytes = bytes, + .int_count = int_count, + .bit_offset = 0, + }; + } + + ///Return the Int stored at index + pub fn get(self: Self, index: usize) Int { + debug.assert(index < self.int_count); + return Io.get(self.bytes, index, self.bit_offset); + } + + ///Copy int into the array at index + pub fn set(self: *Self, index: usize, int: Int) void { + debug.assert(index < self.int_count); + return Io.set(self.bytes, index, self.bit_offset, int); + } + + ///Create a PackedIntSlice of this slice from given start to given end + pub fn slice(self: Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) { + debug.assert(start < self.int_count); + debug.assert(end <= self.int_count); + return Io.slice(self.bytes, self.bit_offset, start, end); + } + + ///Create a PackedIntSlice of this slice using NewInt as the bit width integer. + /// NewInt's bit width must fit evenly within this slice's Int's total bits. + pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSliceEndian(NewInt, endian) { + return self.sliceCastEndian(NewInt, endian); + } + + ///Create a PackedIntSlice of this slice using NewInt as the bit width integer + /// and new_endian as the new endianess. NewInt's bit width must fit evenly within + /// this slice's Int's total bits. + pub fn sliceCastEndian(self: Self, comptime NewInt: type, comptime new_endian: builtin.Endian) PackedIntSliceEndian(NewInt, new_endian) { + return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.int_count); + } + }; +} + +test "PackedIntArray" { + @setEvalBranchQuota(10000); + const max_bits = 256; + const int_count = 19; + + comptime var bits = 0; + inline while (bits <= 256) : (bits += 1) { + //alternate unsigned and signed + const even = bits % 2 == 0; + const I = @IntType(even, bits); + + const PackedArray = PackedIntArray(I, int_count); + const expected_bytes = ((bits * int_count) + 7) / 8; + testing.expect(@sizeOf(PackedArray) == expected_bytes); + + var data = PackedArray(undefined); + + //write values, counting up + var i = usize(0); + var count = I(0); + while (i < data.len()) : (i += 1) { + data.set(i, count); + if (bits > 0) count +%= 1; + } + + //read and verify values + i = 0; + count = 0; + while (i < data.len()) : (i += 1) { + const val = data.get(i); + testing.expect(val == count); + if (bits > 0) count +%= 1; + } + } +} + +test "PackedIntArray init" { + const PackedArray = PackedIntArray(u3, 8); + var packed_array = PackedArray.init([]u3{ 0, 1, 2, 3, 4, 5, 6, 7 }); + var i = usize(0); + while (i < packed_array.len()) : (i += 1) testing.expect(packed_array.get(i) == i); +} + +test "PackedIntSlice" { + @setEvalBranchQuota(10000); + const max_bits = 256; + const int_count = 19; + const total_bits = max_bits * int_count; + const total_bytes = (total_bits + 7) / 8; + + var buffer: [total_bytes]u8 = undefined; + + comptime var bits = 0; + inline while (bits <= 256) : (bits += 1) { + //alternate unsigned and signed + const even = bits % 2 == 0; + const I = @IntType(even, bits); + const P = PackedIntSlice(I); + + var data = P.init(&buffer, int_count); + + //write values, counting up + var i = usize(0); + var count = I(0); + while (i < data.len()) : (i += 1) { + data.set(i, count); + if (bits > 0) count +%= 1; + } + + //read and verify values + i = 0; + count = 0; + while (i < data.len()) : (i += 1) { + const val = data.get(i); + testing.expect(val == count); + if (bits > 0) count +%= 1; + } + } +} + +test "PackedIntSlice of PackedInt(Array/Slice)" { + const max_bits = 16; + const int_count = 19; + + comptime var bits = 0; + inline while (bits <= max_bits) : (bits += 1) { + const Int = @IntType(false, bits); + + const PackedArray = PackedIntArray(Int, int_count); + var packed_array = PackedArray(undefined); + + const limit = (1 << bits); + + var i = usize(0); + while (i < packed_array.len()) : (i += 1) { + packed_array.set(i, @intCast(Int, i % limit)); + } + + //slice of array + var packed_slice = packed_array.slice(2, 5); + testing.expect(packed_slice.len() == 3); + const ps_bit_count = (bits * packed_slice.len()) + packed_slice.bit_offset; + const ps_expected_bytes = (ps_bit_count + 7) / 8; + testing.expect(packed_slice.bytes.len == ps_expected_bytes); + testing.expect(packed_slice.get(0) == 2 % limit); + testing.expect(packed_slice.get(1) == 3 % limit); + testing.expect(packed_slice.get(2) == 4 % limit); + packed_slice.set(1, 7 % limit); + testing.expect(packed_slice.get(1) == 7 % limit); + + //write through slice + testing.expect(packed_array.get(3) == 7 % limit); + + //slice of a slice + const packed_slice_two = packed_slice.slice(0, 3); + testing.expect(packed_slice_two.len() == 3); + const ps2_bit_count = (bits * packed_slice_two.len()) + packed_slice_two.bit_offset; + const ps2_expected_bytes = (ps2_bit_count + 7) / 8; + testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes); + testing.expect(packed_slice_two.get(1) == 7 % limit); + testing.expect(packed_slice_two.get(2) == 4 % limit); + + //size one case + const packed_slice_three = packed_slice_two.slice(1, 2); + testing.expect(packed_slice_three.len() == 1); + const ps3_bit_count = (bits * packed_slice_three.len()) + packed_slice_three.bit_offset; + const ps3_expected_bytes = (ps3_bit_count + 7) / 8; + testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes); + testing.expect(packed_slice_three.get(0) == 7 % limit); + + //empty slice case + const packed_slice_empty = packed_slice.slice(0, 0); + testing.expect(packed_slice_empty.len() == 0); + testing.expect(packed_slice_empty.bytes.len == 0); + + //slicing at byte boundaries + const packed_slice_edge = packed_array.slice(8, 16); + testing.expect(packed_slice_edge.len() == 8); + const pse_bit_count = (bits * packed_slice_edge.len()) + packed_slice_edge.bit_offset; + const pse_expected_bytes = (pse_bit_count + 7) / 8; + testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes); + testing.expect(packed_slice_edge.bit_offset == 0); + } +} + +test "PackedIntSlice accumulating bit offsets" { + //bit_offset is u3, so standard debugging asserts should catch + // anything + { + const PackedArray = PackedIntArray(u3, 16); + var packed_array = PackedArray(undefined); + + var packed_slice = packed_array.slice(0, packed_array.len()); + var i = usize(0); + while (i < packed_array.len() - 1) : (i += 1) { + packed_slice = packed_slice.slice(1, packed_slice.len()); + } + } + { + const PackedArray = PackedIntArray(u11, 88); + var packed_array = PackedArray(undefined); + + var packed_slice = packed_array.slice(0, packed_array.len()); + var i = usize(0); + while (i < packed_array.len() - 1) : (i += 1) { + packed_slice = packed_slice.slice(1, packed_slice.len()); + } + } +} + +//@NOTE: As I do not have a big endian system to test this on, +// big endian values were not tested +test "PackedInt(Array/Slice) sliceCast" { + const PackedArray = PackedIntArray(u1, 16); + var packed_array = PackedArray.init([]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }); + const packed_slice_cast_2 = packed_array.sliceCast(u2); + const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4); + var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len() / 9) * 9).sliceCast(u9); + const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3); + + var i = usize(0); + while (i < packed_slice_cast_2.len()) : (i += 1) { + const val = switch (builtin.endian) { + .Big => 0b01, + .Little => 0b10, + }; + testing.expect(packed_slice_cast_2.get(i) == val); + } + i = 0; + while (i < packed_slice_cast_4.len()) : (i += 1) { + const val = switch (builtin.endian) { + .Big => 0b0101, + .Little => 0b1010, + }; + testing.expect(packed_slice_cast_4.get(i) == val); + } + i = 0; + while (i < packed_slice_cast_9.len()) : (i += 1) { + const val = 0b010101010; + testing.expect(packed_slice_cast_9.get(i) == val); + packed_slice_cast_9.set(i, 0b111000111); + } + i = 0; + while (i < packed_slice_cast_3.len()) : (i += 1) { + const val = switch (builtin.endian) { + .Big => if (i % 2 == 0) u3(0b111) else u3(0b000), + .Little => if (i % 2 == 0) u3(0b111) else u3(0b000), + }; + testing.expect(packed_slice_cast_3.get(i) == val); + } +} + +test "PackedInt(Array/Slice)Endian" { + { + const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8); + var packed_array_be = PackedArrayBe.init([]u4{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + }); + testing.expect(packed_array_be.bytes[0] == 0b00000001); + testing.expect(packed_array_be.bytes[1] == 0b00100011); + + var i = usize(0); + while (i < packed_array_be.len()) : (i += 1) { + testing.expect(packed_array_be.get(i) == i); + } + + var packed_slice_le = packed_array_be.sliceCastEndian(u4, .Little); + i = 0; + while (i < packed_slice_le.len()) : (i += 1) { + const val = if (i % 2 == 0) i + 1 else i - 1; + testing.expect(packed_slice_le.get(i) == val); + } + + var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u4, .Little); + i = 0; + while (i < packed_slice_le_shift.len()) : (i += 1) { + const val = if (i % 2 == 0) i else i + 2; + testing.expect(packed_slice_le_shift.get(i) == val); + } + } + + { + const PackedArrayBe = PackedIntArrayEndian(u11, .Big, 8); + var packed_array_be = PackedArrayBe.init([]u11{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + }); + testing.expect(packed_array_be.bytes[0] == 0b00000000); + testing.expect(packed_array_be.bytes[1] == 0b00000000); + testing.expect(packed_array_be.bytes[2] == 0b00000100); + testing.expect(packed_array_be.bytes[3] == 0b00000001); + testing.expect(packed_array_be.bytes[4] == 0b00000000); + + var i = usize(0); + while (i < packed_array_be.len()) : (i += 1) { + testing.expect(packed_array_be.get(i) == i); + } + + var packed_slice_le = packed_array_be.sliceCastEndian(u11, .Little); + testing.expect(packed_slice_le.get(0) == 0b00000000000); + testing.expect(packed_slice_le.get(1) == 0b00010000000); + testing.expect(packed_slice_le.get(2) == 0b00000000100); + testing.expect(packed_slice_le.get(3) == 0b00000000000); + testing.expect(packed_slice_le.get(4) == 0b00010000011); + testing.expect(packed_slice_le.get(5) == 0b00000000010); + testing.expect(packed_slice_le.get(6) == 0b10000010000); + testing.expect(packed_slice_le.get(7) == 0b00000111001); + + var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u11, .Little); + testing.expect(packed_slice_le_shift.get(0) == 0b00010000000); + testing.expect(packed_slice_le_shift.get(1) == 0b00000000100); + testing.expect(packed_slice_le_shift.get(2) == 0b00000000000); + testing.expect(packed_slice_le_shift.get(3) == 0b00010000011); + } +} + +//@NOTE: Need to manually update this list as more posix os's get +// added to DirectAllocator. Windows can be added too when DirectAllocator +// switches to VirtualAlloc. + +//These tests prove we aren't accidentally accessing memory past +// the end of the array/slice by placing it at the end of a page +// and reading the last element. The assumption is that the page +// after this one is not mapped and will cause a segfault if we +// don't account for the bounds. +test "PackedIntArray at end of available memory" { + switch (builtin.os) { + .linux, .macosx, .ios, .freebsd, .netbsd => {}, + else => return, + } + const PackedArray = PackedIntArray(u3, 8); + + const Padded = struct { + _: [std.os.page_size - @sizeOf(PackedArray)]u8, + p: PackedArray, + }; + + var da = std.heap.DirectAllocator.init(); + const allocator = &da.allocator; + + var pad = try allocator.create(Padded); + defer allocator.destroy(pad); + pad.p.set(7, std.math.maxInt(u3)); +} + +test "PackedIntSlice at end of available memory" { + switch (builtin.os) { + .linux, .macosx, .ios, .freebsd, .netbsd => {}, + else => return, + } + const PackedSlice = PackedIntSlice(u11); + + var da = std.heap.DirectAllocator.init(); + const allocator = &da.allocator; + + var page = try allocator.alloc(u8, std.os.page_size); + defer allocator.free(page); + + var p = PackedSlice.init(page[std.os.page_size - 2 ..], 1); + p.set(0, std.math.maxInt(u11)); +} diff --git a/std/pdb.zig b/std/pdb.zig index 2b02a84871..043be2bcf4 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -588,7 +588,7 @@ const SuperBlock = packed struct { const MsfStream = struct { in_file: os.File, - pos: usize, + pos: u64, blocks: []u32, block_size: u32, @@ -598,7 +598,7 @@ const MsfStream = struct { pub const Error = @typeOf(read).ReturnType.ErrorSet; pub const Stream = io.InStream(Error); - fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream { + fn init(block_size: u32, block_count: u32, pos: u64, file: os.File, allocator: *mem.Allocator) !MsfStream { var stream = MsfStream{ .in_file = file, .pos = 0, @@ -660,23 +660,24 @@ const MsfStream = struct { return size; } - fn seekForward(self: *MsfStream, len: usize) !void { + // XXX: The `len` parameter should be signed + fn seekForward(self: *MsfStream, len: u64) !void { self.pos += len; if (self.pos >= self.blocks.len * self.block_size) return error.EOF; } - fn seekTo(self: *MsfStream, len: usize) !void { + fn seekTo(self: *MsfStream, len: u64) !void { self.pos = len; if (self.pos >= self.blocks.len * self.block_size) return error.EOF; } - fn getSize(self: *const MsfStream) usize { + fn getSize(self: *const MsfStream) u64 { return self.blocks.len * self.block_size; } - fn getFilePos(self: MsfStream) usize { + fn getFilePos(self: MsfStream) u64 { const block_id = self.pos / self.block_size; const block = self.blocks[block_id]; const offset = self.pos % self.block_size; diff --git a/std/rand.zig b/std/rand.zig index a2fdfed6fd..4a6563f65a 100644 --- a/std/rand.zig +++ b/std/rand.zig @@ -768,10 +768,10 @@ pub const Isaac64 = struct { const x = self.m[base + m1]; self.a = mix +% self.m[base + m2]; - const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len]; + const y = self.a +% self.b +% self.m[@intCast(usize, (x >> 3) % self.m.len)]; self.m[base + m1] = y; - self.b = x +% self.m[(y >> 11) % self.m.len]; + self.b = x +% self.m[@intCast(usize, (y >> 11) % self.m.len)]; self.r[self.r.len - 1 - base - m1] = self.b; } diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 32f913a5b0..e6505c836b 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -20,6 +20,10 @@ comptime { } nakedcc fn _start() noreturn { + if (builtin.os == builtin.Os.wasi) { + std.os.wasi.proc_exit(callMain()); + } + switch (builtin.arch) { builtin.Arch.x86_64 => { argc_ptr = asm ("lea (%%rsp), %[argc]" @@ -63,24 +67,19 @@ fn posixCallMainAndExit() noreturn { var envp_count: usize = 0; while (envp_optional[envp_count]) |_| : (envp_count += 1) {} const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; + if (builtin.os == builtin.Os.linux) { - // Scan auxiliary vector. + // Find the beginning of the auxiliary vector const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); std.os.linux_elf_aux_maybe = auxv; - var i: usize = 0; - var at_phdr: usize = 0; - var at_phnum: usize = 0; - var at_phent: usize = 0; - while (auxv[i].a_un.a_val != 0) : (i += 1) { - switch (auxv[i].a_type) { - std.elf.AT_PAGESZ => assert(auxv[i].a_un.a_val == std.os.page_size), - std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, - std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, - std.elf.AT_PHENT => at_phent = auxv[i].a_un.a_val, - else => {}, - } + // Initialize the TLS area + std.os.linux.tls.initTLS(); + + if (std.os.linux.tls.tls_image) |tls_img| { + const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); + const tp = std.os.linux.tls.copyTLS(tls_addr); + std.os.linux.tls.setThreadPointer(tp); } - if (!builtin.single_threaded) linuxInitializeThreadLocalStorage(at_phdr, at_phnum, at_phent); } std.os.posix.exit(callMainWithArgs(argc, argv, envp)); @@ -136,50 +135,3 @@ inline fn callMain() u8 { const main_thread_tls_align = 32; var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; - -fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent: usize) void { - var phdr_addr = at_phdr; - var n = at_phnum; - var base: usize = 0; - while (n != 0) : ({ - n -= 1; - phdr_addr += at_phent; - }) { - const phdr = @intToPtr(*std.elf.Phdr, phdr_addr); - // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917 - switch (phdr.p_type) { - std.elf.PT_PHDR => base = at_phdr - phdr.p_vaddr, - std.elf.PT_TLS => std.os.linux_tls_phdr = phdr, - else => continue, - } - } - const tls_phdr = std.os.linux_tls_phdr orelse return; - std.os.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr); - const end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz; - const max_end_addr = @ptrToInt(&main_thread_tls_bytes) + main_thread_tls_bytes.len; - assert(max_end_addr >= end_addr + @sizeOf(usize)); // not enough preallocated Thread Local Storage - assert(main_thread_tls_align >= tls_phdr.p_align); // preallocated Thread Local Storage not aligned enough - @memcpy(&main_thread_tls_bytes, std.os.linux_tls_img_src, tls_phdr.p_filesz); - const end_ptr = @intToPtr(*usize, end_addr); - end_ptr.* = end_addr; - linuxSetThreadArea(end_addr); -} - -fn linuxSetThreadArea(addr: usize) void { - switch (builtin.arch) { - builtin.Arch.x86_64 => { - const ARCH_SET_FS = 0x1002; - const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, ARCH_SET_FS, addr); - // acrh_prctl is documented to never fail - assert(rc == 0); - }, - builtin.Arch.aarch64 => { - asm volatile ( - \\ msr tpidr_el0,x0 - \\ mov w0,#0 - \\ ret - ); - }, - else => @compileError("Unsupported architecture"), - } -} diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index 56cfe3bcb5..dfc3838577 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -94,6 +94,16 @@ pub fn main() !void { return usageAndErr(&builder, false, try stderr_stream); }); builder.addSearchPrefix(search_prefix); + } else if (mem.eql(u8, arg, "--override-std-dir")) { + builder.override_std_dir = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected argument after --override-std-dir\n\n"); + return usageAndErr(&builder, false, try stderr_stream); + }); + } else if (mem.eql(u8, arg, "--override-lib-dir")) { + builder.override_lib_dir = try unwrapArg(arg_it.next(allocator) orelse { + warn("Expected argument after --override-lib-dir\n\n"); + return usageAndErr(&builder, false, try stderr_stream); + }); } else if (mem.eql(u8, arg, "--verbose-tokenize")) { builder.verbose_tokenize = true; } else if (mem.eql(u8, arg, "--verbose-ast")) { @@ -187,15 +197,17 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { try 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 - \\ --verbose-cc Enable compiler debug output for C compilation + \\ --build-file [file] Override path to build.zig + \\ --cache-dir [path] Override path to zig cache directory + \\ --override-std-dir [arg] Override path to Zig standard library + \\ --override-lib-dir [arg] Override path to Zig lib 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 + \\ --verbose-cc Enable compiler debug output for C compilation \\ ); } diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig index e8d522eea1..b4df7aea5f 100644 --- a/std/special/compiler_rt.zig +++ b/std/special/compiler_rt.zig @@ -5,20 +5,47 @@ comptime { const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; + switch (builtin.arch) { + .i386, .x86_64 => @export("__zig_probe_stack", @import("compiler_rt/stack_probe.zig").zig_probe_stack, linkage), + else => {}, + } + + @export("__lesf2", @import("compiler_rt/comparesf2.zig").__lesf2, linkage); + @export("__ledf2", @import("compiler_rt/comparedf2.zig").__ledf2, linkage); @export("__letf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage); + + @export("__gesf2", @import("compiler_rt/comparesf2.zig").__gesf2, linkage); + @export("__gedf2", @import("compiler_rt/comparedf2.zig").__gedf2, linkage); @export("__getf2", @import("compiler_rt/comparetf2.zig").__getf2, linkage); if (!is_test) { // only create these aliases when not testing + @export("__cmpsf2", @import("compiler_rt/comparesf2.zig").__lesf2, linkage); + @export("__cmpdf2", @import("compiler_rt/comparedf2.zig").__ledf2, linkage); @export("__cmptf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage); + + @export("__eqsf2", @import("compiler_rt/comparesf2.zig").__eqsf2, linkage); + @export("__eqdf2", @import("compiler_rt/comparedf2.zig").__eqdf2, linkage); @export("__eqtf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage); + + @export("__ltsf2", @import("compiler_rt/comparesf2.zig").__ltsf2, linkage); + @export("__ltdf2", @import("compiler_rt/comparedf2.zig").__ltdf2, linkage); @export("__lttf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage); + + @export("__nesf2", @import("compiler_rt/comparesf2.zig").__nesf2, linkage); + @export("__nedf2", @import("compiler_rt/comparedf2.zig").__nedf2, linkage); @export("__netf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage); + + @export("__gtsf2", @import("compiler_rt/comparesf2.zig").__gtsf2, linkage); + @export("__gtdf2", @import("compiler_rt/comparedf2.zig").__gtdf2, linkage); @export("__gttf2", @import("compiler_rt/comparetf2.zig").__getf2, linkage); + @export("__gnu_h2f_ieee", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage); @export("__gnu_f2h_ieee", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage); } + @export("__unordsf2", @import("compiler_rt/comparesf2.zig").__unordsf2, linkage); + @export("__unorddf2", @import("compiler_rt/comparedf2.zig").__unorddf2, linkage); @export("__unordtf2", @import("compiler_rt/comparetf2.zig").__unordtf2, linkage); @export("__addsf3", @import("compiler_rt/addXf3.zig").__addsf3, linkage); @@ -35,6 +62,17 @@ comptime { @export("__divsf3", @import("compiler_rt/divsf3.zig").__divsf3, linkage); @export("__divdf3", @import("compiler_rt/divdf3.zig").__divdf3, linkage); + @export("__ashlti3", @import("compiler_rt/ashlti3.zig").__ashlti3, linkage); + @export("__lshrti3", @import("compiler_rt/lshrti3.zig").__lshrti3, linkage); + @export("__ashrti3", @import("compiler_rt/ashrti3.zig").__ashrti3, linkage); + + @export("__floatsidf", @import("compiler_rt/floatsiXf.zig").__floatsidf, linkage); + @export("__floatsisf", @import("compiler_rt/floatsiXf.zig").__floatsisf, linkage); + @export("__floatdidf", @import("compiler_rt/floatdidf.zig").__floatdidf, linkage); + @export("__floatsitf", @import("compiler_rt/floatsiXf.zig").__floatsitf, linkage); + @export("__floatunsidf", @import("compiler_rt/floatunsidf.zig").__floatunsidf, linkage); + @export("__floatundidf", @import("compiler_rt/floatundidf.zig").__floatundidf, linkage); + @export("__floattitf", @import("compiler_rt/floattitf.zig").__floattitf, linkage); @export("__floattidf", @import("compiler_rt/floattidf.zig").__floattidf, linkage); @export("__floattisf", @import("compiler_rt/floattisf.zig").__floattisf, linkage); @@ -55,6 +93,10 @@ comptime { @export("__trunctfdf2", @import("compiler_rt/truncXfYf2.zig").__trunctfdf2, linkage); @export("__trunctfsf2", @import("compiler_rt/truncXfYf2.zig").__trunctfsf2, linkage); + @export("__truncdfsf2", @import("compiler_rt/truncXfYf2.zig").__truncdfsf2, linkage); + + @export("__extendsfdf2", @import("compiler_rt/extendXfYf2.zig").__extendsfdf2, linkage); + @export("__fixunssfsi", @import("compiler_rt/fixunssfsi.zig").__fixunssfsi, linkage); @export("__fixunssfdi", @import("compiler_rt/fixunssfdi.zig").__fixunssfdi, linkage); @export("__fixunssfti", @import("compiler_rt/fixunssfti.zig").__fixunssfti, linkage); @@ -80,18 +122,33 @@ comptime { @export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage); @export("__popcountdi2", @import("compiler_rt/popcountdi2.zig").__popcountdi2, linkage); + @export("__divmoddi4", __divmoddi4, linkage); + @export("__divsi3", __divsi3, linkage); + @export("__divdi3", __divdi3, linkage); @export("__udivsi3", __udivsi3, linkage); @export("__udivdi3", __udivdi3, linkage); + @export("__modsi3", __modsi3, linkage); + @export("__moddi3", __moddi3, linkage); + @export("__umodsi3", __umodsi3, linkage); @export("__umoddi3", __umoddi3, linkage); + @export("__divmodsi4", __divmodsi4, linkage); @export("__udivmodsi4", __udivmodsi4, linkage); @export("__negsf2", @import("compiler_rt/negXf2.zig").__negsf2, linkage); @export("__negdf2", @import("compiler_rt/negXf2.zig").__negdf2, linkage); if (is_arm_arch and !is_arm_64) { + @export("__aeabi_unwind_cpp_pr0", __aeabi_unwind_cpp_pr0, strong_linkage); + @export("__aeabi_unwind_cpp_pr1", __aeabi_unwind_cpp_pr1, linkage); + @export("__aeabi_unwind_cpp_pr2", __aeabi_unwind_cpp_pr2, linkage); + + @export("__aeabi_ldivmod", __aeabi_ldivmod, linkage); @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); - @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); + + @export("__aeabi_idiv", __divsi3, linkage); + @export("__aeabi_idivmod", __aeabi_idivmod, linkage); @export("__aeabi_uidiv", __udivsi3, linkage); + @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); @export("__aeabi_memcpy", __aeabi_memcpy, linkage); @export("__aeabi_memcpy4", __aeabi_memcpy, linkage); @@ -113,6 +170,12 @@ comptime { @export("__aeabi_memcmp4", __aeabi_memcmp, linkage); @export("__aeabi_memcmp8", __aeabi_memcmp, linkage); + @export("__aeabi_f2d", @import("compiler_rt/extendXfYf2.zig").__extendsfdf2, linkage); + @export("__aeabi_i2d", @import("compiler_rt/floatsiXf.zig").__floatsidf, linkage); + @export("__aeabi_l2d", @import("compiler_rt/floatdidf.zig").__floatdidf, linkage); + @export("__aeabi_ui2d", @import("compiler_rt/floatunsidf.zig").__floatunsidf, linkage); + @export("__aeabi_ul2d", @import("compiler_rt/floatundidf.zig").__floatundidf, linkage); + @export("__aeabi_fneg", @import("compiler_rt/negXf2.zig").__negsf2, linkage); @export("__aeabi_dneg", @import("compiler_rt/negXf2.zig").__negdf2, linkage); @@ -132,6 +195,9 @@ comptime { @export("__aeabi_h2f", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage); @export("__aeabi_f2h", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage); + @export("__aeabi_i2f", @import("compiler_rt/floatsiXf.zig").__floatsisf, linkage); + @export("__aeabi_d2f", @import("compiler_rt/truncXfYf2.zig").__truncdfsf2, linkage); + @export("__aeabi_fadd", @import("compiler_rt/addXf3.zig").__addsf3, linkage); @export("__aeabi_dadd", @import("compiler_rt/addXf3.zig").__adddf3, linkage); @export("__aeabi_fsub", @import("compiler_rt/addXf3.zig").__subsf3, linkage); @@ -144,26 +210,41 @@ comptime { @export("__aeabi_fdiv", @import("compiler_rt/divsf3.zig").__divsf3, linkage); @export("__aeabi_ddiv", @import("compiler_rt/divdf3.zig").__divdf3, linkage); + + @export("__aeabi_fcmpeq", @import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpeq, linkage); + @export("__aeabi_fcmplt", @import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmplt, linkage); + @export("__aeabi_fcmple", @import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmple, linkage); + @export("__aeabi_fcmpge", @import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpge, linkage); + @export("__aeabi_fcmpgt", @import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpgt, linkage); + @export("__aeabi_fcmpun", @import("compiler_rt/comparesf2.zig").__unordsf2, linkage); + + @export("__aeabi_dcmpeq", @import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpeq, linkage); + @export("__aeabi_dcmplt", @import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmplt, linkage); + @export("__aeabi_dcmple", @import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmple, linkage); + @export("__aeabi_dcmpge", @import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpge, linkage); + @export("__aeabi_dcmpgt", @import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpgt, linkage); + @export("__aeabi_dcmpun", @import("compiler_rt/comparedf2.zig").__unorddf2, linkage); } if (builtin.os == builtin.Os.windows) { + if (!builtin.link_libc) { + @export("_chkstk", @import("compiler_rt/stack_probe.zig")._chkstk, strong_linkage); + @export("__chkstk", @import("compiler_rt/stack_probe.zig").__chkstk, strong_linkage); + @export("___chkstk", @import("compiler_rt/stack_probe.zig").___chkstk, strong_linkage); + @export("__chkstk_ms", @import("compiler_rt/stack_probe.zig").__chkstk_ms, strong_linkage); + @export("___chkstk_ms", @import("compiler_rt/stack_probe.zig").___chkstk_ms, strong_linkage); + } + switch (builtin.arch) { builtin.Arch.i386 => { - if (!builtin.link_libc) { - @export("_chkstk", _chkstk, strong_linkage); - @export("__chkstk_ms", __chkstk_ms, linkage); - } @export("_aulldiv", @import("compiler_rt/aulldiv.zig")._aulldiv, strong_linkage); @export("_aullrem", @import("compiler_rt/aullrem.zig")._aullrem, strong_linkage); }, builtin.Arch.x86_64 => { - if (!builtin.link_libc) { - @export("__chkstk", __chkstk, strong_linkage); - @export("___chkstk_ms", ___chkstk_ms, linkage); - } + // The "ti" functions must use @Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. @export("__divti3", @import("compiler_rt/divti3.zig").__divti3_windows_x86_64, linkage); @export("__modti3", @import("compiler_rt/modti3.zig").__modti3_windows_x86_64, linkage); @export("__multi3", @import("compiler_rt/multi3.zig").__multi3_windows_x86_64, linkage); - @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4_windows_x86_64, linkage); @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3_windows_x86_64, linkage); @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4_windows_x86_64, linkage); @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3_windows_x86_64, linkage); @@ -174,11 +255,12 @@ comptime { @export("__divti3", @import("compiler_rt/divti3.zig").__divti3, linkage); @export("__modti3", @import("compiler_rt/modti3.zig").__modti3, linkage); @export("__multi3", @import("compiler_rt/multi3.zig").__multi3, linkage); - @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4, linkage); @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3, linkage); @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4, linkage); @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3, linkage); } + @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4, linkage); + @export("__mulodi4", @import("compiler_rt/mulodi4.zig").__mulodi4, linkage); } const std = @import("std"); @@ -198,15 +280,49 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn } } -pub fn setXmm0(comptime T: type, value: T) void { - comptime assert(builtin.arch == builtin.Arch.x86_64); - const aligned_value: T align(16) = value; - asm volatile ( - \\movaps (%[ptr]), %%xmm0 - : - : [ptr] "r" (&aligned_value) - : "xmm0" - ); +extern fn __aeabi_unwind_cpp_pr0() void { + unreachable; +} +extern fn __aeabi_unwind_cpp_pr1() void { + unreachable; +} +extern fn __aeabi_unwind_cpp_pr2() void { + unreachable; +} + +extern fn __divmoddi4(a: i64, b: i64, rem: *i64) i64 { + @setRuntimeSafety(is_test); + + const d = __divdi3(a, b); + rem.* = a -% (d *% b); + return d; +} + +extern fn __divdi3(a: i64, b: i64) i64 { + @setRuntimeSafety(is_test); + + // Set aside the sign of the quotient. + const sign = @bitCast(u64, (a ^ b) >> 63); + // Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63). + const abs_a = (a ^ (a >> 63)) -% (a >> 63); + const abs_b = (b ^ (b >> 63)) -% (b >> 63); + // Unsigned division + const res = __udivmoddi4(@bitCast(u64, abs_a), @bitCast(u64, abs_b), null); + // Apply sign of quotient to result and return. + return @bitCast(i64, (res ^ sign) -% sign); +} + +extern fn __moddi3(a: i64, b: i64) i64 { + @setRuntimeSafety(is_test); + + // Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63). + const abs_a = (a ^ (a >> 63)) -% (a >> 63); + const abs_b = (b ^ (b >> 63)) -% (b >> 63); + // Unsigned division + var r: u64 = undefined; + _ = __udivmoddi4(@bitCast(u64, abs_a), @bitCast(u64, abs_b), &r); + // Apply the sign of the dividend and return. + return (@bitCast(i64, r) ^ (a >> 63)) -% (a >> 63); } extern fn __udivdi3(a: u64, b: u64) u64 { @@ -222,14 +338,35 @@ extern fn __umoddi3(a: u64, b: u64) u64 { return r; } -const AeabiUlDivModResult = extern struct { - quot: u64, - rem: u64, -}; -extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult { +extern fn __aeabi_uidivmod(n: u32, d: u32) extern struct{q: u32, r: u32} { + @setRuntimeSafety(is_test); + + var result: @typeOf(__aeabi_uidivmod).ReturnType = undefined; + result.q = __udivmodsi4(n, d, &result.r); + return result; +} + +extern fn __aeabi_uldivmod(n: u64, d: u64) extern struct{q: u64, r: u64} { + @setRuntimeSafety(is_test); + + var result: @typeOf(__aeabi_uldivmod).ReturnType = undefined; + result.q = __udivmoddi4(n, d, &result.r); + return result; +} + +extern fn __aeabi_idivmod(n: i32, d: i32) extern struct{q: i32, r: i32} { + @setRuntimeSafety(is_test); + + var result: @typeOf(__aeabi_idivmod).ReturnType = undefined; + result.q = __divmodsi4(n, d, &result.r); + return result; +} + +extern fn __aeabi_ldivmod(n: i64, d: i64) extern struct{q: i64, r:i64} { @setRuntimeSafety(is_test); - var result: AeabiUlDivModResult = undefined; - result.quot = __udivmoddi4(numerator, denominator, &result.rem); + + var result: @typeOf(__aeabi_ldivmod).ReturnType = undefined; + result.q = __divmoddi4(n, d, &result.r); return result; } @@ -253,29 +390,74 @@ const is_arm_arch = switch (builtin.arch) { const is_arm_32 = is_arm_arch and !is_arm_64; -const use_thumb_1 = is_arm_32 and switch (builtin.arch.arm) { - builtin.Arch.Arm32.v6, - builtin.Arch.Arm32.v6m, - builtin.Arch.Arm32.v6k, - builtin.Arch.Arm32.v6t2, - => true, - else => false, -}; +const use_thumb_1 = usesThumb1(builtin.arch); + +fn usesThumb1(arch: builtin.Arch) bool { + return switch (arch) { + .arm => switch (arch.arm) { + .v6m => true, + else => false, + }, + .armeb => switch (arch.armeb) { + .v6m => true, + else => false, + }, + .thumb => switch (arch.thumb) { + .v5, + .v5te, + .v4t, + .v6, + .v6m, + .v6k, + => true, + else => false, + }, + .thumbeb => switch (arch.thumbeb) { + .v5, + .v5te, + .v4t, + .v6, + .v6m, + .v6k, + => true, + else => false, + }, + else => false, + }; +} -nakedcc fn __aeabi_uidivmod() void { - @setRuntimeSafety(false); - asm volatile ( - \\ push { lr } - \\ sub sp, sp, #4 - \\ mov r2, sp - \\ bl __udivmodsi4 - \\ ldr r1, [sp] - \\ add sp, sp, #4 - \\ pop { pc } - : - : - : "r2", "r1" - ); +test "usesThumb1" { + testing.expect(usesThumb1(builtin.Arch{ .arm = .v6m })); + testing.expect(!usesThumb1(builtin.Arch{ .arm = .v5 })); + //etc. + + testing.expect(usesThumb1(builtin.Arch{ .armeb = .v6m })); + testing.expect(!usesThumb1(builtin.Arch{ .armeb = .v5 })); + //etc. + + testing.expect(usesThumb1(builtin.Arch{ .thumb = .v5 })); + testing.expect(usesThumb1(builtin.Arch{ .thumb = .v5te })); + testing.expect(usesThumb1(builtin.Arch{ .thumb = .v4t })); + testing.expect(usesThumb1(builtin.Arch{ .thumb = .v6 })); + testing.expect(usesThumb1(builtin.Arch{ .thumb = .v6k })); + testing.expect(usesThumb1(builtin.Arch{ .thumb = .v6m })); + testing.expect(!usesThumb1(builtin.Arch{ .thumb = .v6t2 })); + //etc. + + testing.expect(usesThumb1(builtin.Arch{ .thumbeb = .v5 })); + testing.expect(usesThumb1(builtin.Arch{ .thumbeb = .v5te })); + testing.expect(usesThumb1(builtin.Arch{ .thumbeb = .v4t })); + testing.expect(usesThumb1(builtin.Arch{ .thumbeb = .v6 })); + testing.expect(usesThumb1(builtin.Arch{ .thumbeb = .v6k })); + testing.expect(usesThumb1(builtin.Arch{ .thumbeb = .v6m })); + testing.expect(!usesThumb1(builtin.Arch{ .thumbeb = .v6t2 })); + //etc. + + testing.expect(!usesThumb1(builtin.Arch{ .aarch64 = .v8 })); + testing.expect(!usesThumb1(builtin.Arch{ .aarch64_be = .v8 })); + testing.expect(!usesThumb1(builtin.Arch.x86_64)); + testing.expect(!usesThumb1(builtin.Arch.riscv32)); + //etc. } nakedcc fn __aeabi_memcpy() noreturn { @@ -368,107 +550,12 @@ nakedcc fn __aeabi_memcmp() noreturn { unreachable; } -// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, -// then decrement %esp by %eax. Preserves all registers except %esp and flags. -// This routine is windows specific -// http://msdn.microsoft.com/en-us/library/ms648426.aspx -nakedcc fn _chkstk() align(4) void { - @setRuntimeSafety(false); - - asm volatile ( - \\ push %%ecx - \\ push %%eax - \\ cmp $0x1000,%%eax - \\ lea 12(%%esp),%%ecx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%ecx - \\ test %%ecx,(%%ecx) - \\ sub $0x1000,%%eax - \\ cmp $0x1000,%%eax - \\ ja 2b - \\ 1: - \\ sub %%eax,%%ecx - \\ test %%ecx,(%%ecx) - \\ pop %%eax - \\ pop %%ecx - \\ ret - ); -} - -nakedcc fn __chkstk() align(4) void { - @setRuntimeSafety(false); - - asm volatile ( - \\ push %%rcx - \\ push %%rax - \\ cmp $0x1000,%%rax - \\ lea 24(%%rsp),%%rcx - \\ jb 1f - \\2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ pop %%rax - \\ pop %%rcx - \\ ret - ); -} - -// _chkstk routine -// This routine is windows specific -// http://msdn.microsoft.com/en-us/library/ms648426.aspx -nakedcc fn __chkstk_ms() align(4) void { - @setRuntimeSafety(false); - - asm volatile ( - \\ push %%ecx - \\ push %%eax - \\ cmp $0x1000,%%eax - \\ lea 12(%%esp),%%ecx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%ecx - \\ test %%ecx,(%%ecx) - \\ sub $0x1000,%%eax - \\ cmp $0x1000,%%eax - \\ ja 2b - \\ 1: - \\ sub %%eax,%%ecx - \\ test %%ecx,(%%ecx) - \\ pop %%eax - \\ pop %%ecx - \\ ret - ); -} - -nakedcc fn ___chkstk_ms() align(4) void { - @setRuntimeSafety(false); +extern fn __divmodsi4(a: i32, b: i32, rem: *i32) i32 { + @setRuntimeSafety(is_test); - asm volatile ( - \\ push %%rcx - \\ push %%rax - \\ cmp $0x1000,%%rax - \\ lea 24(%%rsp),%%rcx - \\ jb 1f - \\2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ pop %%rax - \\ pop %%rcx - \\ ret - ); + const d = __divsi3(a, b); + rem.* = a -% (d * b); + return d; } extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 { @@ -479,6 +566,20 @@ extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 { return d; } +extern fn __divsi3(n: i32, d: i32) i32 { + @setRuntimeSafety(is_test); + + // Set aside the sign of the quotient. + const sign = @bitCast(u32, (n ^ d) >> 31); + // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). + const abs_n = (n ^ (n >> 31)) -% (n >> 31); + const abs_d = (d ^ (d >> 31)) -% (d >> 31); + // abs(a) / abs(b) + const res = @bitCast(u32, abs_n) / @bitCast(u32, abs_d); + // Apply sign of quotient to result and return. + return @bitCast(i32, (res ^ sign) -% sign); +} + extern fn __udivsi3(n: u32, d: u32) u32 { @setRuntimeSafety(is_test); @@ -520,6 +621,18 @@ extern fn __udivsi3(n: u32, d: u32) u32 { return q; } +extern fn __modsi3(n: i32, d: i32) i32 { + @setRuntimeSafety(is_test); + + return n -% __divsi3(n, d) *% d; +} + +extern fn __umodsi3(n: u32, d: u32) u32 { + @setRuntimeSafety(is_test); + + return n -% __udivsi3(n, d) *% d; +} + test "test_umoddi3" { test_one_umoddi3(0, 1, 0); test_one_umoddi3(2, 1, 0); @@ -1206,3 +1319,279 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void { const q: u32 = __udivsi3(a, b); testing.expect(q == expected_q); } + +test "test_divsi3" { + const cases = [][3]i32{ + []i32{ 0, 1, 0 }, + []i32{ 0, -1, 0 }, + []i32{ 2, 1, 2 }, + []i32{ 2, -1, -2 }, + []i32{ -2, 1, -2 }, + []i32{ -2, -1, 2 }, + + []i32{ @bitCast(i32, u32(0x80000000)), 1, @bitCast(i32, u32(0x80000000)) }, + []i32{ @bitCast(i32, u32(0x80000000)), -1, @bitCast(i32, u32(0x80000000)) }, + []i32{ @bitCast(i32, u32(0x80000000)), -2, 0x40000000 }, + []i32{ @bitCast(i32, u32(0x80000000)), 2, @bitCast(i32, u32(0xC0000000)) }, + }; + + for (cases) |case| { + test_one_divsi3(case[0], case[1], case[2]); + } +} + +fn test_one_divsi3(a: i32, b: i32, expected_q: i32) void { + const q: i32 = __divsi3(a, b); + testing.expect(q == expected_q); +} + +test "test_divmodsi4" { + const cases = [][4]i32{ + []i32{ 0, 1, 0, 0 }, + []i32{ 0, -1, 0, 0 }, + []i32{ 2, 1, 2, 0 }, + []i32{ 2, -1, -2, 0 }, + []i32{ -2, 1, -2, 0 }, + []i32{ -2, -1, 2, 0 }, + []i32{ 7, 5, 1, 2 }, + []i32{ -7, 5, -1, -2 }, + []i32{ 19, 5, 3, 4 }, + []i32{ 19, -5, -3, 4 }, + + []i32{ @bitCast(i32, u32(0x80000000)), 8, @bitCast(i32, u32(0xf0000000)), 0 }, + []i32{ @bitCast(i32, u32(0x80000007)), 8, @bitCast(i32, u32(0xf0000001)), -1 }, + }; + + for (cases) |case| { + test_one_divmodsi4(case[0], case[1], case[2], case[3]); + } +} + +fn test_one_divmodsi4(a: i32, b: i32, expected_q: i32, expected_r: i32) void { + var r: i32 = undefined; + const q: i32 = __divmodsi4(a, b, &r); + testing.expect(q == expected_q and r == expected_r); +} + +test "test_divdi3" { + const cases = [][3]i64{ + []i64{ 0, 1, 0 }, + []i64{ 0, -1, 0 }, + []i64{ 2, 1, 2 }, + []i64{ 2, -1, -2 }, + []i64{ -2, 1, -2 }, + []i64{ -2, -1, 2 }, + + []i64{ @bitCast(i64, u64(0x8000000000000000)), 1, @bitCast(i64, u64(0x8000000000000000)) }, + []i64{ @bitCast(i64, u64(0x8000000000000000)), -1, @bitCast(i64, u64(0x8000000000000000)) }, + []i64{ @bitCast(i64, u64(0x8000000000000000)), -2, 0x4000000000000000 }, + []i64{ @bitCast(i64, u64(0x8000000000000000)), 2, @bitCast(i64, u64(0xC000000000000000)) }, + }; + + for (cases) |case| { + test_one_divdi3(case[0], case[1], case[2]); + } +} + +fn test_one_divdi3(a: i64, b: i64, expected_q: i64) void { + const q: i64 = __divdi3(a, b); + testing.expect(q == expected_q); +} + +test "test_moddi3" { + const cases = [][3]i64{ + []i64{ 0, 1, 0 }, + []i64{ 0, -1, 0 }, + []i64{ 5, 3, 2 }, + []i64{ 5, -3, 2 }, + []i64{ -5, 3, -2 }, + []i64{ -5, -3, -2 }, + + []i64{ @bitCast(i64, @intCast(u64, 0x8000000000000000)), 1, 0 }, + []i64{ @bitCast(i64, @intCast(u64, 0x8000000000000000)), -1, 0 }, + []i64{ @bitCast(i64, @intCast(u64, 0x8000000000000000)), 2, 0 }, + []i64{ @bitCast(i64, @intCast(u64, 0x8000000000000000)), -2, 0 }, + []i64{ @bitCast(i64, @intCast(u64, 0x8000000000000000)), 3, -2 }, + []i64{ @bitCast(i64, @intCast(u64, 0x8000000000000000)), -3, -2 }, + }; + + for (cases) |case| { + test_one_moddi3(case[0], case[1], case[2]); + } +} + +fn test_one_moddi3(a: i64, b: i64, expected_r: i64) void { + const r: i64 = __moddi3(a, b); + testing.expect(r == expected_r); +} + +test "test_modsi3" { + const cases = [][3]i32{ + []i32{ 0, 1, 0 }, + []i32{ 0, -1, 0 }, + []i32{ 5, 3, 2 }, + []i32{ 5, -3, 2 }, + []i32{ -5, 3, -2 }, + []i32{ -5, -3, -2 }, + []i32{ @bitCast(i32, @intCast(u32, 0x80000000)), 1, 0x0 }, + []i32{ @bitCast(i32, @intCast(u32, 0x80000000)), 2, 0x0 }, + []i32{ @bitCast(i32, @intCast(u32, 0x80000000)), -2, 0x0 }, + []i32{ @bitCast(i32, @intCast(u32, 0x80000000)), 3, -2 }, + []i32{ @bitCast(i32, @intCast(u32, 0x80000000)), -3, -2 }, + }; + + for (cases) |case| { + test_one_modsi3(case[0], case[1], case[2]); + } +} + +fn test_one_modsi3(a: i32, b: i32, expected_r: i32) void { + const r: i32 = __modsi3(a, b); + testing.expect(r == expected_r); +} + +test "test_umodsi3" { + const cases = [][3]u32{ + []u32{ 0x00000000, 0x00000001, 0x00000000 }, + []u32{ 0x00000000, 0x00000002, 0x00000000 }, + []u32{ 0x00000000, 0x00000003, 0x00000000 }, + []u32{ 0x00000000, 0x00000010, 0x00000000 }, + []u32{ 0x00000000, 0x078644FA, 0x00000000 }, + []u32{ 0x00000000, 0x0747AE14, 0x00000000 }, + []u32{ 0x00000000, 0x7FFFFFFF, 0x00000000 }, + []u32{ 0x00000000, 0x80000000, 0x00000000 }, + []u32{ 0x00000000, 0xFFFFFFFD, 0x00000000 }, + []u32{ 0x00000000, 0xFFFFFFFE, 0x00000000 }, + []u32{ 0x00000000, 0xFFFFFFFF, 0x00000000 }, + []u32{ 0x00000001, 0x00000001, 0x00000000 }, + []u32{ 0x00000001, 0x00000002, 0x00000001 }, + []u32{ 0x00000001, 0x00000003, 0x00000001 }, + []u32{ 0x00000001, 0x00000010, 0x00000001 }, + []u32{ 0x00000001, 0x078644FA, 0x00000001 }, + []u32{ 0x00000001, 0x0747AE14, 0x00000001 }, + []u32{ 0x00000001, 0x7FFFFFFF, 0x00000001 }, + []u32{ 0x00000001, 0x80000000, 0x00000001 }, + []u32{ 0x00000001, 0xFFFFFFFD, 0x00000001 }, + []u32{ 0x00000001, 0xFFFFFFFE, 0x00000001 }, + []u32{ 0x00000001, 0xFFFFFFFF, 0x00000001 }, + []u32{ 0x00000002, 0x00000001, 0x00000000 }, + []u32{ 0x00000002, 0x00000002, 0x00000000 }, + []u32{ 0x00000002, 0x00000003, 0x00000002 }, + []u32{ 0x00000002, 0x00000010, 0x00000002 }, + []u32{ 0x00000002, 0x078644FA, 0x00000002 }, + []u32{ 0x00000002, 0x0747AE14, 0x00000002 }, + []u32{ 0x00000002, 0x7FFFFFFF, 0x00000002 }, + []u32{ 0x00000002, 0x80000000, 0x00000002 }, + []u32{ 0x00000002, 0xFFFFFFFD, 0x00000002 }, + []u32{ 0x00000002, 0xFFFFFFFE, 0x00000002 }, + []u32{ 0x00000002, 0xFFFFFFFF, 0x00000002 }, + []u32{ 0x00000003, 0x00000001, 0x00000000 }, + []u32{ 0x00000003, 0x00000002, 0x00000001 }, + []u32{ 0x00000003, 0x00000003, 0x00000000 }, + []u32{ 0x00000003, 0x00000010, 0x00000003 }, + []u32{ 0x00000003, 0x078644FA, 0x00000003 }, + []u32{ 0x00000003, 0x0747AE14, 0x00000003 }, + []u32{ 0x00000003, 0x7FFFFFFF, 0x00000003 }, + []u32{ 0x00000003, 0x80000000, 0x00000003 }, + []u32{ 0x00000003, 0xFFFFFFFD, 0x00000003 }, + []u32{ 0x00000003, 0xFFFFFFFE, 0x00000003 }, + []u32{ 0x00000003, 0xFFFFFFFF, 0x00000003 }, + []u32{ 0x00000010, 0x00000001, 0x00000000 }, + []u32{ 0x00000010, 0x00000002, 0x00000000 }, + []u32{ 0x00000010, 0x00000003, 0x00000001 }, + []u32{ 0x00000010, 0x00000010, 0x00000000 }, + []u32{ 0x00000010, 0x078644FA, 0x00000010 }, + []u32{ 0x00000010, 0x0747AE14, 0x00000010 }, + []u32{ 0x00000010, 0x7FFFFFFF, 0x00000010 }, + []u32{ 0x00000010, 0x80000000, 0x00000010 }, + []u32{ 0x00000010, 0xFFFFFFFD, 0x00000010 }, + []u32{ 0x00000010, 0xFFFFFFFE, 0x00000010 }, + []u32{ 0x00000010, 0xFFFFFFFF, 0x00000010 }, + []u32{ 0x078644FA, 0x00000001, 0x00000000 }, + []u32{ 0x078644FA, 0x00000002, 0x00000000 }, + []u32{ 0x078644FA, 0x00000003, 0x00000000 }, + []u32{ 0x078644FA, 0x00000010, 0x0000000A }, + []u32{ 0x078644FA, 0x078644FA, 0x00000000 }, + []u32{ 0x078644FA, 0x0747AE14, 0x003E96E6 }, + []u32{ 0x078644FA, 0x7FFFFFFF, 0x078644FA }, + []u32{ 0x078644FA, 0x80000000, 0x078644FA }, + []u32{ 0x078644FA, 0xFFFFFFFD, 0x078644FA }, + []u32{ 0x078644FA, 0xFFFFFFFE, 0x078644FA }, + []u32{ 0x078644FA, 0xFFFFFFFF, 0x078644FA }, + []u32{ 0x0747AE14, 0x00000001, 0x00000000 }, + []u32{ 0x0747AE14, 0x00000002, 0x00000000 }, + []u32{ 0x0747AE14, 0x00000003, 0x00000002 }, + []u32{ 0x0747AE14, 0x00000010, 0x00000004 }, + []u32{ 0x0747AE14, 0x078644FA, 0x0747AE14 }, + []u32{ 0x0747AE14, 0x0747AE14, 0x00000000 }, + []u32{ 0x0747AE14, 0x7FFFFFFF, 0x0747AE14 }, + []u32{ 0x0747AE14, 0x80000000, 0x0747AE14 }, + []u32{ 0x0747AE14, 0xFFFFFFFD, 0x0747AE14 }, + []u32{ 0x0747AE14, 0xFFFFFFFE, 0x0747AE14 }, + []u32{ 0x0747AE14, 0xFFFFFFFF, 0x0747AE14 }, + []u32{ 0x7FFFFFFF, 0x00000001, 0x00000000 }, + []u32{ 0x7FFFFFFF, 0x00000002, 0x00000001 }, + []u32{ 0x7FFFFFFF, 0x00000003, 0x00000001 }, + []u32{ 0x7FFFFFFF, 0x00000010, 0x0000000F }, + []u32{ 0x7FFFFFFF, 0x078644FA, 0x00156B65 }, + []u32{ 0x7FFFFFFF, 0x0747AE14, 0x043D70AB }, + []u32{ 0x7FFFFFFF, 0x7FFFFFFF, 0x00000000 }, + []u32{ 0x7FFFFFFF, 0x80000000, 0x7FFFFFFF }, + []u32{ 0x7FFFFFFF, 0xFFFFFFFD, 0x7FFFFFFF }, + []u32{ 0x7FFFFFFF, 0xFFFFFFFE, 0x7FFFFFFF }, + []u32{ 0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF }, + []u32{ 0x80000000, 0x00000001, 0x00000000 }, + []u32{ 0x80000000, 0x00000002, 0x00000000 }, + []u32{ 0x80000000, 0x00000003, 0x00000002 }, + []u32{ 0x80000000, 0x00000010, 0x00000000 }, + []u32{ 0x80000000, 0x078644FA, 0x00156B66 }, + []u32{ 0x80000000, 0x0747AE14, 0x043D70AC }, + []u32{ 0x80000000, 0x7FFFFFFF, 0x00000001 }, + []u32{ 0x80000000, 0x80000000, 0x00000000 }, + []u32{ 0x80000000, 0xFFFFFFFD, 0x80000000 }, + []u32{ 0x80000000, 0xFFFFFFFE, 0x80000000 }, + []u32{ 0x80000000, 0xFFFFFFFF, 0x80000000 }, + []u32{ 0xFFFFFFFD, 0x00000001, 0x00000000 }, + []u32{ 0xFFFFFFFD, 0x00000002, 0x00000001 }, + []u32{ 0xFFFFFFFD, 0x00000003, 0x00000001 }, + []u32{ 0xFFFFFFFD, 0x00000010, 0x0000000D }, + []u32{ 0xFFFFFFFD, 0x078644FA, 0x002AD6C9 }, + []u32{ 0xFFFFFFFD, 0x0747AE14, 0x01333341 }, + []u32{ 0xFFFFFFFD, 0x7FFFFFFF, 0x7FFFFFFE }, + []u32{ 0xFFFFFFFD, 0x80000000, 0x7FFFFFFD }, + []u32{ 0xFFFFFFFD, 0xFFFFFFFD, 0x00000000 }, + []u32{ 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFD }, + []u32{ 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFD }, + []u32{ 0xFFFFFFFE, 0x00000001, 0x00000000 }, + []u32{ 0xFFFFFFFE, 0x00000002, 0x00000000 }, + []u32{ 0xFFFFFFFE, 0x00000003, 0x00000002 }, + []u32{ 0xFFFFFFFE, 0x00000010, 0x0000000E }, + []u32{ 0xFFFFFFFE, 0x078644FA, 0x002AD6CA }, + []u32{ 0xFFFFFFFE, 0x0747AE14, 0x01333342 }, + []u32{ 0xFFFFFFFE, 0x7FFFFFFF, 0x00000000 }, + []u32{ 0xFFFFFFFE, 0x80000000, 0x7FFFFFFE }, + []u32{ 0xFFFFFFFE, 0xFFFFFFFD, 0x00000001 }, + []u32{ 0xFFFFFFFE, 0xFFFFFFFE, 0x00000000 }, + []u32{ 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFE }, + []u32{ 0xFFFFFFFF, 0x00000001, 0x00000000 }, + []u32{ 0xFFFFFFFF, 0x00000002, 0x00000001 }, + []u32{ 0xFFFFFFFF, 0x00000003, 0x00000000 }, + []u32{ 0xFFFFFFFF, 0x00000010, 0x0000000F }, + []u32{ 0xFFFFFFFF, 0x078644FA, 0x002AD6CB }, + []u32{ 0xFFFFFFFF, 0x0747AE14, 0x01333343 }, + []u32{ 0xFFFFFFFF, 0x7FFFFFFF, 0x00000001 }, + []u32{ 0xFFFFFFFF, 0x80000000, 0x7FFFFFFF }, + []u32{ 0xFFFFFFFF, 0xFFFFFFFD, 0x00000002 }, + []u32{ 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001 }, + []u32{ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, + }; + + for (cases) |case| { + test_one_umodsi3(case[0], case[1], case[2]); + } +} + +fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) void { + const r: u32 = __umodsi3(a, b); + testing.expect(r == expected_r); +} diff --git a/std/special/compiler_rt/addXf3.zig b/std/special/compiler_rt/addXf3.zig index 3a70461eca..5852f3e50d 100644 --- a/std/special/compiler_rt/addXf3.zig +++ b/std/special/compiler_rt/addXf3.zig @@ -78,8 +78,8 @@ fn addXf3(comptime T: type, a: T, b: T) T { const infRep = @bitCast(Z, std.math.inf(T)); // Detect if a or b is zero, infinity, or NaN. - if (aAbs - Z(1) >= infRep - Z(1) or - bAbs - Z(1) >= infRep - Z(1)) + if (aAbs -% Z(1) >= infRep - Z(1) or + bAbs -% Z(1) >= infRep - Z(1)) { // NaN + anything = qNaN if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); diff --git a/std/special/compiler_rt/arm/aeabi_dcmp.zig b/std/special/compiler_rt/arm/aeabi_dcmp.zig new file mode 100644 index 0000000000..a51d9854ce --- /dev/null +++ b/std/special/compiler_rt/arm/aeabi_dcmp.zig @@ -0,0 +1,108 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_dcmp.S + +const compiler_rt_armhf_target = false; // TODO + +const ConditionalOperator = enum { + Eq, + Lt, + Le, + Ge, + Gt, +}; + +pub nakedcc fn __aeabi_dcmpeq() noreturn { + @setRuntimeSafety(false); + aeabi_dcmp(.Eq); + unreachable; +} + +pub nakedcc fn __aeabi_dcmplt() noreturn { + @setRuntimeSafety(false); + aeabi_dcmp(.Lt); + unreachable; +} + +pub nakedcc fn __aeabi_dcmple() noreturn { + @setRuntimeSafety(false); + aeabi_dcmp(.Le); + unreachable; +} + +pub nakedcc fn __aeabi_dcmpge() noreturn { + @setRuntimeSafety(false); + aeabi_dcmp(.Ge); + unreachable; +} + +pub nakedcc fn __aeabi_dcmpgt() noreturn { + @setRuntimeSafety(false); + aeabi_dcmp(.Gt); + unreachable; +} + +inline fn convert_dcmp_args_to_df2_args() void { + asm volatile ( + \\ vmov d0, r0, r1 + \\ vmov d1, r2, r3 + ); +} + +inline fn aeabi_dcmp(comptime cond: ConditionalOperator) void { + @setRuntimeSafety(false); + asm volatile ( + \\ push { r4, lr } + ); + + if (compiler_rt_armhf_target) { + convert_dcmp_args_to_df2_args(); + } + + switch (cond) { + .Eq => asm volatile ( + \\ bl __eqdf2 + \\ cmp r0, #0 + \\ beq 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Lt => asm volatile ( + \\ bl __ltdf2 + \\ cmp r0, #0 + \\ blt 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Le => asm volatile ( + \\ bl __ledf2 + \\ cmp r0, #0 + \\ ble 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Ge => asm volatile ( + \\ bl __ltdf2 + \\ cmp r0, #0 + \\ bge 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Gt => asm volatile ( + \\ bl __gtdf2 + \\ cmp r0, #0 + \\ bgt 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + } + asm volatile ( + \\ movs r0, #1 + \\ pop { r4, pc } + ); +} diff --git a/std/special/compiler_rt/arm/aeabi_fcmp.zig b/std/special/compiler_rt/arm/aeabi_fcmp.zig new file mode 100644 index 0000000000..f82dd25270 --- /dev/null +++ b/std/special/compiler_rt/arm/aeabi_fcmp.zig @@ -0,0 +1,108 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_fcmp.S + +const compiler_rt_armhf_target = false; // TODO + +const ConditionalOperator = enum { + Eq, + Lt, + Le, + Ge, + Gt, +}; + +pub nakedcc fn __aeabi_fcmpeq() noreturn { + @setRuntimeSafety(false); + aeabi_fcmp(.Eq); + unreachable; +} + +pub nakedcc fn __aeabi_fcmplt() noreturn { + @setRuntimeSafety(false); + aeabi_fcmp(.Lt); + unreachable; +} + +pub nakedcc fn __aeabi_fcmple() noreturn { + @setRuntimeSafety(false); + aeabi_fcmp(.Le); + unreachable; +} + +pub nakedcc fn __aeabi_fcmpge() noreturn { + @setRuntimeSafety(false); + aeabi_fcmp(.Ge); + unreachable; +} + +pub nakedcc fn __aeabi_fcmpgt() noreturn { + @setRuntimeSafety(false); + aeabi_fcmp(.Gt); + unreachable; +} + +inline fn convert_fcmp_args_to_sf2_args() void { + asm volatile ( + \\ vmov s0, r0 + \\ vmov s1, r1 + ); +} + +inline fn aeabi_fcmp(comptime cond: ConditionalOperator) void { + @setRuntimeSafety(false); + asm volatile ( + \\ push { r4, lr } + ); + + if (compiler_rt_armhf_target) { + convert_fcmp_args_to_sf2_args(); + } + + switch (cond) { + .Eq => asm volatile ( + \\ bl __eqsf2 + \\ cmp r0, #0 + \\ beq 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Lt => asm volatile ( + \\ bl __ltsf2 + \\ cmp r0, #0 + \\ blt 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Le => asm volatile ( + \\ bl __lesf2 + \\ cmp r0, #0 + \\ ble 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Ge => asm volatile ( + \\ bl __ltsf2 + \\ cmp r0, #0 + \\ bge 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + .Gt => asm volatile ( + \\ bl __gtsf2 + \\ cmp r0, #0 + \\ bgt 1f + \\ movs r0, #0 + \\ pop { r4, pc } + \\ 1: + ), + } + asm volatile ( + \\ movs r0, #1 + \\ pop { r4, pc } + ); +} diff --git a/std/special/compiler_rt/ashlti3.zig b/std/special/compiler_rt/ashlti3.zig new file mode 100644 index 0000000000..65b23f22e5 --- /dev/null +++ b/std/special/compiler_rt/ashlti3.zig @@ -0,0 +1,41 @@ +const builtin = @import("builtin"); +const compiler_rt = @import("../compiler_rt.zig"); + +pub extern fn __ashlti3(a: i128, b: i32) i128 { + var input = twords{ .all = a }; + var result: twords = undefined; + + if (b > 63) { + // 64 <= b < 128 + result.s.low = 0; + result.s.high = input.s.low << @intCast(u6, b - 64); + } else { + // 0 <= b < 64 + if (b == 0) return a; + result.s.low = input.s.low << @intCast(u6, b); + result.s.high = input.s.low >> @intCast(u6, 64 - b); + result.s.high |= input.s.high << @intCast(u6, b); + } + + return result.all; +} + +const twords = extern union { + all: i128, + s: S, + + const S = if (builtin.endian == builtin.Endian.Little) + struct { + low: u64, + high: u64, + } + else + struct { + high: u64, + low: u64, + }; +}; + +test "import ashlti3" { + _ = @import("ashlti3_test.zig"); +} diff --git a/std/special/compiler_rt/ashlti3_test.zig b/std/special/compiler_rt/ashlti3_test.zig new file mode 100644 index 0000000000..4ba21c138e --- /dev/null +++ b/std/special/compiler_rt/ashlti3_test.zig @@ -0,0 +1,46 @@ +const __ashlti3 = @import("ashlti3.zig").__ashlti3; +const testing = @import("std").testing; + +fn test__ashlti3(a: i128, b: i32, expected: i128) void { + const x = __ashlti3(a, b); + testing.expect(x == expected); +} + +test "ashlti3" { + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, @bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, @bitCast(i128, @intCast(u128, 0xFDB97530ECA8642BFDB97530ECA8642A))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, @bitCast(i128, @intCast(u128, 0xFB72EA61D950C857FB72EA61D950C854))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, @bitCast(i128, @intCast(u128, 0xF6E5D4C3B2A190AFF6E5D4C3B2A190A8))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, @bitCast(i128, @intCast(u128, 0xEDCBA9876543215FEDCBA98765432150))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, @bitCast(i128, @intCast(u128, 0x876543215FEDCBA98765432150000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, @bitCast(i128, @intCast(u128, 0x0ECA8642BFDB97530ECA8642A0000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, @bitCast(i128, @intCast(u128, 0x1D950C857FB72EA61D950C8540000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, @bitCast(i128, @intCast(u128, 0x3B2A190AFF6E5D4C3B2A190A80000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, @bitCast(i128, @intCast(u128, 0x76543215FEDCBA987654321500000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, @bitCast(i128, @intCast(u128, 0xECA8642BFDB97530ECA8642A00000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, @bitCast(i128, @intCast(u128, 0xD950C857FB72EA61D950C85400000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, @bitCast(i128, @intCast(u128, 0xB2A190AFF6E5D4C3B2A190A800000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, @bitCast(i128, @intCast(u128, 0x6543215FEDCBA9876543215000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, @bitCast(i128, @intCast(u128, 0x5FEDCBA9876543215000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, @bitCast(i128, @intCast(u128, 0xBFDB97530ECA8642A000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, @bitCast(i128, @intCast(u128, 0x7FB72EA61D950C854000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, @bitCast(i128, @intCast(u128, 0xFF6E5D4C3B2A190A8000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, @bitCast(i128, @intCast(u128, 0xFEDCBA98765432150000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, @bitCast(i128, @intCast(u128, 0xFDB97530ECA8642A0000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, @bitCast(i128, @intCast(u128, 0xFB72EA61D950C8540000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, @bitCast(i128, @intCast(u128, 0xF6E5D4C3B2A190A80000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, @bitCast(i128, @intCast(u128, 0xEDCBA987654321500000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, @bitCast(i128, @intCast(u128, 0x87654321500000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, @bitCast(i128, @intCast(u128, 0x0ECA8642A00000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, @bitCast(i128, @intCast(u128, 0x1D950C85400000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, @bitCast(i128, @intCast(u128, 0x3B2A190A800000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, @bitCast(i128, @intCast(u128, 0x76543215000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, @bitCast(i128, @intCast(u128, 0xECA8642A000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, @bitCast(i128, @intCast(u128, 0xD950C854000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, @bitCast(i128, @intCast(u128, 0xB2A190A8000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, @bitCast(i128, @intCast(u128, 0x65432150000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, @bitCast(i128, @intCast(u128, 0x50000000000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, @bitCast(i128, @intCast(u128, 0xA0000000000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, @bitCast(i128, @intCast(u128, 0x40000000000000000000000000000000))); + test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, @bitCast(i128, @intCast(u128, 0x80000000000000000000000000000000))); +} diff --git a/std/special/compiler_rt/ashrti3.zig b/std/special/compiler_rt/ashrti3.zig new file mode 100644 index 0000000000..40ee89c3c4 --- /dev/null +++ b/std/special/compiler_rt/ashrti3.zig @@ -0,0 +1,42 @@ +const builtin = @import("builtin"); +const compiler_rt = @import("../compiler_rt.zig"); + +pub extern fn __ashrti3(a: i128, b: i32) i128 { + var input = twords{ .all = a }; + var result: twords = undefined; + + if (b > 63) { + // 64 <= b < 128 + result.s.low = input.s.high >> @intCast(u6, b - 64); + result.s.high = input.s.high >> 63; + } else { + // 0 <= b < 64 + if (b == 0) return a; + result.s.low = input.s.high << @intCast(u6, 64 - b); + // Avoid sign-extension here + result.s.low |= @bitCast(i64, @bitCast(u64, input.s.low) >> @intCast(u6, b)); + result.s.high = input.s.high >> @intCast(u6, b); + } + + return result.all; +} + +const twords = extern union { + all: i128, + s: S, + + const S = if (builtin.endian == builtin.Endian.Little) + struct { + low: i64, + high: i64, + } + else + struct { + high: i64, + low: i64, + }; +}; + +test "import ashrti3" { + _ = @import("ashrti3_test.zig"); +} diff --git a/std/special/compiler_rt/ashrti3_test.zig b/std/special/compiler_rt/ashrti3_test.zig new file mode 100644 index 0000000000..04ae5abd82 --- /dev/null +++ b/std/special/compiler_rt/ashrti3_test.zig @@ -0,0 +1,58 @@ +const __ashrti3 = @import("ashrti3.zig").__ashrti3; +const testing = @import("std").testing; + +fn test__ashrti3(a: i128, b: i32, expected: i128) void { + const x = __ashrti3(a, b); + // @import("std").debug.warn("got 0x{x}\nexp 0x{x}\n", @truncate(u64, +// @bitCast(u128, x) >> 64), @truncate(u64, @bitCast(u128, expected)) >> 64); + testing.expect(x == expected); +} + +test "ashrti3" { + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, @bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, @bitCast(i128, @intCast(u128, 0xFF6E5D4C3B2A190AFF6E5D4C3B2A190A))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, @bitCast(i128, @intCast(u128, 0xFFB72EA61D950C857FB72EA61D950C85))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, @bitCast(i128, @intCast(u128, 0xFFDB97530ECA8642BFDB97530ECA8642))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, @bitCast(i128, @intCast(u128, 0xFFEDCBA9876543215FEDCBA987654321))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, @bitCast(i128, @intCast(u128, 0xFFFFFFFFEDCBA9876543215FEDCBA987))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, @bitCast(i128, @intCast(u128, 0xFFFFFFFFF6E5D4C3B2A190AFF6E5D4C3))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFB72EA61D950C857FB72EA61))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFDB97530ECA8642BFDB97530))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFEDCBA9876543215FEDCBA98))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFF6E5D4C3B2A190AFF6E5D4C))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFB72EA61D950C857FB72EA6))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFDB97530ECA8642BFDB9753))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFEDCBA9876543215FEDCBA9))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFEDCBA9876543215F))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFF6E5D4C3B2A190AF))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFB72EA61D950C857))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFDB97530ECA8642B))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFEDCBA9876543215))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFF6E5D4C3B2A190A))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFB72EA61D950C85))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFDB97530ECA8642))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFEDCBA987654321))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFEDCBA987))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFF6E5D4C3))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFB72EA61))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFDB97530))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA98))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFF6E5D4C))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFB72EA6))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFDB9753))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA9))); + + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))); + test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))); +} diff --git a/std/special/compiler_rt/comparedf2.zig b/std/special/compiler_rt/comparedf2.zig new file mode 100644 index 0000000000..f97e2474be --- /dev/null +++ b/std/special/compiler_rt/comparedf2.zig @@ -0,0 +1,122 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparedf2.c + +const std = @import("std"); +const builtin = @import("builtin"); +const is_test = builtin.is_test; + +const fp_t = f64; +const rep_t = u64; +const srep_t = i64; + +const typeWidth = rep_t.bit_count; +const significandBits = std.math.floatMantissaBits(fp_t); +const exponentBits = std.math.floatExponentBits(fp_t); +const signBit = (rep_t(1) << (significandBits + exponentBits)); +const absMask = signBit - 1; +const implicitBit = rep_t(1) << significandBits; +const significandMask = implicitBit - 1; +const exponentMask = absMask ^ significandMask; +const infRep = @bitCast(rep_t, std.math.inf(fp_t)); + +// TODO https://github.com/ziglang/zig/issues/641 +// and then make the return types of some of these functions the enum instead of c_int +const LE_LESS = c_int(-1); +const LE_EQUAL = c_int(0); +const LE_GREATER = c_int(1); +const LE_UNORDERED = c_int(1); + +pub extern fn __ledf2(a: fp_t, b: fp_t) c_int { + @setRuntimeSafety(is_test); + const aInt: srep_t = @bitCast(srep_t, a); + const bInt: srep_t = @bitCast(srep_t, b); + const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask; + const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) { + return LE_LESS; + } else if (aInt == bInt) { + return LE_EQUAL; + } else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) { + return LE_LESS; + } else if (aInt == bInt) { + return LE_EQUAL; + } else return LE_GREATER; + } +} + +// TODO https://github.com/ziglang/zig/issues/641 +// and then make the return types of some of these functions the enum instead of c_int +const GE_LESS = c_int(-1); +const GE_EQUAL = c_int(0); +const GE_GREATER = c_int(1); +const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED + +pub extern fn __gedf2(a: fp_t, b: fp_t) c_int { + @setRuntimeSafety(is_test); + const aInt: srep_t = @bitCast(srep_t, a); + const bInt: srep_t = @bitCast(srep_t, b); + const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask; + const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask; + + if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) { + return GE_LESS; + } else if (aInt == bInt) { + return GE_EQUAL; + } else return GE_GREATER; + } else { + if (aInt > bInt) { + return GE_LESS; + } else if (aInt == bInt) { + return GE_EQUAL; + } else return GE_GREATER; + } +} + +pub extern fn __unorddf2(a: fp_t, b: fp_t) c_int { + @setRuntimeSafety(is_test); + const aAbs: rep_t = @bitCast(rep_t, a) & absMask; + const bAbs: rep_t = @bitCast(rep_t, b) & absMask; + return @boolToInt(aAbs > infRep or bAbs > infRep); +} + +pub extern fn __eqdf2(a: fp_t, b: fp_t) c_int { + return __ledf2(a, b); +} + +pub extern fn __ltdf2(a: fp_t, b: fp_t) c_int { + return __ledf2(a, b); +} + +pub extern fn __nedf2(a: fp_t, b: fp_t) c_int { + return __ledf2(a, b); +} + +pub extern fn __gtdf2(a: fp_t, b: fp_t) c_int { + return __gedf2(a, b); +} + +test "import comparedf2" { + _ = @import("comparedf2_test.zig"); +} diff --git a/std/special/compiler_rt/comparedf2_test.zig b/std/special/compiler_rt/comparedf2_test.zig new file mode 100644 index 0000000000..9c08389994 --- /dev/null +++ b/std/special/compiler_rt/comparedf2_test.zig @@ -0,0 +1,101 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparedf2_test.c + +const std = @import("std"); +const builtin = @import("builtin"); +const is_test = builtin.is_test; + +const comparedf2 = @import("comparedf2.zig"); + +const TestVector = struct { + a: f64, + b: f64, + eqReference: c_int, + geReference: c_int, + gtReference: c_int, + leReference: c_int, + ltReference: c_int, + neReference: c_int, + unReference: c_int, +}; + +fn test__cmpdf2(vector: TestVector) bool { + if (comparedf2.__eqdf2(vector.a, vector.b) != vector.eqReference) { + return false; + } + if (comparedf2.__gedf2(vector.a, vector.b) != vector.geReference) { + return false; + } + if (comparedf2.__gtdf2(vector.a, vector.b) != vector.gtReference) { + return false; + } + if (comparedf2.__ledf2(vector.a, vector.b) != vector.leReference) { + return false; + } + if (comparedf2.__ltdf2(vector.a, vector.b) != vector.ltReference) { + return false; + } + if (comparedf2.__nedf2(vector.a, vector.b) != vector.neReference) { + return false; + } + if (comparedf2.__unorddf2(vector.a, vector.b) != vector.unReference) { + return false; + } + return true; +} + +const arguments = []f64{ + std.math.nan(f64), + -std.math.inf(f64), + -0x1.fffffffffffffp1023, + -0x1.0000000000001p0 - 0x1.0000000000000p0, + -0x1.fffffffffffffp-1, + -0x1.0000000000000p-1022, + -0x0.fffffffffffffp-1022, + -0x0.0000000000001p-1022, + -0.0, + 0.0, + 0x0.0000000000001p-1022, + 0x0.fffffffffffffp-1022, + 0x1.0000000000000p-1022, + 0x1.fffffffffffffp-1, + 0x1.0000000000000p0, + 0x1.0000000000001p0, + 0x1.fffffffffffffp1023, + std.math.inf(f64), +}; + +fn generateVector(comptime a: f64, comptime b: f64) TestVector { + const leResult = if (a < b) -1 else if (a == b) 0 else 1; + const geResult = if (a > b) 1 else if (a == b) 0 else -1; + const unResult = if (a != a or b != b) 1 else 0; + return TestVector{ + .a = a, + .b = b, + .eqReference = leResult, + .geReference = geResult, + .gtReference = geResult, + .leReference = leResult, + .ltReference = leResult, + .neReference = leResult, + .unReference = unResult, + }; +} + +const test_vectors = init: { + @setEvalBranchQuota(10000); + var vectors: [arguments.len * arguments.len]TestVector = undefined; + for (arguments[0..]) |arg_i, i| { + for (arguments[0..]) |arg_j, j| { + vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j); + } + } + break :init vectors; +}; + +test "compare f64" { + for (test_vectors) |vector, i| { + std.testing.expect(test__cmpdf2(vector)); + } +} diff --git a/std/special/compiler_rt/comparesf2.zig b/std/special/compiler_rt/comparesf2.zig new file mode 100644 index 0000000000..e99e0bb3dd --- /dev/null +++ b/std/special/compiler_rt/comparesf2.zig @@ -0,0 +1,122 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c + +const std = @import("std"); +const builtin = @import("builtin"); +const is_test = builtin.is_test; + +const fp_t = f32; +const rep_t = u32; +const srep_t = i32; + +const typeWidth = rep_t.bit_count; +const significandBits = std.math.floatMantissaBits(fp_t); +const exponentBits = std.math.floatExponentBits(fp_t); +const signBit = (rep_t(1) << (significandBits + exponentBits)); +const absMask = signBit - 1; +const implicitBit = rep_t(1) << significandBits; +const significandMask = implicitBit - 1; +const exponentMask = absMask ^ significandMask; +const infRep = @bitCast(rep_t, std.math.inf(fp_t)); + +// TODO https://github.com/ziglang/zig/issues/641 +// and then make the return types of some of these functions the enum instead of c_int +const LE_LESS = c_int(-1); +const LE_EQUAL = c_int(0); +const LE_GREATER = c_int(1); +const LE_UNORDERED = c_int(1); + +pub extern fn __lesf2(a: fp_t, b: fp_t) c_int { + @setRuntimeSafety(is_test); + const aInt: srep_t = @bitCast(srep_t, a); + const bInt: srep_t = @bitCast(srep_t, b); + const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask; + const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) { + return LE_LESS; + } else if (aInt == bInt) { + return LE_EQUAL; + } else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) { + return LE_LESS; + } else if (aInt == bInt) { + return LE_EQUAL; + } else return LE_GREATER; + } +} + +// TODO https://github.com/ziglang/zig/issues/641 +// and then make the return types of some of these functions the enum instead of c_int +const GE_LESS = c_int(-1); +const GE_EQUAL = c_int(0); +const GE_GREATER = c_int(1); +const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED + +pub extern fn __gesf2(a: fp_t, b: fp_t) c_int { + @setRuntimeSafety(is_test); + const aInt: srep_t = @bitCast(srep_t, a); + const bInt: srep_t = @bitCast(srep_t, b); + const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask; + const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask; + + if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) { + return GE_LESS; + } else if (aInt == bInt) { + return GE_EQUAL; + } else return GE_GREATER; + } else { + if (aInt > bInt) { + return GE_LESS; + } else if (aInt == bInt) { + return GE_EQUAL; + } else return GE_GREATER; + } +} + +pub extern fn __unordsf2(a: fp_t, b: fp_t) c_int { + @setRuntimeSafety(is_test); + const aAbs: rep_t = @bitCast(rep_t, a) & absMask; + const bAbs: rep_t = @bitCast(rep_t, b) & absMask; + return @boolToInt(aAbs > infRep or bAbs > infRep); +} + +pub extern fn __eqsf2(a: fp_t, b: fp_t) c_int { + return __lesf2(a, b); +} + +pub extern fn __ltsf2(a: fp_t, b: fp_t) c_int { + return __lesf2(a, b); +} + +pub extern fn __nesf2(a: fp_t, b: fp_t) c_int { + return __lesf2(a, b); +} + +pub extern fn __gtsf2(a: fp_t, b: fp_t) c_int { + return __gesf2(a, b); +} + +test "import comparesf2" { + _ = @import("comparesf2_test.zig"); +} diff --git a/std/special/compiler_rt/comparesf2_test.zig b/std/special/compiler_rt/comparesf2_test.zig new file mode 100644 index 0000000000..e460634fad --- /dev/null +++ b/std/special/compiler_rt/comparesf2_test.zig @@ -0,0 +1,101 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparesf2_test.c + +const std = @import("std"); +const builtin = @import("builtin"); +const is_test = builtin.is_test; + +const comparesf2 = @import("comparesf2.zig"); + +const TestVector = struct { + a: f32, + b: f32, + eqReference: c_int, + geReference: c_int, + gtReference: c_int, + leReference: c_int, + ltReference: c_int, + neReference: c_int, + unReference: c_int, +}; + +fn test__cmpsf2(vector: TestVector) bool { + if (comparesf2.__eqsf2(vector.a, vector.b) != vector.eqReference) { + return false; + } + if (comparesf2.__gesf2(vector.a, vector.b) != vector.geReference) { + return false; + } + if (comparesf2.__gtsf2(vector.a, vector.b) != vector.gtReference) { + return false; + } + if (comparesf2.__lesf2(vector.a, vector.b) != vector.leReference) { + return false; + } + if (comparesf2.__ltsf2(vector.a, vector.b) != vector.ltReference) { + return false; + } + if (comparesf2.__nesf2(vector.a, vector.b) != vector.neReference) { + return false; + } + if (comparesf2.__unordsf2(vector.a, vector.b) != vector.unReference) { + return false; + } + return true; +} + +const arguments = []f32{ + std.math.nan(f32), + -std.math.inf(f32), + -0x1.fffffep127, + -0x1.000002p0 - 0x1.000000p0, + -0x1.fffffep-1, + -0x1.000000p-126, + -0x0.fffffep-126, + -0x0.000002p-126, + -0.0, + 0.0, + 0x0.000002p-126, + 0x0.fffffep-126, + 0x1.000000p-126, + 0x1.fffffep-1, + 0x1.000000p0, + 0x1.000002p0, + 0x1.fffffep127, + std.math.inf(f32), +}; + +fn generateVector(comptime a: f32, comptime b: f32) TestVector { + const leResult = if (a < b) -1 else if (a == b) 0 else 1; + const geResult = if (a > b) 1 else if (a == b) 0 else -1; + const unResult = if (a != a or b != b) 1 else 0; + return TestVector{ + .a = a, + .b = b, + .eqReference = leResult, + .geReference = geResult, + .gtReference = geResult, + .leReference = leResult, + .ltReference = leResult, + .neReference = leResult, + .unReference = unResult, + }; +} + +const test_vectors = init: { + @setEvalBranchQuota(10000); + var vectors: [arguments.len * arguments.len]TestVector = undefined; + for (arguments[0..]) |arg_i, i| { + for (arguments[0..]) |arg_j, j| { + vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j); + } + } + break :init vectors; +}; + +test "compare f32" { + for (test_vectors) |vector, i| { + std.testing.expect(test__cmpsf2(vector)); + } +} diff --git a/std/special/compiler_rt/divti3.zig b/std/special/compiler_rt/divti3.zig index e89a1ada5c..d5b2778a34 100644 --- a/std/special/compiler_rt/divti3.zig +++ b/std/special/compiler_rt/divti3.zig @@ -16,9 +16,9 @@ pub extern fn __divti3(a: i128, b: i128) i128 { return (@bitCast(i128, r) ^ s) -% s; } -pub extern fn __divti3_windows_x86_64(a: *const i128, b: *const i128) void { - @setRuntimeSafety(builtin.is_test); - compiler_rt.setXmm0(i128, __divti3(a.*, b.*)); +const v128 = @Vector(2, u64); +pub extern fn __divti3_windows_x86_64(a: v128, b: v128) v128 { + return @bitCast(v128, @inlineCall(__divti3, @bitCast(i128, a), @bitCast(i128, b))); } test "import divti3" { diff --git a/std/special/compiler_rt/extendXfYf2.zig b/std/special/compiler_rt/extendXfYf2.zig index 099e27b74a..42559784bb 100644 --- a/std/special/compiler_rt/extendXfYf2.zig +++ b/std/special/compiler_rt/extendXfYf2.zig @@ -2,21 +2,27 @@ const std = @import("std"); const builtin = @import("builtin"); const is_test = builtin.is_test; +pub extern fn __extendsfdf2(a: f32) f64 { + return @inlineCall(extendXfYf2, f64, f32, @bitCast(u32, a)); +} + pub extern fn __extenddftf2(a: f64) f128 { - return extendXfYf2(f128, f64, a); + return @inlineCall(extendXfYf2, f128, f64, @bitCast(u64, a)); } pub extern fn __extendsftf2(a: f32) f128 { - return extendXfYf2(f128, f32, a); + return @inlineCall(extendXfYf2, f128, f32, @bitCast(u32, a)); } pub extern fn __extendhfsf2(a: u16) f32 { - return extendXfYf2(f32, f16, @bitCast(f16, a)); + return @inlineCall(extendXfYf2, f32, f16, a); } const CHAR_BIT = 8; -inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { +fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: @IntType(false, @typeInfo(src_t).Float.bits)) dst_t { + @setRuntimeSafety(builtin.is_test); + const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits); const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); diff --git a/std/special/compiler_rt/floatdidf.zig b/std/special/compiler_rt/floatdidf.zig new file mode 100644 index 0000000000..1610136413 --- /dev/null +++ b/std/special/compiler_rt/floatdidf.zig @@ -0,0 +1,22 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const twop52: f64 = 0x1.0p52; +const twop32: f64 = 0x1.0p32; + +pub extern fn __floatdidf(a: i64) f64 { + @setRuntimeSafety(builtin.is_test); + + if (a == 0) return 0; + + var low = @bitCast(i64, twop52); + const high = @intToFloat(f64, @truncate(i32, a >> 32)) * twop32; + + low |= @bitCast(i64, a & 0xFFFFFFFF); + + return (high - twop52) + @bitCast(f64, low); +} + +test "import floatdidf" { + _ = @import("floatdidf_test.zig"); +} diff --git a/std/special/compiler_rt/floatdidf_test.zig b/std/special/compiler_rt/floatdidf_test.zig new file mode 100644 index 0000000000..c854183809 --- /dev/null +++ b/std/special/compiler_rt/floatdidf_test.zig @@ -0,0 +1,53 @@ +const __floatdidf = @import("floatdidf.zig").__floatdidf; +const testing = @import("std").testing; + +fn test__floatdidf(a: i64, expected: f64) void { + const r = __floatdidf(a); + testing.expect(r == expected); +} + +test "floatdidf" { + test__floatdidf(0, 0.0); + test__floatdidf(1, 1.0); + test__floatdidf(2, 2.0); + test__floatdidf(20, 20.0); + test__floatdidf(-1, -1.0); + test__floatdidf(-2, -2.0); + test__floatdidf(-20, -20.0); + test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); + test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000800)), -0x1.FFFFFFFFFFFFEp+62); + test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); + test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000001000)), -0x1.FFFFFFFFFFFFCp+62); + test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000000)), -0x1.000000p+63); + test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000001)), -0x1.000000p+63); + test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +} diff --git a/std/special/compiler_rt/floatsiXf.zig b/std/special/compiler_rt/floatsiXf.zig new file mode 100644 index 0000000000..83b3940c1e --- /dev/null +++ b/std/special/compiler_rt/floatsiXf.zig @@ -0,0 +1,109 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const maxInt = std.math.maxInt; + +fn floatsiXf(comptime T: type, a: i32) T { + @setRuntimeSafety(builtin.is_test); + + const Z = @IntType(false, T.bit_count); + const S = @IntType(false, T.bit_count - @clz(Z(T.bit_count) - 1)); + + if (a == 0) { + return T(0.0); + } + + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + const exponentBias = ((1 << exponentBits - 1) - 1); + + const implicitBit = Z(1) << significandBits; + const signBit = Z(1 << Z.bit_count - 1); + + const sign = a >> 31; + // Take absolute value of a via abs(x) = (x^(x >> 31)) - (x >> 31). + const abs_a = (a ^ sign) -% sign; + // The exponent is the width of abs(a) + const exp = Z(31 - @clz(abs_a)); + + const sign_bit = if (sign < 0) signBit else 0; + + var mantissa: Z = undefined; + // Shift a into the significand field and clear the implicit bit. + if (exp <= significandBits) { + // No rounding needed + const shift = @intCast(S, significandBits - exp); + mantissa = @intCast(Z, @bitCast(u32, abs_a)) << shift ^ implicitBit; + } else { + const shift = @intCast(S, exp - significandBits); + // Round to the nearest number after truncation + mantissa = @intCast(Z, @bitCast(u32, abs_a)) >> shift ^ implicitBit; + // Align to the left and check if the truncated part is halfway over + const round = @bitCast(u32, abs_a) << @intCast(u5, 31 - shift); + mantissa += @boolToInt(round > 0x80000000); + // Tie to even + mantissa += mantissa & 1; + } + + // Use the addition instead of a or since we may have a carry from the + // mantissa to the exponent + var result = mantissa; + result += (exp + exponentBias) << significandBits; + result += sign_bit; + + return @bitCast(T, result); +} + +pub extern fn __floatsisf(arg: i32) f32 { + @setRuntimeSafety(builtin.is_test); + return @inlineCall(floatsiXf, f32, arg); +} + +pub extern fn __floatsidf(arg: i32) f64 { + @setRuntimeSafety(builtin.is_test); + return @inlineCall(floatsiXf, f64, arg); +} + +pub extern fn __floatsitf(arg: i32) f128 { + @setRuntimeSafety(builtin.is_test); + return @inlineCall(floatsiXf, f128, arg); +} + +fn test_one_floatsitf(a: i32, expected: u128) void { + const r = __floatsitf(a); + std.testing.expect(@bitCast(u128, r) == expected); +} + +fn test_one_floatsidf(a: i32, expected: u64) void { + const r = __floatsidf(a); + std.testing.expect(@bitCast(u64, r) == expected); +} + +fn test_one_floatsisf(a: i32, expected: u32) void { + const r = __floatsisf(a); + std.testing.expect(@bitCast(u32, r) == expected); +} + +test "floatsidf" { + test_one_floatsidf(0, 0x0000000000000000); + test_one_floatsidf(1, 0x3ff0000000000000); + test_one_floatsidf(-1, 0xbff0000000000000); + test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); + test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000); +} + +test "floatsisf" { + test_one_floatsisf(0, 0x00000000); + test_one_floatsisf(1, 0x3f800000); + test_one_floatsisf(-1, 0xbf800000); + test_one_floatsisf(0x7FFFFFFF, 0x4f000000); + test_one_floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000); +} + +test "floatsitf" { + test_one_floatsitf(0, 0); + test_one_floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); + test_one_floatsitf(0x12345678, 0x401b2345678000000000000000000000); + test_one_floatsitf(-0x12345678, 0xc01b2345678000000000000000000000); + test_one_floatsitf(@bitCast(i32, @intCast(u32, 0xffffffff)), 0xbfff0000000000000000000000000000); + test_one_floatsitf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc01e0000000000000000000000000000); +} diff --git a/std/special/compiler_rt/floatundidf.zig b/std/special/compiler_rt/floatundidf.zig new file mode 100644 index 0000000000..68759a2acd --- /dev/null +++ b/std/special/compiler_rt/floatundidf.zig @@ -0,0 +1,24 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const twop52: f64 = 0x1.0p52; +const twop84: f64 = 0x1.0p84; +const twop84_plus_twop52: f64 = 0x1.00000001p84; + +pub extern fn __floatundidf(a: u64) f64 { + @setRuntimeSafety(builtin.is_test); + + if (a == 0) return 0; + + var high = @bitCast(u64, twop84); + var low = @bitCast(u64, twop52); + + high |= a >> 32; + low |= a & 0xFFFFFFFF; + + return (@bitCast(f64, high) - twop84_plus_twop52) + @bitCast(f64, low); +} + +test "import floatundidf" { + _ = @import("floatundidf_test.zig"); +} diff --git a/std/special/compiler_rt/floatundidf_test.zig b/std/special/compiler_rt/floatundidf_test.zig new file mode 100644 index 0000000000..084ada51c9 --- /dev/null +++ b/std/special/compiler_rt/floatundidf_test.zig @@ -0,0 +1,50 @@ +const __floatundidf = @import("floatundidf.zig").__floatundidf; +const testing = @import("std").testing; + +fn test__floatundidf(a: u64, expected: f64) void { + const r = __floatundidf(a); + testing.expect(r == expected); +} + +test "floatundidf" { + test__floatundidf(0, 0.0); + test__floatundidf(1, 1.0); + test__floatundidf(2, 2.0); + test__floatundidf(20, 20.0); + test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + test__floatundidf(0x8000008000000000, 0x1.000001p+63); + test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63); + test__floatundidf(0x8000010000000000, 0x1.000002p+63); + test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63); + test__floatundidf(0x8000000000000000, 0x1p+63); + test__floatundidf(0x8000000000000001, 0x1p+63); + test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +} diff --git a/std/special/compiler_rt/floatunsidf.zig b/std/special/compiler_rt/floatunsidf.zig new file mode 100644 index 0000000000..db02894448 --- /dev/null +++ b/std/special/compiler_rt/floatunsidf.zig @@ -0,0 +1,33 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const maxInt = std.math.maxInt; + +const implicitBit = u64(1) << 52; + +pub extern fn __floatunsidf(arg: u32) f64 { + @setRuntimeSafety(builtin.is_test); + + if (arg == 0) return 0.0; + + // The exponent is the width of abs(a) + const exp = u64(31) - @clz(arg); + // Shift a into the significand field and clear the implicit bit + const shift = @intCast(u6, 52 - exp); + const mant = u64(arg) << shift ^ implicitBit; + + return @bitCast(f64, mant | (exp + 1023) << 52); +} + +fn test_one_floatunsidf(a: u32, expected: u64) void { + const r = __floatunsidf(a); + std.testing.expect(@bitCast(u64, r) == expected); +} + +test "floatsidf" { + // Test the produced bit pattern + test_one_floatunsidf(0, 0x0000000000000000); + test_one_floatunsidf(1, 0x3ff0000000000000); + test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000); + test_one_floatunsidf(@intCast(u32, 0x80000000), 0x41e0000000000000); + test_one_floatunsidf(@intCast(u32, 0xFFFFFFFF), 0x41efffffffe00000); +} diff --git a/std/special/compiler_rt/lshrti3.zig b/std/special/compiler_rt/lshrti3.zig new file mode 100644 index 0000000000..329968ae40 --- /dev/null +++ b/std/special/compiler_rt/lshrti3.zig @@ -0,0 +1,41 @@ +const builtin = @import("builtin"); +const compiler_rt = @import("../compiler_rt.zig"); + +pub extern fn __lshrti3(a: i128, b: i32) i128 { + var input = twords{ .all = a }; + var result: twords = undefined; + + if (b > 63) { + // 64 <= b < 128 + result.s.low = input.s.high >> @intCast(u6, b - 64); + result.s.high = 0; + } else { + // 0 <= b < 64 + if (b == 0) return a; + result.s.low = input.s.high << @intCast(u6, 64 - b); + result.s.low |= input.s.low >> @intCast(u6, b); + result.s.high = input.s.high >> @intCast(u6, b); + } + + return result.all; +} + +const twords = extern union { + all: i128, + s: S, + + const S = if (builtin.endian == builtin.Endian.Little) + struct { + low: u64, + high: u64, + } + else + struct { + high: u64, + low: u64, + }; +}; + +test "import lshrti3" { + _ = @import("lshrti3_test.zig"); +} diff --git a/std/special/compiler_rt/lshrti3_test.zig b/std/special/compiler_rt/lshrti3_test.zig new file mode 100644 index 0000000000..60f83d816e --- /dev/null +++ b/std/special/compiler_rt/lshrti3_test.zig @@ -0,0 +1,46 @@ +const __lshrti3 = @import("lshrti3.zig").__lshrti3; +const testing = @import("std").testing; + +fn test__lshrti3(a: i128, b: i32, expected: i128) void { + const x = __lshrti3(a, b); + testing.expect(x == expected); +} + +test "lshrti3" { + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, @bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, @bitCast(i128, @intCast(u128, 0x7F6E5D4C3B2A190AFF6E5D4C3B2A190A))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, @bitCast(i128, @intCast(u128, 0x3FB72EA61D950C857FB72EA61D950C85))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, @bitCast(i128, @intCast(u128, 0x1FDB97530ECA8642BFDB97530ECA8642))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, @bitCast(i128, @intCast(u128, 0x0FEDCBA9876543215FEDCBA987654321))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, @bitCast(i128, @intCast(u128, 0x0000000FEDCBA9876543215FEDCBA987))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, @bitCast(i128, @intCast(u128, 0x00000007F6E5D4C3B2A190AFF6E5D4C3))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, @bitCast(i128, @intCast(u128, 0x00000003FB72EA61D950C857FB72EA61))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, @bitCast(i128, @intCast(u128, 0x00000001FDB97530ECA8642BFDB97530))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, @bitCast(i128, @intCast(u128, 0x00000000FEDCBA9876543215FEDCBA98))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, @bitCast(i128, @intCast(u128, 0x000000007F6E5D4C3B2A190AFF6E5D4C))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, @bitCast(i128, @intCast(u128, 0x000000003FB72EA61D950C857FB72EA6))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, @bitCast(i128, @intCast(u128, 0x000000001FDB97530ECA8642BFDB9753))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, @bitCast(i128, @intCast(u128, 0x000000000FEDCBA9876543215FEDCBA9))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, @bitCast(i128, @intCast(u128, 0x000000000000000FEDCBA9876543215F))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, @bitCast(i128, @intCast(u128, 0x0000000000000007F6E5D4C3B2A190AF))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, @bitCast(i128, @intCast(u128, 0x0000000000000003FB72EA61D950C857))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, @bitCast(i128, @intCast(u128, 0x0000000000000001FDB97530ECA8642B))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, @bitCast(i128, @intCast(u128, 0x0000000000000000FEDCBA9876543215))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, @bitCast(i128, @intCast(u128, 0x00000000000000007F6E5D4C3B2A190A))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, @bitCast(i128, @intCast(u128, 0x00000000000000003FB72EA61D950C85))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, @bitCast(i128, @intCast(u128, 0x00000000000000001FDB97530ECA8642))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, @bitCast(i128, @intCast(u128, 0x00000000000000000FEDCBA987654321))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, @bitCast(i128, @intCast(u128, 0x00000000000000000000000FEDCBA987))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, @bitCast(i128, @intCast(u128, 0x000000000000000000000007F6E5D4C3))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, @bitCast(i128, @intCast(u128, 0x000000000000000000000003FB72EA61))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, @bitCast(i128, @intCast(u128, 0x000000000000000000000001FDB97530))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, @bitCast(i128, @intCast(u128, 0x000000000000000000000000FEDCBA98))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, @bitCast(i128, @intCast(u128, 0x0000000000000000000000007F6E5D4C))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, @bitCast(i128, @intCast(u128, 0x0000000000000000000000003FB72EA6))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, @bitCast(i128, @intCast(u128, 0x0000000000000000000000001FDB9753))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, @bitCast(i128, @intCast(u128, 0x0000000000000000000000000FEDCBA9))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, @bitCast(i128, @intCast(u128, 0x0000000000000000000000000000000F))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, @bitCast(i128, @intCast(u128, 0x00000000000000000000000000000007))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, @bitCast(i128, @intCast(u128, 0x00000000000000000000000000000003))); + test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, @bitCast(i128, @intCast(u128, 0x00000000000000000000000000000001))); +} diff --git a/std/special/compiler_rt/modti3.zig b/std/special/compiler_rt/modti3.zig index 03222cadf5..16f2f38ba3 100644 --- a/std/special/compiler_rt/modti3.zig +++ b/std/special/compiler_rt/modti3.zig @@ -20,9 +20,9 @@ pub extern fn __modti3(a: i128, b: i128) i128 { return (@bitCast(i128, r) ^ s_a) -% s_a; // negate if s == -1 } -pub extern fn __modti3_windows_x86_64(a: *const i128, b: *const i128) void { - @setRuntimeSafety(builtin.is_test); - compiler_rt.setXmm0(i128, __modti3(a.*, b.*)); +const v128 = @Vector(2, u64); +pub extern fn __modti3_windows_x86_64(a: v128, b: v128) v128 { + return @bitCast(v128, @inlineCall(__modti3, @bitCast(i128, a), @bitCast(i128, b))); } test "import modti3" { diff --git a/std/special/compiler_rt/mulodi4.zig b/std/special/compiler_rt/mulodi4.zig new file mode 100644 index 0000000000..82e9ef3253 --- /dev/null +++ b/std/special/compiler_rt/mulodi4.zig @@ -0,0 +1,44 @@ +const builtin = @import("builtin"); +const compiler_rt = @import("../compiler_rt.zig"); +const maxInt = std.math.maxInt; +const minInt = std.math.minInt; + +pub extern fn __mulodi4(a: i64, b: i64, overflow: *c_int) i64 { + @setRuntimeSafety(builtin.is_test); + + const min = @bitCast(i64, u64(1 << (i64.bit_count - 1))); + const max = ~min; + + overflow.* = 0; + const result = a *% b; + + // Edge cases + if (a == min) { + if (b != 0 and b != 1) overflow.* = 1; + return result; + } + if (b == min) { + if (a != 0 and a != 1) overflow.* = 1; + return result; + } + + // Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63). + const abs_a = (a ^ (a >> 63)) -% (a >> 63); + const abs_b = (b ^ (b >> 63)) -% (b >> 63); + + // Unitary magnitude, cannot have overflow + if (abs_a < 2 or abs_b < 2) return result; + + // Compare the signs of the operands + if ((a ^ b) >> 63 != 0) { + if (abs_a > @divTrunc(max, abs_b)) overflow.* = 1; + } else { + if (abs_a > @divTrunc(min, -abs_b)) overflow.* = 1; + } + + return result; +} + +test "import mulodi4" { + _ = @import("mulodi4_test.zig"); +} diff --git a/std/special/compiler_rt/mulodi4_test.zig b/std/special/compiler_rt/mulodi4_test.zig new file mode 100644 index 0000000000..7575c77044 --- /dev/null +++ b/std/special/compiler_rt/mulodi4_test.zig @@ -0,0 +1,85 @@ +const __mulodi4 = @import("mulodi4.zig").__mulodi4; +const testing = @import("std").testing; + +fn test__mulodi4(a: i64, b: i64, expected: i64, expected_overflow: c_int) void { + var overflow: c_int = undefined; + const x = __mulodi4(a, b, &overflow); + testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); +} + +test "mulodi4" { + test__mulodi4(0, 0, 0, 0); + test__mulodi4(0, 1, 0, 0); + test__mulodi4(1, 0, 0, 0); + test__mulodi4(0, 10, 0, 0); + test__mulodi4(10, 0, 0, 0); + test__mulodi4(0, 81985529216486895, 0, 0); + test__mulodi4(81985529216486895, 0, 0, 0); + + test__mulodi4(0, -1, 0, 0); + test__mulodi4(-1, 0, 0, 0); + test__mulodi4(0, -10, 0, 0); + test__mulodi4(-10, 0, 0, 0); + test__mulodi4(0, -81985529216486895, 0, 0); + test__mulodi4(-81985529216486895, 0, 0, 0); + + test__mulodi4(1, 1, 1, 0); + test__mulodi4(1, 10, 10, 0); + test__mulodi4(10, 1, 10, 0); + test__mulodi4(1, 81985529216486895, 81985529216486895, 0); + test__mulodi4(81985529216486895, 1, 81985529216486895, 0); + + test__mulodi4(1, -1, -1, 0); + test__mulodi4(1, -10, -10, 0); + test__mulodi4(-10, 1, -10, 0); + test__mulodi4(1, -81985529216486895, -81985529216486895, 0); + test__mulodi4(-81985529216486895, 1, -81985529216486895, 0); + + test__mulodi4(3037000499, 3037000499, 9223372030926249001, 0); + test__mulodi4(-3037000499, 3037000499, -9223372030926249001, 0); + test__mulodi4(3037000499, -3037000499, -9223372030926249001, 0); + test__mulodi4(-3037000499, -3037000499, 9223372030926249001, 0); + + test__mulodi4(4398046511103, 2097152, 9223372036852678656, 0); + test__mulodi4(-4398046511103, 2097152, -9223372036852678656, 0); + test__mulodi4(4398046511103, -2097152, -9223372036852678656, 0); + test__mulodi4(-4398046511103, -2097152, 9223372036852678656, 0); + + test__mulodi4(2097152, 4398046511103, 9223372036852678656, 0); + test__mulodi4(-2097152, 4398046511103, -9223372036852678656, 0); + test__mulodi4(2097152, -4398046511103, -9223372036852678656, 0); + test__mulodi4(-2097152, -4398046511103, 9223372036852678656, 0); + + test__mulodi4(0x7FFFFFFFFFFFFFFF, -2, 2, 1); + test__mulodi4(-2, 0x7FFFFFFFFFFFFFFF, 2, 1); + test__mulodi4(0x7FFFFFFFFFFFFFFF, -1, @bitCast(i64, u64(0x8000000000000001)), 0); + test__mulodi4(-1, 0x7FFFFFFFFFFFFFFF, @bitCast(i64, u64(0x8000000000000001)), 0); + test__mulodi4(0x7FFFFFFFFFFFFFFF, 0, 0, 0); + test__mulodi4(0, 0x7FFFFFFFFFFFFFFF, 0, 0); + test__mulodi4(0x7FFFFFFFFFFFFFFF, 1, 0x7FFFFFFFFFFFFFFF, 0); + test__mulodi4(1, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0); + test__mulodi4(0x7FFFFFFFFFFFFFFF, 2, @bitCast(i64, u64(0x8000000000000001)), 1); + test__mulodi4(2, 0x7FFFFFFFFFFFFFFF, @bitCast(i64, u64(0x8000000000000001)), 1); + + test__mulodi4(@bitCast(i64, u64(0x8000000000000000)), -2, @bitCast(i64, u64(0x8000000000000000)), 1); + test__mulodi4(-2, @bitCast(i64, u64(0x8000000000000000)), @bitCast(i64, u64(0x8000000000000000)), 1); + test__mulodi4(@bitCast(i64, u64(0x8000000000000000)), -1, @bitCast(i64, u64(0x8000000000000000)), 1); + test__mulodi4(-1, @bitCast(i64, u64(0x8000000000000000)), @bitCast(i64, u64(0x8000000000000000)), 1); + test__mulodi4(@bitCast(i64, u64(0x8000000000000000)), 0, 0, 0); + test__mulodi4(0, @bitCast(i64, u64(0x8000000000000000)), 0, 0); + test__mulodi4(@bitCast(i64, u64(0x8000000000000000)), 1, @bitCast(i64, u64(0x8000000000000000)), 0); + test__mulodi4(1, @bitCast(i64, u64(0x8000000000000000)), @bitCast(i64, u64(0x8000000000000000)), 0); + test__mulodi4(@bitCast(i64, u64(0x8000000000000000)), 2, @bitCast(i64, u64(0x8000000000000000)), 1); + test__mulodi4(2, @bitCast(i64, u64(0x8000000000000000)), @bitCast(i64, u64(0x8000000000000000)), 1); + + test__mulodi4(@bitCast(i64, u64(0x8000000000000001)), -2, @bitCast(i64, u64(0x8000000000000001)), 1); + test__mulodi4(-2, @bitCast(i64, u64(0x8000000000000001)), @bitCast(i64, u64(0x8000000000000001)), 1); + test__mulodi4(@bitCast(i64, u64(0x8000000000000001)), -1, 0x7FFFFFFFFFFFFFFF, 0); + test__mulodi4(-1, @bitCast(i64, u64(0x8000000000000001)), 0x7FFFFFFFFFFFFFFF, 0); + test__mulodi4(@bitCast(i64, u64(0x8000000000000001)), 0, 0, 0); + test__mulodi4(0, @bitCast(i64, u64(0x8000000000000001)), 0, 0); + test__mulodi4(@bitCast(i64, u64(0x8000000000000001)), 1, @bitCast(i64, u64(0x8000000000000001)), 0); + test__mulodi4(1, @bitCast(i64, u64(0x8000000000000001)), @bitCast(i64, u64(0x8000000000000001)), 0); + test__mulodi4(@bitCast(i64, u64(0x8000000000000001)), 2, @bitCast(i64, u64(0x8000000000000000)), 1); + test__mulodi4(2, @bitCast(i64, u64(0x8000000000000001)), @bitCast(i64, u64(0x8000000000000000)), 1); +} diff --git a/std/special/compiler_rt/muloti4.zig b/std/special/compiler_rt/muloti4.zig index fd6855072b..ccde8e3e6c 100644 --- a/std/special/compiler_rt/muloti4.zig +++ b/std/special/compiler_rt/muloti4.zig @@ -1,4 +1,3 @@ -const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); @@ -33,11 +32,11 @@ pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 { } if (sa == sb) { - if (abs_a > @divFloor(max, abs_b)) { + if (abs_a > @divTrunc(max, abs_b)) { overflow.* = 1; } } else { - if (abs_a > @divFloor(min, -abs_b)) { + if (abs_a > @divTrunc(min, -abs_b)) { overflow.* = 1; } } @@ -45,11 +44,6 @@ pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 { return r; } -pub extern fn __muloti4_windows_x86_64(a: *const i128, b: *const i128, overflow: *c_int) void { - @setRuntimeSafety(builtin.is_test); - compiler_rt.setXmm0(i128, __muloti4(a.*, b.*, overflow)); -} - test "import muloti4" { _ = @import("muloti4_test.zig"); } diff --git a/std/special/compiler_rt/multi3.zig b/std/special/compiler_rt/multi3.zig index a0c84adaf4..799b1f575d 100644 --- a/std/special/compiler_rt/multi3.zig +++ b/std/special/compiler_rt/multi3.zig @@ -14,9 +14,9 @@ pub extern fn __multi3(a: i128, b: i128) i128 { return r.all; } -pub extern fn __multi3_windows_x86_64(a: *const i128, b: *const i128) void { - @setRuntimeSafety(builtin.is_test); - compiler_rt.setXmm0(i128, __multi3(a.*, b.*)); +const v128 = @Vector(2, u64); +pub extern fn __multi3_windows_x86_64(a: v128, b: v128) v128 { + return @bitCast(v128, @inlineCall(__multi3, @bitCast(i128, a), @bitCast(i128, b))); } fn __mulddi3(a: u64, b: u64) i128 { diff --git a/std/special/compiler_rt/stack_probe.zig b/std/special/compiler_rt/stack_probe.zig new file mode 100644 index 0000000000..71a349d2a8 --- /dev/null +++ b/std/special/compiler_rt/stack_probe.zig @@ -0,0 +1,206 @@ +const builtin = @import("builtin"); + +// Zig's own stack-probe routine (available only on x86 and x86_64) +pub nakedcc fn zig_probe_stack() void { + @setRuntimeSafety(false); + + // Versions of the Linux kernel before 5.1 treat any access below SP as + // invalid so let's update it on the go, otherwise we'll get a segfault + // instead of triggering the stack growth. + + switch (builtin.arch) { + .x86_64 => { + // %rax = probe length, %rsp = stack pointer + asm volatile ( + \\ push %%rcx + \\ mov %%rax, %%rcx + \\ cmp $0x1000,%%rcx + \\ jb 2f + \\ 1: + \\ sub $0x1000,%%rsp + \\ orl $0,16(%%rsp) + \\ sub $0x1000,%%rcx + \\ cmp $0x1000,%%rcx + \\ ja 1b + \\ 2: + \\ sub %%rcx, %%rsp + \\ orl $0,16(%%rsp) + \\ add %%rax,%%rsp + \\ pop %%rcx + \\ ret + ); + }, + .i386 => { + // %eax = probe length, %esp = stack pointer + asm volatile ( + \\ push %%ecx + \\ mov %%eax, %%ecx + \\ cmp $0x1000,%%ecx + \\ jb 2f + \\ 1: + \\ sub $0x1000,%%esp + \\ orl $0,8(%%esp) + \\ sub $0x1000,%%ecx + \\ cmp $0x1000,%%ecx + \\ ja 1b + \\ 2: + \\ sub %%ecx, %%esp + \\ orl $0,8(%%esp) + \\ add %%eax,%%esp + \\ pop %%ecx + \\ ret + ); + }, + else => { } + } + + unreachable; +} + +fn win_probe_stack_only() void { + @setRuntimeSafety(false); + + switch (builtin.arch) { + .x86_64 => { + asm volatile ( + \\ push %%rcx + \\ push %%rax + \\ cmp $0x1000,%%rax + \\ lea 24(%%rsp),%%rcx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\ 1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ pop %%rax + \\ pop %%rcx + \\ ret + ); + }, + .i386 => { + asm volatile ( + \\ push %%ecx + \\ push %%eax + \\ cmp $0x1000,%%eax + \\ lea 12(%%esp),%%ecx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%ecx + \\ test %%ecx,(%%ecx) + \\ sub $0x1000,%%eax + \\ cmp $0x1000,%%eax + \\ ja 2b + \\ 1: + \\ sub %%eax,%%ecx + \\ test %%ecx,(%%ecx) + \\ pop %%eax + \\ pop %%ecx + \\ ret + ); + }, + else => { } + } + + unreachable; +} + +fn win_probe_stack_adjust_sp() void { + @setRuntimeSafety(false); + + switch (builtin.arch) { + .x86_64 => { + asm volatile ( + \\ push %%rcx + \\ cmp $0x1000,%%rax + \\ lea 16(%%rsp),%%rcx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\ 1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ + \\ lea 8(%%rsp),%%rax + \\ mov %%rcx,%%rsp + \\ mov -8(%%rax),%%rcx + \\ push (%%rax) + \\ sub %%rsp,%%rax + \\ ret + ); + }, + .i386 => { + asm volatile ( + \\ push %%ecx + \\ cmp $0x1000,%%eax + \\ lea 8(%%esp),%%ecx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%ecx + \\ test %%ecx,(%%ecx) + \\ sub $0x1000,%%eax + \\ cmp $0x1000,%%eax + \\ ja 2b + \\ 1: + \\ sub %%eax,%%ecx + \\ test %%ecx,(%%ecx) + \\ + \\ lea 4(%%esp),%%eax + \\ mov %%ecx,%%esp + \\ mov -4(%%eax),%%ecx + \\ push (%%eax) + \\ sub %%esp,%%eax + \\ ret + ); + }, + else => { }, + } + + unreachable; +} + +// Windows has a multitude of stack-probing functions with similar names and +// slightly different behaviours: some behave as alloca() and update the stack +// pointer after probing the stack, other do not. +// +// Function name | Adjusts the SP? | +// | x86 | x86_64 | +// ---------------------------------------- +// _chkstk (_alloca) | yes | yes | +// __chkstk | yes | no | +// __chkstk_ms | no | no | +// ___chkstk (__alloca) | yes | yes | +// ___chkstk_ms | no | no | + +pub nakedcc fn _chkstk() void { + @setRuntimeSafety(false); + @inlineCall(win_probe_stack_adjust_sp); +} +pub nakedcc fn __chkstk() void { + @setRuntimeSafety(false); + switch (builtin.arch) { + .i386 => @inlineCall(win_probe_stack_adjust_sp), + .x86_64 => @inlineCall(win_probe_stack_only), + else => unreachable + } +} +pub nakedcc fn ___chkstk() void { + @setRuntimeSafety(false); + @inlineCall(win_probe_stack_adjust_sp); +} +pub nakedcc fn __chkstk_ms() void { + @setRuntimeSafety(false); + @inlineCall(win_probe_stack_only); +} +pub nakedcc fn ___chkstk_ms() void { + @setRuntimeSafety(false); + @inlineCall(win_probe_stack_only); +} diff --git a/std/special/compiler_rt/truncXfYf2.zig b/std/special/compiler_rt/truncXfYf2.zig index b385090a93..e4c4aa38a7 100644 --- a/std/special/compiler_rt/truncXfYf2.zig +++ b/std/special/compiler_rt/truncXfYf2.zig @@ -16,6 +16,10 @@ pub extern fn __trunctfdf2(a: f128) f64 { return truncXfYf2(f64, f128, a); } +pub extern fn __truncdfsf2(a: f64) f32 { + return truncXfYf2(f32, f64, a); +} + inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits); const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits); diff --git a/std/special/compiler_rt/truncXfYf2_test.zig b/std/special/compiler_rt/truncXfYf2_test.zig index 429372c3f1..eccf7efb7e 100644 --- a/std/special/compiler_rt/truncXfYf2_test.zig +++ b/std/special/compiler_rt/truncXfYf2_test.zig @@ -200,3 +200,40 @@ test "trunctfdf2" { test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); } + +const __truncdfsf2 = @import("truncXfYf2.zig").__truncdfsf2; + +fn test__truncdfsf2(a: f64, expected: u32) void { + const x = __truncdfsf2(a); + + const rep = @bitCast(u32, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7fc00000) { + if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { + return; + } + } + + @import("std").debug.warn("got 0x{x} wanted 0x{x}\n", rep, expected); + + @panic("__trunctfsf2 test failure"); +} + +test "truncdfsf2" { + // nan & qnan + test__truncdfsf2(@bitCast(f64, u64(0x7ff8000000000000)), 0x7fc00000); + test__truncdfsf2(@bitCast(f64, u64(0x7ff0000000000001)), 0x7fc00000); + // inf + test__truncdfsf2(@bitCast(f64, u64(0x7ff0000000000000)), 0x7f800000); + test__truncdfsf2(@bitCast(f64, u64(0xfff0000000000000)), 0xff800000); + + test__truncdfsf2(0.0, 0x0); + test__truncdfsf2(1.0, 0x3f800000); + test__truncdfsf2(-1.0, 0xbf800000); + + // huge number becomes inf + test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); +} diff --git a/std/special/compiler_rt/udivmodti4.zig b/std/special/compiler_rt/udivmodti4.zig index 6a037d3bae..c74dff512d 100644 --- a/std/special/compiler_rt/udivmodti4.zig +++ b/std/special/compiler_rt/udivmodti4.zig @@ -7,9 +7,10 @@ pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) u128 { return udivmod(u128, a, b, maybe_rem); } -pub extern fn __udivmodti4_windows_x86_64(a: *const u128, b: *const u128, maybe_rem: ?*u128) void { +const v128 = @Vector(2, u64); +pub extern fn __udivmodti4_windows_x86_64(a: v128, b: v128, maybe_rem: ?*u128) v128 { @setRuntimeSafety(builtin.is_test); - compiler_rt.setXmm0(u128, udivmod(u128, a.*, b.*, maybe_rem)); + return @bitCast(v128, udivmod(u128, @bitCast(u128, a), @bitCast(u128, b), maybe_rem)); } test "import udivmodti4" { diff --git a/std/special/compiler_rt/udivti3.zig b/std/special/compiler_rt/udivti3.zig index 510e21ac1d..ab451859bf 100644 --- a/std/special/compiler_rt/udivti3.zig +++ b/std/special/compiler_rt/udivti3.zig @@ -6,7 +6,8 @@ pub extern fn __udivti3(a: u128, b: u128) u128 { return udivmodti4.__udivmodti4(a, b, null); } -pub extern fn __udivti3_windows_x86_64(a: *const u128, b: *const u128) void { +const v128 = @Vector(2, u64); +pub extern fn __udivti3_windows_x86_64(a: v128, b: v128) v128 { @setRuntimeSafety(builtin.is_test); - udivmodti4.__udivmodti4_windows_x86_64(a, b, null); + return udivmodti4.__udivmodti4_windows_x86_64(a, b, null); } diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig index 12aca8b036..7add0b2ffe 100644 --- a/std/special/compiler_rt/umodti3.zig +++ b/std/special/compiler_rt/umodti3.zig @@ -9,7 +9,7 @@ pub extern fn __umodti3(a: u128, b: u128) u128 { return r; } -pub extern fn __umodti3_windows_x86_64(a: *const u128, b: *const u128) void { - @setRuntimeSafety(builtin.is_test); - compiler_rt.setXmm0(u128, __umodti3(a.*, b.*)); +const v128 = @Vector(2, u64); +pub extern fn __umodti3_windows_x86_64(a: v128, b: v128) v128 { + return @bitCast(v128, @inlineCall(__umodti3, @bitCast(u128, a), @bitCast(u128, b))); } diff --git a/std/special/panic.zig b/std/special/panic.zig index 7cb7143955..40b1d5e7fe 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -9,10 +9,15 @@ const std = @import("std"); pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { @setCold(true); switch (builtin.os) { - // TODO: fix panic in zen. + // TODO: fix panic in zen builtin.Os.freestanding, builtin.Os.zen => { while (true) {} }, + builtin.Os.wasi => { + std.debug.warn("{}", msg); + _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); + unreachable; + }, builtin.Os.uefi => { // TODO look into using the debug info and logging helpful messages std.os.abort(); diff --git a/std/special/test_runner.zig b/std/special/test_runner.zig index 36b098bd61..db01293059 100644 --- a/std/special/test_runner.zig +++ b/std/special/test_runner.zig @@ -8,7 +8,7 @@ pub fn main() !void { var ok_count: usize = 0; var skip_count: usize = 0; for (test_fn_list) |test_fn, i| { - warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name); + warn("{}/{} {}...", i + 1, test_fn_list.len, test_fn.name); if (test_fn.func()) |_| { ok_count += 1; diff --git a/std/std.zig b/std/std.zig index f68edf6435..8ec042fdb8 100644 --- a/std/std.zig +++ b/std/std.zig @@ -9,6 +9,10 @@ pub const DynLib = @import("dynamic_library.zig").DynLib; pub const HashMap = @import("hash_map.zig").HashMap; pub const LinkedList = @import("linked_list.zig").LinkedList; pub const Mutex = @import("mutex.zig").Mutex; +pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian; +pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray; +pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; +pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; pub const SegmentedList = @import("segmented_list.zig").SegmentedList; @@ -87,6 +91,7 @@ test "std" { _ = @import("net.zig"); _ = @import("os.zig"); _ = @import("pdb.zig"); + _ = @import("packed_int_array.zig"); _ = @import("priority_queue.zig"); _ = @import("rand.zig"); _ = @import("sort.zig"); @@ -94,4 +99,6 @@ test "std" { _ = @import("unicode.zig"); _ = @import("valgrind.zig"); _ = @import("zig.zig"); + + _ = @import("debug/leb128.zig"); } diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 77e487f1ef..75a811220f 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -18,7 +18,11 @@ pub const Tree = struct { pub const ErrorList = SegmentedList(Error, 0); pub fn deinit(self: *Tree) void { - self.arena_allocator.deinit(); + // Here we copy the arena allocator into stack memory, because + // otherwise it would destroy itself while it was still working. + var arena_allocator = self.arena_allocator; + arena_allocator.deinit(); + // self is destroyed } pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void { @@ -551,7 +555,6 @@ pub const Node = struct { doc_comments: ?*DocComment, decls: DeclList, eof_token: TokenIndex, - shebang: ?TokenIndex, pub const DeclList = SegmentedList(*Node, 4); @@ -563,7 +566,6 @@ pub const Node = struct { } pub fn firstToken(self: *const Root) TokenIndex { - if (self.shebang) |shebang| return shebang; return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken(); } @@ -2307,7 +2309,6 @@ test "iterate" { .doc_comments = null, .decls = Node.Root.DeclList.init(std.debug.global_allocator), .eof_token = 0, - .shebang = null, }; var base = &root.base; testing.expect(base.iterate(0) == null); diff --git a/std/zig/parse.zig b/std/zig/parse.zig index 96aec714ab..efe83a7dac 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -9,7 +9,7 @@ const Error = ast.Error; /// Result should be freed with tree.deinit() when there are /// no more references to any of the tokens or nodes. -pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { +pub fn parse(allocator: *mem.Allocator, source: []const u8) !*ast.Tree { var tree_arena = std.heap.ArenaAllocator.init(allocator); errdefer tree_arena.deinit(); @@ -22,12 +22,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .base = ast.Node{ .id = ast.Node.Id.Root }, .decls = ast.Node.Root.DeclList.init(arena), .doc_comments = null, - .shebang = null, // initialized when we get the eof token .eof_token = undefined, }; - var tree = ast.Tree{ + const tree = try arena.create(ast.Tree); + tree.* = ast.Tree{ .source = source, .root_node = root_node, .arena_allocator = tree_arena, @@ -43,15 +43,6 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } var tok_it = tree.tokens.iterator(0); - // skip over shebang line - shebang: { - const shebang_tok_index = tok_it.index; - const shebang_tok_ptr = tok_it.peek() orelse break :shebang; - if (shebang_tok_ptr.id != Token.Id.ShebangLine) break :shebang; - root_node.shebang = shebang_tok_index; - _ = tok_it.next(); - } - // skip over line comments at the top of the file while (true) { const next_tok = tok_it.peek() orelse break; @@ -67,9 +58,9 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { switch (state) { State.TopLevel => { - const comments = try eatDocComments(arena, &tok_it, &tree); + const comments = try eatDocComments(arena, &tok_it, tree); - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -150,7 +141,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State.TopLevel) catch unreachable; try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{ @@ -166,7 +157,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.TopLevelExtern => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -201,7 +192,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .TopLevelDecl = ctx }) catch unreachable; continue; }, @@ -209,11 +200,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.TopLevelLibname => |ctx| { const lib_name = blk: { - const lib_name_token = nextToken(&tok_it, &tree); + const lib_name_token = nextToken(&tok_it, tree); const lib_name_token_index = lib_name_token.index; const lib_name_token_ptr = lib_name_token.ptr; - break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) orelse { - prevToken(&tok_it, &tree); + break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, tree)) orelse { + prevToken(&tok_it, tree); break :blk null; }; }; @@ -230,7 +221,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.ThreadLocal => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -256,7 +247,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.TopLevelDecl => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -397,7 +388,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.TopLevelExternOrField => |ctx| { - if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| { + if (eatToken(&tok_it, tree, Token.Id.Identifier)) |identifier| { const node = try arena.create(ast.Node.StructField); node.* = ast.Node.StructField{ .base = ast.Node{ .id = ast.Node.Id.StructField }, @@ -434,11 +425,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.FieldInitValue => |ctx| { - const eq_tok = nextToken(&tok_it, &tree); + const eq_tok = nextToken(&tok_it, tree); const eq_tok_index = eq_tok.index; const eq_tok_ptr = eq_tok.ptr; if (eq_tok_ptr.id != Token.Id.Equal) { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } stack.append(State{ .Expression = ctx }) catch unreachable; @@ -446,7 +437,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ContainerKind => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; const node = try arena.create(ast.Node.ContainerDecl); @@ -479,7 +470,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ContainerInitArgStart => |container_decl| { - if (eatToken(&tok_it, &tree, Token.Id.LParen) == null) { + if (eatToken(&tok_it, tree, Token.Id.LParen) == null) { continue; } @@ -489,24 +480,24 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ContainerInitArg => |container_decl| { - const init_arg_token = nextToken(&tok_it, &tree); + const init_arg_token = nextToken(&tok_it, tree); const init_arg_token_index = init_arg_token.index; const init_arg_token_ptr = init_arg_token.ptr; switch (init_arg_token_ptr.id) { Token.Id.Keyword_enum => { container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Enum = null }; - const lparen_tok = nextToken(&tok_it, &tree); + const lparen_tok = nextToken(&tok_it, tree); const lparen_tok_index = lparen_tok.index; const lparen_tok_ptr = lparen_tok.ptr; if (lparen_tok_ptr.id == Token.Id.LParen) { try stack.append(State{ .ExpectToken = Token.Id.RParen }); try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } }); } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); } }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined }; stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable; }, @@ -515,8 +506,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ContainerDecl => |container_decl| { - const comments = try eatDocComments(arena, &tok_it, &tree); - const token = nextToken(&tok_it, &tree); + const comments = try eatDocComments(arena, &tok_it, tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -629,6 +620,35 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }); continue; }, + Token.Id.Keyword_comptime => { + const block = try arena.create(ast.Node.Block); + block.* = ast.Node.Block{ + .base = ast.Node{ .id = ast.Node.Id.Block }, + .label = null, + .lbrace = undefined, + .statements = ast.Node.Block.StatementList.init(arena), + .rbrace = undefined, + }; + + const node = try arena.create(ast.Node.Comptime); + node.* = ast.Node.Comptime{ + .base = ast.Node{ .id = ast.Node.Id.Comptime }, + .comptime_token = token_index, + .expr = &block.base, + .doc_comments = comments, + }; + try container_decl.fields_and_decls.push(&node.base); + + stack.append(State{ .ContainerDecl = container_decl }) catch unreachable; + try stack.append(State{ .Block = block }); + try stack.append(State{ + .ExpectTokenSave = ExpectTokenSave{ + .id = Token.Id.LBrace, + .ptr = &block.lbrace, + }, + }); + continue; + }, Token.Id.RBrace => { if (comments != null) { ((try tree.errors.addOne())).* = Error{ .UnattachedDocComment = Error.UnattachedDocComment{ .token = token_index } }; @@ -638,7 +658,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .ContainerDecl = container_decl }) catch unreachable; try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{ @@ -690,7 +710,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.VarDeclAlign => |var_decl| { try stack.append(State{ .VarDeclSection = var_decl }); - const next_token = nextToken(&tok_it, &tree); + const next_token = nextToken(&tok_it, tree); const next_token_index = next_token.index; const next_token_ptr = next_token.ptr; if (next_token_ptr.id == Token.Id.Keyword_align) { @@ -700,13 +720,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, State.VarDeclSection => |var_decl| { try stack.append(State{ .VarDeclEq = var_decl }); - const next_token = nextToken(&tok_it, &tree); + const next_token = nextToken(&tok_it, tree); const next_token_index = next_token.index; const next_token_ptr = next_token.ptr; if (next_token_ptr.id == Token.Id.Keyword_linksection) { @@ -716,11 +736,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, State.VarDeclEq => |var_decl| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -742,7 +762,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.VarDeclSemiColon => |var_decl| { - const semicolon_token = nextToken(&tok_it, &tree); + const semicolon_token = nextToken(&tok_it, tree); if (semicolon_token.ptr.id != Token.Id.Semicolon) { ((try tree.errors.addOne())).* = Error{ @@ -756,18 +776,18 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { var_decl.semicolon_token = semicolon_token.index; - if (eatToken(&tok_it, &tree, Token.Id.DocComment)) |doc_comment_token| { + if (eatToken(&tok_it, tree, Token.Id.DocComment)) |doc_comment_token| { const loc = tree.tokenLocation(semicolon_token.ptr.end, doc_comment_token); if (loc.line == 0) { try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments); } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); } } }, State.FnDef => |fn_proto| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -796,7 +816,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .ParamDecl = fn_proto }); try stack.append(State{ .ExpectToken = Token.Id.LParen }); - if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| { + if (eatToken(&tok_it, tree, Token.Id.Identifier)) |name_token| { fn_proto.name_token = name_token; } continue; @@ -804,7 +824,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.FnProtoAlign => |fn_proto| { stack.append(State{ .FnProtoSection = fn_proto }) catch unreachable; - if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_align)) |align_token| { try stack.append(State{ .ExpectToken = Token.Id.RParen }); try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &fn_proto.align_expr } }); try stack.append(State{ .ExpectToken = Token.Id.LParen }); @@ -814,7 +834,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.FnProtoSection => |fn_proto| { stack.append(State{ .FnProtoReturnType = fn_proto }) catch unreachable; - if (eatToken(&tok_it, &tree, Token.Id.Keyword_linksection)) |align_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_linksection)) |align_token| { try stack.append(State{ .ExpectToken = Token.Id.RParen }); try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &fn_proto.section_expr } }); try stack.append(State{ .ExpectToken = Token.Id.LParen }); @@ -822,7 +842,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.FnProtoReturnType => |fn_proto| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -845,7 +865,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined }; stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable; continue; @@ -854,8 +874,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ParamDecl => |fn_proto| { - const comments = try eatDocComments(arena, &tok_it, &tree); - if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| { + const comments = try eatDocComments(arena, &tok_it, tree); + if (eatToken(&tok_it, tree, Token.Id.RParen)) |_| { continue; } const param_decl = try arena.create(ast.Node.ParamDecl); @@ -881,9 +901,9 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.ParamDeclAliasOrComptime => |param_decl| { - if (eatToken(&tok_it, &tree, Token.Id.Keyword_comptime)) |comptime_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_comptime)) |comptime_token| { param_decl.comptime_token = comptime_token; - } else if (eatToken(&tok_it, &tree, Token.Id.Keyword_noalias)) |noalias_token| { + } else if (eatToken(&tok_it, tree, Token.Id.Keyword_noalias)) |noalias_token| { param_decl.noalias_token = noalias_token; } continue; @@ -891,20 +911,20 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.ParamDeclName => |param_decl| { // TODO: Here, we eat two tokens in one state. This means that we can't have // comments between these two tokens. - if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| { - if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| { + if (eatToken(&tok_it, tree, Token.Id.Identifier)) |ident_token| { + if (eatToken(&tok_it, tree, Token.Id.Colon)) |_| { param_decl.name_token = ident_token; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); } } continue; }, State.ParamDeclEnd => |ctx| { - if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| { + if (eatToken(&tok_it, tree, Token.Id.Ellipsis3)) |ellipsis3| { ctx.param_decl.var_args_token = ellipsis3; - switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) { + switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RParen)) { ExpectCommaOrEndResult.end_token => |t| { if (t == null) { stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable; @@ -924,7 +944,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.ParamDeclComma => |fn_proto| { - switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) { + switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RParen)) { ExpectCommaOrEndResult.end_token => |t| { if (t == null) { stack.append(State{ .ParamDecl = fn_proto }) catch unreachable; @@ -939,7 +959,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.MaybeLabeledExpression => |ctx| { - if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| { + if (eatToken(&tok_it, tree, Token.Id.Colon)) |_| { stack.append(State{ .LabeledExpression = LabelCtx{ .label = ctx.label, @@ -953,7 +973,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.LabeledExpression => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1008,13 +1028,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, } }, State.Inline => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1046,7 +1066,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, } @@ -1103,7 +1123,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.Else => |dest| { - if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_else)) |else_token| { const node = try arena.create(ast.Node.Else); node.* = ast.Node.Else{ .base = ast.Node{ .id = ast.Node.Id.Else }, @@ -1122,7 +1142,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.Block => |block| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1131,7 +1151,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .Block = block }) catch unreachable; try stack.append(State{ .Statement = block }); @@ -1140,7 +1160,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.Statement => |block| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1197,7 +1217,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); const statement = try block.statements.addOne(); try stack.append(State{ .Semicolon = statement }); try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } }); @@ -1206,7 +1226,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.ComptimeStatement => |ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1226,8 +1246,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); + prevToken(&tok_it, tree); const statement = try ctx.block.statements.addOne(); try stack.append(State{ .Semicolon = statement }); try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } }); @@ -1245,11 +1265,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.AsmOutputItems => |items| { - const lbracket = nextToken(&tok_it, &tree); + const lbracket = nextToken(&tok_it, tree); const lbracket_index = lbracket.index; const lbracket_ptr = lbracket.ptr; if (lbracket_ptr.id != Token.Id.LBracket) { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } @@ -1280,7 +1300,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.AsmOutputReturnOrType => |node| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1300,11 +1320,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.AsmInputItems => |items| { - const lbracket = nextToken(&tok_it, &tree); + const lbracket = nextToken(&tok_it, tree); const lbracket_index = lbracket.index; const lbracket_ptr = lbracket.ptr; if (lbracket_ptr.id != Token.Id.LBracket) { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } @@ -1335,16 +1355,16 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.AsmClobberItems => |items| { - while (eatToken(&tok_it, &tree, Token.Id.StringLiteral)) |strlit| { + while (eatToken(&tok_it, tree, Token.Id.StringLiteral)) |strlit| { try items.push(strlit); - if (eatToken(&tok_it, &tree, Token.Id.Comma) == null) + if (eatToken(&tok_it, tree, Token.Id.Comma) == null) break; } continue; }, State.ExprListItemOrEnd => |list_state| { - if (eatToken(&tok_it, &tree, list_state.end)) |token_index| { + if (eatToken(&tok_it, tree, list_state.end)) |token_index| { (list_state.ptr).* = token_index; continue; } @@ -1354,7 +1374,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.ExprListCommaOrEnd => |list_state| { - switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) { + switch (expectCommaOrEnd(&tok_it, tree, list_state.end)) { ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| { (list_state.ptr).* = end; continue; @@ -1369,7 +1389,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.FieldInitListItemOrEnd => |list_state| { - if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| { + if (eatToken(&tok_it, tree, Token.Id.RBrace)) |rbrace| { (list_state.ptr).* = rbrace; continue; } @@ -1401,7 +1421,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.FieldInitListCommaOrEnd => |list_state| { - switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) { + switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RBrace)) { ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| { (list_state.ptr).* = end; continue; @@ -1416,17 +1436,17 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.FieldListCommaOrEnd => |field_ctx| { - const end_token = nextToken(&tok_it, &tree); + const end_token = nextToken(&tok_it, tree); const end_token_index = end_token.index; const end_token_ptr = end_token.ptr; switch (end_token_ptr.id) { Token.Id.Comma => { - if (eatToken(&tok_it, &tree, Token.Id.DocComment)) |doc_comment_token| { + if (eatToken(&tok_it, tree, Token.Id.DocComment)) |doc_comment_token| { const loc = tree.tokenLocation(end_token_ptr.end, doc_comment_token); if (loc.line == 0) { try pushDocComment(arena, doc_comment_token, field_ctx.doc_comments); } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); } } @@ -1449,7 +1469,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.ErrorTagListItemOrEnd => |list_state| { - if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| { + if (eatToken(&tok_it, tree, Token.Id.RBrace)) |rbrace| { (list_state.ptr).* = rbrace; continue; } @@ -1461,7 +1481,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.ErrorTagListCommaOrEnd => |list_state| { - switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) { + switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RBrace)) { ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| { (list_state.ptr).* = end; continue; @@ -1476,12 +1496,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.SwitchCaseOrEnd => |list_state| { - if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| { + if (eatToken(&tok_it, tree, Token.Id.RBrace)) |rbrace| { (list_state.ptr).* = rbrace; continue; } - const comments = try eatDocComments(arena, &tok_it, &tree); + const comments = try eatDocComments(arena, &tok_it, tree); const node = try arena.create(ast.Node.SwitchCase); node.* = ast.Node.SwitchCase{ .base = ast.Node{ .id = ast.Node.Id.SwitchCase }, @@ -1500,7 +1520,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.SwitchCaseCommaOrEnd => |list_state| { - switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) { + switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RBrace)) { ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| { (list_state.ptr).* = end; continue; @@ -1516,7 +1536,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.SwitchCaseFirstItem => |switch_case| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id == Token.Id.Keyword_else) { @@ -1535,26 +1555,26 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }); continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable; try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } }); continue; } }, State.SwitchCaseItemOrEnd => |switch_case| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); if (token.ptr.id == Token.Id.EqualAngleBracketRight) { switch_case.arrow_token = token.index; continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable; try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } }); continue; } }, State.SwitchCaseItemCommaOrEnd => |switch_case| { - switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) { + switch (expectCommaOrEnd(&tok_it, tree, Token.Id.EqualAngleBracketRight)) { ExpectCommaOrEndResult.end_token => |end_token| { if (end_token) |t| { switch_case.arrow_token = t; @@ -1572,14 +1592,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.SuspendBody => |suspend_node| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); switch (token.ptr.id) { Token.Id.Semicolon => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, Token.Id.LBrace => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } }); continue; }, @@ -1589,7 +1609,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.AsyncAllocator => |async_node| { - if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) { + if (eatToken(&tok_it, tree, Token.Id.AngleBracketLeft) == null) { continue; } @@ -1630,7 +1650,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ExternType => |ctx| { - if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_fn)) |fn_token| { const fn_proto = try arena.create(ast.Node.FnProto); fn_proto.* = ast.Node.FnProto{ .base = ast.Node{ .id = ast.Node.Id.FnProto }, @@ -1663,7 +1683,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.SliceOrArrayAccess => |node| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1696,7 +1716,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.SliceOrArrayType => |node| { - if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| { + if (eatToken(&tok_it, tree, Token.Id.RBracket)) |_| { node.op = ast.Node.PrefixOp.Op{ .SliceType = ast.Node.PrefixOp.PtrInfo{ .align_info = null, @@ -1718,7 +1738,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.PtrTypeModifiers => |addr_of_info| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1768,14 +1788,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, } }, State.AlignBitRange => |align_info| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); switch (token.ptr.id) { Token.Id.Colon => { align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined); @@ -1798,7 +1818,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.Payload => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id != Token.Id.Pipe) { @@ -1812,7 +1832,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } @@ -1835,7 +1855,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.PointerPayload => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id != Token.Id.Pipe) { @@ -1849,7 +1869,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } @@ -1879,7 +1899,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.PointerIndexPayload => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id != Token.Id.Pipe) { @@ -1893,7 +1913,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } @@ -1927,7 +1947,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.Expression => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -1981,7 +2001,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, else => { if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr.*, token_index)) { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable; } continue; @@ -1996,7 +2016,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.RangeExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| { + if (eatToken(&tok_it, tree, Token.Id.Ellipsis3)) |ellipsis3| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2019,7 +2039,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.AssignmentExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToAssignment(token_ptr.id)) |ass_id| { @@ -2036,7 +2056,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }); continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } }, @@ -2050,7 +2070,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.UnwrapExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| { @@ -2072,7 +2092,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } }, @@ -2086,7 +2106,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.BoolOrExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_or)) |or_token| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2111,7 +2131,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.BoolAndExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_and)) |and_token| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2136,7 +2156,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.ComparisonExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToComparison(token_ptr.id)) |comp_id| { @@ -2153,7 +2173,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } }, @@ -2167,7 +2187,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.BinaryOrExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| { + if (eatToken(&tok_it, tree, Token.Id.Pipe)) |pipe| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2192,7 +2212,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.BinaryXorExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| { + if (eatToken(&tok_it, tree, Token.Id.Caret)) |caret| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2217,7 +2237,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.BinaryAndExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| { + if (eatToken(&tok_it, tree, Token.Id.Ampersand)) |ampersand| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2242,7 +2262,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.BitShiftExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| { @@ -2259,7 +2279,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } }, @@ -2273,7 +2293,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.AdditionExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToAddition(token_ptr.id)) |add_id| { @@ -2290,7 +2310,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } }, @@ -2304,7 +2324,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.MultiplyExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToMultiply(token_ptr.id)) |mult_id| { @@ -2321,7 +2341,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } }, @@ -2386,7 +2406,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.TypeExprEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| { + if (eatToken(&tok_it, tree, Token.Id.Bang)) |bang| { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2403,7 +2423,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.PrefixOpExpression => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| { @@ -2435,14 +2455,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } continue; } else { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable; continue; } }, State.SuffixOpExpressionBegin => |opt_ctx| { - if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| { + if (eatToken(&tok_it, tree, Token.Id.Keyword_async)) |async_token| { const async_node = try arena.create(ast.Node.AsyncAttribute); async_node.* = ast.Node.AsyncAttribute{ .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, @@ -2470,7 +2490,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.SuffixOpExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() orelse continue; - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; switch (token_ptr.id) { @@ -2515,7 +2535,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Period => { - if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| { + if (eatToken(&tok_it, tree, Token.Id.Asterisk)) |asterisk_token| { const node = try arena.create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, @@ -2527,7 +2547,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; continue; } - if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| { + if (eatToken(&tok_it, tree, Token.Id.QuestionMark)) |question_token| { const node = try arena.create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, @@ -2554,21 +2574,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, else => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; }, } }, State.PrimaryExpression => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); switch (token.ptr.id) { Token.Id.IntegerLiteral => { _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.IntegerLiteral, token.index); continue; }, Token.Id.Period => { - const name_token = nextToken(&tok_it, &tree); + const name_token = nextToken(&tok_it, tree); if (name_token.ptr.id != Token.Id.Identifier) { ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{ @@ -2624,11 +2644,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .result = null, }; opt_ctx.store(&node.base); - const next_token = nextToken(&tok_it, &tree); + const next_token = nextToken(&tok_it, tree); const next_token_index = next_token.index; const next_token_ptr = next_token.ptr; if (next_token_ptr.id != Token.Id.Arrow) { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); continue; } node.result = ast.Node.PromiseType.Result{ @@ -2640,7 +2660,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => { - opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) orelse unreachable); + opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, tree)) orelse unreachable); continue; }, Token.Id.LParen => { @@ -2728,7 +2748,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); stack.append(State{ .ContainerKind = ContainerKindCtx{ .opt_ctx = opt_ctx, @@ -2845,7 +2865,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, else => { if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr.*, token.index)) { - prevToken(&tok_it, &tree); + prevToken(&tok_it, tree); if (opt_ctx != OptionalCtx.Optional) { ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } }; return tree; @@ -2857,7 +2877,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ErrorTypeOrSetDecl => |ctx| { - if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) { + if (eatToken(&tok_it, tree, Token.Id.LBrace) == null) { const node = try arena.create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, @@ -2895,11 +2915,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.StringLiteral => |opt_ctx| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; - opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) orelse { - prevToken(&tok_it, &tree); + opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, tree)) orelse { + prevToken(&tok_it, tree); if (opt_ctx != OptionalCtx.Optional) { ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } }; return tree; @@ -2910,13 +2930,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.Identifier => |opt_ctx| { - if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| { + if (eatToken(&tok_it, tree, Token.Id.Identifier)) |ident_token| { _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token); continue; } if (opt_ctx != OptionalCtx.Optional) { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; ((try tree.errors.addOne())).* = Error{ @@ -2930,8 +2950,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ErrorTag => |node_ptr| { - const comments = try eatDocComments(arena, &tok_it, &tree); - const ident_token = nextToken(&tok_it, &tree); + const comments = try eatDocComments(arena, &tok_it, tree); + const ident_token = nextToken(&tok_it, tree); const ident_token_index = ident_token.index; const ident_token_ptr = ident_token.ptr; if (ident_token_ptr.id != Token.Id.Identifier) { @@ -2955,7 +2975,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.ExpectToken => |token_id| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id != token_id) { @@ -2970,7 +2990,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.ExpectTokenSave => |expect_token_save| { - const token = nextToken(&tok_it, &tree); + const token = nextToken(&tok_it, tree); const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id != expect_token_save.id) { @@ -2986,7 +3006,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.IfToken => |token_id| { - if (eatToken(&tok_it, &tree, token_id)) |_| { + if (eatToken(&tok_it, tree, token_id)) |_| { continue; } @@ -2994,7 +3014,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.IfTokenSave => |if_token_save| { - if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| { + if (eatToken(&tok_it, tree, if_token_save.id)) |token_index| { (if_token_save.ptr).* = token_index; continue; } @@ -3003,7 +3023,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.OptionalTokenSave => |optional_token_save| { - if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| { + if (eatToken(&tok_it, tree, optional_token_save.id)) |token_index| { (optional_token_save.ptr).* = token_index; continue; } diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 955e65eeed..6977e4e6b1 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,10 +1,3 @@ -test "temporary trivial example" { - try testCanonical( - \\const x = true; - \\ - ); -} - test "zig fmt: allowzero pointer" { try testCanonical( \\const T = [*]allowzero const u8; @@ -57,14 +50,6 @@ test "zig fmt: linksection" { ); } -test "zig fmt: shebang line" { - try testCanonical( - \\#!/usr/bin/env zig - \\pub fn main() void {} - \\ - ); -} - test "zig fmt: correctly move doc comments on struct fields" { try testTransform( \\pub const section_64 = extern struct { @@ -2125,6 +2110,21 @@ test "zig fmt: error return" { ); } +test "zig fmt: comptime block in container" { + try testCanonical( + \\pub fn container() type { + \\ return struct { + \\ comptime { + \\ if (false) { + \\ unreachable; + \\ } + \\ } + \\ }; + \\} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; @@ -2137,7 +2137,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b var stderr_file = try io.getStdErr(); var stderr = &stderr_file.outStream().stream; - var tree = try std.zig.parse2(allocator, source); + const tree = try std.zig.parse(allocator, source); defer tree.deinit(); var error_it = tree.errors.iterator(0); @@ -2170,7 +2170,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b errdefer buffer.deinit(); var buffer_out_stream = io.BufferOutStream.init(&buffer); - anything_changed.* = try std.zig.render(allocator, &buffer_out_stream.stream, &tree); + anything_changed.* = try std.zig.render(allocator, &buffer_out_stream.stream, tree); return buffer.toOwnedSlice(); } @@ -2215,7 +2215,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { needed_alloc_count, failing_allocator.allocated_bytes, failing_allocator.freed_bytes, - failing_allocator.index, + failing_allocator.allocations, failing_allocator.deallocations, ); return error.MemoryLeakDetected; diff --git a/std/zig/render.zig b/std/zig/render.zig index f1fe23c2a8..cabc4ea9ef 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -73,11 +73,6 @@ fn renderRoot( ) (@typeOf(stream).Child.Error || Error)!void { var tok_it = tree.tokens.iterator(0); - // render the shebang line - if (tree.root_node.shebang) |shebang| { - try stream.write(tree.tokenSlice(shebang)); - } - // render all the line comments at the beginning of the file while (tok_it.next()) |token| { if (token.id != Token.Id.LineComment) break; @@ -753,7 +748,7 @@ fn renderExpression( counting_stream.bytes_written = 0; var dummy_col: usize = 0; try renderExpression(allocator, &counting_stream.stream, tree, 0, &dummy_col, expr.*, Space.None); - const width = counting_stream.bytes_written; + const width = @intCast(usize, counting_stream.bytes_written); const col = i % row_size; column_widths[col] = std.math.max(column_widths[col], width); expr_widths[i] = width; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a31605b02a..297673235d 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3,6 +3,64 @@ const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( + "peer cast then implicit cast const pointer to mutable C pointer", + \\export fn func() void { + \\ var strValue: [*c]u8 = undefined; + \\ strValue = strValue orelse c""; + \\} + , + "tmp.zig:3:32: error: cast discards const qualifier", + ); + + cases.add( + "overflow in enum value allocation", + \\const Moo = enum(u8) { + \\ Last = 255, + \\ Over, + \\}; + \\pub fn main() void { + \\ var y = Moo.Last; + \\} + , + "tmp.zig:3:5: error: enumeration value 256 too large for type 'u8'", + ); + + cases.add( + "attempt to cast enum literal to error", + \\export fn entry() void { + \\ switch (error.Hi) { + \\ .Hi => {}, + \\ } + \\} + , + "tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'", + ); + + cases.add( + "@sizeOf bad type", + \\export fn entry() void { + \\ _ = @sizeOf(@typeOf(null)); + \\} + , + "tmp.zig:2:17: error: no size available for type '(null)'", + ); + + cases.add( + "Generic function where return type is self-referenced", + \\fn Foo(comptime T: type) Foo(T) { + \\ return struct{ x: T }; + \\} + \\export fn entry() void { + \\ const t = Foo(u32) { + \\ .x = 1 + \\ }; + \\} + , + "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches", + "tmp.zig:1:29: note: called from here", + ); + + cases.add( "@ptrToInt 0 to non optional pointer", \\export fn entry() void { \\ var b = @intToPtr(*i32, 0); @@ -553,15 +611,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "threadlocal qualifier on local variable", - \\export fn entry() void { - \\ threadlocal var x: i32 = 1234; - \\} - , - "tmp.zig:2:5: error: function-local variable 'x' cannot be threadlocal", - ); - - cases.add( "@bitCast same size but bit count mismatch", \\export fn entry(byte: u8) void { \\ var oops = @bitCast(u7, byte); @@ -839,7 +888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = &x == null; \\} , - "tmp.zig:3:12: error: only optionals (not '*i32') can compare to null", + "tmp.zig:3:12: error: comparison of '*i32' with null", ); cases.add( @@ -5347,8 +5396,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:12:20: note: referenced here", ); - cases.add( - "specify enum tag type that is too small", + cases.add("specify enum tag type that is too small", \\const Small = enum (u2) { \\ One, \\ Two, @@ -5360,9 +5408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() void { \\ var x = Small.One; \\} - , - "tmp.zig:1:21: error: 'u2' too small to hold all bits; must be at least 'u3'", - ); + , "tmp.zig:6:5: error: enumeration value 4 too large for type 'u2'"); cases.add( "specify non-integer enum tag type", @@ -5413,22 +5459,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "non unsigned integer enum tag type", - \\const Small = enum(i2) { - \\ One, - \\ Two, - \\ Three, - \\ Four, - \\}; - \\ - \\export fn entry() void { - \\ var y = Small.Two; - \\} - , - "tmp.zig:1:20: error: expected unsigned integer, found 'i2'", - ); - - cases.add( "struct fields with value assignments", \\const MultipleChoice = struct { \\ A: i32 = 20, @@ -5486,8 +5516,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x = MultipleChoice.C; \\} , - "tmp.zig:6:9: error: enum tag value 60 already taken", - "tmp.zig:4:9: note: other occurrence here", + "tmp.zig:6:5: error: enum tag value 60 already taken", + "tmp.zig:4:5: note: other occurrence here", ); cases.add( @@ -5892,4 +5922,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , "tmp.zig:3:23: error: expected type '[]u32', found '*const u32'", ); + + cases.add( + "for loop body expression ignored", + \\fn returns() usize { + \\ return 2; + \\} + \\export fn f1() void { + \\ for ("hello") |_| returns(); + \\} + \\export fn f2() void { + \\ var x: anyerror!i32 = error.Bad; + \\ for ("hello") |_| returns() else unreachable; + \\} + , + "tmp.zig:5:30: error: expression value is ignored", + "tmp.zig:9:30: error: expression value is ignored", + ); } diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 78b45ac05f..b10accd213 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -1,6 +1,26 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { + cases.addRuntimeSafety(".? operator on null pointer", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var ptr: ?*i32 = null; + \\ var b = ptr.?; + \\} + ); + + cases.addRuntimeSafety(".? operator on C pointer", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var ptr: [*c]i32 = null; + \\ var b = ptr.?; + \\} + ); + cases.addRuntimeSafety("@ptrToInt address zero to non-optional pointer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index da90660bf1..bc3be172ab 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -20,9 +20,12 @@ comptime { _ = @import("behavior/bugs/1442.zig"); _ = @import("behavior/bugs/1486.zig"); _ = @import("behavior/bugs/1500.zig"); + _ = @import("behavior/bugs/1607.zig"); _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/1914.zig"); _ = @import("behavior/bugs/2006.zig"); + _ = @import("behavior/bugs/2114.zig"); + _ = @import("behavior/bugs/2346.zig"); _ = @import("behavior/bugs/394.zig"); _ = @import("behavior/bugs/421.zig"); _ = @import("behavior/bugs/529.zig"); diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig index 610acc06c2..1877c8cdcb 100644 --- a/test/stage1/behavior/bit_shifting.zig +++ b/test/stage1/behavior/bit_shifting.zig @@ -86,3 +86,13 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c expect(table.get(@intCast(Key, i)) == node); } } + +// #2225 +test "comptime shr of BigInt" { + comptime { + var n0 = 0xdeadbeef0000000000000000; + std.debug.assert(n0 >> 64 == 0xdeadbeef); + var n1 = 17908056155735594659; + std.debug.assert(n1 >> 64 == 0); + } +} diff --git a/test/stage1/behavior/bugs/1607.zig b/test/stage1/behavior/bugs/1607.zig new file mode 100644 index 0000000000..f32eeb03d6 --- /dev/null +++ b/test/stage1/behavior/bugs/1607.zig @@ -0,0 +1,15 @@ +const std = @import("std"); +const testing = std.testing; + +const a = []u8{ 1, 2, 3 }; + +fn checkAddress(s: []const u8) void { + for (s) |*i, j| { + testing.expect(i == &a[j]); + } +} + +test "slices pointing at the same address as global array." { + checkAddress(a); + comptime checkAddress(a); +} diff --git a/test/stage1/behavior/bugs/2114.zig b/test/stage1/behavior/bugs/2114.zig new file mode 100644 index 0000000000..61ea2675b9 --- /dev/null +++ b/test/stage1/behavior/bugs/2114.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const expect = std.testing.expect; +const math = std.math; + +fn ctz(x: var) usize { + return @ctz(x); +} + +test "fixed" { + testClz(); + comptime testClz(); +} + +fn testClz() void { + expect(ctz(u128(0x40000000000000000000000000000000)) == 126); + expect(math.rotl(u128, u128(0x40000000000000000000000000000000), u8(1)) == u128(0x80000000000000000000000000000000)); + expect(ctz(u128(0x80000000000000000000000000000000)) == 127); + expect(ctz(math.rotl(u128, u128(0x40000000000000000000000000000000), u8(1))) == 127); +} diff --git a/test/stage1/behavior/bugs/2346.zig b/test/stage1/behavior/bugs/2346.zig new file mode 100644 index 0000000000..c8cea34813 --- /dev/null +++ b/test/stage1/behavior/bugs/2346.zig @@ -0,0 +1,6 @@ +test "fixed" { + const a: *void = undefined; + const b: *[1]void = a; + const c: *[0]u8 = undefined; + const d: []u8 = c; +} diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index f584fc265a..8a5edaa3dd 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -923,3 +923,42 @@ test "peer type resolution with enum literal" { expect(Items.two == .two); expect(.two == Items.two); } + +test "enum literal in array literal" { + const Items = enum { + one, + two, + }; + + const array = []Items { + .one, + .two, + }; + + expect(array[0] == .one); + expect(array[1] == .two); +} + +test "signed integer as enum tag" { + const SignedEnum = enum(i2) { + A0 = -1, + A1 = 0, + A2 = 1, + }; + + expect(@enumToInt(SignedEnum.A0) == -1); + expect(@enumToInt(SignedEnum.A1) == 0); + expect(@enumToInt(SignedEnum.A2) == 1); +} + +test "enum value allocation" { + const LargeEnum = enum(u32) { + A0 = 0x80000000, + A1, + A2, + }; + + expect(@enumToInt(LargeEnum.A0) == 0x80000000); + expect(@enumToInt(LargeEnum.A1) == 0x80000001); + expect(@enumToInt(LargeEnum.A2) == 0x80000002); +} diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index 23dc6d1feb..acbd9209df 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -632,3 +632,10 @@ fn testNanEqNan(comptime F: type) void { expect(!(nan1 < nan2)); expect(!(nan1 <= nan2)); } + +test "128-bit multiplication" { + var a: i128 = 3; + var b: i128 = 2; + var c = a * b; + expect(c == 6); +} diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index be47718358..50b36fe583 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -150,3 +150,53 @@ test "allowzero pointer and slice" { expect(@typeInfo(@typeOf(ptr)).Pointer.is_allowzero); expect(@typeInfo(@typeOf(slice)).Pointer.is_allowzero); } + +test "assign null directly to C pointer and test null equality" { + var x: [*c]i32 = null; + expect(x == null); + expect(null == x); + expect(!(x != null)); + expect(!(null != x)); + if (x) |same_x| { + @panic("fail"); + } + var otherx: i32 = undefined; + expect((x orelse &otherx) == &otherx); + + const y: [*c]i32 = null; + comptime expect(y == null); + comptime expect(null == y); + comptime expect(!(y != null)); + comptime expect(!(null != y)); + if (y) |same_y| @panic("fail"); + const othery: i32 = undefined; + comptime expect((y orelse &othery) == &othery); + + var n: i32 = 1234; + var x1: [*c]i32 = &n; + expect(!(x1 == null)); + expect(!(null == x1)); + expect(x1 != null); + expect(null != x1); + expect(x1.?.* == 1234); + if (x1) |same_x1| { + expect(same_x1.* == 1234); + } else { + @panic("fail"); + } + expect((x1 orelse &otherx) == x1); + + const nc: i32 = 1234; + const y1: [*c]const i32 = &nc; + comptime expect(!(y1 == null)); + comptime expect(!(null == y1)); + comptime expect(y1 != null); + comptime expect(null != y1); + comptime expect(y1.?.* == 1234); + if (y1) |same_y1| { + expect(same_y1.* == 1234); + } else { + @compileError("fail"); + } + comptime expect((y1 orelse &othery) == y1); +} diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig index 58a6c81759..cfad311e06 100644 --- a/test/stage1/behavior/sizeof_and_typeof.zig +++ b/test/stage1/behavior/sizeof_and_typeof.zig @@ -67,3 +67,10 @@ test "@bitOffsetOf" { expect(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); expect(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); } + +test "@sizeOf on compile-time types" { + expect(@sizeOf(comptime_int) == 0); + expect(@sizeOf(comptime_float) == 0); + expect(@sizeOf(@typeOf(.hi)) == 0); + expect(@sizeOf(@typeOf(type)) == 0); +} diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 62fb41ca28..114f06982b 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -2,8 +2,7 @@ const std = @import("std"); const expect = std.testing.expect; const expectEqualSlices = std.testing.expectEqualSlices; const builtin = @import("builtin"); -const maxInt = std.math.maxInt; - +const maxInt = std.math.maxInt; const StructWithNoFields = struct { fn add(a: i32, b: i32) i32 { return a + b; @@ -505,3 +504,22 @@ test "packed struct with u0 field access" { var s = S{ .f0 = 0 }; comptime expect(s.f0 == 0); } + +const S0 = struct{ + bar: S1, + + pub const S1 = struct{ + value: u8, + }; + + fn init() @This() { + return S0{ .bar = S1{ .value = 123 } }; + } +}; + +var g_foo: S0 = S0.init(); + +test "access to global struct fields" { + g_foo.bar.value = 42; + expect(g_foo.bar.value == 42); +} diff --git a/test/stage1/behavior/syntax.zig b/test/stage1/behavior/syntax.zig index 451e396142..12df8a4315 100644 --- a/test/stage1/behavior/syntax.zig +++ b/test/stage1/behavior/syntax.zig @@ -1,6 +1,14 @@ // Test trailing comma syntax // zig fmt: off +extern var a: c_int; +extern "c" var b: c_int; +export var c: c_int = 0; +threadlocal var d: c_int; +extern threadlocal var e: c_int; +extern "c" threadlocal var f: c_int; +export threadlocal var g: c_int = 0; + const struct_trailing_comma = struct { x: i32, y: i32, }; const struct_no_comma = struct { x: i32, y: i32 }; const struct_fn_no_comma = struct { fn m() void {} y: i32 }; diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index bbba867667..b8bb9a51b8 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -365,3 +365,40 @@ test "@enumToInt works on unions" { expect(@enumToInt(b) == 1); expect(@enumToInt(c) == 2); } + +const Attribute = union(enum) { + A: bool, + B: u8, +}; + +fn setAttribute(attr: Attribute) void {} + +fn Setter(attr: Attribute) type { + return struct{ + fn set() void { + setAttribute(attr); + } + }; +} + +test "comptime union field value equality" { + const a0 = Setter(Attribute{ .A = false }); + const a1 = Setter(Attribute{ .A = true }); + const a2 = Setter(Attribute{ .A = false }); + + const b0 = Setter(Attribute{ .B = 5 }); + const b1 = Setter(Attribute{ .B = 9 }); + const b2 = Setter(Attribute{ .B = 5 }); + + expect(a0 == a0); + expect(a1 == a1); + expect(a0 == a2); + + expect(b0 == b0); + expect(b1 == b1); + expect(b0 == b2); + + expect(a0 != b0); + expect(a0 != a1); + expect(b0 != b1); +} diff --git a/test/tests.zig b/test/tests.zig index 61fd0426f1..4b67cf0f6c 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -903,6 +903,7 @@ pub const TranslateCContext = struct { sources: ArrayList(SourceFile), expected_lines: ArrayList([]const u8), allow_warnings: bool, + stage2: bool, const SourceFile = struct { filename: []const u8, @@ -955,7 +956,8 @@ pub const TranslateCContext = struct { var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; - zig_args.append("translate-c") catch unreachable; + const translate_c_cmd = if (self.case.stage2) "translate-c-2" else "translate-c"; + zig_args.append(translate_c_cmd) catch unreachable; zig_args.append(b.pathFromRoot(root_src)) catch unreachable; warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name); @@ -1052,6 +1054,7 @@ pub const TranslateCContext = struct { .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), .expected_lines = ArrayList([]const u8).init(self.b.allocator), .allow_warnings = allow_warnings, + .stage2 = false, }; tc.addSourceFile(filename, source); @@ -1072,6 +1075,34 @@ pub const TranslateCContext = struct { self.addCase(tc); } + pub fn add_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void { + for ([]bool{ false, true }) |stage2| { + const tc = self.create(false, "source.h", name, source, expected_lines); + tc.stage2 = stage2; + self.addCase(tc); + } + } + + pub fn addC_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void { + for ([]bool{ false, true }) |stage2| { + const tc = self.create(false, "source.c", name, source, expected_lines); + tc.stage2 = stage2; + self.addCase(tc); + } + } + + pub fn add_2(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void { + const tc = self.create(false, "source.h", name, source, expected_lines); + tc.stage2 = true; + self.addCase(tc); + } + + pub fn addC_2(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void { + const tc = self.create(false, "source.c", name, source, expected_lines); + tc.stage2 = true; + self.addCase(tc); + } + pub fn addAllowWarnings(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void { const tc = self.create(true, "source.h", name, source, expected_lines); self.addCase(tc); @@ -1080,7 +1111,8 @@ pub const TranslateCContext = struct { pub fn addCase(self: *TranslateCContext, case: *const TestCase) void { const b = self.b; - const annotated_case_name = fmt.allocPrint(self.b.allocator, "translate-c {}", case.name) catch unreachable; + const translate_c_cmd = if (case.stage2) "translate-c-2" else "translate-c"; + const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {}", translate_c_cmd, case.name) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) return; } diff --git a/test/translate_c.zig b/test/translate_c.zig index cd8e7cb6d0..930442f293 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1,7 +1,66 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); +// add_both - test for stage1 and stage2, in #include mode +// add - test stage1 only, in #include mode +// add_2 - test stage2 only, in #include mode +// addC_both - test for stage1 and stage2, in -c mode +// addC - test stage1 only, in -c mode +// addC_2 - test stage2 only, in -c mode + pub fn addCases(cases: *tests.TranslateCContext) void { + /////////////// Cases that pass for both stage1/stage2 //////////////// + cases.add_both("simple function prototypes", + \\void __attribute__((noreturn)) foo(void); + \\int bar(void); + , + \\pub extern fn foo() noreturn; + \\pub extern fn bar() c_int; + ); + + /////////////// Cases that pass for only stage2 //////////////// + cases.add_2("Parameterless function prototypes", + \\void a() {} + \\void b(void) {} + \\void c(); + \\void d(void); + , + \\pub export fn a() void {} + \\pub export fn b() void {} + \\pub extern fn c(...) void; + \\pub extern fn d() void; + ); + + cases.add_2("simple function definition", + \\void foo(void) {} + \\static void bar(void) {} + , + \\pub export fn foo() void {} + \\pub extern fn bar() void {} + ); + + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// + + cases.add("macro with left shift", + \\#define REDISMODULE_READ (1<<0) + , + \\pub const REDISMODULE_READ = 1 << 0; + ); + + cases.add("casting pointers to ints and ints to pointers", + \\void foo(void); + \\void bar(void) { + \\ void *func_ptr = foo; + \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; + \\} + , + \\pub extern fn foo() void; + \\pub fn bar() void { + \\ var func_ptr: ?*c_void = @ptrCast(?*c_void, foo); + \\ var typed_func_ptr: ?extern fn() void = @intToPtr(?extern fn() void, c_ulong(@ptrToInt(func_ptr))); + \\} + ); + if (builtin.os != builtin.Os.windows) { // Windows treats this as an enum with type c_int cases.add("big negative enum init values when C ABI supports long long enums", @@ -72,7 +131,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ _ = c"void foo(void)"; \\} ); - + cases.add("ignore result", \\void foo() { \\ int a; @@ -648,11 +707,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; - \\ if ((b != 0) and (c != 0)) return 1; - \\ if ((a != 0) and (c != 0)) return 2; + \\ if ((b != 0) and (c != null)) return 1; + \\ if ((a != 0) and (c != null)) return 2; \\ if ((a != 0) or (b != 0)) return 3; - \\ if ((b != 0) or (c != 0)) return 4; - \\ if ((a != 0) or (c != 0)) return 5; + \\ if ((b != 0) or (c != null)) return 4; + \\ if ((a != 0) or (c != null)) return 5; \\ return 6; \\} ); @@ -832,7 +891,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub export fn foo() [*c]c_int { - \\ return 0; + \\ return null; \\} ); @@ -1334,7 +1393,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\fn ptrcast(a: [*c]c_int) [*c]f32 { - \\ return @ptrCast([*c]f32, a); + \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); \\} ); @@ -1360,7 +1419,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); - \\ return !(c != 0); + \\ return !(c != null); \\} ); @@ -1417,7 +1476,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; - \\ if (c != 0) return 2; + \\ if (c != null) return 2; \\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3; \\ return 4; \\} @@ -1434,7 +1493,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; - \\ while (c != 0) return 2; + \\ while (c != null) return 2; \\ return 3; \\} ); @@ -1450,7 +1509,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; - \\ while (c != 0) return 2; + \\ while (c != null) return 2; \\ return 3; \\} ); @@ -1497,14 +1556,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} ); - cases.addC("Parameterless function prototypes", - \\void foo() {} - \\void bar(void) {} - , - \\pub export fn foo() void {} - \\pub export fn bar() void {} - ); - cases.addC( "u integer suffix after 0 (zero) in macro definition", "#define ZERO 0U", @@ -1553,33 +1604,101 @@ pub fn addCases(cases: *tests.TranslateCContext) void { "pub const NOT_ZERO = ~c_uint(0);", ); - // cases.add("empty array with initializer", - // "int a[4] = {};" - // , - // "pub var a: [4]c_int = [1]c_int{0} ** 4;" - // ); - - // cases.add("array with initialization", - // "int a[4] = {1, 2, 3, 4};" - // , - // "pub var a: [4]c_int = [4]c_int{1, 2, 3, 4};" - // ); - - // cases.add("array with incomplete initialization", - // "int a[4] = {3, 4};" - // , - // "pub var a: [4]c_int = [2]c_int{3, 4} ++ ([1]c_int{0} ** 2);" - // ); - - // cases.add("2D array with initialization", - // "int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };" - // , - // "pub var a: [3][3]c_int = [3][3]c_int{[3]c_int{1, 2, 3}, [3]c_int{4, 5, 6}, [3]c_int{7, 8, 9}};" - // ); - - // cases.add("2D array with incomplete initialization", - // "int a[3][3] = { {1, 2}, {4, 5, 6} };" - // , - // "pub var a: [3][3]c_int = [2][3]c_int{[2]c_int{1, 2} ++ [1]c_int{0}, [3]c_int{4, 5, 6}} ++ [1][3]c_int{[1]c_int{0} ** 3};" - // ); + cases.addC("implicit casts", + \\#include <stdbool.h> + \\ + \\void fn_int(int x); + \\void fn_f32(float x); + \\void fn_f64(double x); + \\void fn_char(char x); + \\void fn_bool(bool x); + \\void fn_ptr(void *x); + \\ + \\void call(int q) { + \\ fn_int(3.0f); + \\ fn_int(3.0); + \\ fn_int(3.0L); + \\ fn_int('ABCD'); + \\ fn_f32(3); + \\ fn_f64(3); + \\ fn_char('3'); + \\ fn_char('\x1'); + \\ fn_char(0); + \\ fn_f32(3.0f); + \\ fn_f64(3.0); + \\ fn_bool(123); + \\ fn_bool(0); + \\ fn_bool(&fn_int); + \\ fn_int(&fn_int); + \\ fn_ptr(42); + \\} + , + \\pub extern fn fn_int(x: c_int) void; + \\pub extern fn fn_f32(x: f32) void; + \\pub extern fn fn_f64(x: f64) void; + \\pub extern fn fn_char(x: u8) void; + \\pub extern fn fn_bool(x: bool) void; + \\pub extern fn fn_ptr(x: ?*c_void) void; + \\pub export fn call(q: c_int) void { + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(1094861636); + \\ fn_f32(@intToFloat(f32, 3)); + \\ fn_f64(@intToFloat(f64, 3)); + \\ fn_char(u8('3')); + \\ fn_char(u8('\x01')); + \\ fn_char(u8(0)); + \\ fn_f32(3.000000); + \\ fn_f64(3.000000); + \\ fn_bool(true); + \\ fn_bool(false); + \\ fn_bool(@ptrToInt(&fn_int) != 0); + \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); + \\ fn_ptr(@intToPtr(?*c_void, 42)); + \\} + ); + + cases.addC("pointer conversion with different alignment", + \\void test_ptr_cast() { + \\ void *p; + \\ { + \\ char *to_char = (char *)p; + \\ short *to_short = (short *)p; + \\ int *to_int = (int *)p; + \\ long long *to_longlong = (long long *)p; + \\ } + \\ { + \\ char *to_char = p; + \\ short *to_short = p; + \\ int *to_int = p; + \\ long long *to_longlong = p; + \\ } + \\} + , + \\pub export fn test_ptr_cast() void { + \\ var p: ?*c_void = undefined; + \\ { + \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); + \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); + \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); + \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); + \\ } + \\ { + \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); + \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); + \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); + \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); + \\ } + \\} + ); + + /////////////// Cases for only stage1 because stage2 behavior is better //////////////// + cases.addC("Parameterless function prototypes", + \\void foo() {} + \\void bar(void) {} + , + \\pub export fn foo() void {} + \\pub export fn bar() void {} + ); } |
