mirror of
https://github.com/ziglang/zig.git
synced 2026-02-10 03:20:58 +00:00
Merge branch 'master' into rebased
This commit is contained in:
commit
3787f34286
111
CMakeLists.txt
111
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/")
|
||||
|
||||
236
README.md
236
README.md
@ -1,140 +1,15 @@
|
||||

|
||||
|
||||
A programming language designed for robustness, optimality, and
|
||||
clarity.
|
||||
Zig is an open-source programming language designed for **robustness**,
|
||||
**optimality**, and **maintainability**.
|
||||
|
||||
[Download & Documentation](https://ziglang.org/download/)
|
||||
## Resources
|
||||
|
||||
## Feature Highlights
|
||||
* [Introduction](https://ziglang.org/#Introduction)
|
||||
* [Download & Documentation](https://ziglang.org/download)
|
||||
* [Community](https://github.com/ziglang/zig/wiki/Community)
|
||||
|
||||
* 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
|
||||
## 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.
|
||||
|
||||
27
build.zig
27
build.zig
@ -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);
|
||||
}
|
||||
|
||||
@ -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/
|
||||
|
||||
@ -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
|
||||
|
||||
12
deps/lld/wasm/OutputSections.cpp
vendored
12
deps/lld/wasm/OutputSections.cpp
vendored
@ -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 {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
866
src-self-hosted/clang.zig
Normal file
866
src-self-hosted/clang.zig
Normal file
@ -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;
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
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");
|
||||
/// 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;
|
||||
}
|
||||
|
||||
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_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {
|
||||
translate_c.freeErrors(errors_ptr[0..errors_len]);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
682
src-self-hosted/translate_c.zig
Normal file
682
src-self-hosted/translate_c.zig
Normal file
@ -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);
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
155
src/analyze.cpp
155
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) {
|
||||
} 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("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) {
|
||||
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);
|
||||
} else {
|
||||
Buf *val_buf = buf_alloc();
|
||||
bigint_append_buf(val_buf, &result->data.x_bigint, 10);
|
||||
assert(result->type->id == ZigTypeIdInt || result->type->id == ZigTypeIdComptimeInt);
|
||||
|
||||
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"));
|
||||
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 {
|
||||
bigint_init_unsigned(&type_enum_field->value, 0);
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
|
||||
#include "list.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
511
src/codegen.cpp
511
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};
|
||||
AstNode *root_node;
|
||||
Error err = parse_h_file(&root_node, &errors, buf_ptr(full_path), g, nullptr);
|
||||
Stage2TranslateMode trans_mode = buf_ends_with_str(full_path, ".h") ?
|
||||
Stage2TranslateModeImport : Stage2TranslateModeTranslate;
|
||||
|
||||
if (err == ErrorCCompileErrors && errors.length > 0) {
|
||||
for (size_t i = 0; i < errors.length; i += 1) {
|
||||
ErrorMsg *err_msg = errors.at(i);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)";
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
379
src/ir.cpp
379
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;
|
||||
@ -12222,6 +12306,44 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
|
||||
source_node, maybe_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 (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);
|
||||
@ -12231,8 +12353,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
|
||||
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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
332
src/link.cpp
332
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" : "";
|
||||
// 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 *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");
|
||||
|
||||
// msvcrt depends on kernel32 and ntdll
|
||||
lj->args.append("kernel32.lib");
|
||||
lj->args.append("ntdll.lib");
|
||||
if (!is_dynamic) {
|
||||
Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str);
|
||||
lj->args.append(buf_ptr(cmt_lib_name));
|
||||
} else {
|
||||
lj->args.append("/NODEFAULTLIB");
|
||||
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 *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");
|
||||
|
||||
// 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;
|
||||
|
||||
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");
|
||||
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,62 +1266,24 @@ 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;
|
||||
switch (g->subsystem) {
|
||||
case TargetSubsystemAuto:
|
||||
if (g->zig_target->os == OsUefi) {
|
||||
add_uefi_link_args(lj);
|
||||
} else {
|
||||
add_nt_link_args(lj, is_library);
|
||||
}
|
||||
break;
|
||||
case TargetSubsystemConsole:
|
||||
lj->args.append("/SUBSYSTEM:console");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemEfiApplication:
|
||||
lj->args.append("/SUBSYSTEM:efi_application");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiBootServiceDriver:
|
||||
lj->args.append("/SUBSYSTEM:efi_boot_service_driver");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiRom:
|
||||
lj->args.append("/SUBSYSTEM:efi_rom");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiRuntimeDriver:
|
||||
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);
|
||||
break;
|
||||
case TargetSubsystemPosix:
|
||||
lj->args.append("/SUBSYSTEM:posix");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemWindows:
|
||||
lj->args.append("/SUBSYSTEM:windows");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
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))));
|
||||
@ -1243,13 +1291,15 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
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");
|
||||
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) {
|
||||
@ -1261,6 +1311,48 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
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_win_link_args(lj, is_library);
|
||||
}
|
||||
break;
|
||||
case TargetSubsystemConsole:
|
||||
lj->args.append("-SUBSYSTEM:console");
|
||||
add_win_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemEfiApplication:
|
||||
lj->args.append("-SUBSYSTEM:efi_application");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiBootServiceDriver:
|
||||
lj->args.append("-SUBSYSTEM:efi_boot_service_driver");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiRom:
|
||||
lj->args.append("-SUBSYSTEM:efi_rom");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiRuntimeDriver:
|
||||
lj->args.append("-SUBSYSTEM:efi_runtime_driver");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemNative:
|
||||
lj->args.append("-SUBSYSTEM:native");
|
||||
add_win_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemPosix:
|
||||
lj->args.append("-SUBSYSTEM:posix");
|
||||
add_win_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemWindows:
|
||||
lj->args.append("-SUBSYSTEM:windows");
|
||||
add_win_link_args(lj, is_library);
|
||||
break;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
|
||||
#include "util.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
template<typename T>
|
||||
struct ZigList {
|
||||
void deinit() {
|
||||
|
||||
169
src/main.cpp
169
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:
|
||||
|
||||
53
src/os.cpp
53
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
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
114
src/parser.cpp
114
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) {
|
||||
Token *layout_token = eat_token_if(pc, TokenIdKeywordExtern);
|
||||
if (layout_token == nullptr)
|
||||
layout_token = eat_token_if(pc, TokenIdKeywordPacked);
|
||||
|
||||
AstNode *res = ast_parse_container_decl_auto(pc);
|
||||
if (res == nullptr) {
|
||||
if (layout_token != nullptr)
|
||||
put_back_token(pc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(res->type == NodeTypeContainerDecl);
|
||||
res->line = extern_token->start_line;
|
||||
res->column = extern_token->start_column;
|
||||
res->data.container_decl.layout = ContainerLayoutExtern;
|
||||
return res;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
3241
src/translate_c.cpp
3241
src/translate_c.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
44
src/userland.cpp
Normal file
44
src/userland.cpp
Normal file
@ -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));
|
||||
}
|
||||
120
src/userland.h
Normal file
120
src/userland.h
Normal file
@ -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
|
||||
10
src/util.cpp
10
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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
1717
src/zig_clang.cpp
1717
src/zig_clang.cpp
File diff suppressed because it is too large
Load Diff
787
src/zig_clang.h
787
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;
|
||||
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,
|
||||
};
|
||||
|
||||
//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;
|
||||
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,
|
||||
};
|
||||
|
||||
//struct ZigClangETK_Class;
|
||||
//struct ZigClangETK_Enum;
|
||||
//struct ZigClangETK_Interface;
|
||||
//struct ZigClangETK_None;
|
||||
//struct ZigClangETK_Struct;
|
||||
//struct ZigClangETK_Typename;
|
||||
//struct ZigClangETK_Union;
|
||||
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,
|
||||
};
|
||||
|
||||
//struct ZigClangSC_None;
|
||||
//struct ZigClangSC_PrivateExtern;
|
||||
//struct ZigClangSC_Static;
|
||||
enum ZigClangAPValueKind {
|
||||
ZigClangAPValueUninitialized,
|
||||
ZigClangAPValueInt,
|
||||
ZigClangAPValueFloat,
|
||||
ZigClangAPValueComplexInt,
|
||||
ZigClangAPValueComplexFloat,
|
||||
ZigClangAPValueLValue,
|
||||
ZigClangAPValueVector,
|
||||
ZigClangAPValueArray,
|
||||
ZigClangAPValueStruct,
|
||||
ZigClangAPValueUnion,
|
||||
ZigClangAPValueMemberPointer,
|
||||
ZigClangAPValueAddrLabelDiff,
|
||||
};
|
||||
|
||||
//struct ZigClangTU_Complete;
|
||||
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,
|
||||
};
|
||||
|
||||
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);
|
||||
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,
|
||||
};
|
||||
|
||||
ZIG_EXTERN_C ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext*, ZigClangQualType T);
|
||||
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);
|
||||
|
||||
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));
|
||||
#endif
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
650
std/debug.zig
650
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 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 opcode_base = try di.dwarf_in_stream.readByte();
|
||||
|
||||
const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
|
||||
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < opcode_base - 1) : (i += 1) {
|
||||
standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
var file_entries = ArrayList(FileEntry).init(di.allocator());
|
||||
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
|
||||
|
||||
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
|
||||
if (minimum_instruction_length == 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,
|
||||
});
|
||||
}
|
||||
|
||||
if (version >= 4) {
|
||||
// maximum_operations_per_instruction
|
||||
_ = try di.dwarf_in_stream.readByte();
|
||||
}
|
||||
try di.dwarf_seekable_stream.seekTo(prog_start_offset);
|
||||
|
||||
const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
|
||||
const line_base = try di.dwarf_in_stream.readByteSigned();
|
||||
while (true) {
|
||||
const opcode = try di.dwarf_in_stream.readByte();
|
||||
|
||||
const line_range = try di.dwarf_in_stream.readByte();
|
||||
if (line_range == 0) return error.InvalidDebugInfo;
|
||||
|
||||
const opcode_base = try di.dwarf_in_stream.readByte();
|
||||
|
||||
const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
var file_entries = ArrayList(FileEntry).init(di.allocator());
|
||||
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
try di.dwarf_seekable_stream.seekTo(prog_start_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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this_offset += next_offset;
|
||||
}
|
||||
|
||||
return error.MissingDebugInfo;
|
||||
}
|
||||
|
||||
const Func = struct {
|
||||
pc_range: ?PcRange,
|
||||
name: ?[]u8,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 (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_unit_offset += next_offset;
|
||||
}
|
||||
}
|
||||
|
||||
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..]);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
228
std/debug/leb128.zig
Normal file
228
std/debug/leb128.zig
Normal file
@ -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);
|
||||
}
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
108
std/fmt.zig
108
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) }"));
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
480
std/heap.zig
480
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;
|
||||
const aligned_addr = mem.alignForward(addr, 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);
|
||||
|
||||
// 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,38 +184,170 @@ 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);
|
||||
}
|
||||
|
||||
const self = @fieldParentPtr(DirectAllocator, "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);
|
||||
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];
|
||||
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;
|
||||
|
||||
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 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
|
||||
/// where you can allocate without freeing, and then free it all together.
|
||||
pub const ArenaAllocator = struct {
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -306,6 +484,103 @@ pub const FixedBufferAllocator = struct {
|
||||
} else if (new_size <= old_mem.len and new_align <= old_align) {
|
||||
// We can't do anything with the memory, so tell the client to keep it.
|
||||
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);
|
||||
@ -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);
|
||||
}
|
||||
|
||||
41
std/io.zig
41
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
std/io/c_out_stream.zig
Normal file
48
std/io/c_out_stream.zig
Normal file
@ -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)),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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));
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
|
||||
1904
std/json/test.zig
Normal file
1904
std/json/test.zig
Normal file
File diff suppressed because it is too large
Load Diff
1904
std/json_test.zig
1904
std/json_test.zig
File diff suppressed because it is too large
Load Diff
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
938
std/math/big/rational.zig
Normal file
938
std/math/big/rational.zig
Normal file
@ -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);
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user