116 Commits
0.8.0 ... 0.7.1

Author SHA1 Message Date
Andrew Kelley
783cb980ab Release 0.7.1 2020-12-13 12:14:58 -07:00
Andrew Kelley
cf0e453cc9 Merge pull request #7406 from ifreund/dyn-musl2
stage2: support dynamically linking musl libc
2020-12-12 16:52:55 -07:00
Andrew Kelley
9d2e5bbcb4 glibc: do not provide -lcrypt
glibc is dropping this functionality moving forward.

This is a partial revert of commit
97c0e1cc41
2020-12-12 12:44:41 -07:00
Andrew Kelley
a42c712934 std.fs.path.extension: different behavior for ending dot
extension("a.") now returns "." instead of "".

This matches both Python and Node.js standard library behavior as well
as my personal opinion on how this function should be defined.

Apologies for missing this in the code review.
2020-12-11 18:23:57 -07:00
Andrew Kelley
1bbf731e7e stage2: proper file extension stripping
Previously it used mem.split on "." and took the first iterated item.
Now it uses fs.path.extension and strips off that number of bytes.

Closes #7404
2020-12-11 17:44:33 -07:00
Andrew Kelley
a6de0b4136 std.fs.path.extension: add additional API guarantee
Added:

The returned slice is guaranteed to have its pointer
within the start and end pointer address range of `path`,
even if it is length zero.
2020-12-11 17:44:27 -07:00
Andrew Kelley
5df9f15843 Merge pull request #7098 from MasterQ32/std.fs.path.extension
Implements std.fs.path.extension
2020-12-11 17:44:19 -07:00
Andrew Kelley
4797fdb3db fix deadlock with build-exe on an object for windows
The steps to repro this issue are:

zig build-obj hello.zig -target x86_64-windows-msvc
zig build-exe hello.obj -target x86_64-windows-msvc --subsystem console
-lkernel32 -lntdll

What was happening is that the main Compilation added a work item to
produce kernel32.lib. Then it added a sub-Compilation to build zig's
libc, which ended up calling a function with extern "kernel32", which
caused the sub-Compilation to also try to produce kernel32.lib. The main
Compilation and sub-Compilation do not coordinate about the set of
import libraries that they will be trying to build, so this caused a
deadlock.

This commit solves the problem by disabling the extern "foo" feature
from working when building compiler_rt or libc. Zig's linker code is now
responsible for putting the appropriate import libs on the linker line,
if any for compiler_rt and libc.

Related: #5825
2020-12-11 17:23:55 -07:00
Andrew Kelley
74c17aa8c5 mingw-w64: add .def files for xinput1_4
closes #7398
2020-12-11 17:23:50 -07:00
Andrew Kelley
465b90c1fa mingw-w64: add support for -lwldap32
closes #7395
2020-12-11 00:51:28 -07:00
LemonBoy
00664dbdce zig fmt: Fix alignment of initializer elements
Resetting `column_counter` is not needed as the effective column number
is calculated by taking that value modulo `row_size`.

Closes #7289
2020-12-11 00:40:05 -07:00
Vexu
c9bc8b9d0c zig fmt: improve var decl initializer formatting 2020-12-11 00:39:52 -07:00
Andrew Kelley
fd4c98cbb7 stage2: detect redundant C/C++ source files
Cache exposes BinDigest.

Compilation gains a set of a BinDigest for every C/C++ source file. We
detect when the same source/flags have already been added and emit a
compile error. This prevents a deadlock in the caching system.

Closes #7308
2020-12-11 00:33:59 -07:00
Andrew Kelley
21236c0151 CLI: improved local cache directory logic
Previously, when choosing the local cache directory, if there was no
root source file, an explicitly chosen path, or other clues, zig would
choose cwd + zig-cache/ as the local cache directory.

This can be problematic if Zig is invoked with the CWD set to a
read-only directory, or a directory unrelated to the actual source files
being compiled. In the real world, we see this when using `zig cc` with
CGo, which for some reason changes the current working directory to the
read-only go standard library path before running the C compiler.

This commit conservatively chooses to use the global cache directory
as the local cache directory when there is no other reasonable choice,
and no longer will rely on the cwd path to choose a local cache directory.

As a reminder, the --cache-dir CLI flag and ZIG_LOCAL_CACHE_DIR
environment variable are available for overriding the decision. For the
zig build system, it will always choose the directory that build.zig is
+ zig-cache/.

Closes #7342
2020-12-10 17:00:46 -07:00
antlilja
ea70a983ba Added global-cache argument to build system + removed extra args.
* Field global_cache_root was added to Builder struct along with
mandatory argument for build_runner.zig. Logic for using the custom
global cache was also added.

* The arguments --cache-dir and --global-cache-dir are no longer passed
directly through to build_runner.zig and are instead only passed through the
mandatory cache_root and global_cache_root arguments.
2020-12-10 17:00:38 -07:00
Vexu
235d56cb82 make std.json.unescapeString pub 2020-12-10 14:10:48 -07:00
Andrew Kelley
b4c0396d3c CLI: infer --name based on first C source file or object
Previously, --name would only be inferred if there was exactly 1 C
source file or exactly 1 object. Now it will be inferred if there is at
least one of either.
2020-12-09 21:21:27 -07:00
Timon Kruiper
97692cb4fe Do not keep the build.zig cache manifest file locked.
This allows to have multiple instances of `zig build` at the same
time. For example when you have a long running `zig build run` and
then want to run `zig build somethingelse`.
2020-12-09 20:16:26 -07:00
Andrew Kelley
d9c808e3ff mingw-w64: patch to silence implicit-function-declaration warnings
Closes #7356

I did this as a patch to the source rather than passing flags so that
it would intentionally be reverted when we update to the next release of
mingw-w64. At this time if any warnings are still emitted we should find
out why and make sure upstream is aware of the problem.
2020-12-09 17:32:32 -07:00
Andrew Kelley
1f09584d05 MoveFileEx can return ACCESS_DENIED
I observed this on Windows 10, trying to use MoveFileEx with
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH
to overwrite a running executable.
2020-12-09 17:32:26 -07:00
Martin Wickham
cad2e8da9d Fix operator precedence documentation 2020-12-09 17:31:49 -07:00
Andrew Kelley
b124d04e6a Merge pull request #7366 from LemonBoy/fix-7346
Some compiler-rt fixes
2020-12-09 12:21:28 -07:00
Lee Cannon
a7eea0813f Fixes #7352 - ignore zig fmt ignore zig-cache 2020-12-09 11:44:40 -07:00
Andrew Kelley
85c1db9222 Merge pull request #7355 from ziglang/lld-child-process
invoke LLD as a child process rather than a library
2020-12-09 00:32:30 -07:00
antlilja
40e37d4324 Change tag returned by zigTagType for c_longdouble to Float.
Function was returning Int before.
2020-12-08 17:10:55 -07:00
Nathanaël Courant
1ec0261518 Fix general purpose allocator incorrectly modifying total_requested_bytes in some cases 2020-12-08 13:57:02 -07:00
Andrew Kelley
5c13a4e54a tests: run-translated-c now respects -Dtarget 2020-12-08 13:56:56 -07:00
Andrew Kelley
c2de3bdc12 always use codeview (pdb) when object_format is PE/COFF
Previously, when mixing Zig and C/C++ code for windows-gnu targets, zig
would get codeview format but the C/C++ code would not get any debug
info. Now, C/C++ code properly emits debug info in codeview format and
everything just works.
2020-12-08 13:56:50 -07:00
Andrew Kelley
ad95eecf37 glibc: additionally provide -lcrypt
also remove redundant "util" string matching.
2020-12-08 13:56:21 -07:00
Nathan Michaels
83b2785a43 Implement msp430 mapping for c_longdouble. (#7333) 2020-12-08 11:14:33 -07:00
LemonBoy
e2104ecc2d stage1: Fix type mapping for c_longdouble
A quick and dirty job to let the compiler use the correct size and
alignment.
2020-12-08 11:14:21 -07:00
xackus
05fefc0d3f std.c: freeing null is a no-op 2020-12-08 11:11:49 -07:00
Veikka Tuominen
01ff3684dc Merge pull request #7313 from LemonBoy/booo
Fix a few unsound optimizations on single-element union/enum
2020-12-06 12:37:18 -07:00
Andrew Kelley
48c8948f49 update to latest clang C headers 2020-12-04 17:25:55 -07:00
Jakub Konka
f385419259 macho: specify -install_name as full dylib's name
This then allows for proper resolution of names via runpath search
path list, i.e., `-rpath @loader_path` will correctly resolve
to `@rpath/libxxx.dylib (...)` in the linked binary.
2020-12-04 14:54:17 -07:00
Jakub Konka
96a703ee6d Version-gate appending -syslibroot flag to lld
This commit version-gates appending `-syslibroot` flag to lld. This
is predicated upon the fact that for versions of macOS lower than
11, lld would fail to find and link against frameworks with this
flag specified.

Co-authored-by: Andrew Kelley <andrew@ziglang.org>
2020-12-04 12:39:07 -07:00
Jakub Konka
32997a2fb0 Merge pull request #7293 from kubkon/fix-7030
stage1: allow idx 0 err to be put into error_name_table
2020-12-04 12:39:01 -07:00
Andrew Kelley
a1d0c77539 add more mingw-w64 .def files
closes #7268
2020-12-03 18:04:39 -07:00
Andrew Kelley
2ce5f84c2f stage1: compile error for pointer arithmetic on ptr-to-array
See #2018
2020-12-03 17:46:21 -07:00
Andrew Kelley
05265160ae add @cImport files to Compilation cache manifest
closes #7007
2020-12-03 16:08:55 -07:00
Koakuma
52de625df9 Fix floating point parsing on BE systems (#7256)
* Fix floating point parsing on BE systems

* Load the appropriate endian.h files for macOS and BSD

* Add endian definition for Windows and extra check for ldshape selection

* Fix endian macro definition for macOS

Apparently their macros are defined without a leading __.

* Define new macro for endian checking purposes

This is gross and I really do not like the lack of standardization
around this part, but what can I do?
2020-12-03 13:47:31 -07:00
Miles Alan
cdde9d8885 std/event: Fix import path for WaitGroup 2020-12-03 13:44:25 -07:00
Andrew Kelley
ff802cc996 stage2: don't pass -l arguments when building .a or .o files
See #7094
2020-12-02 20:25:03 -07:00
LemonBoy
0ac43154eb std: Add nosuspend around stderr.print calls 2020-12-02 17:54:34 -07:00
Vexu
401d091fb4 std.build: addBuildOption special handling for SemanticVersion 2020-12-02 17:54:29 -07:00
Andrew Kelley
b1f52ca7f2 stage2: linkAsArchive: respect disable_lld_caching
Closes #7274
Closes #6943
2020-12-02 16:40:00 -07:00
LemonBoy
02cb3841a6 ci: Retry apt-get install at most three times
Try harder instead of failing after the first invocation fails.
2020-12-02 16:16:36 -07:00
LemonBoy
7c13bec7cb std: make the use of pthread_join POSIX-compliant
Applications supplying their own custom stack to pthread_create are not
allowed to free the allocated memory after pthread_join returns as,
according to the specification, the thread is not guaranteed to be dead
after the join call returns.

Avoid this class of problems by avoiding the use of a custom stack
altogether, let pthread handle its own resources.

Allocations made on the child stack are now done on the C heap.

Thanks @semarie for noticing the problem on OpenBSD and suggesting a
fix.

Closes #7275
2020-12-02 16:16:31 -07:00
Mathieu Guay-Paquet
7add370371 fix the tinyest typo 2020-12-02 16:16:02 -07:00
daurnimator
d15a0ec7b2 Localhost is special (#6955)
* std: always return loopback address when looking up localhost

* std: also return Ipv6 loopback

* std: remove commented out obsolete code
2020-12-01 17:14:43 -07:00
LemonBoy
0858d7b0df stage2: Create cache manifest before calling final
If we enter the `if` because `comp.disable_c_depfile` is false the `man`
object has no manifest and calling .final on it will trip an assertion.

Closes #7096
2020-12-01 16:52:52 -07:00
Andrew Kelley
a4c8bd8fd4 stage2: add -femit-foo=bar args to the cache hash
Closes #6979
Closes #7036
2020-12-01 16:36:37 -07:00
Alexandros Naskos
7099dff7ea Add package names and paths to the zig root module cache hash.
Add package names to the stage1 cache hash and package files to the
stage1 manifest file.
2020-12-01 14:57:27 -07:00
Timon Kruiper
6bf19e32e7 Make sure to include the root_name in the cache.
This fixes a bug where the caching system did not notice when the
--name flag changed.
2020-12-01 11:39:15 -07:00
Andrew Kelley
c8b8f0ea13 COFF linking: fix incorrectly passing .dll instead of .lib
commit 9d1816111d used the "output path"
as the path for passing shared library artifact paths to the Zig CLI.
For Windows, this was incorrect because it would pass the .dll instead
of the .lib file. This commit passes the "output lib path" instead,
which makes it pass the .lib path in case of a .dll on Windows.

This way the linker does not complain and say, "bad file type. Did you
specify a DLL instead of an import library?"
2020-12-01 11:31:48 -07:00
Andrew Kelley
d2445764a9 restore -target wasm32-freestanding-musl for C headers
See #5854

Some tiny tweaks too:
 * Use `wasm-freestanding-musl` instead of `wasm32-freestanding-musl`,
   making it pointer-size-agnostic.
 * Fix trying to build non-existent wasm musl start files.
2020-11-30 20:58:31 -07:00
Andrew Kelley
a9b7d8fa07 stage2: fix not detecting all dynamic libraries
Positional shared library arguments were not being detected as causing
dynamic linking, resulting in invalid linker lines. LLD did not have an
error message for this when targeting x86_64-linux but it did emit an
error message when targeting aarch64-linux, which is how I noticed the
problem.

This surfaced an error having to do with fifo.pipe() in the cat example
which I did not diagnose but solved the issue by doing the revamp that
was already overdue for that example.

It appears that the zig-window project was exploiting the previous
behavior for it to function properly, so this prompts the question, is
there some kind of static/dynamic executable hybrid that the compiler
should recognize? Unclear - but we can discuss that in #7240.
2020-11-30 20:58:15 -07:00
Andrew Kelley
57ac835a03 Merge branch 'alexnask-fix_6868' into master
Closes #7139
Closes #6868
2020-11-30 18:13:06 -07:00
Andrew Kelley
3c907e51d1 fix regression on wasm targets
The previous commit broke wasm targets because the linking step would
look for the compiler-rt lib in the wrong place. Fixed in this commit.
2020-11-30 17:47:24 -07:00
Andrew Kelley
791e38da8c Merge branch 'alexnask-bundle_compiler_rt' into master
Closes #7013
Closes #6817
2020-11-30 16:50:56 -07:00
Michael Freundorfer
1a61a9d4bf Fix WindowsDynLib.openW trying to strip the \??\ prefix when it does not exist 2020-11-30 12:13:17 -07:00
Jonathan Marler
8f346d9a4b fix memory leak in BufMap 2020-11-30 11:40:44 -07:00
LemonBoy
a7c2cfe16d stage1: Fix typeInfo generation for arrays w/o sentinel
ZigTypeIdOptional types have a different way of specifying their payload
value depending on whether the child type is a pointer or not (plus some
other special cases).

Fixes #7251
2020-11-29 11:39:35 -07:00
LemonBoy
0a4a99ec87 stage1: Add missing bitcast when rendering var ptr
Some types require this extra bitcast, eg. structs or unions with extra
padding fields inserted by the compiler.

Fixes #7250
2020-11-29 11:37:44 -07:00
LemonBoy
be2adff087 std: Avoid deadlock in the signal handler
stderr_mutex may still be held when we reach the signal handler, grab
our own stderr handle to print the error messages and avoid deadlocking.

Closes #7247
2020-11-29 11:31:38 -07:00
christian-stephen
a6222d1d4b Add readAllArrayListAligned to Reader which can accept an arbitrary alignment 2020-11-27 18:01:49 -07:00
Andrew Kelley
f09f960ce4 Merge branch 'kubkon-elf-soname-opt-in' into master
closes #7162
2020-11-27 17:57:11 -07:00
LemonBoy
288b8b535f stage1: Fix crash in *[N]T to []T conversion with zst
Prevent the crash by not making the codegen try to access the
non-existing ptr field in the slice.

Closes #6951
2020-11-27 15:34:13 -07:00
LemonBoy
36b8f5d194 stage1: Force union member types to be resolved
No test case because I couldn't reduce the huuuge test case.
Fixes the problem discovered by @ifreund.
2020-11-26 11:50:38 -07:00
Isaac Freund
41d57b051f std/os: fix prctl constants 2020-11-25 16:47:44 -07:00
LemonBoy
24d4bfb666 stage1: Fix ICE when generating struct fields with padding
Make gen_const_ptr_struct_recursive aware of the possible presence of
some trailing padding by always bitcasting the pointer to its expected
type.

Not an elegant solution but makes LLVM happy and is consistent with how
the other callsites are handling this case.

Fixes #5398
2020-11-25 16:36:57 -07:00
Jonathan Marler
06a75c16ff fix for GCC 9.2: -Wno-maybe-uninitialized 2020-11-24 18:32:57 -07:00
Frank Denis
8af016c5be Update the minimum cmake version we require
Recent versions of cmake complain about it:

<<
  CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 2.8.12 will be removed from a future version of
  CMake.
>>

We don't require anything from version 2.8.5, and version 2.8.12 was
released in 2011, so it is very unlikely that anyone still uses 2.8.5.
2020-11-24 18:32:51 -07:00
Isaac Freund
a05ae01b4f std/os: define and use dev_t for linux x86_64 2020-11-20 18:36:23 -07:00
Isaac Freund
1344706b47 std/os: add time_t definiton for x86_64 linux 2020-11-20 18:36:15 -07:00
LemonBoy
72980388ca stage1: Resolve usingnamespace decls when calling @typeInfo
Closes #7176
2020-11-20 18:02:20 -07:00
LemonBoy
c6c25a1c09 stage1: Fix undefined assignment for bitfields
Prevents silent memory corruption.

Closes #7055
2020-11-18 22:51:34 -07:00
Frank Denis
3f134cfe5e edwards25519 - skip useless operations and duplicate lookup table
Just some trivial changes; no functional changes.

Skip useless nul additions and multiplications and comptime the
basepoint multiples only once.
2020-11-18 21:45:42 -08:00
breakin
e814f71052 Change seed for Murmur2_64 from u32 to u64 2020-11-18 18:06:04 -07:00
Veikka Tuominen
50269f2315 Merge pull request #6649 from Rocknest/verparse
make Version.parse less strict
2020-11-18 17:47:43 -07:00
Vexu
8af0a1987b make help in commands more consistent
Closes #7101

Co-authored-by: pfg <pfg@pfg.pw>
2020-11-18 17:37:14 -07:00
Timon Kruiper
b498d26376 Allow Zig to be built with clang 11 and -Werror
This was brought to the horizon when using zig-bootstrap to cross compile
Zig for windows-gnu.
2020-11-18 17:32:48 -07:00
LemonBoy
d3f1a4edce stage1: Add architecture-specific clobbers to asm()
We're basically following Clang's lead, add the necessary clobbers to
minimize the risk of generating wrong code.
2020-11-18 17:32:41 -07:00
Veikka Tuominen
1add7c616f Merge pull request #7084 from xackus/mem-volatile
std.mem: make sliceAsBytes, etc. respect volatile
2020-11-18 17:31:11 -07:00
Frank Denis
5f9a664de9 STAGE1_SOURCES: In 0.7.x, leb128.zig is in std/debug (#7148)
* STAGE1_SOURCES: In 0.7.x, leb128.zig is in std/debug

* codegen/aarch64.zig doesn't exist in 0.7.x

Co-authored-by: Frank Denis <github@purftpd.org>
2020-11-18 14:53:47 -05:00
LemonBoy
1c8cd268be stage1: Fix asyncCall with non-abi-aligned arguments
Make the code used to calculate the variable slot index into the frame
match what's done during the structure layout calculation.

Prevents a few nasty LLVM errors when such types are passed around.
2020-11-17 16:55:44 -07:00
Andrew Kelley
eea4cd2924 cli: make -h, --help consistent in usage text and parsing
also trivial fixes in the general usage text
2020-11-17 16:54:15 -07:00
Guoxin Yin
4d44a813de Add -h alias for --help 2020-11-17 11:39:42 -07:00
johnLate
51ffb0548d CMake: properly detect when to rebuild zig1.o
This is andrewrk's patch from ziglang#6724 (rebased)

CMake: Fix dependency problem

I don't know whether the error was expected cmake behavior or a bug.
This change seems to fix the issue. See ziglang#6724 for details.

cmake: add the correct set of zig stage2 sources
2020-11-16 18:04:54 -07:00
Alex Cameron
5b42704ea7 Prevent double file close in MachO linking 2020-11-16 15:00:22 -07:00
Frank Denis
c8b6e407ba Enable loop interleaving when unrolling is enabled
This mimics clang's default behavior.
2020-11-16 15:00:16 -07:00
LemonBoy
9e1e91dafc std: Make windows.ReadFile allow short reads
Make it behave like the read() wrapper for unix systems.
Reading the whole buffer breaks some use-cases like buffered readers
over sockets.

Closes #7121
2020-11-16 14:35:28 -07:00
LemonBoy
6624f9cd5c stage1: Fix generation of pass-by-value args in async fns
The mismatch between the argument slot type in the frame structure and
the one used in the store operation made the generated code write
garbage over the nearby fields.

Fixes #7104
2020-11-16 11:37:49 -07:00
Andrew Kelley
7d0c461b77 std.fs.path.dirname: return null when input path is root
This intentionally diverges from the unix dirname command, as well as
Python and Node.js standard libraries, which all have this edge case
return the input path, unmodified. This is a footgun, and nobody should
have ever done it this way.

Even the man page contradicts the behavior. It says:
"strip last component from file name". Now consider, if you
remove the last item from an array of length 1, then you
have now an array of length 0. After you strip the last component, there
should be no components remaining. Clearly, returning the input parameter
unmodified in this case does not match the documented behavior. This is
my justification for taking a stand on this API design.

closes #6746
closes #6727
closes #6584
closes #6592
closes #6602
2020-11-15 10:53:06 -07:00
LemonBoy
2d280825cd stage1: Disambiguate Wasm imports with same name
Closes #7088
2020-11-13 14:33:20 -07:00
LemonBoy
10617593f8 stage1: Resolve ErrorUnion children types
Since the code is accessing the abi_size field compute the full type
size for both err_set_type and payload_type, not only for the latter.
2020-11-13 14:29:38 -07:00
LemonBoy
10b1001a12 stage1: Ask LLVM to produce compact code in ReleaseSize mode
Let's follow what Clang does for -Oz and apply the `minsize` and
`optsize` attributes by default.

Closes #7048
Supersedes #7077
2020-11-13 10:27:26 -07:00
Hubert Jasudowicz
eaa1db2002 std: Fix code model argument 2020-11-11 19:33:10 -07:00
Vexu
1aec406311 std: fix HashMap.clearRetainingCapacity 2020-11-11 19:33:03 -07:00
Vexu
b6350a2b3f std: fix HashMap.putAssumeCapacity 2020-11-11 19:32:58 -07:00
Vexu
8c62733927 ensure TypeInfo payload is not undefined 2020-11-11 19:32:30 -07:00
LemonBoy
aa6fc29744 stage1: Fix crash in comptime struct generation
Using the gen_index rather than the src_index is needed to handle
structures containing zero-sized or comptime only types.

Closes #7027
2020-11-11 19:14:03 -07:00
Jonas Carpay
01a927a0cb Fix backticked code in langref 2020-11-11 19:13:52 -07:00
LemonBoy
7d3c5f207a stage1: Avoid resolving type entry in [0]T
The logic was already there but this rule was only applied in some
places, apply it in the remaining code paths.

Closes #7058
2020-11-11 19:13:04 -07:00
Andrew Kelley
0405698696 add missing -m<os>-version-min CLI args to clang
This fixes some code generation issues when targeting macOS and
compiling C/C++ code.
2020-11-10 15:24:57 -07:00
Andrew Kelley
73455eaf42 std.Target: bump default version max for macos 2020-11-10 15:24:51 -07:00
LemonBoy
85665386c6 stage1: Fix comparison of unions containing zero-sized types
The code tried to be too smart and skipped the equality (returning true)
if the payload type was zero-sized.
This optimization is completely wrong when the union payload is a
metatype!

Fixes #7047
2020-11-10 15:24:41 -07:00
Andrew Kelley
2c0caa8533 main: updateModule returns an error when there are any compile errors
closes #6976
2020-11-09 20:52:08 -07:00
daurnimator
904c513a1e Fix json parser close tracking (#6865)
* std: fix json parsing with unmatched closing tokens

* std: fix swapped json parsing errors
2020-11-09 16:29:22 -07:00
LemonBoy
0e2eb6eb65 stage1: Print correct error message for vector @intCast 2020-11-09 16:25:47 -07:00
Frank Denis
c2c3177d82 Don't prevent compilation on platforms where debug info is unsupported
We don't support debug information on platforms that are not tier-1,
but it shouldn't be a hard error that completely prevents compilation.
2020-11-09 16:23:27 -07:00
Alexandros Naskos
a28c244afb Windows TLS startup symbols are already provided by libcrt when linking against libc 2020-11-09 15:47:37 -07:00
Andrew Kelley
97ec177953 std.ResetEvent: disable flaky test on Windows
See #7009
2020-11-09 15:36:51 -07:00
data-man
810c03f426 Fix reduce documentation 2020-11-09 15:36:46 -07:00
Andrew Kelley
0f4b893d6d langref: add 0.7.0 link 2020-11-09 15:36:36 -07:00
Frank Denis
61507d95d8 Bump Zig version to 0.7.0 2020-11-09 15:36:26 -07:00
104 changed files with 9749 additions and 1095 deletions

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.5)
cmake_minimum_required(VERSION 2.8.12)
# Use ccache if possible
FIND_PROGRAM(CCACHE_PROGRAM ccache)
@@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
set(ZIG_VERSION_MAJOR 0)
set(ZIG_VERSION_MINOR 7)
set(ZIG_VERSION_PATCH 0)
set(ZIG_VERSION_PATCH 1)
set(ZIG_VERSION "" CACHE STRING "Override Zig version string. Default is to find out with git.")
if("${ZIG_VERSION}" STREQUAL "")
@@ -258,6 +258,15 @@ set(SOFTFLOAT_LIBRARIES embedded_softfloat)
find_package(Threads)
set(ZIG_LIB_DIR "lib/zig")
set(C_HEADERS_DEST "${ZIG_LIB_DIR}/include")
set(LIBC_FILES_DEST "${ZIG_LIB_DIR}/libc")
set(LIBUNWIND_FILES_DEST "${ZIG_LIB_DIR}/libunwind")
set(LIBCXX_FILES_DEST "${ZIG_LIB_DIR}/libcxx")
set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std")
set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")
set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
# This is our shim which will be replaced by stage1.zig.
set(ZIG0_SOURCES
"${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp"
@@ -299,6 +308,258 @@ set(ZIG_CPP_SOURCES
# https://github.com/ziglang/zig/issues/6363
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
)
# Needed because we use cmake, not the zig build system, to build zig1.o.
# This list is generated by building zig and then clearing the zig-cache directory,
# then manually running the build-obj command (see BUILD_ZIG1_ARGS), and then looking
# in the zig-cache directory for the compiler-generated list of zig file dependencies.
set(ZIG_STAGE2_SOURCES
"${ZIG_CONFIG_ZIG_OUT}"
"${CMAKE_SOURCE_DIR}/lib/std/array_hash_map.zig"
"${CMAKE_SOURCE_DIR}/lib/std/array_list.zig"
"${CMAKE_SOURCE_DIR}/lib/std/ascii.zig"
"${CMAKE_SOURCE_DIR}/lib/std/atomic.zig"
"${CMAKE_SOURCE_DIR}/lib/std/atomic/int.zig"
"${CMAKE_SOURCE_DIR}/lib/std/atomic/queue.zig"
"${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig"
"${CMAKE_SOURCE_DIR}/lib/std/auto_reset_event.zig"
"${CMAKE_SOURCE_DIR}/lib/std/base64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/buf_map.zig"
"${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
"${CMAKE_SOURCE_DIR}/lib/std/c.zig"
"${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
"${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig"
"${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"
"${CMAKE_SOURCE_DIR}/lib/std/coff.zig"
"${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig"
"${CMAKE_SOURCE_DIR}/lib/std/crypto.zig"
"${CMAKE_SOURCE_DIR}/lib/std/crypto/blake3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/crypto/siphash.zig"
"${CMAKE_SOURCE_DIR}/lib/std/debug.zig"
"${CMAKE_SOURCE_DIR}/lib/std/debug/leb128.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf_bits.zig"
"${CMAKE_SOURCE_DIR}/lib/std/elf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/event.zig"
"${CMAKE_SOURCE_DIR}/lib/std/event/batch.zig"
"${CMAKE_SOURCE_DIR}/lib/std/event/loop.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fifo.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fmt.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fmt/errol.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fmt/errol/enum3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fmt/errol/lookup.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fmt/parse_float.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fs.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fs/file.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fs/get_app_data_dir.zig"
"${CMAKE_SOURCE_DIR}/lib/std/fs/path.zig"
"${CMAKE_SOURCE_DIR}/lib/std/hash.zig"
"${CMAKE_SOURCE_DIR}/lib/std/hash/auto_hash.zig"
"${CMAKE_SOURCE_DIR}/lib/std/hash/wyhash.zig"
"${CMAKE_SOURCE_DIR}/lib/std/hash_map.zig"
"${CMAKE_SOURCE_DIR}/lib/std/heap.zig"
"${CMAKE_SOURCE_DIR}/lib/std/heap/arena_allocator.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/auto_indenting_stream.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/buffered_atomic_file.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/buffered_writer.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/change_detection_stream.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/counting_writer.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/find_byte_out_stream.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/fixed_buffer_stream.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/reader.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/seekable_stream.zig"
"${CMAKE_SOURCE_DIR}/lib/std/io/writer.zig"
"${CMAKE_SOURCE_DIR}/lib/std/json.zig"
"${CMAKE_SOURCE_DIR}/lib/std/json/write_stream.zig"
"${CMAKE_SOURCE_DIR}/lib/std/linked_list.zig"
"${CMAKE_SOURCE_DIR}/lib/std/log.zig"
"${CMAKE_SOURCE_DIR}/lib/std/macho.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/big.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/big/int.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/floor.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/frexp.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/inf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/isinf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/isnan.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/ln.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/log.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/log10.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/log2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/nan.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/signbit.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/sqrt.zig"
"${CMAKE_SOURCE_DIR}/lib/std/mem.zig"
"${CMAKE_SOURCE_DIR}/lib/std/mem/Allocator.zig"
"${CMAKE_SOURCE_DIR}/lib/std/meta.zig"
"${CMAKE_SOURCE_DIR}/lib/std/meta/trailer_flags.zig"
"${CMAKE_SOURCE_DIR}/lib/std/meta/trait.zig"
"${CMAKE_SOURCE_DIR}/lib/std/mutex.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/errno-generic.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/netlink.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/prctl.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/securebits.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/x86_64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/io_uring.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/bits.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/ntstatus.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/win32error.zig"
"${CMAKE_SOURCE_DIR}/lib/std/pdb.zig"
"${CMAKE_SOURCE_DIR}/lib/std/process.zig"
"${CMAKE_SOURCE_DIR}/lib/std/progress.zig"
"${CMAKE_SOURCE_DIR}/lib/std/rand.zig"
"${CMAKE_SOURCE_DIR}/lib/std/reset_event.zig"
"${CMAKE_SOURCE_DIR}/lib/std/sort.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/clear_cache.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/clzsi2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/compareXf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divdf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divsf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divtf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/extendXfYf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixdfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixdfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixdfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixint.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixsfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixsfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixsfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixtfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixtfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixtfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixuint.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunsdfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunsdfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunsdfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunssfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunssfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunssfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunstfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunstfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunstfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatXisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatdidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatditf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatsiXf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floattidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floattitf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatundidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatundisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunditf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunsidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunsisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunsitf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatuntidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatuntisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatuntitf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/int.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulodi4.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muloti4.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcountdi2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/shift.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/stack_probe.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/truncXfYf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmod.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmodti4.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/umodti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/spinlock.zig"
"${CMAKE_SOURCE_DIR}/lib/std/start.zig"
"${CMAKE_SOURCE_DIR}/lib/std/std.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/aarch64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/amdgpu.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/arm.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/avr.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/bpf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/hexagon.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/mips.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/msp430.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/nvptx.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/powerpc.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/riscv.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/sparc.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/systemz.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/wasm.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/x86.zig"
"${CMAKE_SOURCE_DIR}/lib/std/thread.zig"
"${CMAKE_SOURCE_DIR}/lib/std/time.zig"
"${CMAKE_SOURCE_DIR}/lib/std/unicode.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/ast.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/cross_target.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/parse.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/render.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/string_literal.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/system.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/system/x86.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
"${CMAKE_SOURCE_DIR}/src/Cache.zig"
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
"${CMAKE_SOURCE_DIR}/src/DepTokenizer.zig"
"${CMAKE_SOURCE_DIR}/src/Module.zig"
"${CMAKE_SOURCE_DIR}/src/Package.zig"
"${CMAKE_SOURCE_DIR}/src/RangeSet.zig"
"${CMAKE_SOURCE_DIR}/src/TypedValue.zig"
"${CMAKE_SOURCE_DIR}/src/astgen.zig"
"${CMAKE_SOURCE_DIR}/src/clang.zig"
"${CMAKE_SOURCE_DIR}/src/clang_options.zig"
"${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
"${CMAKE_SOURCE_DIR}/src/codegen.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/arm.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/c.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/riscv64.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/spu-mk2.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/wasm.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/x86_64.zig"
"${CMAKE_SOURCE_DIR}/src/glibc.zig"
"${CMAKE_SOURCE_DIR}/src/introspect.zig"
"${CMAKE_SOURCE_DIR}/src/ir.zig"
"${CMAKE_SOURCE_DIR}/src/libc_installation.zig"
"${CMAKE_SOURCE_DIR}/src/libcxx.zig"
"${CMAKE_SOURCE_DIR}/src/libunwind.zig"
"${CMAKE_SOURCE_DIR}/src/link.zig"
"${CMAKE_SOURCE_DIR}/src/link/C.zig"
"${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
"${CMAKE_SOURCE_DIR}/src/link/MachO.zig"
"${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
"${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
"${CMAKE_SOURCE_DIR}/src/link/cbe.h"
"${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
"${CMAKE_SOURCE_DIR}/src/liveness.zig"
"${CMAKE_SOURCE_DIR}/src/llvm.zig"
"${CMAKE_SOURCE_DIR}/src/main.zig"
"${CMAKE_SOURCE_DIR}/src/mingw.zig"
"${CMAKE_SOURCE_DIR}/src/musl.zig"
"${CMAKE_SOURCE_DIR}/src/print_env.zig"
"${CMAKE_SOURCE_DIR}/src/print_targets.zig"
"${CMAKE_SOURCE_DIR}/src/stage1.zig"
"${CMAKE_SOURCE_DIR}/src/target.zig"
"${CMAKE_SOURCE_DIR}/src/tracy.zig"
"${CMAKE_SOURCE_DIR}/src/translate_c.zig"
"${CMAKE_SOURCE_DIR}/src/type.zig"
"${CMAKE_SOURCE_DIR}/src/value.zig"
"${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"
"${CMAKE_SOURCE_DIR}/src/zir.zig"
"${CMAKE_SOURCE_DIR}/src/zir_sema.zig"
)
if(MSVC)
set(MSVC_DIA_SDK_DIR "$ENV{VSINSTALLDIR}DIA SDK")
@@ -308,14 +569,6 @@ if(MSVC)
endif()
endif()
set(ZIG_LIB_DIR "lib/zig")
set(C_HEADERS_DEST "${ZIG_LIB_DIR}/include")
set(LIBC_FILES_DEST "${ZIG_LIB_DIR}/libc")
set(LIBUNWIND_FILES_DEST "${ZIG_LIB_DIR}/libunwind")
set(LIBCXX_FILES_DEST "${ZIG_LIB_DIR}/libcxx")
set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std")
set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")
set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
configure_file (
"${CMAKE_SOURCE_DIR}/src/stage1/config.h.in"
"${ZIG_CONFIG_H_OUT}"
@@ -348,6 +601,10 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0)
set(EXE_CFLAGS "${EXE_CFLAGS} -Werror=implicit-fallthrough")
endif()
# GCC 9.2 and older are unable to detect valid variable initialization in some cases
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 9.2)
set(EXE_CFLAGS "${EXE_CFLAGS} -Wno-maybe-uninitialized")
endif()
endif()
endif()
@@ -468,10 +725,10 @@ set(BUILD_ZIG1_ARGS
)
if("${ZIG_EXECUTABLE}" STREQUAL "")
add_custom_target(zig_build_zig1 ALL
add_custom_command(
OUTPUT "${ZIG1_OBJECT}"
COMMAND zig0 ${BUILD_ZIG1_ARGS}
DEPENDS zig0
BYPRODUCTS "${ZIG1_OBJECT}"
DEPENDS zig0 "${ZIG_STAGE2_SOURCES}"
COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
@@ -480,28 +737,29 @@ if("${ZIG_EXECUTABLE}" STREQUAL "")
set(ZIG_EXECUTABLE "${ZIG_EXECUTABLE}.exe")
endif()
else()
add_custom_target(zig_build_zig1 ALL
COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG1_ARGS}
add_custom_command(
OUTPUT "${ZIG1_OBJECT}"
BYPRODUCTS "${ZIG1_OBJECT}"
COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG1_ARGS}
DEPENDS ${ZIG_STAGE2_SOURCES}
COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
endif()
# cmake won't let us configure an executable without C sources.
add_executable(zig "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp")
add_executable(zig "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG1_OBJECT}")
set_target_properties(zig PROPERTIES
COMPILE_FLAGS ${EXE_CFLAGS}
LINK_FLAGS ${EXE_LDFLAGS}
)
target_link_libraries(zig "${ZIG1_OBJECT}" zigstage1)
target_link_libraries(zig zigstage1)
if(MSVC)
target_link_libraries(zig ntdll.lib)
elseif(MINGW)
target_link_libraries(zig ntdll)
endif()
add_dependencies(zig zig_build_zig1)
install(TARGETS zig DESTINATION bin)

View File

@@ -11,7 +11,7 @@ const fs = std.fs;
const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
const assert = std.debug.assert;
const zig_version = std.builtin.Version{ .major = 0, .minor = 6, .patch = 0 };
const zig_version = std.builtin.Version{ .major = 0, .minor = 7, .patch = 1 };
pub fn build(b: *Builder) !void {
b.setPreferredReleaseMode(.ReleaseFast);
@@ -128,11 +128,11 @@ pub fn build(b: *Builder) !void {
break :s b.fmt("dirty{x}", .{@truncate(u32, dirty_hash)});
};
// This will look like e.g. "0.6.0^0" for a tag commit.
// This will look like e.g. "0.7.0^0" for a tag commit.
if (mem.endsWith(u8, git_sha_trimmed, "^0")) {
const git_ver_string = git_sha_trimmed[0 .. git_sha_trimmed.len - 2];
if (!mem.eql(u8, git_ver_string, version_string)) {
std.debug.print("Expected git tag '{}', found '{}'", .{ version_string, git_ver_string });
std.debug.print("Expected git tag '{}', found '{}'\n", .{ version_string, git_ver_string });
std.process.exit(1);
}
break :v b.fmt("{}{}", .{ version_string, dirty_suffix });
@@ -215,7 +215,7 @@ pub fn build(b: *Builder) !void {
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
test_step.dependOn(tests.addTranslateCTests(b, test_filter));
test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter));
test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
// tests for this feature are disabled until we have the self-hosted compiler available
// test_step.dependOn(tests.addGenHTests(b, test_filter));
if (!skip_compile_errors) {

View File

@@ -8,11 +8,27 @@ BUILDDIR="$(pwd)"
sudo sh -c 'echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main" >> /etc/apt/sources.list'
wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update -q
sudo apt-get remove -y llvm-*
sudo rm -rf /usr/local/*
sudo apt-get install -y libxml2-dev libclang-11-dev llvm-11 llvm-11-dev liblld-11-dev cmake s3cmd gcc-7 g++-7 ninja-build tidy
# Some APT mirrors can be flaky, retry the download instead of failing right
# away.
APT_MAX_RETRY=3
for i in $(seq 1 "$APT_MAX_RETRY"); do
sudo apt-get update -q
sudo apt-get install -y \
libxml2-dev libclang-11-dev llvm-11 llvm-11-dev liblld-11-dev cmake s3cmd \
gcc-7 g++-7 ninja-build tidy \
&& break
if [ "$i" -eq "$APT_MAX_RETRY" ]; then
echo 'apt-get failed, giving up...'
exit 1
fi
echo 'apt-get failed, retrying...'
sleep 5s
done
QEMUBASE="qemu-linux-x86_64-5.1.0"
wget https://ziglang.org/deps/$QEMUBASE.tar.xz

View File

@@ -189,6 +189,7 @@
<a href="https://ziglang.org/documentation/0.4.0/">0.4.0</a> |
<a href="https://ziglang.org/documentation/0.5.0/">0.5.0</a> |
<a href="https://ziglang.org/documentation/0.6.0/">0.6.0</a> |
<a href="https://ziglang.org/documentation/0.7.0/">0.7.0</a> |
master
<h1>Contents</h1>
{#nav#}
@@ -1742,8 +1743,8 @@ const B = error{Two};
{#header_open|Precedence#}
<pre>{#syntax#}x() x[] x.y
a!b
!x -x -%x ~x &x ?x
x{} x.* x.?
!x -x -%x ~x &x ?x
! * / % ** *% ||
+ - ++ +% -%
<< >>
@@ -7454,7 +7455,7 @@ test "main" {
<p>
If the binary is built with error return tracing, and this function is invoked in a
function that calls a function with an error or error union return type, returns a
stack trace object. Otherwise returns `null`.
stack trace object. Otherwise returns {#link|null#}.
</p>
{#header_close#}
@@ -7987,7 +7988,7 @@ test "@wasmMemoryGrow" {
{#header_close#}
{#header_open|@setEvalBranchQuota#}
<pre>{#syntax#}@setEvalBranchQuota(new_quota: usize){#endsyntax#}</pre>
<pre>{#syntax#}@setEvalBranchQuota(new_quota: u32){#endsyntax#}</pre>
<p>
Changes the maximum number of backwards branches that compile-time code
execution can use before giving up and making a compile error.
@@ -8214,8 +8215,7 @@ test "vector @splat" {
<pre>{#syntax#}@reduce(comptime op: builtin.ReduceOp, value: anytype) std.meta.Child(value){#endsyntax#}</pre>
<p>
Transforms a {#link|vector|Vectors#} into a scalar value by performing a
sequential horizontal reduction of its elements using the specified
specified operator {#syntax#}op{#endsyntax#}.
sequential horizontal reduction of its elements using the specified operator {#syntax#}op{#endsyntax#}.
</p>
<p>
Not every operator is available for every vector element type:
@@ -9446,17 +9446,17 @@ test "string literal to constant slice" {
}
{#code_end#}
<p>
Just like string literals, `const` declarations, when the value is known at {#link|comptime#},
Just like string literals, {#syntax#}const{#endsyntax#} declarations, when the value is known at {#link|comptime#},
are stored in the global constant data section. Also {#link|Compile Time Variables#} are stored
in the global constant data section.
</p>
<p>
`var` declarations inside functions are stored in the function's stack frame. Once a function returns,
{#syntax#}var{#endsyntax#} declarations inside functions are stored in the function's stack frame. Once a function returns,
any {#link|Pointers#} to variables in the function's stack frame become invalid references, and
dereferencing them becomes unchecked {#link|Undefined Behavior#}.
</p>
<p>
`var` declarations at the top level or in {#link|struct#} declarations are stored in the global
{#syntax#}var{#endsyntax#} declarations at the top level or in {#link|struct#} declarations are stored in the global
data section.
</p>
<p>

View File

@@ -16,7 +16,7 @@
// to work with CUDA and OpenMP target offloading [in C and C++ mode].)
#pragma push_macro("__DEVICE__")
#ifdef _OPENMP
#ifdef __OPENMP_NVPTX__
#pragma omp declare target
#define __DEVICE__ __attribute__((noinline, nothrow, cold, weak))
#else
@@ -26,7 +26,7 @@
// To make the algorithms available for C and C++ in CUDA and OpenMP we select
// different but equivalent function versions. TODO: For OpenMP we currently
// select the native builtins as the overload support for templates is lacking.
#if !defined(_OPENMP)
#if !defined(__OPENMP_NVPTX__)
#define _ISNANd std::isnan
#define _ISNANf std::isnan
#define _ISINFd std::isinf
@@ -250,7 +250,7 @@ __DEVICE__ float _Complex __divsc3(float __a, float __b, float __c, float __d) {
#undef _LOGBd
#undef _LOGBf
#ifdef _OPENMP
#ifdef __OPENMP_NVPTX__
#pragma omp end declare target
#endif

View File

@@ -18,7 +18,9 @@
#include <cmath>
#define __CUDA__
#define __OPENMP_NVPTX__
#include <__clang_cuda_complex_builtins.h>
#undef __OPENMP_NVPTX__
#endif
// Grab the host header too.

View File

@@ -18,7 +18,9 @@
#include <math.h>
#define __CUDA__
#define __OPENMP_NVPTX__
#include <__clang_cuda_complex_builtins.h>
#undef __OPENMP_NVPTX__
#endif
// Grab the host header too.

View File

@@ -0,0 +1,385 @@
#define _Addr long
#define _Int64 long long
#define _Reg long
#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
typedef __builtin_va_list va_list;
#define __DEFINED_va_list
#endif
#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
typedef __builtin_va_list __isoc_va_list;
#define __DEFINED___isoc_va_list
#endif
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
typedef int wchar_t;
#define __DEFINED_wchar_t
#endif
#endif
#if defined(__NEED_float_t) && !defined(__DEFINED_float_t)
typedef float float_t;
#define __DEFINED_float_t
#endif
#if defined(__NEED_double_t) && !defined(__DEFINED_double_t)
typedef double double_t;
#define __DEFINED_double_t
#endif
#if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t)
typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
typedef long time_t;
#define __DEFINED_time_t
#endif
#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
typedef long suseconds_t;
#define __DEFINED_suseconds_t
#endif
#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
typedef struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
#define __DEFINED_pthread_attr_t
#endif
#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
#define __DEFINED_pthread_mutex_t
#endif
#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
#define __DEFINED_mtx_t
#endif
#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
#define __DEFINED_pthread_cond_t
#endif
#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
#define __DEFINED_cnd_t
#endif
#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
#define __DEFINED_pthread_rwlock_t
#endif
#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
#define __DEFINED_pthread_barrier_t
#endif
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
#define __DEFINED_size_t
#endif
#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t)
typedef unsigned _Addr uintptr_t;
#define __DEFINED_uintptr_t
#endif
#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t)
typedef _Addr ptrdiff_t;
#define __DEFINED_ptrdiff_t
#endif
#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t)
typedef _Addr ssize_t;
#define __DEFINED_ssize_t
#endif
#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t)
typedef _Addr intptr_t;
#define __DEFINED_intptr_t
#endif
#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t)
typedef _Addr regoff_t;
#define __DEFINED_regoff_t
#endif
#if defined(__NEED_register_t) && !defined(__DEFINED_register_t)
typedef _Reg register_t;
#define __DEFINED_register_t
#endif
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
#define __DEFINED_int8_t
#endif
#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t)
typedef signed short int16_t;
#define __DEFINED_int16_t
#endif
#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t)
typedef signed int int32_t;
#define __DEFINED_int32_t
#endif
#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t)
typedef signed _Int64 int64_t;
#define __DEFINED_int64_t
#endif
#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t)
typedef signed _Int64 intmax_t;
#define __DEFINED_intmax_t
#endif
#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t)
typedef unsigned char uint8_t;
#define __DEFINED_uint8_t
#endif
#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t)
typedef unsigned short uint16_t;
#define __DEFINED_uint16_t
#endif
#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t)
typedef unsigned int uint32_t;
#define __DEFINED_uint32_t
#endif
#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t)
typedef unsigned _Int64 uint64_t;
#define __DEFINED_uint64_t
#endif
#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t)
typedef unsigned _Int64 u_int64_t;
#define __DEFINED_u_int64_t
#endif
#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t)
typedef unsigned _Int64 uintmax_t;
#define __DEFINED_uintmax_t
#endif
#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t)
typedef unsigned mode_t;
#define __DEFINED_mode_t
#endif
#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t)
typedef unsigned _Reg nlink_t;
#define __DEFINED_nlink_t
#endif
#if defined(__NEED_off_t) && !defined(__DEFINED_off_t)
typedef _Int64 off_t;
#define __DEFINED_off_t
#endif
#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t)
typedef unsigned _Int64 ino_t;
#define __DEFINED_ino_t
#endif
#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t)
typedef unsigned _Int64 dev_t;
#define __DEFINED_dev_t
#endif
#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t)
typedef long blksize_t;
#define __DEFINED_blksize_t
#endif
#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t)
typedef _Int64 blkcnt_t;
#define __DEFINED_blkcnt_t
#endif
#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t)
typedef unsigned _Int64 fsblkcnt_t;
#define __DEFINED_fsblkcnt_t
#endif
#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t)
typedef unsigned _Int64 fsfilcnt_t;
#define __DEFINED_fsfilcnt_t
#endif
#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t)
typedef unsigned wint_t;
#define __DEFINED_wint_t
#endif
#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t)
typedef unsigned long wctype_t;
#define __DEFINED_wctype_t
#endif
#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t)
typedef void * timer_t;
#define __DEFINED_timer_t
#endif
#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t)
typedef int clockid_t;
#define __DEFINED_clockid_t
#endif
#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t)
typedef long clock_t;
#define __DEFINED_clock_t
#endif
#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval)
struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#define __DEFINED_struct_timeval
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
struct timespec { time_t tv_sec; long tv_nsec; };
#define __DEFINED_struct_timespec
#endif
#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t)
typedef int pid_t;
#define __DEFINED_pid_t
#endif
#if defined(__NEED_id_t) && !defined(__DEFINED_id_t)
typedef unsigned id_t;
#define __DEFINED_id_t
#endif
#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t)
typedef unsigned uid_t;
#define __DEFINED_uid_t
#endif
#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t)
typedef unsigned gid_t;
#define __DEFINED_gid_t
#endif
#if defined(__NEED_key_t) && !defined(__DEFINED_key_t)
typedef int key_t;
#define __DEFINED_key_t
#endif
#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t)
typedef unsigned useconds_t;
#define __DEFINED_useconds_t
#endif
#ifdef __cplusplus
#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t)
typedef unsigned long pthread_t;
#define __DEFINED_pthread_t
#endif
#else
#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t)
typedef struct __pthread * pthread_t;
#define __DEFINED_pthread_t
#endif
#endif
#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t)
typedef int pthread_once_t;
#define __DEFINED_pthread_once_t
#endif
#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t)
typedef unsigned pthread_key_t;
#define __DEFINED_pthread_key_t
#endif
#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t)
typedef int pthread_spinlock_t;
#define __DEFINED_pthread_spinlock_t
#endif
#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t)
typedef struct { unsigned __attr; } pthread_mutexattr_t;
#define __DEFINED_pthread_mutexattr_t
#endif
#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t)
typedef struct { unsigned __attr; } pthread_condattr_t;
#define __DEFINED_pthread_condattr_t
#endif
#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t)
typedef struct { unsigned __attr; } pthread_barrierattr_t;
#define __DEFINED_pthread_barrierattr_t
#endif
#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t)
typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t;
#define __DEFINED_pthread_rwlockattr_t
#endif
#if defined(__NEED_FILE) && !defined(__DEFINED_FILE)
typedef struct _IO_FILE FILE;
#define __DEFINED_FILE
#endif
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
#endif
#if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t)
typedef struct __locale_struct * locale_t;
#define __DEFINED_locale_t
#endif
#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t)
typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t;
#define __DEFINED_sigset_t
#endif
#if defined(__NEED_struct_iovec) && !defined(__DEFINED_struct_iovec)
struct iovec { void *iov_base; size_t iov_len; };
#define __DEFINED_struct_iovec
#endif
#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t)
typedef unsigned socklen_t;
#define __DEFINED_socklen_t
#endif
#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t)
typedef unsigned short sa_family_t;
#define __DEFINED_sa_family_t
#endif
#undef _Addr
#undef _Int64
#undef _Reg

View File

@@ -0,0 +1,24 @@
#ifndef _ERRNO_H
#define _ERRNO_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef WASM_THREAD_MODEL_SINGLE
extern int errno;
#else
#ifdef __cplusplus
extern thread_local int errno;
#else
extern _Thread_local int errno;
#endif
#endif
#define errno errno
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,354 @@
;
; Definition file of IPHLPAPI.DLL
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "IPHLPAPI.DLL"
EXPORTS
AddIPAddress
AllocateAndGetArpEntTableFromStack
AllocateAndGetIfTableFromStack
AllocateAndGetInterfaceInfoFromStack
AllocateAndGetIpAddrTableFromStack
AllocateAndGetIpForwardTableFromStack
AllocateAndGetIpNetTableFromStack
AllocateAndGetTcpExTable2FromStack
AllocateAndGetTcpExTableFromStack
AllocateAndGetTcpTableFromStack
AllocateAndGetUdpExTable2FromStack
AllocateAndGetUdpExTableFromStack
AllocateAndGetUdpTableFromStack
CPNatfwtCreateProviderInstance
CPNatfwtDeregisterProviderInstance
CPNatfwtDestroyProviderInstance
CPNatfwtIndicateReceivedBuffers
CPNatfwtRegisterProviderInstance
CancelIfTimestampConfigChange
CancelIPChangeNotify
CancelSecurityHealthChangeNotify
CancelMibChangeNotify2
CaptureInterfaceHardwareCrossTimestamp
CloseCompartment
CloseGetIPPhysicalInterfaceForDestination
ConvertCompartmentGuidToId
ConvertCompartmentIdToGuid
ConvertGuidToStringA
ConvertGuidToStringW
ConvertInterfaceAliasToLuid
ConvertInterfaceGuidToLuid
ConvertInterfaceIndexToLuid
ConvertInterfaceLuidToAlias
ConvertInterfaceLuidToGuid
ConvertInterfaceLuidToIndex
ConvertInterfaceLuidToNameA
ConvertInterfaceLuidToNameW
ConvertInterfaceNameToLuidA
ConvertInterfaceNameToLuidW
ConvertInterfacePhysicalAddressToLuid
ConvertIpv4MaskToLength
ConvertLengthToIpv4Mask
ConvertRemoteInterfaceAliasToLuid
ConvertRemoteInterfaceGuidToLuid
ConvertRemoteInterfaceIndexToLuid
ConvertRemoteInterfaceLuidToAlias
ConvertRemoteInterfaceLuidToGuid
ConvertRemoteInterfaceLuidToIndex
ConvertStringToGuidA
ConvertStringToGuidW
ConvertStringToInterfacePhysicalAddress
CreateAnycastIpAddressEntry
CreateCompartment
CreateIpForwardEntry
CreateIpForwardEntry2
CreateIpNetEntry
CreateIpNetEntry2
CreatePersistentTcpPortReservation
CreatePersistentUdpPortReservation
CreateProxyArpEntry
CreateSortedAddressPairs
CreateUnicastIpAddressEntry
DeleteAnycastIpAddressEntry
DeleteCompartment
DeleteIPAddress
DeleteIpForwardEntry
DeleteIpForwardEntry2
DeleteIpNetEntry
DeleteIpNetEntry2
DeletePersistentTcpPortReservation
DeletePersistentUdpPortReservation
DeleteProxyArpEntry
DeleteUnicastIpAddressEntry
DisableMediaSense
EnableRouter
FlushIpNetTable
FlushIpNetTable2
FlushIpNetTableFromStack
FlushIpPathTable
FreeDnsSettings
FreeInterfaceDnsSettings
FreeMibTable
GetAdapterIndex
GetAdapterOrderMap
GetAdaptersAddresses
GetAdaptersInfo
GetAnycastIpAddressEntry
GetAnycastIpAddressTable
GetBestInterface
GetBestInterfaceEx
GetBestInterfaceFromStack
GetBestRoute
GetBestRoute2
GetBestRouteFromStack
GetCurrentThreadCompartmentId
GetCurrentThreadCompartmentScope
GetDefaultCompartmentId
GetDnsSettings
GetExtendedTcpTable
GetExtendedUdpTable
GetFriendlyIfIndex
GetIcmpStatistics
GetIcmpStatisticsEx
GetIcmpStatsFromStack
GetIcmpStatsFromStackEx
GetIfEntry
GetIfEntry2
GetIfEntry2Ex
GetIfEntryFromStack
GetIfStackTable
GetIfTable
GetIfTableFromStack
GetIgmpList
GetIfTable2
GetIfTable2Ex
GetInterfaceCompartmentId
GetInterfaceCurrentTimestampCapabilities
GetInterfaceDnsSettings
GetInterfaceHardwareTimestampCapabilities
GetInterfaceInfo
GetInvertedIfStackTable
GetIpAddrTable
GetIpAddrTableFromStack
GetIpErrorString
GetIpForwardEntry2
GetIpForwardTable
GetIpForwardTableFromStack
GetIpForwardTable2
GetIpInterfaceEntry
GetIpInterfaceTable
GetIpNetEntry2
GetIpNetTable
GetIpNetTable2
GetIpNetTableFromStack
GetIpNetworkConnectionBandwidthEstimates
GetIpPathEntry
GetIpPathTable
GetIpStatistics
GetIpStatisticsEx
GetIpStatsFromStack
GetIpStatsFromStackEx
GetJobCompartmentId
GetMulticastIpAddressEntry
GetMulticastIpAddressTable
GetNetworkConnectivityHint
GetNetworkConnectivityHintForInterface
GetNetworkInformation
GetNetworkParams
GetNumberOfInterfaces
GetOwnerModuleFromPidAndInfo
GetOwnerModuleFromTcp6Entry
GetOwnerModuleFromTcpEntry
GetOwnerModuleFromUdp6Entry
GetOwnerModuleFromUdpEntry
GetPerAdapterInfo
GetPerTcp6ConnectionEStats
GetPerTcp6ConnectionStats
GetPerTcpConnectionEStats
GetPerTcpConnectionStats
GetRTTAndHopCount
GetTcpExTable2FromStack
GetSessionCompartmentId
GetTcp6Table
GetTcp6Table2
GetTcpStatistics
GetTcpStatisticsEx
GetTcpStatisticsEx2
GetTcpStatsFromStack
GetTcpStatsFromStackEx
GetTcpTable
GetTcpTable2
GetTcpTableFromStack
GetUdpExTable2FromStack
GetTeredoPort
GetUdp6Table
GetUdpStatistics
GetUdpStatisticsEx
GetUdpStatisticsEx2
GetUdpStatsFromStack
GetUdpStatsFromStackEx
GetUdpTable
GetUdpTableFromStack
GetUniDirectionalAdapterInfo
GetUnicastIpAddressEntry
GetUnicastIpAddressTable
GetWPAOACSupportLevel
Icmp6CreateFile
Icmp6ParseReplies
Icmp6SendEcho2
IcmpCloseHandle
IcmpCreateFile
IcmpParseReplies
IcmpSendEcho
IcmpSendEcho2
IcmpSendEcho2Ex
InitializeCompartmentEntry
InitializeIpForwardEntry
InitializeIpInterfaceEntry
InitializeUnicastIpAddressEntry
InternalCleanupPersistentStore
InternalCreateAnycastIpAddressEntry
InternalCreateIpForwardEntry
InternalCreateIpForwardEntry2
InternalCreateIpNetEntry
InternalCreateIpNetEntry2
InternalCreateUnicastIpAddressEntry
InternalDeleteAnycastIpAddressEntry
InternalDeleteIpForwardEntry
InternalDeleteIpForwardEntry2
InternalDeleteIpNetEntry
InternalDeleteIpNetEntry2
InternalDeleteUnicastIpAddressEntry
InternalFindInterfaceByAddress
InternalGetAnycastIpAddressEntry
InternalGetAnycastIpAddressTable
InternalGetBoundTcp6EndpointTable
InternalGetBoundTcpEndpointTable
InternalGetForwardIpTable2
InternalGetIPPhysicalInterfaceForDestination
InternalGetIfEntry2
InternalGetIfTable
InternalGetIfTable2
InternalGetIpAddrTable
InternalGetIpForwardEntry2
InternalGetIpForwardTable
InternalGetIpInterfaceEntry
InternalGetIpInterfaceTable
InternalGetIpNetEntry2
InternalGetIpNetTable
InternalGetIpNetTable2
InternalGetMulticastIpAddressEntry
InternalGetMulticastIpAddressTable
InternalGetRtcSlotInformation
InternalGetTcp6Table2
InternalGetTcp6TableWithOwnerModule
InternalGetTcp6TableWithOwnerPid
InternalGetTcpTable
InternalGetTcpTable2
InternalGetTcpTableEx
InternalGetTcpTableWithOwnerModule
InternalGetTcpTableWithOwnerPid
InternalGetTunnelPhysicalAdapter
InternalGetUdp6TableWithOwnerModule
InternalGetUdp6TableWithOwnerPid
InternalGetUdpTable
InternalGetUdpTableEx
InternalGetUdpTableWithOwnerModule
InternalGetUdpTableWithOwnerPid
InternalGetUnicastIpAddressEntry
InternalGetUnicastIpAddressTable
InternalIcmpCreateFileEx
InternalSetIfEntry
InternalSetIpForwardEntry
InternalSetIpForwardEntry2
InternalSetIpInterfaceEntry
InternalSetIpNetEntry
InternalSetIpNetEntry2
InternalSetIpStats
InternalSetTcpEntry
InternalSetTeredoPort
InternalSetUnicastIpAddressEntry
IpReleaseAddress
IpRenewAddress
IsLocalAddress
LookupPersistentTcpPortReservation
LookupPersistentUdpPortReservation
NTPTimeToNTFileTime
NTTimeToNTPTime
NhGetGuidFromInterfaceName
NhGetInterfaceDescriptionFromGuid
NhGetInterfaceNameFromDeviceGuid
NhGetInterfaceNameFromGuid
NhpAllocateAndGetInterfaceInfoFromStack
NhpGetInterfaceIndexFromStack
NotifyAddrChange
NotifyCompartmentChange
NotifyIfTimestampConfigChange
NotifyIpInterfaceChange
NotifyNetworkConnectivityHintChange
NotifyRouteChange
NotifyRouteChange2
NotifyRouteChangeEx
NotifySecurityHealthChange
NotifyStableUnicastIpAddressTable
NotifyTeredoPortChange
NotifyUnicastIpAddressChange
OpenCompartment
ParseNetworkString
PfAddFiltersToInterface
PfAddGlobalFilterToInterface
PfBindInterfaceToIPAddress
PfBindInterfaceToIndex
PfCreateInterface
PfDeleteInterface
PfDeleteLog
PfGetInterfaceStatistics
PfMakeLog
PfRebindFilters
PfRemoveFilterHandles
PfRemoveFiltersFromInterface
PfRemoveGlobalFilterFromInterface
PfSetLogBuffer
PfTestPacket
PfUnBindInterface
ResolveIpNetEntry2
ResolveNeighbor
RestoreMediaSense
SendARP
SetAdapterIpAddress
SetBlockRoutes
SetCurrentThreadCompartmentId
SetCurrentThreadCompartmentScope
SetDnsSettings
SetIfEntry
SetIfEntryToStack
SetInterfaceDnsSettings
SetIpForwardEntry
SetIpForwardEntry2
SetIpForwardEntryToStack
SetIpMultihopRouteEntryToStack
SetIpInterfaceEntry
SetIpNetEntry
SetIpNetEntry2
SetIpNetEntryToStack
SetIpRouteEntryToStack
SetIpStatistics
SetIpStatsToStack
SetIpStatisticsEx
SetIpTTL
SetJobCompartmentId
SetProxyArpEntryToStack
SetRouteWithRef
SetNetworkInformation
SetPerTcp6ConnectionEStats
SetPerTcp6ConnectionStats
SetPerTcpConnectionEStats
SetPerTcpConnectionStats
SetSessionCompartmentId
SetTcpEntry
SetTcpEntryToStack
SetUnicastIpAddressEntry
UnenableRouter
do_echo_rep
do_echo_req
if_indextoname
if_nametoindex
register_icmp

View File

@@ -0,0 +1,62 @@
;
; Definition file of USERENV.dll
; Automatic generated by gendef
; written by Kai Tietz 2008-2014
;
LIBRARY "USERENV.dll"
EXPORTS
RsopLoggingEnabled
AreThereVisibleLogoffScripts
AreThereVisibleShutdownScripts
CreateAppContainerProfile
CreateEnvironmentBlock
CreateProfile
DeleteAppContainerProfile
DeleteProfileA
DeleteProfileW
DeriveAppContainerSidFromAppContainerName
DestroyEnvironmentBlock
DllGetContractDescription
EnterCriticalPolicySection
ExpandEnvironmentStringsForUserA
ExpandEnvironmentStringsForUserW
ForceSyncFgPolicy
FreeGPOListA
FreeGPOListW
GenerateRsopPolicy
GenerateGPNotification
GetAllUsersProfileDirectoryA
GetAllUsersProfileDirectoryW
GetAppContainerFolderPath
GetAppContainerRegistryLocation
GetAppliedGPOListA
GetAppliedGPOListW
GetDefaultUserProfileDirectoryA
GetDefaultUserProfileDirectoryW
GetGPOListA
GetGPOListW
GetNextFgPolicyRefreshInfo
GetPreviousFgPolicyRefreshInfo
GetProfileType
GetProfilesDirectoryA
GetProfilesDirectoryW
GetUserProfileDirectoryA
GetUserProfileDirectoryW
HasPolicyForegroundProcessingCompleted
LeaveCriticalPolicySection
LoadUserProfileA
LoadUserProfileW
ProcessGroupPolicyCompleted
ProcessGroupPolicyCompletedEx
RefreshPolicy
RefreshPolicyEx
RegisterGPNotification
RsopAccessCheckByType
RsopFileAccessCheck
RsopLoggingEnabled
RsopResetPolicySettingStatus
RsopSetPolicySettingStatus
UnloadUserProfile
UnregisterGPNotification
WaitForMachinePolicyForegroundProcessing
WaitForUserPolicyForegroundProcessing

View File

@@ -0,0 +1,253 @@
;
; Exports of file WLDAP32.dll
;
; Autogenerated by gen_exportdef
; Written by Kai Tietz, 2007
;
LIBRARY WLDAP32.dll
EXPORTS
ldap_abandon
ldap_add
ldap_get_optionW
ldap_unbind
ldap_set_optionW
LdapGetLastError
cldap_open
LdapMapErrorToWin32
ldap_compare
ldap_delete
ldap_result2error
ldap_err2string
ldap_modify
ldap_modrdn
ldap_open
ldap_first_entry
ldap_next_entry
cldap_openW
LdapUTF8ToUnicode
ldap_get_dn
ldap_dn2ufn
ldap_first_attribute
ldap_next_attribute
ldap_get_values
ldap_get_values_len
ldap_count_entries
ldap_count_values
ldap_value_free
ldap_explode_dn
ldap_result
ldap_msgfree
ldap_addW
ldap_search
ldap_add_s
ldap_bind_s
ldap_unbind_s
ldap_delete_s
ldap_modify_s
ldap_modrdn_s
ldap_search_s
ldap_search_st
ldap_compare_s
LdapUnicodeToUTF8
ber_bvfree
cldap_openA
ldap_addA
ldap_add_ext
ldap_add_extA
ldap_simple_bind
ldap_simple_bind_s
ldap_bind
ldap_add_extW
ldap_add_ext_s
ldap_add_ext_sA
ldap_add_ext_sW
ldap_add_sA
ldap_modrdn2
ldap_modrdn2_s
ldap_add_sW
ldap_bindA
ldap_bindW
ldap_bind_sA
ldap_bind_sW
ldap_close_extended_op
ldap_compareA
ldap_compareW
ldap_count_values_len
ldap_compare_ext
ldap_value_free_len
ldap_compare_extA
ldap_compare_extW
ldap_perror
ldap_compare_ext_s
ldap_compare_ext_sA
ldap_compare_ext_sW
ldap_compare_sA
ldap_compare_sW
ldap_connect
ldap_control_free
ldap_control_freeA
ldap_control_freeW
ldap_controls_free
ldap_controls_freeA
ldap_controls_freeW
ldap_count_references
ldap_count_valuesA
ldap_count_valuesW
ldap_create_page_control
ldap_create_page_controlA
ldap_create_page_controlW
ldap_create_sort_control
ldap_create_sort_controlA
ldap_create_sort_controlW
ldap_deleteA
ldap_deleteW
ldap_delete_ext
ldap_delete_extA
ldap_delete_extW
ldap_delete_ext_s
ldap_delete_ext_sA
ldap_delete_ext_sW
ldap_delete_sA
ldap_delete_sW
ldap_dn2ufnW
ldap_encode_sort_controlA
ldap_encode_sort_controlW
ldap_err2stringA
ldap_err2stringW
ldap_escape_filter_elementA
ldap_escape_filter_elementW
ldap_explode_dnA
ldap_explode_dnW
ldap_extended_operation
ldap_extended_operationA
ldap_extended_operationW
ldap_first_attributeA
ldap_first_attributeW
ldap_first_reference
ldap_free_controls
ldap_free_controlsA
ldap_free_controlsW
ldap_get_dnA
ldap_get_dnW
ldap_get_next_page
ldap_get_next_page_s
ldap_get_option
ldap_get_optionA
ldap_get_paged_count
ldap_get_valuesA
ldap_get_valuesW
ldap_get_values_lenA
ldap_get_values_lenW
ldap_init
ldap_initA
ldap_initW
ldap_memfreeA
ldap_memfreeW
ldap_modifyA
ldap_modifyW
ldap_modify_ext
ldap_modify_extA
ldap_modify_extW
ldap_modify_ext_s
ldap_modify_ext_sA
ldap_modify_ext_sW
ldap_modify_sA
ldap_modify_sW
ldap_modrdn2A
ldap_modrdn2W
ldap_modrdn2_sA
ldap_modrdn2_sW
ldap_modrdnA
ldap_modrdnW
ldap_modrdn_sA
ldap_modrdn_sW
ldap_next_attributeA
ldap_next_attributeW
ldap_next_reference
ldap_openA
ldap_openW
ldap_parse_page_control
ldap_parse_page_controlA
ldap_parse_page_controlW
ldap_parse_reference
ldap_parse_referenceA
ldap_parse_referenceW
ldap_parse_result
ldap_parse_resultA
ldap_parse_resultW
ldap_parse_sort_control
ldap_parse_sort_controlA
ldap_parse_sort_controlW
ldap_rename_ext
ldap_rename_extA
ldap_rename_extW
ldap_rename_ext_s
ldap_rename_ext_sA
ldap_rename_ext_sW
ldap_searchA
ldap_searchW
ldap_search_abandon_page
ldap_search_ext
ldap_search_extA
ldap_search_extW
ldap_search_ext_s
ldap_search_ext_sA
ldap_escape_filter_element
ldap_set_dbg_flags
ldap_set_dbg_routine
ldap_memfree
ldap_startup
ldap_cleanup
ldap_search_ext_sW
ldap_search_init_page
ldap_search_init_pageA
ldap_search_init_pageW
ldap_search_sA
ldap_search_sW
ldap_search_stA
ldap_search_stW
ldap_set_option
ldap_set_optionA
ldap_simple_bindA
ldap_simple_bindW
ldap_simple_bind_sA
ldap_simple_bind_sW
ldap_sslinit
ldap_sslinitA
ldap_sslinitW
ldap_ufn2dn
ldap_ufn2dnA
ldap_ufn2dnW
ldap_value_freeA
ldap_value_freeW
ldap_check_filterA
ldap_check_filterW
ldap_dn2ufnA
ber_init
ber_free
ber_bvecfree
ber_bvdup
ber_alloc_t
ber_skip_tag
ber_peek_tag
ber_first_element
ber_next_element
ber_flatten
ber_printf
ber_scanf
ldap_conn_from_msg
ldap_sasl_bindW
ldap_sasl_bind_sW
ldap_sasl_bindA
ldap_sasl_bind_sA
ldap_parse_extended_resultW
ldap_parse_extended_resultA
ldap_create_vlv_controlW
ldap_create_vlv_controlA
ldap_parse_vlv_controlW
ldap_parse_vlv_controlA
ldap_start_tls_sW
ldap_start_tls_sA
ldap_stop_tls_s
ldap_extended_operation_sW
ldap_extended_operation_sA

View File

@@ -0,0 +1,21 @@
;
; Definition file of XINPUT1_4.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "XINPUT1_4.dll"
EXPORTS
;DllMain
XInputGetState
XInputSetState
XInputGetCapabilities
XInputEnable
XInputGetBatteryInformation
XInputGetKeystroke
XInputGetAudioDeviceIds
;ord_100 @100
;ord_101 @101
;ord_102 @102
;ord_103 @103
;ord_104 @104
;ord_108 @108

View File

@@ -0,0 +1,308 @@
;
; Definition file of IPHLPAPI.DLL
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "IPHLPAPI.DLL"
EXPORTS
AddIPAddress@20
AllocateAndGetInterfaceInfoFromStack@20
AllocateAndGetIpAddrTableFromStack@16
CPNatfwtCreateProviderInstance@20
CPNatfwtDeregisterProviderInstance@4
CPNatfwtDestroyProviderInstance@4
CPNatfwtIndicateReceivedBuffers@24
CPNatfwtRegisterProviderInstance@20
CancelIPChangeNotify@4
CancelIfTimestampConfigChange@4
CancelMibChangeNotify2@4
CaptureInterfaceHardwareCrossTimestamp@8
CloseCompartment@4
CloseGetIPPhysicalInterfaceForDestination@4
ConvertCompartmentGuidToId@8
ConvertCompartmentIdToGuid@8
ConvertGuidToStringA@12
ConvertGuidToStringW@12
ConvertInterfaceAliasToLuid@8
ConvertInterfaceGuidToLuid@8
ConvertInterfaceIndexToLuid@8
ConvertInterfaceLuidToAlias@12
ConvertInterfaceLuidToGuid@8
ConvertInterfaceLuidToIndex@8
ConvertInterfaceLuidToNameA@12
ConvertInterfaceLuidToNameW@12
ConvertInterfaceNameToLuidA@8
ConvertInterfaceNameToLuidW@8
ConvertInterfacePhysicalAddressToLuid@12
ConvertIpv4MaskToLength@8
ConvertLengthToIpv4Mask@8
ConvertRemoteInterfaceAliasToLuid@12
ConvertRemoteInterfaceGuidToLuid@12
ConvertRemoteInterfaceIndexToLuid@12
ConvertRemoteInterfaceLuidToAlias@16
ConvertRemoteInterfaceLuidToGuid@12
ConvertRemoteInterfaceLuidToIndex@12
ConvertStringToGuidA@8
ConvertStringToGuidW@8
ConvertStringToInterfacePhysicalAddress@8
CreateAnycastIpAddressEntry@4
CreateCompartment@4
CreateIpForwardEntry2@4
CreateIpForwardEntry@4
CreateIpNetEntry2@4
CreateIpNetEntry@4
CreatePersistentTcpPortReservation@12
CreatePersistentUdpPortReservation@12
CreateProxyArpEntry@12
CreateSortedAddressPairs@28
CreateUnicastIpAddressEntry@4
DeleteAnycastIpAddressEntry@4
DeleteCompartment@4
DeleteIPAddress@4
DeleteIpForwardEntry2@4
DeleteIpForwardEntry@4
DeleteIpNetEntry2@4
DeleteIpNetEntry@4
DeletePersistentTcpPortReservation@8
DeletePersistentUdpPortReservation@8
DeleteProxyArpEntry@12
DeleteUnicastIpAddressEntry@4
DisableMediaSense@8
EnableRouter@8
FlushIpNetTable2@8
FlushIpNetTable@4
FlushIpPathTable@4
FreeDnsSettings@4
FreeInterfaceDnsSettings@4
FreeMibTable@4
GetAdapterIndex@8
GetAdapterOrderMap@0
GetAdaptersAddresses@20
GetAdaptersInfo@8
GetAnycastIpAddressEntry@4
GetAnycastIpAddressTable@8
GetBestInterface@8
GetBestInterfaceEx@8
GetBestRoute2@28
GetBestRoute@12
GetCurrentThreadCompartmentId@0
GetCurrentThreadCompartmentScope@8
GetDefaultCompartmentId@0
GetDnsSettings@4
GetExtendedTcpTable@24
GetExtendedUdpTable@24
GetFriendlyIfIndex@4
GetIcmpStatistics@4
GetIcmpStatisticsEx@8
GetIfEntry2@4
GetIfEntry2Ex@8
GetIfEntry@4
GetIfStackTable@4
GetIfTable2@4
GetIfTable2Ex@8
GetIfTable@12
GetInterfaceCompartmentId@4
GetInterfaceCurrentTimestampCapabilities@8
GetInterfaceDnsSettings@20
GetInterfaceHardwareTimestampCapabilities@8
GetInterfaceInfo@8
GetInvertedIfStackTable@4
GetIpAddrTable@12
GetIpErrorString@12
GetIpForwardEntry2@4
GetIpForwardTable2@8
GetIpForwardTable@12
GetIpInterfaceEntry@4
GetIpInterfaceTable@8
GetIpNetEntry2@4
GetIpNetTable2@8
GetIpNetTable@12
GetIpNetworkConnectionBandwidthEstimates@12
GetIpPathEntry@4
GetIpPathTable@8
GetIpStatistics@4
GetIpStatisticsEx@8
GetJobCompartmentId@4
GetMulticastIpAddressEntry@4
GetMulticastIpAddressTable@8
GetNetworkConnectivityHint@4
GetNetworkConnectivityHintForInterface@8
GetNetworkInformation@20
GetNetworkParams@8
GetNumberOfInterfaces@4
GetOwnerModuleFromPidAndInfo@20
GetOwnerModuleFromTcp6Entry@16
GetOwnerModuleFromTcpEntry@16
GetOwnerModuleFromUdp6Entry@16
GetOwnerModuleFromUdpEntry@16
GetPerAdapterInfo@12
GetPerTcp6ConnectionEStats@44
GetPerTcp6ConnectionStats@32
GetPerTcpConnectionEStats@44
GetPerTcpConnectionStats@32
GetRTTAndHopCount@16
GetSessionCompartmentId@4
GetTcp6Table2@12
GetTcp6Table@12
GetTcpStatistics@4
GetTcpStatisticsEx2@8
GetTcpStatisticsEx@8
GetTcpTable2@12
GetTcpTable@12
GetTeredoPort@4
GetUdp6Table@12
GetUdpStatistics@4
GetUdpStatisticsEx2@8
GetUdpStatisticsEx@8
GetUdpTable@12
GetUniDirectionalAdapterInfo@8
GetUnicastIpAddressEntry@4
GetUnicastIpAddressTable@8
GetWPAOACSupportLevel@0
Icmp6CreateFile@0
Icmp6ParseReplies@8
Icmp6SendEcho2@48
IcmpCloseHandle@4
IcmpCreateFile@0
IcmpParseReplies@8
IcmpSendEcho2@44
IcmpSendEcho2Ex@48
IcmpSendEcho@32
InitializeCompartmentEntry@4
InitializeIpForwardEntry@4
InitializeIpInterfaceEntry@4
InitializeUnicastIpAddressEntry@4
InternalCleanupPersistentStore@8
InternalCreateAnycastIpAddressEntry@8
InternalCreateIpForwardEntry2@8
InternalCreateIpForwardEntry@4
InternalCreateIpNetEntry2@8
InternalCreateIpNetEntry@4
InternalCreateUnicastIpAddressEntry@8
InternalDeleteAnycastIpAddressEntry@8
InternalDeleteIpForwardEntry2@8
InternalDeleteIpForwardEntry@4
InternalDeleteIpNetEntry2@8
InternalDeleteIpNetEntry@4
InternalDeleteUnicastIpAddressEntry@8
InternalFindInterfaceByAddress@8
InternalGetAnycastIpAddressEntry@8
InternalGetAnycastIpAddressTable@12
InternalGetBoundTcp6EndpointTable@12
InternalGetBoundTcpEndpointTable@12
InternalGetForwardIpTable2@12
InternalGetIPPhysicalInterfaceForDestination@28
InternalGetIfEntry2@8
InternalGetIfTable2@8
InternalGetIfTable@12
InternalGetIpAddrTable@12
InternalGetIpForwardEntry2@8
InternalGetIpForwardTable@12
InternalGetIpInterfaceEntry@8
InternalGetIpInterfaceTable@12
InternalGetIpNetEntry2@8
InternalGetIpNetTable2@12
InternalGetIpNetTable@12
InternalGetMulticastIpAddressEntry@8
InternalGetMulticastIpAddressTable@12
InternalGetRtcSlotInformation@12
InternalGetTcp6Table2@12
InternalGetTcp6TableWithOwnerModule@12
InternalGetTcp6TableWithOwnerPid@12
InternalGetTcpTable2@12
InternalGetTcpTable@12
InternalGetTcpTableEx@12
InternalGetTcpTableWithOwnerModule@12
InternalGetTcpTableWithOwnerPid@12
InternalGetTunnelPhysicalAdapter@8
InternalGetUdp6TableWithOwnerModule@12
InternalGetUdp6TableWithOwnerPid@12
InternalGetUdpTable@12
InternalGetUdpTableEx@12
InternalGetUdpTableWithOwnerModule@12
InternalGetUdpTableWithOwnerPid@12
InternalGetUnicastIpAddressEntry@8
InternalGetUnicastIpAddressTable@12
InternalIcmpCreateFileEx@4
InternalSetIfEntry@4
InternalSetIpForwardEntry2@8
InternalSetIpForwardEntry@4
InternalSetIpInterfaceEntry@8
InternalSetIpNetEntry2@8
InternalSetIpNetEntry@4
InternalSetIpStats@4
InternalSetTcpEntry@4
InternalSetTeredoPort@4
InternalSetUnicastIpAddressEntry@8
IpReleaseAddress@4
IpRenewAddress@4
LookupPersistentTcpPortReservation@12
LookupPersistentUdpPortReservation@12
NTPTimeToNTFileTime@12
NTTimeToNTPTime@8
NhGetGuidFromInterfaceName@16
NhGetInterfaceDescriptionFromGuid@20
NhGetInterfaceNameFromDeviceGuid@20
NhGetInterfaceNameFromGuid@20
NhpAllocateAndGetInterfaceInfoFromStack@20
NotifyAddrChange@8
NotifyCompartmentChange@16
NotifyIfTimestampConfigChange@12
NotifyIpInterfaceChange@20
NotifyNetworkConnectivityHintChange@16
NotifyRouteChange2@20
NotifyRouteChange@8
NotifyStableUnicastIpAddressTable@20
NotifyTeredoPortChange@16
NotifyUnicastIpAddressChange@20
OpenCompartment@8
ParseNetworkString@20
_PfAddFiltersToInterface@24
_PfAddGlobalFilterToInterface@8
_PfBindInterfaceToIPAddress@12
_PfBindInterfaceToIndex@16
_PfCreateInterface@24
_PfDeleteInterface@4
_PfDeleteLog@0
_PfGetInterfaceStatistics@16
_PfMakeLog@4
_PfRebindFilters@8
_PfRemoveFilterHandles@12
_PfRemoveFiltersFromInterface@20
_PfRemoveGlobalFilterFromInterface@8
_PfSetLogBuffer@28
_PfTestPacket@20
_PfUnBindInterface@4
ResolveIpNetEntry2@8
ResolveNeighbor@12
RestoreMediaSense@8
SendARP@16
SetAdapterIpAddress@20
SetCurrentThreadCompartmentId@4
SetCurrentThreadCompartmentScope@4
SetDnsSettings@4
SetIfEntry@4
SetInterfaceDnsSettings@20
SetIpForwardEntry2@4
SetIpForwardEntry@4
SetIpInterfaceEntry@4
SetIpNetEntry2@4
SetIpNetEntry@4
SetIpStatistics@4
SetIpStatisticsEx@8
SetIpTTL@4
SetJobCompartmentId@8
SetNetworkInformation@12
SetPerTcp6ConnectionEStats@24
SetPerTcp6ConnectionStats@20
SetPerTcpConnectionEStats@24
SetPerTcpConnectionStats@20
SetSessionCompartmentId@8
SetTcpEntry@4
SetUnicastIpAddressEntry@4
UnenableRouter@8
do_echo_rep@40
do_echo_req@40
if_indextoname@8
if_nametoindex@4
register_icmp@0

View File

@@ -0,0 +1,55 @@
;
; Definition file of USERENV.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "USERENV.dll"
EXPORTS
RsopLoggingEnabled@0
CreateEnvironmentBlock@12
CreateProfile@16
DeleteProfileA@12
DeleteProfileW@12
DestroyEnvironmentBlock@4
;DllCanUnloadNow@0
;DllGetClassObject@12
;DllGetContractDescription@8
;DllRegisterServer@0
;DllUnregisterServer@0
EnterCriticalPolicySection@4
ExpandEnvironmentStringsForUserA@16
ExpandEnvironmentStringsForUserW@16
ForceSyncFgPolicy@4
FreeGPOListA@4
FreeGPOListW@4
GetAllUsersProfileDirectoryA@8
GetAllUsersProfileDirectoryW@8
GetAppliedGPOListA@20
GetAppliedGPOListW@20
GetDefaultUserProfileDirectoryA@8
GetDefaultUserProfileDirectoryW@8
GetGPOListA@24
GetGPOListW@24
GetNextFgPolicyRefreshInfo@8
GetPreviousFgPolicyRefreshInfo@8
GetProfileType@4
GetProfilesDirectoryA@8
GetProfilesDirectoryW@8
GetUserProfileDirectoryA@12
GetUserProfileDirectoryW@12
LeaveCriticalPolicySection@4
LoadUserProfileA@8
LoadUserProfileW@8
ProcessGroupPolicyCompleted@12
ProcessGroupPolicyCompletedEx@16
RefreshPolicy@4
RefreshPolicyEx@8
RegisterGPNotification@8
RsopAccessCheckByType@44
RsopFileAccessCheck@20
RsopResetPolicySettingStatus@12
RsopSetPolicySettingStatus@20
UnloadUserProfile@8
UnregisterGPNotification@4
WaitForMachinePolicyForegroundProcessing@0
WaitForUserPolicyForegroundProcessing@0

View File

@@ -0,0 +1,257 @@
;
; wldap32.def - Import definition file for the Windows LDAP API
;
; Written by Filip Navara <xnavara@volny.cz>
;
; This library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
;
LIBRARY wldap32.dll
EXPORTS
ldap_abandon
ldap_add
ldap_get_optionW
ldap_unbind
ldap_set_optionW
LdapGetLastError
cldap_open
LdapMapErrorToWin32
ldap_compare
ldap_delete
ldap_result2error
ldap_err2string
ldap_modify
ldap_modrdn
ldap_open
ldap_first_entry
ldap_next_entry
cldap_openW
LdapUTF8ToUnicode
ldap_get_dn
ldap_dn2ufn
ldap_first_attribute
ldap_next_attribute
ldap_get_values
ldap_get_values_len
ldap_count_entries
ldap_count_values
ldap_value_free
ldap_explode_dn
ldap_result
ldap_msgfree
ldap_addW
ldap_search
ldap_add_s
ldap_bind_s
ldap_unbind_s
ldap_delete_s
ldap_modify_s
ldap_modrdn_s
ldap_search_s
ldap_search_st
ldap_compare_s
LdapUnicodeToUTF8
ber_bvfree
cldap_openA
ldap_addA
ldap_add_ext
ldap_add_extA
ldap_simple_bind
ldap_simple_bind_s
ldap_bind
ldap_add_extW
ldap_add_ext_s
ldap_add_ext_sA
ldap_add_ext_sW
ldap_add_sA
ldap_modrdn2
ldap_modrdn2_s
ldap_add_sW
ldap_bindA
ldap_bindW
ldap_bind_sA
ldap_bind_sW
ldap_close_extended_op
ldap_compareA
ldap_compareW
ldap_count_values_len
ldap_compare_ext
ldap_value_free_len
ldap_compare_extA
ldap_compare_extW
ldap_perror
ldap_compare_ext_s
ldap_compare_ext_sA
ldap_compare_ext_sW
ldap_compare_sA
ldap_compare_sW
ldap_connect
ldap_control_free
ldap_control_freeA
ldap_control_freeW
ldap_controls_free
ldap_controls_freeA
ldap_controls_freeW
ldap_count_references
ldap_count_valuesA
ldap_count_valuesW
ldap_create_page_control
ldap_create_page_controlA
ldap_create_page_controlW
ldap_create_sort_control
ldap_create_sort_controlA
ldap_create_sort_controlW
ldap_deleteA
ldap_deleteW
ldap_delete_ext
ldap_delete_extA
ldap_delete_extW
ldap_delete_ext_s
ldap_delete_ext_sA
ldap_delete_ext_sW
ldap_delete_sA
ldap_delete_sW
ldap_dn2ufnW
ldap_encode_sort_controlA
ldap_encode_sort_controlW
ldap_err2stringA
ldap_err2stringW
ldap_escape_filter_elementA
ldap_escape_filter_elementW
ldap_explode_dnA
ldap_explode_dnW
ldap_extended_operation
ldap_extended_operationA
ldap_extended_operationW
ldap_first_attributeA
ldap_first_attributeW
ldap_first_reference
ldap_free_controls
ldap_free_controlsA
ldap_free_controlsW
ldap_get_dnA
ldap_get_dnW
ldap_get_next_page
ldap_get_next_page_s
ldap_get_option
ldap_get_optionA
ldap_get_paged_count
ldap_get_valuesA
ldap_get_valuesW
ldap_get_values_lenA
ldap_get_values_lenW
ldap_init
ldap_initA
ldap_initW
ldap_memfreeA
ldap_memfreeW
ldap_modifyA
ldap_modifyW
ldap_modify_ext
ldap_modify_extA
ldap_modify_extW
ldap_modify_ext_s
ldap_modify_ext_sA
ldap_modify_ext_sW
ldap_modify_sA
ldap_modify_sW
ldap_modrdn2A
ldap_modrdn2W
ldap_modrdn2_sA
ldap_modrdn2_sW
ldap_modrdnA
ldap_modrdnW
ldap_modrdn_sA
ldap_modrdn_sW
ldap_next_attributeA
ldap_next_attributeW
ldap_next_reference
ldap_openA
ldap_openW
ldap_parse_page_control
ldap_parse_page_controlA
ldap_parse_page_controlW
ldap_parse_reference
ldap_parse_referenceA
ldap_parse_referenceW
ldap_parse_result
ldap_parse_resultA
ldap_parse_resultW
ldap_parse_sort_control
ldap_parse_sort_controlA
ldap_parse_sort_controlW
ldap_rename_ext
ldap_rename_extA
ldap_rename_extW
ldap_rename_ext_s
ldap_rename_ext_sA
ldap_rename_ext_sW
ldap_searchA
ldap_searchW
ldap_search_abandon_page
ldap_search_ext
ldap_search_extA
ldap_search_extW
ldap_search_ext_s
ldap_search_ext_sA
ldap_escape_filter_element
ldap_set_dbg_flags
ldap_set_dbg_routine
ldap_memfree
ldap_startup
ldap_cleanup
ldap_search_ext_sW
ldap_search_init_page
ldap_search_init_pageA
ldap_search_init_pageW
ldap_search_sA
ldap_search_sW
ldap_search_stA
ldap_search_stW
ldap_set_option
ldap_set_optionA
ldap_simple_bindA
ldap_simple_bindW
ldap_simple_bind_sA
ldap_simple_bind_sW
ldap_sslinit
ldap_sslinitA
ldap_sslinitW
ldap_ufn2dn
ldap_ufn2dnA
ldap_ufn2dnW
ldap_value_freeA
ldap_value_freeW
ldap_check_filterA
ldap_check_filterW
ldap_dn2ufnA
ber_init
ber_free
ber_bvecfree
ber_bvdup
ber_alloc_t
ber_skip_tag
ber_peek_tag
ber_first_element
ber_next_element
ber_flatten
ber_printf
ber_scanf
ldap_conn_from_msg
ldap_sasl_bindW
ldap_sasl_bind_sW
ldap_sasl_bindA
ldap_sasl_bind_sA
ldap_parse_extended_resultW
ldap_parse_extended_resultA
ldap_create_vlv_controlW
ldap_create_vlv_controlA
ldap_parse_vlv_controlW
ldap_parse_vlv_controlA
ldap_start_tls_sW
ldap_start_tls_sA
ldap_stop_tls_s
ldap_extended_operation_sW
ldap_extended_operation_sA

View File

@@ -0,0 +1,21 @@
;
; Definition file of XINPUT1_4.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "XINPUT1_4.dll"
EXPORTS
;DllMain@12
XInputGetState@8
XInputSetState@8
XInputGetCapabilities@12
XInputEnable@4
XInputGetBatteryInformation@12
XInputGetKeystroke@12
XInputGetAudioDeviceIds@20
;ord_100@8 @100
;ord_101@12 @101
;ord_102@4 @102
;ord_103@4 @103
;ord_104@8 @104
;ord_108@16 @108

View File

@@ -33,8 +33,13 @@ vsprintf_s (char *_DstBuf, size_t _Size, const char *_Format, va_list _ArgList)
return _stub (_DstBuf, _Size, _Format, _ArgList);
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wimplicit-function-declaration"
static int __cdecl
_int_vsprintf_s (char *_DstBuf, size_t _Size, const char *_Format, va_list _ArgList)
{
return __ms_vsnprintf (_DstBuf, _Size, _Format, _ArgList);
}
#pragma clang diagnostic pop

View File

@@ -10,7 +10,12 @@
#include <wchar.h>
#include <stdio.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wimplicit-function-declaration"
int __ms_vwscanf (const wchar_t * __restrict__ format, va_list arg)
{
return __ms_vfwscanf(stdin, format, arg);
}
#pragma clang diagnostic pop

5097
lib/libc/musl/libc.s Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,7 @@ pub const BufMap = struct {
const get_or_put = try self.hash_map.getOrPut(key);
if (get_or_put.found_existing) {
self.free(get_or_put.entry.key);
self.free(get_or_put.entry.value);
get_or_put.entry.key = key;
}
get_or_put.entry.value = value;
@@ -88,7 +89,8 @@ pub const BufMap = struct {
};
test "BufMap" {
var bufmap = BufMap.init(std.testing.allocator);
const allocator = std.testing.allocator;
var bufmap = BufMap.init(allocator);
defer bufmap.deinit();
try bufmap.set("x", "1");
@@ -105,4 +107,7 @@ test "BufMap" {
bufmap.delete("x");
testing.expect(0 == bufmap.count());
try bufmap.setMove(try allocator.dupe(u8, "k"), try allocator.dupe(u8, "v1"));
try bufmap.setMove(try allocator.dupe(u8, "k"), try allocator.dupe(u8, "v2"));
}

View File

@@ -61,6 +61,7 @@ pub const Builder = struct {
installed_files: ArrayList(InstalledFile),
build_root: []const u8,
cache_root: []const u8,
global_cache_root: []const u8,
release_mode: ?builtin.Mode,
is_release: bool,
override_lib_dir: ?[]const u8,
@@ -126,6 +127,7 @@ pub const Builder = struct {
zig_exe: []const u8,
build_root: []const u8,
cache_root: []const u8,
global_cache_root: []const u8,
) !*Builder {
const env_map = try allocator.create(BufMap);
env_map.* = try process.getEnvMap(allocator);
@@ -135,6 +137,7 @@ pub const Builder = struct {
.zig_exe = zig_exe,
.build_root = build_root,
.cache_root = try fs.path.relative(allocator, build_root, cache_root),
.global_cache_root = global_cache_root,
.verbose = false,
.verbose_tokenize = false,
.verbose_ast = false,
@@ -1128,7 +1131,13 @@ test "builder.findProgram compiles" {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const builder = try Builder.create(&arena.allocator, "zig", "zig-cache", "zig-cache");
const builder = try Builder.create(
&arena.allocator,
"zig",
"zig-cache",
"zig-cache",
"zig-cache",
);
defer builder.destroy();
_ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
}
@@ -1216,7 +1225,7 @@ pub const LibExeObjStep = struct {
emit_bin: bool = true,
emit_docs: bool = false,
emit_h: bool = false,
bundle_compiler_rt: bool,
bundle_compiler_rt: ?bool = null,
disable_stack_probing: bool,
disable_sanitize_c: bool,
rdynamic: bool,
@@ -1392,7 +1401,6 @@ pub const LibExeObjStep = struct {
.exec_cmd_args = null,
.name_prefix = "",
.filter = null,
.bundle_compiler_rt = false,
.disable_stack_probing = false,
.disable_sanitize_c = false,
.rdynamic = false,
@@ -1430,24 +1438,24 @@ pub const LibExeObjStep = struct {
self.out_lib_filename = self.out_filename;
} else if (self.version) |version| {
if (target.isDarwin()) {
self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", .{
self.major_only_filename = self.builder.fmt("lib{s}.{d}.dylib", .{
self.name,
version.major,
});
self.name_only_filename = self.builder.fmt("lib{}.dylib", .{self.name});
self.name_only_filename = self.builder.fmt("lib{s}.dylib", .{self.name});
self.out_lib_filename = self.out_filename;
} else if (target.os.tag == .windows) {
self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
} else {
self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, version.major });
self.name_only_filename = self.builder.fmt("lib{}.so", .{self.name});
self.major_only_filename = self.builder.fmt("lib{s}.so.{d}", .{ self.name, version.major });
self.name_only_filename = self.builder.fmt("lib{s}.so", .{self.name});
self.out_lib_filename = self.out_filename;
}
} else {
if (target.isDarwin()) {
self.out_lib_filename = self.out_filename;
} else if (target.os.tag == .windows) {
self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
} else {
self.out_lib_filename = self.out_filename;
}
@@ -1806,6 +1814,29 @@ pub const LibExeObjStep = struct {
}
return;
},
std.SemanticVersion => {
out.print(
\\pub const {z}: @import("std").SemanticVersion = .{{
\\ .major = {d},
\\ .minor = {d},
\\ .patch = {d},
\\
, .{
name,
value.major,
value.minor,
value.patch,
}) catch unreachable;
if (value.pre) |some| {
out.print(" .pre = \"{Z}\",\n", .{some}) catch unreachable;
}
if (value.build) |some| {
out.print(" .build = \"{Z}\",\n", .{some}) catch unreachable;
}
out.writeAll("};\n") catch unreachable;
return;
},
else => {},
}
switch (@typeInfo(T)) {
@@ -1978,13 +2009,10 @@ pub const LibExeObjStep = struct {
try zig_args.append(other.getOutputPath());
},
.Lib => {
if (!other.is_dynamic or self.target.isWindows()) {
try zig_args.append(other.getOutputLibPath());
} else {
const full_path_lib = other.getOutputPath();
try zig_args.append("--library");
try zig_args.append(full_path_lib);
const full_path_lib = other.getOutputLibPath();
try zig_args.append(full_path_lib);
if (other.is_dynamic and !self.target.isWindows()) {
if (fs.path.dirname(full_path_lib)) |dirname| {
try zig_args.append("-rpath");
try zig_args.append(dirname);
@@ -2105,6 +2133,9 @@ pub const LibExeObjStep = struct {
try zig_args.append("--cache-dir");
try zig_args.append(builder.pathFromRoot(builder.cache_root));
try zig_args.append("--global-cache-dir");
try zig_args.append(builder.pathFromRoot(builder.global_cache_root));
zig_args.append("--name") catch unreachable;
zig_args.append(self.name) catch unreachable;
@@ -2117,8 +2148,12 @@ pub const LibExeObjStep = struct {
if (self.is_dynamic) {
try zig_args.append("-dynamic");
}
if (self.bundle_compiler_rt) {
try zig_args.append("--bundle-compiler-rt");
if (self.bundle_compiler_rt) |x| {
if (x) {
try zig_args.append("-fcompiler-rt");
} else {
try zig_args.append("-fno-compiler-rt");
}
}
if (self.disable_stack_probing) {
try zig_args.append("-fno-stack-check");
@@ -2131,7 +2166,7 @@ pub const LibExeObjStep = struct {
}
if (self.code_model != .default) {
try zig_args.append("-code-model");
try zig_args.append("-mcmodel");
try zig_args.append(@tagName(self.code_model));
}
@@ -2712,6 +2747,7 @@ test "Builder.dupePkg()" {
"test",
"test",
"test",
"test",
);
defer builder.destroy();
@@ -2755,6 +2791,7 @@ test "LibExeObjStep.addBuildOption" {
"test",
"test",
"test",
"test",
);
defer builder.destroy();
@@ -2763,12 +2800,20 @@ test "LibExeObjStep.addBuildOption" {
exe.addBuildOption(?usize, "option2", null);
exe.addBuildOption([]const u8, "string", "zigisthebest");
exe.addBuildOption(?[]const u8, "optional_string", null);
exe.addBuildOption(std.SemanticVersion, "semantic_version", try std.SemanticVersion.parse("0.1.2-foo+bar"));
std.testing.expectEqualStrings(
\\pub const option1: usize = 1;
\\pub const option2: ?usize = null;
\\pub const string: []const u8 = "zigisthebest";
\\pub const optional_string: ?[]const u8 = null;
\\pub const semantic_version: @import("std").SemanticVersion = .{
\\ .major = 0,
\\ .minor = 1,
\\ .patch = 2,
\\ .pre = "foo",
\\ .build = "bar",
\\};
\\
, exe.build_options_contents.items);
}
@@ -2784,6 +2829,7 @@ test "LibExeObjStep.addPackage" {
"test",
"test",
"test",
"test",
);
defer builder.destroy();

View File

@@ -490,11 +490,26 @@ pub const Version = struct {
}
pub fn parse(text: []const u8) !Version {
var it = std.mem.split(text, ".");
var end: usize = 0;
while (end < text.len) : (end += 1) {
const c = text[end];
if (!std.ascii.isDigit(c) and c != '.') break;
}
// found no digits or '.' before unexpected character
if (end == 0) return error.InvalidVersion;
var it = std.mem.split(text[0..end], ".");
// substring is not empty, first call will succeed
const major = it.next().?;
if (major.len == 0) return error.InvalidVersion;
const minor = it.next() orelse "0";
// ignore 'patch' if 'minor' is invalid
const patch = if (minor.len == 0) "0" else (it.next() orelse "0");
return Version{
.major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
.minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
.patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
.major = try std.fmt.parseUnsigned(u32, major, 10),
.minor = try std.fmt.parseUnsigned(u32, if (minor.len == 0) "0" else minor, 10),
.patch = try std.fmt.parseUnsigned(u32, if (patch.len == 0) "0" else patch, 10),
};
}
@@ -520,6 +535,56 @@ pub const Version = struct {
}
};
test "Version.parse" {
@setEvalBranchQuota(3000);
try testVersionParse();
comptime (try testVersionParse());
}
pub fn testVersionParse() !void {
const f = struct {
fn eql(text: []const u8, v1: u32, v2: u32, v3: u32) !void {
const v = try Version.parse(text);
std.testing.expect(v.major == v1 and v.minor == v2 and v.patch == v3);
}
fn err(text: []const u8, expected_err: anyerror) !void {
_ = Version.parse(text) catch |actual_err| {
if (actual_err == expected_err) return;
return actual_err;
};
return error.Unreachable;
}
};
try f.eql("2.6.32.11-svn21605", 2, 6, 32); // Debian PPC
try f.eql("2.11.2(0.329/5/3)", 2, 11, 2); // MinGW
try f.eql("5.4.0-1018-raspi", 5, 4, 0); // Ubuntu
try f.eql("5.7.12_3", 5, 7, 12); // Void
try f.eql("2.13-DEVELOPMENT", 2, 13, 0); // DragonFly
try f.eql("2.3-35", 2, 3, 0);
try f.eql("1a.4", 1, 0, 0);
try f.eql("3.b1.0", 3, 0, 0);
try f.eql("1.4beta", 1, 4, 0);
try f.eql("2.7.pre", 2, 7, 0);
try f.eql("0..3", 0, 0, 0);
try f.eql("8.008.", 8, 8, 0);
try f.eql("01...", 1, 0, 0);
try f.eql("55", 55, 0, 0);
try f.eql("4294967295.0.1", 4294967295, 0, 1);
try f.eql("429496729_6", 429496729, 0, 0);
try f.err("foobar", error.InvalidVersion);
try f.err("", error.InvalidVersion);
try f.err("-1", error.InvalidVersion);
try f.err("+4", error.InvalidVersion);
try f.err(".", error.InvalidVersion);
try f.err("....3", error.InvalidVersion);
try f.err("4294967296", error.Overflow);
try f.err("5000877755", error.Overflow);
// error.InvalidCharacter is not possible anymore
}
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const CallOptions = struct {

View File

@@ -259,7 +259,7 @@ pub usingnamespace switch (builtin.os.tag) {
};
pub extern "c" fn realloc(?*c_void, usize) ?*c_void;
pub extern "c" fn free(*c_void) void;
pub extern "c" fn free(?*c_void) void;
pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
pub extern "c" fn futimes(fd: fd_t, times: *[2]timeval) c_int;
@@ -271,6 +271,7 @@ pub extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int;
pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: fn (?*c_void) callconv(.C) ?*c_void, noalias arg: ?*c_void) c_int;
pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) c_int;
pub extern "c" fn pthread_attr_setguardsize(attr: *pthread_attr_t, guardsize: usize) c_int;
pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
pub extern "c" fn pthread_self() pthread_t;

View File

@@ -144,7 +144,7 @@ pub const Edwards25519 = struct {
inline fn pcSelect(pc: [16]Edwards25519, b: u8) Edwards25519 {
var t = Edwards25519.identityElement;
comptime var i: u8 = 0;
comptime var i: u8 = 1;
inline while (i < 16) : (i += 1) {
t.cMov(pc[i], ((@as(usize, b ^ i) -% 1) >> 8) & 1);
}
@@ -155,7 +155,6 @@ pub const Edwards25519 = struct {
var q = Edwards25519.identityElement;
var pos: usize = 252;
while (true) : (pos -= 4) {
q = q.dbl().dbl().dbl().dbl();
const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf;
if (vartime) {
if (bit != 0) {
@@ -165,6 +164,7 @@ pub const Edwards25519 = struct {
q = q.add(pcSelect(pc, bit));
}
if (pos == 0) break;
q = q.dbl().dbl().dbl().dbl();
}
try q.rejectIdentity();
return q;
@@ -181,32 +181,31 @@ pub const Edwards25519 = struct {
return pc;
}
const basePointPc = comptime pc: {
@setEvalBranchQuota(10000);
break :pc precompute(Edwards25519.basePoint);
};
/// Multiply an Edwards25519 point by a scalar without clamping it.
/// Return error.WeakPublicKey if the resulting point is
/// the identity element.
pub fn mul(p: Edwards25519, s: [32]u8) !Edwards25519 {
var pc: [16]Edwards25519 = undefined;
if (p.is_base) {
@setEvalBranchQuota(10000);
pc = comptime precompute(Edwards25519.basePoint);
} else {
pc = precompute(p);
pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
}
const pc = if (p.is_base) basePointPc else pc: {
const xpc = precompute(p);
xpc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
break :pc xpc;
};
return pcMul(pc, s, false);
}
/// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
/// This can be used for signature verification.
pub fn mulPublic(p: Edwards25519, s: [32]u8) !Edwards25519 {
var pc: [16]Edwards25519 = undefined;
if (p.is_base) {
@setEvalBranchQuota(10000);
pc = comptime precompute(Edwards25519.basePoint);
} else {
pc = precompute(p);
pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
}
const pc = if (p.is_base) basePointPc else pc: {
const xpc = precompute(p);
xpc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
break :pc xpc;
};
return pcMul(pc, s, true);
}
@@ -215,18 +214,15 @@ pub const Edwards25519 = struct {
pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) !Edwards25519 {
var pcs: [count][16]Edwards25519 = undefined;
for (ps) |p, i| {
if (p.is_base) {
@setEvalBranchQuota(10000);
pcs[i] = comptime precompute(Edwards25519.basePoint);
} else {
pcs[i] = precompute(p);
pcs[i][4].rejectIdentity() catch |_| return error.WeakPublicKey;
}
pcs[i] = if (p.is_base) basePointPc else pc: {
const xpc = precompute(p);
xpc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
break :pc xpc;
};
}
var q = Edwards25519.identityElement;
var pos: usize = 252;
while (true) : (pos -= 4) {
q = q.dbl().dbl().dbl().dbl();
for (ss) |s, i| {
const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf;
if (bit != 0) {
@@ -234,6 +230,7 @@ pub const Edwards25519 = struct {
}
}
if (pos == 0) break;
q = q.dbl().dbl().dbl().dbl();
}
try q.rejectIdentity();
return q;

View File

@@ -666,7 +666,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
.macos,
.windows,
=> return DebugInfo.init(allocator),
else => @compileError("openSelfDebugInfo unsupported for this platform"),
else => return error.UnsupportedDebugInfo,
}
}
}
@@ -1762,12 +1762,18 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v
.netbsd => @ptrToInt(info.info.reason.fault.addr),
else => unreachable,
};
switch (sig) {
os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}),
os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}),
os.SIGBUS => std.debug.warn("Bus error at address 0x{x}\n", .{addr}),
else => unreachable,
// Don't use std.debug.print() as stderr_mutex may still be locked.
nosuspend {
const stderr = io.getStdErr().writer();
_ = switch (sig) {
os.SIGSEGV => stderr.print("Segmentation fault at address 0x{x}\n", .{addr}),
os.SIGILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}),
os.SIGBUS => stderr.print("Bus error at address 0x{x}\n", .{addr}),
else => unreachable,
} catch os.abort();
}
switch (builtin.arch) {
.i386 => {
const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
@@ -1818,11 +1824,15 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u
const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress);
if (@hasDecl(windows, "CONTEXT")) {
const regs = info.ContextRecord.getRegs();
switch (msg) {
0 => std.debug.warn("{}\n", .{format.?}),
1 => std.debug.warn("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
2 => std.debug.warn("Illegal instruction at address 0x{x}\n", .{regs.ip}),
else => unreachable,
// Don't use std.debug.print() as stderr_mutex may still be locked.
nosuspend {
const stderr = io.getStdErr().writer();
_ = switch (msg) {
0 => stderr.print("{s}\n", .{format.?}),
1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
2 => stderr.print("Illegal instruction at address 0x{x}\n", .{regs.ip}),
else => unreachable,
} catch os.abort();
}
dumpStackTraceFromBase(regs.bp, regs.ip);

View File

@@ -344,9 +344,14 @@ pub const WindowsDynLib = struct {
}
pub fn openW(path_w: [*:0]const u16) !WindowsDynLib {
return WindowsDynLib{
var offset: usize = 0;
if (path_w[0] == '\\' and path_w[1] == '?' and path_w[2] == '?' and path_w[3] == '\\') {
// + 4 to skip over the \??\
.dll = try windows.LoadLibraryW(path_w + 4),
offset = 4;
}
return WindowsDynLib{
.dll = try windows.LoadLibraryW(path_w + offset),
};
}

View File

@@ -12,7 +12,7 @@ pub const Locked = @import("event/locked.zig").Locked;
pub const RwLock = @import("event/rwlock.zig").RwLock;
pub const RwLocked = @import("event/rwlocked.zig").RwLocked;
pub const Loop = @import("event/loop.zig").Loop;
pub const WaitGroup = @import("event/WaitGroup.zig").WaitGroup;
pub const WaitGroup = @import("event/wait_group.zig").WaitGroup;
test "import event tests" {
_ = @import("event/channel.zig");

View File

@@ -687,7 +687,7 @@ pub const Dir = struct {
return self.openFileZ(&path_c, flags);
}
/// Save as `openFile` but WASI only.
/// Same as `openFile` but WASI only.
pub fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
const w = os.wasi;
var fdflags: w.fdflags_t = 0x0;

View File

@@ -394,7 +394,7 @@ pub const File = struct {
var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap);
defer array_list.deinit();
self.reader().readAllArrayList(&array_list, max_bytes) catch |err| switch (err) {
self.reader().readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) {
error.StreamTooLong => return error.FileTooBig,
else => |e| return e,
};

View File

@@ -28,6 +28,7 @@ pub const delimiter_windows = ';';
pub const delimiter_posix = ':';
pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix;
/// Returns if the given byte is a valid path separator
pub fn isSep(byte: u8) bool {
if (builtin.os.tag == .windows) {
return byte == '/' or byte == '\\';
@@ -749,8 +750,12 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void {
return testing.expect(mem.eql(u8, actual, expected));
}
/// Strip the last component from a file path.
///
/// If the path is a file in the current directory (no directory component)
/// then returns null
/// then returns null.
///
/// If the path is the root directory, returns null.
pub fn dirname(path: []const u8) ?[]const u8 {
if (builtin.os.tag == .windows) {
return dirnameWindows(path);
@@ -765,19 +770,19 @@ pub fn dirnameWindows(path: []const u8) ?[]const u8 {
const root_slice = diskDesignatorWindows(path);
if (path.len == root_slice.len)
return path;
return null;
const have_root_slash = path.len > root_slice.len and (path[root_slice.len] == '/' or path[root_slice.len] == '\\');
var end_index: usize = path.len - 1;
while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
while (path[end_index] == '/' or path[end_index] == '\\') {
if (end_index == 0)
return null;
end_index -= 1;
}
while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
while (path[end_index] != '/' and path[end_index] != '\\') {
if (end_index == 0)
return null;
end_index -= 1;
@@ -800,7 +805,7 @@ pub fn dirnamePosix(path: []const u8) ?[]const u8 {
var end_index: usize = path.len - 1;
while (path[end_index] == '/') {
if (end_index == 0)
return path[0..1];
return null;
end_index -= 1;
}
@@ -810,7 +815,7 @@ pub fn dirnamePosix(path: []const u8) ?[]const u8 {
end_index -= 1;
}
if (end_index == 0 and path[end_index] == '/')
if (end_index == 0 and path[0] == '/')
return path[0..1];
if (end_index == 0)
@@ -823,8 +828,10 @@ test "dirnamePosix" {
testDirnamePosix("/a/b/c", "/a/b");
testDirnamePosix("/a/b/c///", "/a/b");
testDirnamePosix("/a", "/");
testDirnamePosix("/", "/");
testDirnamePosix("////", "/");
testDirnamePosix("/", null);
testDirnamePosix("//", null);
testDirnamePosix("///", null);
testDirnamePosix("////", null);
testDirnamePosix("", null);
testDirnamePosix("a", null);
testDirnamePosix("a/", null);
@@ -832,27 +839,27 @@ test "dirnamePosix" {
}
test "dirnameWindows" {
testDirnameWindows("c:\\", "c:\\");
testDirnameWindows("c:\\", null);
testDirnameWindows("c:\\foo", "c:\\");
testDirnameWindows("c:\\foo\\", "c:\\");
testDirnameWindows("c:\\foo\\bar", "c:\\foo");
testDirnameWindows("c:\\foo\\bar\\", "c:\\foo");
testDirnameWindows("c:\\foo\\bar\\baz", "c:\\foo\\bar");
testDirnameWindows("\\", "\\");
testDirnameWindows("\\", null);
testDirnameWindows("\\foo", "\\");
testDirnameWindows("\\foo\\", "\\");
testDirnameWindows("\\foo\\bar", "\\foo");
testDirnameWindows("\\foo\\bar\\", "\\foo");
testDirnameWindows("\\foo\\bar\\baz", "\\foo\\bar");
testDirnameWindows("c:", "c:");
testDirnameWindows("c:foo", "c:");
testDirnameWindows("c:foo\\", "c:");
testDirnameWindows("c:", null);
testDirnameWindows("c:foo", null);
testDirnameWindows("c:foo\\", null);
testDirnameWindows("c:foo\\bar", "c:foo");
testDirnameWindows("c:foo\\bar\\", "c:foo");
testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
testDirnameWindows("file:stream", null);
testDirnameWindows("dir\\file:stream", "dir");
testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
testDirnameWindows("\\\\unc\\share", null);
testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
testDirnameWindows("\\\\unc\\share\\foo\\", "\\\\unc\\share\\");
testDirnameWindows("\\\\unc\\share\\foo\\bar", "\\\\unc\\share\\foo");
@@ -862,8 +869,8 @@ test "dirnameWindows" {
testDirnameWindows("/a/b", "/a");
testDirnameWindows("/a", "/");
testDirnameWindows("", null);
testDirnameWindows("/", "/");
testDirnameWindows("////", "/");
testDirnameWindows("/", null);
testDirnameWindows("////", null);
testDirnameWindows("foo", null);
}
@@ -1182,3 +1189,68 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
defer testing.allocator.free(result);
testing.expectEqualSlices(u8, expected_output, result);
}
/// Returns the extension of the file name (if any).
/// This function will search for the file extension (separated by a `.`) and will return the text after the `.`.
/// Files that end with `.` are considered to have no extension, files that start with `.`
/// Examples:
/// - `"main.zig"` ⇒ `".zig"`
/// - `"src/main.zig"` ⇒ `".zig"`
/// - `".gitignore"` ⇒ `""`
/// - `"keep."` ⇒ `"."`
/// - `"src.keep.me"` ⇒ `".me"`
/// - `"/src/keep.me"` ⇒ `".me"`
/// - `"/src/keep.me/"` ⇒ `".me"`
/// The returned slice is guaranteed to have its pointer within the start and end
/// pointer address range of `path`, even if it is length zero.
pub fn extension(path: []const u8) []const u8 {
const filename = basename(path);
const index = mem.lastIndexOf(u8, filename, ".") orelse return path[path.len..];
if (index == 0) return path[path.len..];
return filename[index..];
}
fn testExtension(path: []const u8, expected: []const u8) void {
std.testing.expectEqualStrings(expected, extension(path));
}
test "extension" {
testExtension("", "");
testExtension(".", "");
testExtension("a.", ".");
testExtension("abc.", ".");
testExtension(".a", "");
testExtension(".file", "");
testExtension(".gitignore", "");
testExtension("file.ext", ".ext");
testExtension("file.ext.", ".");
testExtension("very-long-file.bruh", ".bruh");
testExtension("a.b.c", ".c");
testExtension("a.b.c/", ".c");
testExtension("/", "");
testExtension("/.", "");
testExtension("/a.", ".");
testExtension("/abc.", ".");
testExtension("/.a", "");
testExtension("/.file", "");
testExtension("/.gitignore", "");
testExtension("/file.ext", ".ext");
testExtension("/file.ext.", ".");
testExtension("/very-long-file.bruh", ".bruh");
testExtension("/a.b.c", ".c");
testExtension("/a.b.c/", ".c");
testExtension("/foo/bar/bam/", "");
testExtension("/foo/bar/bam/.", "");
testExtension("/foo/bar/bam/a.", ".");
testExtension("/foo/bar/bam/abc.", ".");
testExtension("/foo/bar/bam/.a", "");
testExtension("/foo/bar/bam/.file", "");
testExtension("/foo/bar/bam/.gitignore", "");
testExtension("/foo/bar/bam/file.ext", ".ext");
testExtension("/foo/bar/bam/file.ext.", ".");
testExtension("/foo/bar/bam/very-long-file.bruh", ".bruh");
testExtension("/foo/bar/bam/a.b.c", ".c");
testExtension("/foo/bar/bam/a.b.c/", ".c");
}

View File

@@ -135,7 +135,7 @@ pub const Murmur2_64 = struct {
return @call(.{ .modifier = .always_inline }, Self.hashUint32WithSeed, .{ v, default_seed });
}
pub fn hashUint32WithSeed(v: u32, seed: u32) u64 {
pub fn hashUint32WithSeed(v: u32, seed: u64) u64 {
const m: u64 = 0xc6a4a7935bd1e995;
const len: u64 = 4;
var h1: u64 = seed ^ (len *% m);
@@ -152,7 +152,7 @@ pub const Murmur2_64 = struct {
return @call(.{ .modifier = .always_inline }, Self.hashUint64WithSeed, .{ v, default_seed });
}
pub fn hashUint64WithSeed(v: u64, seed: u32) u64 {
pub fn hashUint64WithSeed(v: u64, seed: u64) u64 {
const m: u64 = 0xc6a4a7935bd1e995;
const len: u64 = 8;
var h1: u64 = seed ^ (len *% m);

View File

@@ -428,7 +428,7 @@ pub fn HashMapUnmanaged(
if (self.metadata) |_| {
self.initMetadatas();
self.size = 0;
self.available = 0;
self.available = @truncate(u32, (self.capacity() * MaxLoadPercentage) / 100);
}
}
@@ -468,41 +468,12 @@ pub fn HashMapUnmanaged(
self.putAssumeCapacityNoClobber(key, value);
}
/// Asserts there is enough capacity to store the new key-value pair.
/// Clobbers any existing data. To detect if a put would clobber
/// existing data, see `getOrPutAssumeCapacity`.
pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
const hash = hashFn(key);
const mask = self.capacity() - 1;
const fingerprint = Metadata.takeFingerprint(hash);
var idx = @truncate(usize, hash & mask);
var first_tombstone_idx: usize = self.capacity(); // invalid index
var metadata = self.metadata.? + idx;
while (metadata[0].isUsed() or metadata[0].isTombstone()) {
if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) {
const entry = &self.entries()[idx];
if (eqlFn(entry.key, key)) {
return;
}
} else if (first_tombstone_idx == self.capacity() and metadata[0].isTombstone()) {
first_tombstone_idx = idx;
}
idx = (idx + 1) & mask;
metadata = self.metadata.? + idx;
}
if (first_tombstone_idx < self.capacity()) {
// Cheap try to lower probing lengths after deletions. Recycle a tombstone.
idx = first_tombstone_idx;
metadata = self.metadata.? + idx;
} else {
// We're using a slot previously free.
self.available -= 1;
}
metadata[0].fill(fingerprint);
const entry = &self.entries()[idx];
entry.* = .{ .key = key, .value = undefined };
self.size += 1;
const gop = self.getOrPutAssumeCapacity(key);
gop.entry.value = value;
}
/// Insert an entry in the map. Assumes it is not already present,
@@ -893,6 +864,11 @@ test "std.hash_map clearRetainingCapacity" {
expectEqual(map.get(1).?, 1);
expectEqual(map.count(), 1);
map.clearRetainingCapacity();
map.putAssumeCapacity(1, 1);
expectEqual(map.get(1).?, 1);
expectEqual(map.count(), 1);
const cap = map.capacity();
expect(cap > 0);
@@ -1148,6 +1124,36 @@ test "std.hash_map put" {
}
}
test "std.hash_map putAssumeCapacity" {
var map = AutoHashMap(u32, u32).init(std.testing.allocator);
defer map.deinit();
try map.ensureCapacity(20);
var i: u32 = 0;
while (i < 20) : (i += 1) {
map.putAssumeCapacityNoClobber(i, i);
}
i = 0;
var sum = i;
while (i < 20) : (i += 1) {
sum += map.get(i).?;
}
expectEqual(sum, 190);
i = 0;
while (i < 20) : (i += 1) {
map.putAssumeCapacity(i, 1);
}
i = 0;
sum = i;
while (i < 20) : (i += 1) {
sum += map.get(i).?;
}
expectEqual(sum, 20);
}
test "std.hash_map getOrPut" {
var map = AutoHashMap(u32, u32).init(std.testing.allocator);
defer map.deinit();

View File

@@ -517,7 +517,11 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
second_free_stack_trace,
});
if (new_size == 0) {
// Recoverable.
// Recoverable. Restore self.total_requested_bytes if needed, as we
// don't return an error value so the errdefer above does not run.
if (config.enable_memory_limit) {
self.total_requested_bytes = prev_req_bytes;
}
return @as(usize, 0);
}
@panic("Unrecoverable double free");

View File

@@ -57,6 +57,15 @@ pub fn Reader(
/// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned
/// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
pub fn readAllArrayList(self: Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
return self.readAllArrayListAligned(null, array_list, max_append_size);
}
pub fn readAllArrayListAligned(
self: Self,
comptime alignment: ?u29,
array_list: *std.ArrayListAligned(u8, alignment),
max_append_size: usize
) !void {
try array_list.ensureCapacity(math.min(max_append_size, 4096));
const original_len = array_list.items.len;
var start_index: usize = original_len;

View File

@@ -375,7 +375,7 @@ pub const StreamingParser = struct {
'}' => {
// unlikely
if (p.stack & 1 != object_bit) {
return error.UnexpectedClosingBracket;
return error.UnexpectedClosingBrace;
}
if (p.stack_used == 0) {
return error.TooManyClosingItems;
@@ -401,7 +401,7 @@ pub const StreamingParser = struct {
},
']' => {
if (p.stack & 1 != array_bit) {
return error.UnexpectedClosingBrace;
return error.UnexpectedClosingBracket;
}
if (p.stack_used == 0) {
return error.TooManyClosingItems;
@@ -571,8 +571,11 @@ pub const StreamingParser = struct {
p.state = .ValueBeginNoClosing;
},
']' => {
if (p.stack & 1 != array_bit) {
return error.UnexpectedClosingBracket;
}
if (p.stack_used == 0) {
return error.UnbalancedBrackets;
return error.TooManyClosingItems;
}
p.state = .ValueEnd;
@@ -589,8 +592,12 @@ pub const StreamingParser = struct {
token.* = Token.ArrayEnd;
},
'}' => {
// unlikely
if (p.stack & 1 != object_bit) {
return error.UnexpectedClosingBrace;
}
if (p.stack_used == 0) {
return error.UnbalancedBraces;
return error.TooManyClosingItems;
}
p.state = .ValueEnd;
@@ -1189,6 +1196,15 @@ test "json.token" {
testing.expect((try p.next()) == null);
}
test "json.token mismatched close" {
var p = TokenStream.init("[102, 111, 111 }");
checkNext(&p, .ArrayBegin);
checkNext(&p, .Number);
checkNext(&p, .Number);
checkNext(&p, .Number);
testing.expectError(error.UnexpectedClosingBrace, p.next());
}
/// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
/// be able to decode the string even if this returns true.
pub fn validate(s: []const u8) bool {
@@ -1207,7 +1223,12 @@ pub fn validate(s: []const u8) bool {
}
test "json.validate" {
testing.expect(validate("{}"));
testing.expectEqual(true, validate("{}"));
testing.expectEqual(true, validate("[]"));
testing.expectEqual(true, validate("[{[[[[{}]]]]}]"));
testing.expectEqual(false, validate("{]"));
testing.expectEqual(false, validate("[}"));
testing.expectEqual(false, validate("{{{{[]}}}]"));
}
const Allocator = std.mem.Allocator;
@@ -2080,7 +2101,7 @@ pub const Parser = struct {
// Unescape a JSON string
// Only to be used on strings already validated by the parser
// (note the unreachable statements and lack of bounds checking)
fn unescapeString(output: []u8, input: []const u8) !void {
pub fn unescapeString(output: []u8, input: []const u8) !void {
var inIndex: usize = 0;
var outIndex: usize = 0;

View File

@@ -95,7 +95,7 @@ fn exp2_32(x: f32) f32 {
uf -= redux;
const z: f64 = x - uf;
var r: f64 = exp2ft[i_0];
var r: f64 = exp2ft[@intCast(usize, i_0)];
const t: f64 = r * z;
r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
return @floatCast(f32, r * uk);
@@ -418,8 +418,8 @@ fn exp2_64(x: f64) f64 {
// r = exp2(y) = exp2t[i_0] * p(z - eps[i])
var z = x - uf;
const t = exp2dt[2 * i_0];
z -= exp2dt[2 * i_0 + 1];
const t = exp2dt[@intCast(usize, 2 * i_0)];
z -= exp2dt[@intCast(usize, 2 * i_0 + 1)];
const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
return math.scalbn(r, ik);

View File

@@ -7,13 +7,14 @@ const std = @import("std.zig");
const debug = std.debug;
const assert = debug.assert;
const math = std.math;
const builtin = @import("builtin");
const builtin = std.builtin;
const mem = @This();
const meta = std.meta;
const trait = meta.trait;
const testing = std.testing;
/// https://github.com/ziglang/zig/issues/2564
/// Compile time known minimum page size.
/// https://github.com/ziglang/zig/issues/4082
pub const page_size = switch (builtin.arch) {
.wasm32, .wasm64 => 64 * 1024,
.aarch64 => switch (builtin.os.tag) {
@@ -139,7 +140,7 @@ test "mem.Allocator basics" {
/// Copy all of source into dest at position 0.
/// dest.len must be >= source.len.
/// dest.ptr must be <= src.ptr.
/// If the slices overlap, dest.ptr must be <= src.ptr.
pub fn copy(comptime T: type, dest: []T, source: []const T) void {
// TODO instead of manually doing this check for the whole array
// and turning off runtime safety, the compiler should detect loops like
@@ -152,7 +153,7 @@ pub fn copy(comptime T: type, dest: []T, source: []const T) void {
/// Copy all of source into dest at position 0.
/// dest.len must be >= source.len.
/// dest.ptr must be >= src.ptr.
/// If the slices overlap, dest.ptr must be >= src.ptr.
pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void {
// TODO instead of manually doing this check for the whole array
// and turning off runtime safety, the compiler should detect loops like
@@ -1936,25 +1937,31 @@ pub fn nativeToBig(comptime T: type, x: T) T {
};
}
fn CopyPtrAttrs(comptime source: type, comptime size: builtin.TypeInfo.Pointer.Size, comptime child: type) type {
const info = @typeInfo(source).Pointer;
return @Type(.{
.Pointer = .{
.size = size,
.is_const = info.is_const,
.is_volatile = info.is_volatile,
.is_allowzero = info.is_allowzero,
.alignment = info.alignment,
.child = child,
.sentinel = null,
},
});
}
fn AsBytesReturnType(comptime P: type) type {
if (!trait.isSingleItemPtr(P))
@compileError("expected single item pointer, passed " ++ @typeName(P));
const size = @sizeOf(meta.Child(P));
const alignment = meta.alignment(P);
if (alignment == 0) {
if (trait.isConstPtr(P))
return *const [size]u8;
return *[size]u8;
}
if (trait.isConstPtr(P))
return *align(alignment) const [size]u8;
return *align(alignment) [size]u8;
return CopyPtrAttrs(P, .One, [size]u8);
}
/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.
/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving pointer attributes.
pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) {
const P = @TypeOf(ptr);
return @ptrCast(AsBytesReturnType(P), ptr);
@@ -1994,6 +2001,20 @@ test "asBytes" {
testing.expect(eql(u8, asBytes(&zero), ""));
}
test "asBytes preserves pointer attributes" {
const inArr: u32 align(16) = 0xDEADBEEF;
const inPtr = @ptrCast(*align(16) const volatile u32, &inArr);
const outSlice = asBytes(inPtr);
const in = @typeInfo(@TypeOf(inPtr)).Pointer;
const out = @typeInfo(@TypeOf(outSlice)).Pointer;
testing.expectEqual(in.is_const, out.is_const);
testing.expectEqual(in.is_volatile, out.is_volatile);
testing.expectEqual(in.is_allowzero, out.is_allowzero);
testing.expectEqual(in.alignment, out.alignment);
}
/// Given any value, returns a copy of its bytes in an array.
pub fn toBytes(value: anytype) [@sizeOf(@TypeOf(value))]u8 {
return asBytes(&value).*;
@@ -2023,13 +2044,11 @@ fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
@compileError(std.fmt.bufPrint(&buf, "expected *[{}]u8, passed " ++ @typeName(B), .{size}) catch unreachable);
}
const alignment = comptime meta.alignment(B);
return if (comptime trait.isConstPtr(B)) *align(alignment) const T else *align(alignment) T;
return CopyPtrAttrs(B, .One, T);
}
/// Given a pointer to an array of bytes, returns a pointer to a value of the specified type
/// backed by those bytes, preserving constness.
/// backed by those bytes, preserving pointer attributes.
pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, @TypeOf(bytes)) {
return @ptrCast(BytesAsValueReturnType(T, @TypeOf(bytes)), bytes);
}
@@ -2071,6 +2090,20 @@ test "bytesAsValue" {
testing.expect(meta.eql(inst, inst2.*));
}
test "bytesAsValue preserves pointer attributes" {
const inArr align(16) = [4]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
const inSlice = @ptrCast(*align(16) const volatile [4]u8, &inArr)[0..];
const outPtr = bytesAsValue(u32, inSlice);
const in = @typeInfo(@TypeOf(inSlice)).Pointer;
const out = @typeInfo(@TypeOf(outPtr)).Pointer;
testing.expectEqual(in.is_const, out.is_const);
testing.expectEqual(in.is_volatile, out.is_volatile);
testing.expectEqual(in.is_allowzero, out.is_allowzero);
testing.expectEqual(in.alignment, out.alignment);
}
/// Given a pointer to an array of bytes, returns a value of the specified type backed by a
/// copy of those bytes.
pub fn bytesToValue(comptime T: type, bytes: anytype) T {
@@ -2086,9 +2119,8 @@ test "bytesToValue" {
testing.expect(deadbeef == @as(u32, 0xDEADBEEF));
}
//TODO copy also is_volatile, etc. I tried to use @typeInfo, modify child type, use @Type, but ran into issues.
fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
if (!(trait.isSlice(bytesType) and meta.Child(bytesType) == u8) and !(trait.isPtrTo(.Array)(bytesType) and meta.Child(meta.Child(bytesType)) == u8)) {
if (!(trait.isSlice(bytesType) or trait.isPtrTo(.Array)(bytesType)) or meta.Elem(bytesType) != u8) {
@compileError("expected []u8 or *[_]u8, passed " ++ @typeName(bytesType));
}
@@ -2096,11 +2128,11 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
@compileError("number of bytes in " ++ @typeName(bytesType) ++ " is not divisible by size of " ++ @typeName(T));
}
const alignment = meta.alignment(bytesType);
return if (trait.isConstPtr(bytesType)) []align(alignment) const T else []align(alignment) T;
return CopyPtrAttrs(bytesType, .Slice, T);
}
/// Given a slice of bytes, returns a slice of the specified type
/// backed by those bytes, preserving pointer attributes.
pub fn bytesAsSlice(comptime T: type, bytes: anytype) BytesAsSliceReturnType(T, @TypeOf(bytes)) {
// let's not give an undefined pointer to @ptrCast
// it may be equal to zero and fail a null check
@@ -2108,10 +2140,7 @@ pub fn bytesAsSlice(comptime T: type, bytes: anytype) BytesAsSliceReturnType(T,
return &[0]T{};
}
const Bytes = @TypeOf(bytes);
const alignment = comptime meta.alignment(Bytes);
const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T;
const cast_target = CopyPtrAttrs(@TypeOf(bytes), .Many, T);
return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))];
}
@@ -2169,17 +2198,29 @@ test "bytesAsSlice with specified alignment" {
testing.expect(slice[0] == 0x33333333);
}
//TODO copy also is_volatile, etc. I tried to use @typeInfo, modify child type, use @Type, but ran into issues.
test "bytesAsSlice preserves pointer attributes" {
const inArr align(16) = [4]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
const inSlice = @ptrCast(*align(16) const volatile [4]u8, &inArr)[0..];
const outSlice = bytesAsSlice(u16, inSlice);
const in = @typeInfo(@TypeOf(inSlice)).Pointer;
const out = @typeInfo(@TypeOf(outSlice)).Pointer;
testing.expectEqual(in.is_const, out.is_const);
testing.expectEqual(in.is_volatile, out.is_volatile);
testing.expectEqual(in.is_allowzero, out.is_allowzero);
testing.expectEqual(in.alignment, out.alignment);
}
fn SliceAsBytesReturnType(comptime sliceType: type) type {
if (!trait.isSlice(sliceType) and !trait.isPtrTo(.Array)(sliceType)) {
@compileError("expected []T or *[_]T, passed " ++ @typeName(sliceType));
}
const alignment = meta.alignment(sliceType);
return if (trait.isConstPtr(sliceType)) []align(alignment) const u8 else []align(alignment) u8;
return CopyPtrAttrs(sliceType, .Slice, u8);
}
/// Given a slice, returns a slice of the underlying bytes, preserving pointer attributes.
pub fn sliceAsBytes(slice: anytype) SliceAsBytesReturnType(@TypeOf(slice)) {
const Slice = @TypeOf(slice);
@@ -2189,9 +2230,7 @@ pub fn sliceAsBytes(slice: anytype) SliceAsBytesReturnType(@TypeOf(slice)) {
return &[0]u8{};
}
const alignment = comptime meta.alignment(Slice);
const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8;
const cast_target = CopyPtrAttrs(Slice, .Many, u8);
return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
}
@@ -2263,6 +2302,20 @@ test "sliceAsBytes and bytesAsSlice back" {
testing.expect(bytes[11] == math.maxInt(u8));
}
test "sliceAsBytes preserves pointer attributes" {
const inArr align(16) = [2]u16{ 0xDEAD, 0xBEEF };
const inSlice = @ptrCast(*align(16) const volatile [2]u16, &inArr)[0..];
const outSlice = sliceAsBytes(inSlice);
const in = @typeInfo(@TypeOf(inSlice)).Pointer;
const out = @typeInfo(@TypeOf(outSlice)).Pointer;
testing.expectEqual(in.is_const, out.is_const);
testing.expectEqual(in.is_volatile, out.is_volatile);
testing.expectEqual(in.is_allowzero, out.is_allowzero);
testing.expectEqual(in.alignment, out.alignment);
}
/// Round an address up to the nearest aligned address
/// The alignment must be a power of 2 and greater than 0.
pub fn alignForward(addr: usize, alignment: usize) usize {

View File

@@ -19,9 +19,6 @@ pub const Address = extern union {
in6: Ip6Address,
un: if (has_unix_sockets) os.sockaddr_un else void,
// TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512
//pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0);
/// Parse the given IP address string into an Address value.
/// It is recommended to use `resolveIp` instead, to handle
/// IPv6 link-local unix addresses.
@@ -839,6 +836,20 @@ fn linuxLookupName(
if (addrs.items.len == 0) {
try linuxLookupNameFromDnsSearch(addrs, canon, name, family, port);
}
if (addrs.items.len == 0) {
// RFC 6761 Section 6.3
// Name resolution APIs and libraries SHOULD recognize localhost
// names as special and SHOULD always return the IP loopback address
// for address queries and negative responses for all other query
// types.
// Check for equal to "localhost" or ends in ".localhost"
if (mem.endsWith(u8, name, "localhost") and (name.len == "localhost".len or name[name.len - "localhost".len] == '.')) {
try addrs.append(LookupAddr{ .addr = .{ .in = Ip4Address.parse("127.0.0.1", port) catch unreachable } });
try addrs.append(LookupAddr{ .addr = .{ .in6 = Ip6Address.parse("::1", port) catch unreachable } });
return;
}
}
}
} else {
try canon.resize(0);

View File

@@ -3734,6 +3734,7 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32
.SUCCESS => return,
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
.OBJECT_NAME_INVALID => unreachable,
.INVALID_PARAMETER => unreachable,
.ACCESS_DENIED => return error.PermissionDenied,
.OBJECT_PATH_SYNTAX_BAD => unreachable,

View File

@@ -86,27 +86,27 @@ pub const PR = extern enum(i32) {
_,
};
pub const PR_SET_PDEATHSIG = @enumToInt(PR.PR_SET_PDEATHSIG);
pub const PR_GET_PDEATHSIG = @enumToInt(PR.PR_GET_PDEATHSIG);
pub const PR_SET_PDEATHSIG = @enumToInt(PR.SET_PDEATHSIG);
pub const PR_GET_PDEATHSIG = @enumToInt(PR.GET_PDEATHSIG);
pub const PR_GET_DUMPABLE = @enumToInt(PR.PR_GET_DUMPABLE);
pub const PR_SET_DUMPABLE = @enumToInt(PR.PR_SET_DUMPABLE);
pub const PR_GET_DUMPABLE = @enumToInt(PR.GET_DUMPABLE);
pub const PR_SET_DUMPABLE = @enumToInt(PR.SET_DUMPABLE);
pub const PR_GET_UNALIGN = @enumToInt(PR.PR_GET_UNALIGN);
pub const PR_SET_UNALIGN = @enumToInt(PR.PR_SET_UNALIGN);
pub const PR_GET_UNALIGN = @enumToInt(PR.GET_UNALIGN);
pub const PR_SET_UNALIGN = @enumToInt(PR.SET_UNALIGN);
pub const PR_UNALIGN_NOPRINT = 1;
pub const PR_UNALIGN_SIGBUS = 2;
pub const PR_GET_KEEPCAPS = @enumToInt(PR.PR_GET_KEEPCAPS);
pub const PR_SET_KEEPCAPS = @enumToInt(PR.PR_SET_KEEPCAPS);
pub const PR_GET_KEEPCAPS = @enumToInt(PR.GET_KEEPCAPS);
pub const PR_SET_KEEPCAPS = @enumToInt(PR.SET_KEEPCAPS);
pub const PR_GET_FPEMU = @enumToInt(PR.PR_GET_FPEMU);
pub const PR_SET_FPEMU = @enumToInt(PR.PR_SET_FPEMU);
pub const PR_GET_FPEMU = @enumToInt(PR.GET_FPEMU);
pub const PR_SET_FPEMU = @enumToInt(PR.SET_FPEMU);
pub const PR_FPEMU_NOPRINT = 1;
pub const PR_FPEMU_SIGFPE = 2;
pub const PR_GET_FPEXC = @enumToInt(PR.PR_GET_FPEXC);
pub const PR_SET_FPEXC = @enumToInt(PR.PR_SET_FPEXC);
pub const PR_GET_FPEXC = @enumToInt(PR.GET_FPEXC);
pub const PR_SET_FPEXC = @enumToInt(PR.SET_FPEXC);
pub const PR_FP_EXC_SW_ENABLE = 0x80;
pub const PR_FP_EXC_DIV = 0x010000;
pub const PR_FP_EXC_OVF = 0x020000;
@@ -118,41 +118,41 @@ pub const PR_FP_EXC_NONRECOV = 1;
pub const PR_FP_EXC_ASYNC = 2;
pub const PR_FP_EXC_PRECISE = 3;
pub const PR_GET_TIMING = @enumToInt(PR.PR_GET_TIMING);
pub const PR_SET_TIMING = @enumToInt(PR.PR_SET_TIMING);
pub const PR_GET_TIMING = @enumToInt(PR.GET_TIMING);
pub const PR_SET_TIMING = @enumToInt(PR.SET_TIMING);
pub const PR_TIMING_STATISTICAL = 0;
pub const PR_TIMING_TIMESTAMP = 1;
pub const PR_SET_NAME = @enumToInt(PR.PR_SET_NAME);
pub const PR_GET_NAME = @enumToInt(PR.PR_GET_NAME);
pub const PR_SET_NAME = @enumToInt(PR.SET_NAME);
pub const PR_GET_NAME = @enumToInt(PR.GET_NAME);
pub const PR_GET_ENDIAN = @enumToInt(PR.PR_GET_ENDIAN);
pub const PR_SET_ENDIAN = @enumToInt(PR.PR_SET_ENDIAN);
pub const PR_GET_ENDIAN = @enumToInt(PR.GET_ENDIAN);
pub const PR_SET_ENDIAN = @enumToInt(PR.SET_ENDIAN);
pub const PR_ENDIAN_BIG = 0;
pub const PR_ENDIAN_LITTLE = 1;
pub const PR_ENDIAN_PPC_LITTLE = 2;
pub const PR_GET_SECCOMP = @enumToInt(PR.PR_GET_SECCOMP);
pub const PR_SET_SECCOMP = @enumToInt(PR.PR_SET_SECCOMP);
pub const PR_GET_SECCOMP = @enumToInt(PR.GET_SECCOMP);
pub const PR_SET_SECCOMP = @enumToInt(PR.SET_SECCOMP);
pub const PR_CAPBSET_READ = @enumToInt(PR.PR_CAPBSET_READ);
pub const PR_CAPBSET_DROP = @enumToInt(PR.PR_CAPBSET_DROP);
pub const PR_CAPBSET_READ = @enumToInt(PR.CAPBSET_READ);
pub const PR_CAPBSET_DROP = @enumToInt(PR.CAPBSET_DROP);
pub const PR_GET_TSC = @enumToInt(PR.PR_GET_TSC);
pub const PR_SET_TSC = @enumToInt(PR.PR_SET_TSC);
pub const PR_GET_TSC = @enumToInt(PR.GET_TSC);
pub const PR_SET_TSC = @enumToInt(PR.SET_TSC);
pub const PR_TSC_ENABLE = 1;
pub const PR_TSC_SIGSEGV = 2;
pub const PR_GET_SECUREBITS = @enumToInt(PR.PR_GET_SECUREBITS);
pub const PR_SET_SECUREBITS = @enumToInt(PR.PR_SET_SECUREBITS);
pub const PR_GET_SECUREBITS = @enumToInt(PR.GET_SECUREBITS);
pub const PR_SET_SECUREBITS = @enumToInt(PR.SET_SECUREBITS);
pub const PR_SET_TIMERSLACK = @enumToInt(PR.PR_SET_TIMERSLACK);
pub const PR_GET_TIMERSLACK = @enumToInt(PR.PR_GET_TIMERSLACK);
pub const PR_SET_TIMERSLACK = @enumToInt(PR.SET_TIMERSLACK);
pub const PR_GET_TIMERSLACK = @enumToInt(PR.GET_TIMERSLACK);
pub const PR_TASK_PERF_EVENTS_DISABLE = @enumToInt(PR.PR_TASK_PERF_EVENTS_DISABLE);
pub const PR_TASK_PERF_EVENTS_ENABLE = @enumToInt(PR.PR_TASK_PERF_EVENTS_ENABLE);
pub const PR_TASK_PERF_EVENTS_DISABLE = @enumToInt(PR.TASK_PERF_EVENTS_DISABLE);
pub const PR_TASK_PERF_EVENTS_ENABLE = @enumToInt(PR.TASK_PERF_EVENTS_ENABLE);
pub const PR_MCE_KILL = @enumToInt(PR.PR_MCE_KILL);
pub const PR_MCE_KILL = @enumToInt(PR.MCE_KILL);
pub const PR_MCE_KILL_CLEAR = 0;
pub const PR_MCE_KILL_SET = 1;
@@ -160,9 +160,9 @@ pub const PR_MCE_KILL_LATE = 0;
pub const PR_MCE_KILL_EARLY = 1;
pub const PR_MCE_KILL_DEFAULT = 2;
pub const PR_MCE_KILL_GET = @enumToInt(PR.PR_MCE_KILL_GET);
pub const PR_MCE_KILL_GET = @enumToInt(PR.MCE_KILL_GET);
pub const PR_SET_MM = @enumToInt(PR.PR_SET_MM);
pub const PR_SET_MM = @enumToInt(PR.SET_MM);
pub const PR_SET_MM_START_CODE = 1;
pub const PR_SET_MM_END_CODE = 2;
pub const PR_SET_MM_START_DATA = 3;
@@ -196,42 +196,42 @@ pub const prctl_mm_map = extern struct {
exe_fd: u32,
};
pub const PR_SET_PTRACER = @enumToInt(PR.PR_SET_PTRACER);
pub const PR_SET_PTRACER = @enumToInt(PR.SET_PTRACER);
pub const PR_SET_PTRACER_ANY = std.math.maxInt(c_ulong);
pub const PR_SET_CHILD_SUBREAPER = @enumToInt(PR.PR_SET_CHILD_SUBREAPER);
pub const PR_GET_CHILD_SUBREAPER = @enumToInt(PR.PR_GET_CHILD_SUBREAPER);
pub const PR_SET_CHILD_SUBREAPER = @enumToInt(PR.SET_CHILD_SUBREAPER);
pub const PR_GET_CHILD_SUBREAPER = @enumToInt(PR.GET_CHILD_SUBREAPER);
pub const PR_SET_NO_NEW_PRIVS = @enumToInt(PR.PR_SET_NO_NEW_PRIVS);
pub const PR_GET_NO_NEW_PRIVS = @enumToInt(PR.PR_GET_NO_NEW_PRIVS);
pub const PR_SET_NO_NEW_PRIVS = @enumToInt(PR.SET_NO_NEW_PRIVS);
pub const PR_GET_NO_NEW_PRIVS = @enumToInt(PR.GET_NO_NEW_PRIVS);
pub const PR_GET_TID_ADDRESS = @enumToInt(PR.PR_GET_TID_ADDRESS);
pub const PR_GET_TID_ADDRESS = @enumToInt(PR.GET_TID_ADDRESS);
pub const PR_SET_THP_DISABLE = @enumToInt(PR.PR_SET_THP_DISABLE);
pub const PR_GET_THP_DISABLE = @enumToInt(PR.PR_GET_THP_DISABLE);
pub const PR_SET_THP_DISABLE = @enumToInt(PR.SET_THP_DISABLE);
pub const PR_GET_THP_DISABLE = @enumToInt(PR.GET_THP_DISABLE);
pub const PR_MPX_ENABLE_MANAGEMENT = @enumToInt(PR.PR_MPX_ENABLE_MANAGEMENT);
pub const PR_MPX_DISABLE_MANAGEMENT = @enumToInt(PR.PR_MPX_DISABLE_MANAGEMENT);
pub const PR_MPX_ENABLE_MANAGEMENT = @enumToInt(PR.MPX_ENABLE_MANAGEMENT);
pub const PR_MPX_DISABLE_MANAGEMENT = @enumToInt(PR.MPX_DISABLE_MANAGEMENT);
pub const PR_SET_FP_MODE = @enumToInt(PR.PR_SET_FP_MODE);
pub const PR_GET_FP_MODE = @enumToInt(PR.PR_GET_FP_MODE);
pub const PR_SET_FP_MODE = @enumToInt(PR.SET_FP_MODE);
pub const PR_GET_FP_MODE = @enumToInt(PR.GET_FP_MODE);
pub const PR_FP_MODE_FR = 1 << 0;
pub const PR_FP_MODE_FRE = 1 << 1;
pub const PR_CAP_AMBIENT = @enumToInt(PR.PR_CAP_AMBIENT);
pub const PR_CAP_AMBIENT = @enumToInt(PR.CAP_AMBIENT);
pub const PR_CAP_AMBIENT_IS_SET = 1;
pub const PR_CAP_AMBIENT_RAISE = 2;
pub const PR_CAP_AMBIENT_LOWER = 3;
pub const PR_CAP_AMBIENT_CLEAR_ALL = 4;
pub const PR_SVE_SET_VL = @enumToInt(PR.PR_SVE_SET_VL);
pub const PR_SVE_SET_VL = @enumToInt(PR.SVE_SET_VL);
pub const PR_SVE_SET_VL_ONEXEC = 1 << 18;
pub const PR_SVE_GET_VL = @enumToInt(PR.PR_SVE_GET_VL);
pub const PR_SVE_GET_VL = @enumToInt(PR.SVE_GET_VL);
pub const PR_SVE_VL_LEN_MASK = 0xffff;
pub const PR_SVE_VL_INHERIT = 1 << 17;
pub const PR_GET_SPECULATION_CTRL = @enumToInt(PR.PR_GET_SPECULATION_CTRL);
pub const PR_SET_SPECULATION_CTRL = @enumToInt(PR.PR_SET_SPECULATION_CTRL);
pub const PR_GET_SPECULATION_CTRL = @enumToInt(PR.GET_SPECULATION_CTRL);
pub const PR_SET_SPECULATION_CTRL = @enumToInt(PR.SET_SPECULATION_CTRL);
pub const PR_SPEC_STORE_BYPASS = 0;
pub const PR_SPEC_NOT_AFFECTED = 0;
pub const PR_SPEC_PRCTL = 1 << 0;

View File

@@ -19,6 +19,7 @@ const iovec = linux.iovec;
const iovec_const = linux.iovec_const;
pub const mode_t = usize;
pub const time_t = isize;
pub const SYS = extern enum(usize) {
read = 0,
@@ -511,10 +512,11 @@ pub const msghdr_const = extern struct {
pub const off_t = i64;
pub const ino_t = u64;
pub const dev_t = u64;
// The `stat` definition used by the Linux kernel.
pub const kernel_stat = extern struct {
dev: u64,
dev: dev_t,
ino: ino_t,
nlink: usize,
@@ -522,7 +524,7 @@ pub const kernel_stat = extern struct {
uid: uid_t,
gid: gid_t,
__pad0: u32,
rdev: u64,
rdev: dev_t,
size: off_t,
blksize: isize,
blocks: i64,

View File

@@ -442,33 +442,30 @@ pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64, io_mode: std.io.Mo
}
return @as(usize, bytes_transferred);
} else {
var index: usize = 0;
while (index < buffer.len) {
const want_read_count = @intCast(DWORD, math.min(@as(DWORD, maxInt(DWORD)), buffer.len - index));
while (true) {
const want_read_count = @intCast(DWORD, math.min(@as(DWORD, maxInt(DWORD)), buffer.len));
var amt_read: DWORD = undefined;
var overlapped_data: OVERLAPPED = undefined;
const overlapped: ?*OVERLAPPED = if (offset) |off| blk: {
overlapped_data = .{
.Internal = 0,
.InternalHigh = 0,
.Offset = @truncate(u32, off + index),
.OffsetHigh = @truncate(u32, (off + index) >> 32),
.Offset = @truncate(u32, off),
.OffsetHigh = @truncate(u32, off >> 32),
.hEvent = null,
};
break :blk &overlapped_data;
} else null;
if (kernel32.ReadFile(in_hFile, buffer.ptr + index, want_read_count, &amt_read, overlapped) == 0) {
if (kernel32.ReadFile(in_hFile, buffer.ptr, want_read_count, &amt_read, overlapped) == 0) {
switch (kernel32.GetLastError()) {
.OPERATION_ABORTED => continue,
.BROKEN_PIPE => return index,
.HANDLE_EOF => return index,
.BROKEN_PIPE => return 0,
.HANDLE_EOF => return 0,
else => |err| return unexpectedError(err),
}
}
if (amt_read == 0) return index;
index += amt_read;
return amt_read;
}
return index;
}
}
@@ -831,7 +828,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
}
}
pub const MoveFileError = error{ FileNotFound, Unexpected };
pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };
pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {
const old_path_w = try sliceToPrefixedFileW(old_path);
@@ -843,6 +840,7 @@ pub fn MoveFileExW(old_path: [*:0]const u16, new_path: [*:0]const u16, flags: DW
if (kernel32.MoveFileExW(old_path, new_path, flags) == 0) {
switch (kernel32.GetLastError()) {
.FILE_NOT_FOUND => return error.FileNotFound,
.ACCESS_DENIED => return error.AccessDenied,
else => |err| return unexpectedError(err),
}
}

View File

@@ -360,7 +360,7 @@ const AtomicEvent = struct {
};
test "ResetEvent" {
if (std.Target.current.os.tag == .macos) {
if (std.Target.current.os.tag == .macos or std.Target.current.os.tag == .windows) {
// https://github.com/ziglang/zig/issues/7009
return error.SkipZigTest;
}

View File

@@ -41,8 +41,18 @@ pub fn main() !void {
warn("Expected third argument to be cache root directory path\n", .{});
return error.InvalidArgs;
};
const global_cache_root = nextArg(args, &arg_idx) orelse {
warn("Expected third argument to be global cache root directory path\n", .{});
return error.InvalidArgs;
};
const builder = try Builder.create(allocator, zig_exe, build_root, cache_root);
const builder = try Builder.create(
allocator,
zig_exe,
build_root,
cache_root,
global_cache_root,
);
defer builder.destroy();
var targets = ArrayList([]const u8).init(allocator);
@@ -69,7 +79,7 @@ pub fn main() !void {
} else if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--verbose")) {
builder.verbose = true;
} else if (mem.eql(u8, arg, "--help")) {
} else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
return usage(builder, false, stdout_stream);
} else if (mem.eql(u8, arg, "--prefix")) {
builder.install_prefix = nextArg(args, &arg_idx) orelse {
@@ -176,7 +186,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void
try out_stream.writeAll(
\\
\\General Options:
\\ --help Print this help and exit
\\ -h, --help Print this help and exit
\\ --verbose Print commands before executing them
\\ --prefix [path] Override default install prefix
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers

View File

@@ -8,6 +8,31 @@ const builtin = std.builtin;
const linkage: builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak;
// This parameter is true iff the target architecture supports the bare minimum
// to implement the atomic load/store intrinsics.
// Some architectures support atomic load/stores but no CAS, but we ignore this
// detail to keep the export logic clean and because we need some kind of CAS to
// implement the spinlocks.
const supports_atomic_ops = switch (builtin.arch) {
.msp430, .avr => false,
.arm, .armeb, .thumb, .thumbeb =>
// The ARM v6m ISA has no ldrex/strex and so it's impossible to do CAS
// operations (unless we're targeting Linux, the kernel provides a way to
// perform CAS operations).
// XXX: The Linux code path is not implemented yet.
!std.Target.arm.featureSetHas(std.Target.current.cpu.features, .has_v6m),
else => true,
};
// The size (in bytes) of the biggest object that the architecture can
// load/store atomically.
// Objects bigger than this threshold require the use of a lock.
const largest_atomic_size = switch (builtin.arch) {
// XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b
// and set this parameter accordingly.
else => @sizeOf(usize),
};
const cache_line_size = 64;
const SpinlockTable = struct {
@@ -94,40 +119,18 @@ fn __atomic_compare_exchange(
}
comptime {
@export(__atomic_load, .{ .name = "__atomic_load", .linkage = linkage });
@export(__atomic_store, .{ .name = "__atomic_store", .linkage = linkage });
@export(__atomic_exchange, .{ .name = "__atomic_exchange", .linkage = linkage });
@export(__atomic_compare_exchange, .{ .name = "__atomic_compare_exchange", .linkage = linkage });
if (supports_atomic_ops) {
@export(__atomic_load, .{ .name = "__atomic_load", .linkage = linkage });
@export(__atomic_store, .{ .name = "__atomic_store", .linkage = linkage });
@export(__atomic_exchange, .{ .name = "__atomic_exchange", .linkage = linkage });
@export(__atomic_compare_exchange, .{ .name = "__atomic_compare_exchange", .linkage = linkage });
}
}
// Specialized versions of the GCC atomic builtin functions.
// LLVM emits those iff the object size is known and the pointers are correctly
// aligned.
// The size (in bytes) of the biggest object that the architecture can
// load/store atomically.
// Objects bigger than this threshold require the use of a lock.
const largest_atomic_size = switch (builtin.arch) {
.x86_64 => 16,
else => @sizeOf(usize),
};
// The size (in bytes) of the biggest object that the architecture can perform
// an atomic CAS operation with.
// Objects bigger than this threshold require the use of a lock.
const largest_atomic_cas_size = switch (builtin.arch) {
.arm, .armeb, .thumb, .thumbeb =>
// The ARM v6m ISA has no ldrex/strex and so it's impossible to do CAS
// operations unless we're targeting Linux or the user provides the missing
// builtin functions.
if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .has_v6m) and
std.Target.current.os.tag != .linux)
0
else
@sizeOf(usize),
else => @sizeOf(usize),
};
fn atomicLoadFn(comptime T: type) fn (*T, i32) callconv(.C) T {
return struct {
fn atomic_load_N(src: *T, model: i32) callconv(.C) T {
@@ -143,10 +146,12 @@ fn atomicLoadFn(comptime T: type) fn (*T, i32) callconv(.C) T {
}
comptime {
@export(atomicLoadFn(u8), .{ .name = "__atomic_load_1", .linkage = linkage });
@export(atomicLoadFn(u16), .{ .name = "__atomic_load_2", .linkage = linkage });
@export(atomicLoadFn(u32), .{ .name = "__atomic_load_4", .linkage = linkage });
@export(atomicLoadFn(u64), .{ .name = "__atomic_load_8", .linkage = linkage });
if (supports_atomic_ops) {
@export(atomicLoadFn(u8), .{ .name = "__atomic_load_1", .linkage = linkage });
@export(atomicLoadFn(u16), .{ .name = "__atomic_load_2", .linkage = linkage });
@export(atomicLoadFn(u32), .{ .name = "__atomic_load_4", .linkage = linkage });
@export(atomicLoadFn(u64), .{ .name = "__atomic_load_8", .linkage = linkage });
}
}
fn atomicStoreFn(comptime T: type) fn (*T, T, i32) callconv(.C) void {
@@ -164,16 +169,18 @@ fn atomicStoreFn(comptime T: type) fn (*T, T, i32) callconv(.C) void {
}
comptime {
@export(atomicStoreFn(u8), .{ .name = "__atomic_store_1", .linkage = linkage });
@export(atomicStoreFn(u16), .{ .name = "__atomic_store_2", .linkage = linkage });
@export(atomicStoreFn(u32), .{ .name = "__atomic_store_4", .linkage = linkage });
@export(atomicStoreFn(u64), .{ .name = "__atomic_store_8", .linkage = linkage });
if (supports_atomic_ops) {
@export(atomicStoreFn(u8), .{ .name = "__atomic_store_1", .linkage = linkage });
@export(atomicStoreFn(u16), .{ .name = "__atomic_store_2", .linkage = linkage });
@export(atomicStoreFn(u32), .{ .name = "__atomic_store_4", .linkage = linkage });
@export(atomicStoreFn(u64), .{ .name = "__atomic_store_8", .linkage = linkage });
}
}
fn atomicExchangeFn(comptime T: type) fn (*T, T, i32) callconv(.C) T {
return struct {
fn atomic_exchange_N(ptr: *T, val: T, model: i32) callconv(.C) T {
if (@sizeOf(T) > largest_atomic_cas_size) {
if (@sizeOf(T) > largest_atomic_size) {
var sl = spinlocks.get(@ptrToInt(ptr));
defer sl.release();
const value = ptr.*;
@@ -187,16 +194,18 @@ fn atomicExchangeFn(comptime T: type) fn (*T, T, i32) callconv(.C) T {
}
comptime {
@export(atomicExchangeFn(u8), .{ .name = "__atomic_exchange_1", .linkage = linkage });
@export(atomicExchangeFn(u16), .{ .name = "__atomic_exchange_2", .linkage = linkage });
@export(atomicExchangeFn(u32), .{ .name = "__atomic_exchange_4", .linkage = linkage });
@export(atomicExchangeFn(u64), .{ .name = "__atomic_exchange_8", .linkage = linkage });
if (supports_atomic_ops) {
@export(atomicExchangeFn(u8), .{ .name = "__atomic_exchange_1", .linkage = linkage });
@export(atomicExchangeFn(u16), .{ .name = "__atomic_exchange_2", .linkage = linkage });
@export(atomicExchangeFn(u32), .{ .name = "__atomic_exchange_4", .linkage = linkage });
@export(atomicExchangeFn(u64), .{ .name = "__atomic_exchange_8", .linkage = linkage });
}
}
fn atomicCompareExchangeFn(comptime T: type) fn (*T, *T, T, i32, i32) callconv(.C) i32 {
return struct {
fn atomic_compare_exchange_N(ptr: *T, expected: *T, desired: T, success: i32, failure: i32) callconv(.C) i32 {
if (@sizeOf(T) > largest_atomic_cas_size) {
if (@sizeOf(T) > largest_atomic_size) {
var sl = spinlocks.get(@ptrToInt(ptr));
defer sl.release();
const value = ptr.*;
@@ -218,16 +227,18 @@ fn atomicCompareExchangeFn(comptime T: type) fn (*T, *T, T, i32, i32) callconv(.
}
comptime {
@export(atomicCompareExchangeFn(u8), .{ .name = "__atomic_compare_exchange_1", .linkage = linkage });
@export(atomicCompareExchangeFn(u16), .{ .name = "__atomic_compare_exchange_2", .linkage = linkage });
@export(atomicCompareExchangeFn(u32), .{ .name = "__atomic_compare_exchange_4", .linkage = linkage });
@export(atomicCompareExchangeFn(u64), .{ .name = "__atomic_compare_exchange_8", .linkage = linkage });
if (supports_atomic_ops) {
@export(atomicCompareExchangeFn(u8), .{ .name = "__atomic_compare_exchange_1", .linkage = linkage });
@export(atomicCompareExchangeFn(u16), .{ .name = "__atomic_compare_exchange_2", .linkage = linkage });
@export(atomicCompareExchangeFn(u32), .{ .name = "__atomic_compare_exchange_4", .linkage = linkage });
@export(atomicCompareExchangeFn(u64), .{ .name = "__atomic_compare_exchange_8", .linkage = linkage });
}
}
fn fetchFn(comptime T: type, comptime op: builtin.AtomicRmwOp) fn (*T, T, i32) callconv(.C) T {
return struct {
pub fn fetch_op_N(ptr: *T, val: T, model: i32) callconv(.C) T {
if (@sizeOf(T) > largest_atomic_cas_size) {
if (@sizeOf(T) > largest_atomic_size) {
var sl = spinlocks.get(@ptrToInt(ptr));
defer sl.release();
@@ -251,33 +262,35 @@ fn fetchFn(comptime T: type, comptime op: builtin.AtomicRmwOp) fn (*T, T, i32) c
}
comptime {
@export(fetchFn(u8, .Add), .{ .name = "__atomic_fetch_add_1", .linkage = linkage });
@export(fetchFn(u16, .Add), .{ .name = "__atomic_fetch_add_2", .linkage = linkage });
@export(fetchFn(u32, .Add), .{ .name = "__atomic_fetch_add_4", .linkage = linkage });
@export(fetchFn(u64, .Add), .{ .name = "__atomic_fetch_add_8", .linkage = linkage });
if (supports_atomic_ops) {
@export(fetchFn(u8, .Add), .{ .name = "__atomic_fetch_add_1", .linkage = linkage });
@export(fetchFn(u16, .Add), .{ .name = "__atomic_fetch_add_2", .linkage = linkage });
@export(fetchFn(u32, .Add), .{ .name = "__atomic_fetch_add_4", .linkage = linkage });
@export(fetchFn(u64, .Add), .{ .name = "__atomic_fetch_add_8", .linkage = linkage });
@export(fetchFn(u8, .Sub), .{ .name = "__atomic_fetch_sub_1", .linkage = linkage });
@export(fetchFn(u16, .Sub), .{ .name = "__atomic_fetch_sub_2", .linkage = linkage });
@export(fetchFn(u32, .Sub), .{ .name = "__atomic_fetch_sub_4", .linkage = linkage });
@export(fetchFn(u64, .Sub), .{ .name = "__atomic_fetch_sub_8", .linkage = linkage });
@export(fetchFn(u8, .Sub), .{ .name = "__atomic_fetch_sub_1", .linkage = linkage });
@export(fetchFn(u16, .Sub), .{ .name = "__atomic_fetch_sub_2", .linkage = linkage });
@export(fetchFn(u32, .Sub), .{ .name = "__atomic_fetch_sub_4", .linkage = linkage });
@export(fetchFn(u64, .Sub), .{ .name = "__atomic_fetch_sub_8", .linkage = linkage });
@export(fetchFn(u8, .And), .{ .name = "__atomic_fetch_and_1", .linkage = linkage });
@export(fetchFn(u16, .And), .{ .name = "__atomic_fetch_and_2", .linkage = linkage });
@export(fetchFn(u32, .And), .{ .name = "__atomic_fetch_and_4", .linkage = linkage });
@export(fetchFn(u64, .And), .{ .name = "__atomic_fetch_and_8", .linkage = linkage });
@export(fetchFn(u8, .And), .{ .name = "__atomic_fetch_and_1", .linkage = linkage });
@export(fetchFn(u16, .And), .{ .name = "__atomic_fetch_and_2", .linkage = linkage });
@export(fetchFn(u32, .And), .{ .name = "__atomic_fetch_and_4", .linkage = linkage });
@export(fetchFn(u64, .And), .{ .name = "__atomic_fetch_and_8", .linkage = linkage });
@export(fetchFn(u8, .Or), .{ .name = "__atomic_fetch_or_1", .linkage = linkage });
@export(fetchFn(u16, .Or), .{ .name = "__atomic_fetch_or_2", .linkage = linkage });
@export(fetchFn(u32, .Or), .{ .name = "__atomic_fetch_or_4", .linkage = linkage });
@export(fetchFn(u64, .Or), .{ .name = "__atomic_fetch_or_8", .linkage = linkage });
@export(fetchFn(u8, .Or), .{ .name = "__atomic_fetch_or_1", .linkage = linkage });
@export(fetchFn(u16, .Or), .{ .name = "__atomic_fetch_or_2", .linkage = linkage });
@export(fetchFn(u32, .Or), .{ .name = "__atomic_fetch_or_4", .linkage = linkage });
@export(fetchFn(u64, .Or), .{ .name = "__atomic_fetch_or_8", .linkage = linkage });
@export(fetchFn(u8, .Xor), .{ .name = "__atomic_fetch_xor_1", .linkage = linkage });
@export(fetchFn(u16, .Xor), .{ .name = "__atomic_fetch_xor_2", .linkage = linkage });
@export(fetchFn(u32, .Xor), .{ .name = "__atomic_fetch_xor_4", .linkage = linkage });
@export(fetchFn(u64, .Xor), .{ .name = "__atomic_fetch_xor_8", .linkage = linkage });
@export(fetchFn(u8, .Xor), .{ .name = "__atomic_fetch_xor_1", .linkage = linkage });
@export(fetchFn(u16, .Xor), .{ .name = "__atomic_fetch_xor_2", .linkage = linkage });
@export(fetchFn(u32, .Xor), .{ .name = "__atomic_fetch_xor_4", .linkage = linkage });
@export(fetchFn(u64, .Xor), .{ .name = "__atomic_fetch_xor_8", .linkage = linkage });
@export(fetchFn(u8, .Nand), .{ .name = "__atomic_fetch_nand_1", .linkage = linkage });
@export(fetchFn(u16, .Nand), .{ .name = "__atomic_fetch_nand_2", .linkage = linkage });
@export(fetchFn(u32, .Nand), .{ .name = "__atomic_fetch_nand_4", .linkage = linkage });
@export(fetchFn(u64, .Nand), .{ .name = "__atomic_fetch_nand_8", .linkage = linkage });
@export(fetchFn(u8, .Nand), .{ .name = "__atomic_fetch_nand_1", .linkage = linkage });
@export(fetchFn(u16, .Nand), .{ .name = "__atomic_fetch_nand_2", .linkage = linkage });
@export(fetchFn(u32, .Nand), .{ .name = "__atomic_fetch_nand_4", .linkage = linkage });
@export(fetchFn(u64, .Nand), .{ .name = "__atomic_fetch_nand_8", .linkage = linkage });
}
}

View File

@@ -3,7 +3,8 @@
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const builtin = @import("builtin");
const std = @import("std");
const builtin = std.builtin;
fn __clzsi2_generic(a: i32) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
@@ -25,8 +26,6 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 {
}
fn __clzsi2_thumb1() callconv(.Naked) void {
@setRuntimeSafety(builtin.is_test);
// Similar to the generic version with the last two rounds replaced by a LUT
asm volatile (
\\ movs r1, #32
@@ -59,8 +58,6 @@ fn __clzsi2_thumb1() callconv(.Naked) void {
}
fn __clzsi2_arm32() callconv(.Naked) void {
@setRuntimeSafety(builtin.is_test);
asm volatile (
\\ // Assumption: n != 0
\\ // r0: n
@@ -107,14 +104,13 @@ fn __clzsi2_arm32() callconv(.Naked) void {
unreachable;
}
pub const __clzsi2 = blk: {
if (builtin.arch.isARM()) {
break :blk __clzsi2_arm32;
} else if (builtin.arch.isThumb()) {
break :blk __clzsi2_thumb1;
} else {
break :blk __clzsi2_generic;
}
pub const __clzsi2 = switch (std.Target.current.cpu.arch) {
.arm, .armeb => if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm))
__clzsi2_thumb1
else
__clzsi2_arm32,
.thumb, .thumbeb => __clzsi2_thumb1,
else => __clzsi2_generic,
};
test "test clzsi2" {

View File

@@ -54,7 +54,7 @@ fn _DllMainCRTStartup(
fdwReason: std.os.windows.DWORD,
lpReserved: std.os.windows.LPVOID,
) callconv(.Stdcall) std.os.windows.BOOL {
if (!builtin.single_threaded) {
if (!builtin.single_threaded and !builtin.link_libc) {
_ = @import("start_windows_tls.zig");
}

View File

@@ -237,7 +237,7 @@ pub const Target = struct {
.macos => return .{
.semver = .{
.min = .{ .major = 10, .minor = 13 },
.max = .{ .major = 10, .minor = 15, .patch = 3 },
.max = .{ .major = 10, .minor = 15, .patch = 7 },
},
},
.ios => return .{

View File

@@ -247,6 +247,7 @@ test "expectWithinEpsilon" {
/// This function is intended to be used only in tests. When the two slices are not
/// equal, prints diagnostics to stderr to show exactly how they are not equal,
/// then aborts.
/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) void {
// TODO better printing of the difference
// If the arrays are small enough we could print the whole thing
@@ -368,6 +369,26 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) void {
}
}
pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) void {
if (std.mem.endsWith(u8, actual, expected_ends_with))
return;
const shortened_actual = if (actual.len >= expected_ends_with.len)
actual[0..expected_ends_with.len]
else
actual;
print("\n====== expected to end with: =========\n", .{});
printWithVisibleNewlines(expected_ends_with);
print("\n====== instead ended with: ===========\n", .{});
printWithVisibleNewlines(shortened_actual);
print("\n========= full output: ==============\n", .{});
printWithVisibleNewlines(actual);
print("\n======================================\n", .{});
@panic("test failure");
}
fn printIndicatorLine(source: []const u8, indicator_index: usize) void {
const line_begin_index = if (std.mem.lastIndexOfScalar(u8, source[0..indicator_index], '\n')) |line_begin|
line_begin + 1

View File

@@ -40,7 +40,7 @@ pub const Thread = struct {
pub const Data = if (use_pthreads)
struct {
handle: Thread.Handle,
memory: []align(mem.page_size) u8,
memory: []u8,
}
else switch (std.Target.current.os.tag) {
.linux => struct {
@@ -63,10 +63,10 @@ pub const Thread = struct {
return c.pthread_self();
} else
return switch (std.Target.current.os.tag) {
.linux => os.linux.gettid(),
.windows => windows.kernel32.GetCurrentThreadId(),
else => @compileError("Unsupported OS"),
};
.linux => os.linux.gettid(),
.windows => windows.kernel32.GetCurrentThreadId(),
else => @compileError("Unsupported OS"),
};
}
/// Returns the handle of this thread.
@@ -79,7 +79,7 @@ pub const Thread = struct {
return self.data.handle;
}
pub fn wait(self: *const Thread) void {
pub fn wait(self: *Thread) void {
if (use_pthreads) {
const err = c.pthread_join(self.data.handle, null);
switch (err) {
@@ -89,7 +89,8 @@ pub const Thread = struct {
os.EDEADLK => unreachable,
else => unreachable,
}
os.munmap(self.data.memory);
std.heap.c_allocator.free(self.data.memory);
std.heap.c_allocator.destroy(self);
} else switch (std.Target.current.os.tag) {
.linux => {
while (true) {
@@ -292,6 +293,47 @@ pub const Thread = struct {
}
};
if (Thread.use_pthreads) {
var attr: c.pthread_attr_t = undefined;
if (c.pthread_attr_init(&attr) != 0) return error.SystemResources;
defer assert(c.pthread_attr_destroy(&attr) == 0);
const thread_obj = try std.heap.c_allocator.create(Thread);
errdefer std.heap.c_allocator.destroy(thread_obj);
if (@sizeOf(Context) > 0) {
thread_obj.data.memory = try std.heap.c_allocator.allocAdvanced(
u8,
@alignOf(Context),
@sizeOf(Context),
.at_least,
);
errdefer std.heap.c_allocator.free(thread_obj.data.memory);
mem.copy(u8, thread_obj.data.memory, mem.asBytes(&context));
} else {
thread_obj.data.memory = @as([*]u8, undefined)[0..0];
}
// Use the same set of parameters used by the libc-less impl.
assert(c.pthread_attr_setstacksize(&attr, default_stack_size) == 0);
assert(c.pthread_attr_setguardsize(&attr, mem.page_size) == 0);
const err = c.pthread_create(
&thread_obj.data.handle,
&attr,
MainFuncs.posixThreadMain,
thread_obj.data.memory.ptr,
);
switch (err) {
0 => return thread_obj,
os.EAGAIN => return error.SystemResources,
os.EPERM => unreachable,
os.EINVAL => unreachable,
else => return os.unexpectedErrno(@intCast(usize, err)),
}
return thread_obj;
}
var guard_end_offset: usize = undefined;
var stack_end_offset: usize = undefined;
var thread_start_offset: usize = undefined;
@@ -315,74 +357,41 @@ pub const Thread = struct {
l += @sizeOf(Context);
}
// Finally, the Thread Local Storage, if any.
if (!Thread.use_pthreads) {
l = mem.alignForward(l, os.linux.tls.tls_image.alloc_align);
tls_start_offset = l;
l += os.linux.tls.tls_image.alloc_size;
}
l = mem.alignForward(l, os.linux.tls.tls_image.alloc_align);
tls_start_offset = l;
l += os.linux.tls.tls_image.alloc_size;
// Round the size to the page size.
break :blk mem.alignForward(l, mem.page_size);
};
const mmap_slice = mem: {
if (std.Target.current.os.tag != .netbsd) {
// Map the whole stack with no rw permissions to avoid
// committing the whole region right away
const mmap_slice = os.mmap(
null,
mmap_len,
os.PROT_NONE,
os.MAP_PRIVATE | os.MAP_ANONYMOUS,
-1,
0,
) catch |err| switch (err) {
error.MemoryMappingNotSupported => unreachable,
error.AccessDenied => unreachable,
error.PermissionDenied => unreachable,
else => |e| return e,
};
errdefer os.munmap(mmap_slice);
// Map the whole stack with no rw permissions to avoid
// committing the whole region right away
const mmap_slice = os.mmap(
null,
mmap_len,
os.PROT_NONE,
os.MAP_PRIVATE | os.MAP_ANONYMOUS,
-1,
0,
) catch |err| switch (err) {
error.MemoryMappingNotSupported => unreachable,
error.AccessDenied => unreachable,
error.PermissionDenied => unreachable,
else => |e| return e,
};
errdefer os.munmap(mmap_slice);
// Map everything but the guard page as rw
os.mprotect(
mmap_slice[guard_end_offset..],
os.PROT_READ | os.PROT_WRITE,
) catch |err| switch (err) {
error.AccessDenied => unreachable,
else => |e| return e,
};
// Map everything but the guard page as rw
os.mprotect(
mmap_slice[guard_end_offset..],
os.PROT_READ | os.PROT_WRITE,
) catch |err| switch (err) {
error.AccessDenied => unreachable,
else => |e| return e,
};
break :mem mmap_slice;
} else {
// NetBSD mprotect is very strict and doesn't allow to "upgrade"
// a PROT_NONE mapping to a RW one so let's allocate everything
// right away
const mmap_slice = os.mmap(
null,
mmap_len,
os.PROT_READ | os.PROT_WRITE,
os.MAP_PRIVATE | os.MAP_ANONYMOUS,
-1,
0,
) catch |err| switch (err) {
error.MemoryMappingNotSupported => unreachable,
error.AccessDenied => unreachable,
error.PermissionDenied => unreachable,
else => |e| return e,
};
errdefer os.munmap(mmap_slice);
// Remap the guard page with no permissions
os.mprotect(
mmap_slice[0..guard_end_offset],
os.PROT_NONE,
) catch |err| switch (err) {
error.AccessDenied => unreachable,
else => |e| return e,
};
break :mem mmap_slice;
}
break :mem mmap_slice;
};
const mmap_addr = @ptrToInt(mmap_slice.ptr);
@@ -397,33 +406,7 @@ pub const Thread = struct {
context_ptr.* = context;
}
if (Thread.use_pthreads) {
// use pthreads
var attr: c.pthread_attr_t = undefined;
if (c.pthread_attr_init(&attr) != 0) return error.SystemResources;
defer assert(c.pthread_attr_destroy(&attr) == 0);
// Tell pthread where the effective stack start is and its size
assert(c.pthread_attr_setstack(
&attr,
mmap_slice.ptr + guard_end_offset,
stack_end_offset - guard_end_offset,
) == 0);
// Even though pthread's man pages state that the guard size is
// ignored when the stack address is explicitly given, on some
// plaforms such as NetBSD we still have to zero it to prevent
// random crashes in pthread_join calls
assert(c.pthread_attr_setguardsize(&attr, 0) == 0);
const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
switch (err) {
0 => return thread_ptr,
os.EAGAIN => return error.SystemResources,
os.EPERM => unreachable,
os.EINVAL => unreachable,
else => return os.unexpectedErrno(@intCast(usize, err)),
}
} else if (std.Target.current.os.tag == .linux) {
if (std.Target.current.os.tag == .linux) {
const flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES |
os.CLONE_SIGHAND | os.CLONE_THREAD | os.CLONE_SYSVSEM |
os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |

View File

@@ -500,8 +500,12 @@ pub const CrossTarget = struct {
self.dynamic_linker.get() == null and self.glibc_version == null;
}
pub fn isNativeAbi(self: CrossTarget) bool {
return self.os_tag == null and self.abi == null;
}
pub fn isNative(self: CrossTarget) bool {
return self.isNativeCpu() and self.isNativeOs() and self.abi == null;
return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi();
}
pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![]u8 {

View File

@@ -274,6 +274,51 @@ test "recovery: missing block after for/while loops" {
});
}
test "zig fmt: respect line breaks after var declarations" {
try testCanonical(
\\const crc =
\\ lookup_tables[0][p[7]] ^
\\ lookup_tables[1][p[6]] ^
\\ lookup_tables[2][p[5]] ^
\\ lookup_tables[3][p[4]] ^
\\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
\\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
\\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
\\ lookup_tables[7][@truncate(u8, self.crc >> 0)];
\\
);
}
test "zig fmt: multiline string mixed with comments" {
try testCanonical(
\\const s1 =
\\ //\\one
\\ \\two)
\\ \\three
\\;
\\const s2 =
\\ \\one
\\ \\two)
\\ //\\three
\\;
\\const s3 =
\\ \\one
\\ //\\two)
\\ \\three
\\;
\\const s4 =
\\ \\one
\\ //\\two
\\ \\three
\\ //\\four
\\ \\five
\\;
\\const a =
\\ 1;
\\
);
}
test "zig fmt: empty file" {
try testCanonical(
\\
@@ -518,6 +563,24 @@ test "zig fmt: anon literal in array" {
);
}
test "zig fmt: alignment in anonymous literal" {
try testTransform(
\\const a = .{
\\ "U", "L", "F",
\\ "U'",
\\ "L'",
\\ "F'",
\\};
\\
,
\\const a = .{
\\ "U", "L", "F",
\\ "U'", "L'", "F'",
\\};
\\
);
}
test "zig fmt: anon struct literal syntax" {
try testCanonical(
\\const x = .{
@@ -3224,7 +3287,8 @@ test "zig fmt: integer literals with underscore separators" {
\\ 1_234_567
\\ +(0b0_1-0o7_0+0xff_FF ) + 0_0;
,
\\const x = 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0;
\\const x =
\\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0;
\\
);
}

View File

@@ -813,12 +813,10 @@ fn renderExpression(
const expr_last_token = expr.*.lastToken() + 1;
const next_expr = section_exprs[i + 1];
const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
if (loc.line == 0) {
column_counter += 1;
} else {
single_line = false;
column_counter = 0;
}
column_counter += 1;
if (loc.line != 0) single_line = false;
} else {
single_line = false;
column_counter = 0;
@@ -2209,10 +2207,10 @@ fn renderAsmOutput(
try ais.writer().writeAll(" (");
switch (asm_output.kind) {
ast.Node.Asm.Output.Kind.Variable => |variable_name| {
.Variable => |variable_name| {
try renderExpression(allocator, ais, tree, &variable_name.base, Space.None);
},
ast.Node.Asm.Output.Kind.Return => |return_type| {
.Return => |return_type| {
try ais.writer().writeAll("-> ");
try renderExpression(allocator, ais, tree, return_type, Space.None);
},
@@ -2304,8 +2302,17 @@ fn renderVarDecl(
}
if (var_decl.getInitNode()) |init_node| {
const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;
try renderToken(tree, ais, var_decl.getEqToken().?, s); // =
const eq_token = var_decl.getEqToken().?;
const eq_space = blk: {
const loc = tree.tokenLocation(tree.token_locs[eq_token].end, tree.nextToken(eq_token));
break :blk if (loc.line == 0) Space.Space else Space.Newline;
};
{
ais.pushIndent();
defer ais.popIndent();
try renderToken(tree, ais, eq_token, eq_space); // =
}
ais.pushIndentOneShot();
try renderExpression(allocator, ais, tree, init_node, Space.None);
}
@@ -2470,20 +2477,20 @@ fn renderTokenOffset(
var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
if (loc.line == 0) {
try ais.writer().print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
if (tree.token_ids[token_index] != .MultilineStringLiteralLine) {
try ais.writer().writeByte(' ');
}
try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
offset = 2;
token_loc = next_token_loc;
next_token_loc = tree.token_locs[token_index + offset];
next_token_id = tree.token_ids[token_index + offset];
if (next_token_id != .LineComment) {
switch (space) {
Space.None, Space.Space => {
.None, .Space, .SpaceOrOutdent => {
try ais.insertNewline();
},
Space.SpaceOrOutdent => {
try ais.insertNewline();
},
Space.Newline => {
.Newline => {
if (next_token_id == .MultilineStringLiteralLine) {
return;
} else {
@@ -2491,8 +2498,8 @@ fn renderTokenOffset(
return;
}
},
Space.NoNewline => {},
Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
.NoNewline => {},
.NoComment, .Comma, .BlockStart => unreachable,
}
return;
}
@@ -2513,7 +2520,7 @@ fn renderTokenOffset(
next_token_id = tree.token_ids[token_index + offset];
if (next_token_id != .LineComment) {
switch (space) {
Space.Newline => {
.Newline => {
if (next_token_id == .MultilineStringLiteralLine) {
return;
} else {
@@ -2521,14 +2528,11 @@ fn renderTokenOffset(
return;
}
},
Space.None, Space.Space => {
.None, .Space, .SpaceOrOutdent => {
try ais.insertNewline();
},
Space.SpaceOrOutdent => {
try ais.insertNewline();
},
Space.NoNewline => {},
Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
.NoNewline => {},
.NoComment, .Comma, .BlockStart => unreachable,
}
return;
}
@@ -2649,6 +2653,8 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
};
}
// Returns the number of nodes in `expr` that are on the same line as `rtoken`,
// or null if they all are on the same line.
fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize {
const first_token = exprs[0].firstToken();
const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken);

View File

@@ -211,16 +211,9 @@ pub const NativeTargetInfo = struct {
.linux => {
const uts = std.os.uname();
const release = mem.spanZ(&uts.release);
// The release field may have several other fields after the
// kernel version
const kernel_version = if (mem.indexOfScalar(u8, release, '-')) |pos|
release[0..pos]
else if (mem.indexOfScalar(u8, release, '_')) |pos|
release[0..pos]
else
release;
if (std.builtin.Version.parse(kernel_version)) |ver| {
// The release field sometimes has a weird format,
// `Version.parse` will attempt to find some meaningful interpretation.
if (std.builtin.Version.parse(release)) |ver| {
os.version_range.linux.range.min = ver;
os.version_range.linux.range.max = ver;
} else |err| switch (err) {

View File

@@ -26,6 +26,7 @@ pub fn obtain(cache: *const Cache) Manifest {
/// This is 128 bits - Even with 2^54 cache entries, the probably of a collision would be under 10^-6
pub const bin_digest_len = 16;
pub const hex_digest_len = bin_digest_len * 2;
pub const BinDigest = [bin_digest_len]u8;
const manifest_file_size_max = 50 * 1024 * 1024;
@@ -41,7 +42,7 @@ pub const File = struct {
path: ?[]const u8,
max_file_size: ?usize,
stat: fs.File.Stat,
bin_digest: [bin_digest_len]u8,
bin_digest: BinDigest,
contents: ?[]const u8,
pub fn deinit(self: *File, allocator: *Allocator) void {
@@ -60,6 +61,8 @@ pub const File = struct {
pub const HashHelper = struct {
hasher: Hasher = hasher_init,
const EmitLoc = @import("Compilation.zig").EmitLoc;
/// Record a slice of bytes as an dependency of the process being cached
pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
hh.hasher.update(mem.asBytes(&bytes.len));
@@ -71,6 +74,15 @@ pub const HashHelper = struct {
hh.addBytes(optional_bytes orelse return);
}
pub fn addEmitLoc(hh: *HashHelper, emit_loc: EmitLoc) void {
hh.addBytes(emit_loc.basename);
}
pub fn addOptionalEmitLoc(hh: *HashHelper, optional_emit_loc: ?EmitLoc) void {
hh.add(optional_emit_loc != null);
hh.addEmitLoc(optional_emit_loc orelse return);
}
pub fn addListOfBytes(hh: *HashHelper, list_of_bytes: []const []const u8) void {
hh.add(list_of_bytes.len);
for (list_of_bytes) |bytes| hh.addBytes(bytes);
@@ -128,16 +140,16 @@ pub const HashHelper = struct {
return copy.final();
}
pub fn peekBin(hh: HashHelper) [bin_digest_len]u8 {
pub fn peekBin(hh: HashHelper) BinDigest {
var copy = hh;
var bin_digest: [bin_digest_len]u8 = undefined;
var bin_digest: BinDigest = undefined;
copy.hasher.final(&bin_digest);
return bin_digest;
}
/// Returns a hex encoded hash of the inputs, mutating the state of the hasher.
pub fn final(hh: *HashHelper) [hex_digest_len]u8 {
var bin_digest: [bin_digest_len]u8 = undefined;
var bin_digest: BinDigest = undefined;
hh.hasher.final(&bin_digest);
var out_digest: [hex_digest_len]u8 = undefined;
@@ -230,7 +242,7 @@ pub const Manifest = struct {
const ext = ".txt";
var manifest_file_path: [self.hex_digest.len + ext.len]u8 = undefined;
var bin_digest: [bin_digest_len]u8 = undefined;
var bin_digest: BinDigest = undefined;
self.hash.hasher.final(&bin_digest);
_ = std.fmt.bufPrint(&self.hex_digest, "{x}", .{bin_digest}) catch unreachable;
@@ -336,7 +348,7 @@ pub const Manifest = struct {
cache_hash_file.stat.inode = 0;
}
var actual_digest: [bin_digest_len]u8 = undefined;
var actual_digest: BinDigest = undefined;
try hashFile(this_file, &actual_digest);
if (!mem.eql(u8, &cache_hash_file.bin_digest, &actual_digest)) {
@@ -370,7 +382,7 @@ pub const Manifest = struct {
return true;
}
pub fn unhit(self: *Manifest, bin_digest: [bin_digest_len]u8, input_file_count: usize) void {
pub fn unhit(self: *Manifest, bin_digest: BinDigest, input_file_count: usize) void {
// Reset the hash.
self.hash.hasher = hasher_init;
self.hash.hasher.update(&bin_digest);
@@ -519,7 +531,7 @@ pub const Manifest = struct {
// cache_release is called we still might be working on creating
// the artifacts to cache.
var bin_digest: [bin_digest_len]u8 = undefined;
var bin_digest: BinDigest = undefined;
self.hash.hasher.final(&bin_digest);
var out_digest: [hex_digest_len]u8 = undefined;

View File

@@ -33,6 +33,7 @@ gpa: *Allocator,
arena_state: std.heap.ArenaAllocator.State,
bin_file: *link.File,
c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
c_object_cache_digest_set: std.AutoHashMapUnmanaged(Cache.BinDigest, void) = .{},
stage1_lock: ?Cache.Lock = null,
stage1_cache_manifest: *Cache.Manifest = undefined,
@@ -93,6 +94,9 @@ libc_static_lib: ?CRTFile = null,
/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
compiler_rt_static_lib: ?CRTFile = null,
/// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
compiler_rt_obj: ?CRTFile = null,
glibc_so_files: ?glibc.BuiltSharedObjects = null,
@@ -164,8 +168,8 @@ const Job = union(enum) {
libcxx: void,
libcxxabi: void,
libssp: void,
/// needed when producing a dynamic library or executable
libcompiler_rt: void,
compiler_rt_lib: void,
compiler_rt_obj: void,
/// needed when not linking libc and using LLVM for code generation because it generates
/// calls to, for example, memcpy and memset.
zig_libc: void,
@@ -346,6 +350,7 @@ pub const InitOptions = struct {
want_sanitize_c: ?bool = null,
want_stack_check: ?bool = null,
want_valgrind: ?bool = null,
want_compiler_rt: ?bool = null,
use_llvm: ?bool = null,
use_lld: ?bool = null,
use_clang: ?bool = null,
@@ -354,13 +359,14 @@ pub const InitOptions = struct {
single_threaded: bool = false,
function_sections: bool = false,
is_native_os: bool,
is_native_abi: bool,
time_report: bool = false,
stack_report: bool = false,
link_eh_frame_hdr: bool = false,
link_emit_relocs: bool = false,
linker_script: ?[]const u8 = null,
version_script: ?[]const u8 = null,
override_soname: ?[]const u8 = null,
soname: ?[]const u8 = null,
linker_gc_sections: ?bool = null,
linker_allow_shlib_undefined: ?bool = null,
linker_bind_global_refs_locally: ?bool = null,
@@ -395,6 +401,50 @@ pub const InitOptions = struct {
subsystem: ?std.Target.SubSystem = null,
};
fn addPackageTableToCacheHash(
hash: *Cache.HashHelper,
arena: *std.heap.ArenaAllocator,
pkg_table: Package.Table,
hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
) (error{OutOfMemory} || std.os.GetCwdError)!void {
const allocator = &arena.allocator;
const packages = try allocator.alloc(Package.Table.Entry, pkg_table.count());
{
// Copy over the hashmap entries to our slice
var table_it = pkg_table.iterator();
var idx: usize = 0;
while (table_it.next()) |entry| : (idx += 1) {
packages[idx] = entry.*;
}
}
// Sort the slice by package name
std.sort.sort(Package.Table.Entry, packages, {}, struct {
fn lessThan(_: void, lhs: Package.Table.Entry, rhs: Package.Table.Entry) bool {
return std.mem.lessThan(u8, lhs.key, rhs.key);
}
}.lessThan);
for (packages) |pkg| {
// Finally insert the package name and path to the cache hash.
hash.addBytes(pkg.key);
switch (hash_type) {
.path_bytes => {
hash.addBytes(pkg.value.root_src_path);
hash.addOptionalBytes(pkg.value.root_src_directory.path);
},
.files => |man| {
const pkg_zig_file = try pkg.value.root_src_directory.join(allocator, &[_][]const u8{
pkg.value.root_src_path,
});
_ = try man.addFile(pkg_zig_file, null);
},
}
// Recurse to handle the package's dependencies
try addPackageTableToCacheHash(hash, arena, pkg.value.table, hash_type);
}
}
pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
const is_dyn_lib = switch (options.output_mode) {
.Obj, .Exe => false,
@@ -405,6 +455,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.Lib => is_dyn_lib,
.Exe => true,
};
const needs_c_symbols = !options.is_compiler_rt_or_libc and
(is_exe_or_dyn_lib or (options.target.isWasm() and options.output_mode != .Obj));
const comp: *Compilation = comp: {
// For allocations that have the same lifetime as Compilation. This arena is used only during this
// initialization and then is freed in deinit().
@@ -479,7 +532,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: {
const opts: DarwinOptions = if (use_lld and options.is_native_os and options.target.isDarwin()) inner: {
const syslibroot = try std.zig.system.getSDKPath(arena);
// TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
// See https://github.com/ziglang/zig/issues/6996
const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
const syslibroot = if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null;
const system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null;
break :inner .{
.syslibroot = syslibroot,
@@ -499,8 +555,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
{
break :dl true;
}
if (options.system_libs.len != 0) {
// when creating a executable that links to system libraries,
const any_dyn_libs: bool = x: {
if (options.system_libs.len != 0)
break :x true;
for (options.link_objects) |obj| {
switch (classifyFileExt(obj)) {
.shared_library => break :x true,
else => continue,
}
}
break :x false;
};
if (any_dyn_libs) {
// When creating a executable that links to system libraries,
// we require dynamic linking, but we must not link static libraries
// or object files dynamically!
break :dl (options.output_mode == .Exe);
@@ -508,7 +575,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
break :dl false;
};
const default_link_mode: std.builtin.LinkMode = if (must_dynamic_link) .Dynamic else .Static;
const default_link_mode: std.builtin.LinkMode = blk: {
if (must_dynamic_link) {
break :blk .Dynamic;
} else if (is_exe_or_dyn_lib and link_libc and
options.is_native_abi and options.target.abi.isMusl())
{
// If targeting the system's native ABI and the system's
// libc is musl, link dynamically by default.
break :blk .Dynamic;
} else {
break :blk .Static;
}
};
const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: {
if (lm == .Static and must_dynamic_link) {
return error.UnableToStaticLink;
@@ -568,6 +647,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
};
const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols;
const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
@@ -613,6 +694,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
cache.hash.addBytes(options.target.cpu.model.name);
cache.hash.add(options.target.cpu.features.ints);
cache.hash.add(options.target.os.tag);
cache.hash.add(options.target.os.getVersionRange());
cache.hash.add(options.is_native_os);
cache.hash.add(options.target.abi);
cache.hash.add(ofmt);
@@ -625,7 +707,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
cache.hash.add(options.link_libcpp);
cache.hash.add(options.output_mode);
cache.hash.add(options.machine_code_model);
cache.hash.add(options.emit_bin != null);
cache.hash.addOptionalEmitLoc(options.emit_bin);
cache.hash.addBytes(options.root_name);
// TODO audit this and make sure everything is in it
const module: ?*Module = if (options.root_pkg) |root_pkg| blk: {
@@ -640,9 +723,13 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
// would be likely to cause cache hits.
hash.addBytes(root_pkg.root_src_path);
hash.addOptionalBytes(root_pkg.root_src_directory.path);
{
var local_arena = std.heap.ArenaAllocator.init(gpa);
defer local_arena.deinit();
try addPackageTableToCacheHash(&hash, &local_arena, root_pkg.table, .path_bytes);
}
hash.add(valgrind);
hash.add(single_threaded);
hash.add(options.target.os.getVersionRange());
hash.add(dll_export_fns);
hash.add(options.is_test);
hash.add(options.is_compiler_rt_or_libc);
@@ -796,6 +883,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.rpath_list = options.rpath_list,
.strip = strip,
.is_native_os = options.is_native_os,
.is_native_abi = options.is_native_abi,
.function_sections = options.function_sections,
.allow_shlib_undefined = options.linker_allow_shlib_undefined,
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
@@ -803,6 +891,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.z_defs = options.linker_z_defs,
.stack_size_override = options.stack_size_override,
.image_base_override = options.image_base_override,
.include_compiler_rt = include_compiler_rt,
.linker_script = options.linker_script,
.version_script = options.version_script,
.gc_sections = options.linker_gc_sections,
@@ -810,7 +899,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.emit_relocs = options.link_emit_relocs,
.rdynamic = options.rdynamic,
.extra_lld_args = options.lld_argv,
.override_soname = options.override_soname,
.soname = options.soname,
.version = options.version,
.libc_installation = libc_dirs.libc_installation,
.pic = pic,
@@ -908,7 +997,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
comp.work_queue.writeAssumeCapacity(&[_]Job{
.{ .musl_crt_file = .crt1_o },
.{ .musl_crt_file = .scrt1_o },
.{ .musl_crt_file = .libc_a },
switch (comp.bin_file.options.link_mode) {
.Static => .{ .musl_crt_file = .libc_a },
.Dynamic => .{ .musl_crt_file = .libc_so },
},
});
}
if (comp.wantBuildMinGWFromSource()) {
@@ -947,16 +1039,35 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
try comp.work_queue.writeItem(.libcxxabi);
}
const needs_compiler_rt_and_c = is_exe_or_dyn_lib or
(comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);
if (needs_compiler_rt_and_c and build_options.is_stage1) {
try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
// MinGW provides no libssp, use our own implementation.
if (comp.getTarget().isMinGW()) {
try comp.work_queue.writeItem(.{ .libssp = {} });
// The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt.
// Once it is capable this condition should be removed.
if (build_options.is_stage1) {
if (comp.bin_file.options.include_compiler_rt) {
if (is_exe_or_dyn_lib or comp.getTarget().isWasm()) {
try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
} else {
try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
if (comp.bin_file.options.object_format != .elf and
comp.bin_file.options.output_mode == .Obj)
{
// For ELF we can rely on using -r to link multiple objects together into one,
// but to truly support `build-obj -fcompiler-rt` will require virtually
// injecting `_ = @import("compiler_rt.zig")` into the root source file of
// the compilation.
fatal("Embedding compiler-rt into {s} objects is not yet implemented.", .{
@tagName(comp.bin_file.options.object_format),
});
}
}
}
if (!comp.bin_file.options.link_libc) {
try comp.work_queue.writeItem(.{ .zig_libc = {} });
if (needs_c_symbols) {
// MinGW provides no libssp, use our own implementation.
if (comp.getTarget().isMinGW()) {
try comp.work_queue.writeItem(.{ .libssp = {} });
}
if (!comp.bin_file.options.link_libc) {
try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
}
}
}
@@ -1017,6 +1128,7 @@ pub fn destroy(self: *Compilation) void {
entry.key.destroy(gpa);
}
self.c_object_table.deinit(gpa);
self.c_object_cache_digest_set.deinit(gpa);
for (self.failed_c_objects.items()) |entry| {
entry.value.destroy(gpa);
@@ -1298,7 +1410,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(
self.gpa,
0,
"unable to build C object: {}",
"unable to build C object: {s}",
.{@errorName(err)},
));
c_object.status = .{ .failure = {} };
@@ -1354,20 +1466,26 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
fatal("unable to build libcxxabi: {}", .{@errorName(err)});
};
},
.libcompiler_rt => {
self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| {
.compiler_rt_lib => {
self.buildOutputFromZig("compiler_rt.zig", .Lib, &self.compiler_rt_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build compiler_rt: {}", .{@errorName(err)});
fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
};
},
.compiler_rt_obj => {
self.buildOutputFromZig("compiler_rt.zig", .Obj, &self.compiler_rt_obj) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
};
},
.libssp => {
self.buildStaticLibFromZig("ssp.zig", &self.libssp_static_lib) catch |err| {
self.buildOutputFromZig("ssp.zig", .Lib, &self.libssp_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build libssp: {}", .{@errorName(err)});
};
},
.zig_libc => {
self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
self.buildOutputFromZig("c.zig", .Lib, &self.libc_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build zig's multitarget libc: {}", .{@errorName(err)});
};
@@ -1512,6 +1630,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
const dep_basename = std.fs.path.basename(out_dep_path);
try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
const digest = man.final();
const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
@@ -1582,6 +1701,17 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
}
}
{
const gop = try comp.c_object_cache_digest_set.getOrPut(comp.gpa, man.hash.peekBin());
if (gop.found_existing) {
return comp.failCObj(
c_object,
"the same source file was already added to the same compilation with the same flags",
.{},
);
}
}
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
defer arena_allocator.deinit();
const arena = &arena_allocator.allocator;
@@ -1601,7 +1731,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
const o_basename_noext = if (direct_o)
comp.bin_file.options.root_name
else
mem.split(c_source_basename, ".").next().?;
c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, comp.getTarget().oFileExt() });
const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
@@ -1619,7 +1749,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile())
null
else
try std.fmt.allocPrint(arena, "{}.d", .{out_obj_path});
try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});
try comp.addCCArgs(arena, &argv, ext, out_dep_path);
try argv.ensureCapacity(argv.items.len + 3);
@@ -1656,7 +1786,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
if (comp.clang_preprocessor_mode == .stdout)
std.process.exit(0);
},
else => std.process.exit(1),
else => std.process.abort(),
}
} else {
child.stdin_behavior = .Ignore;
@@ -1702,6 +1832,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
};
}
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
if (comp.disable_c_depfile) _ = try man.hit();
// Rename into place.
const digest = man.final();
const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
@@ -1849,14 +1982,47 @@ pub fn addCCArgs(
try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={}", .{@tagName(mcmodel)}));
}
// windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning.
// So for this target, we disable this warning.
if (target.os.tag == .windows and target.abi.isGnu()) {
try argv.append("-Wno-pragma-pack");
switch (target.os.tag) {
.windows => {
// windows.h has files such as pshpack1.h which do #pragma packing,
// triggering a clang warning. So for this target, we disable this warning.
if (target.abi.isGnu()) {
try argv.append("-Wno-pragma-pack");
}
},
.macos => {
// Pass the proper -m<os>-version-min argument for darwin.
const ver = target.os.version_range.semver.min;
try argv.append(try std.fmt.allocPrint(arena, "-mmacos-version-min={d}.{d}.{d}", .{
ver.major, ver.minor, ver.patch,
}));
},
.ios, .tvos, .watchos => switch (target.cpu.arch) {
// Pass the proper -m<os>-version-min argument for darwin.
.i386, .x86_64 => {
const ver = target.os.version_range.semver.min;
try argv.append(try std.fmt.allocPrint(
arena,
"-m{s}-simulator-version-min={d}.{d}.{d}",
.{ @tagName(target.os.tag), ver.major, ver.minor, ver.patch },
));
},
else => {
const ver = target.os.version_range.semver.min;
try argv.append(try std.fmt.allocPrint(arena, "-m{s}-version-min={d}.{d}.{d}", .{
@tagName(target.os.tag), ver.major, ver.minor, ver.patch,
}));
},
},
else => {},
}
if (!comp.bin_file.options.strip) {
try argv.append("-g");
switch (comp.bin_file.options.object_format) {
.coff, .pe => try argv.append("-gcodeview"),
else => {},
}
}
if (comp.haveFramePointer()) {
@@ -2263,7 +2429,8 @@ fn wantBuildGLibCFromSource(comp: Compilation) bool {
}
fn wantBuildMuslFromSource(comp: Compilation) bool {
return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl();
return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl() and
!comp.getTarget().isWasm();
}
fn wantBuildMinGWFromSource(comp: Compilation) bool {
@@ -2502,10 +2669,16 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
}
}
fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !void {
fn buildOutputFromZig(
comp: *Compilation,
src_basename: []const u8,
output_mode: std.builtin.OutputMode,
out: *?CRTFile,
) !void {
const tracy = trace(@src());
defer tracy.end();
std.debug.assert(output_mode != .Exe);
const special_sub = "std" ++ std.fs.path.sep_str ++ "special";
const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub});
defer comp.gpa.free(special_path);
@@ -2520,13 +2693,13 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
},
.root_src_path = src_basename,
};
const root_name = mem.split(src_basename, ".").next().?;
const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
const target = comp.getTarget();
const output_mode: std.builtin.OutputMode = if (target.cpu.arch.isWasm()) .Obj else .Lib;
const fixed_output_mode = if (target.cpu.arch.isWasm()) .Obj else output_mode;
const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
.root_name = root_name,
.target = target,
.output_mode = output_mode,
.output_mode = fixed_output_mode,
});
defer comp.gpa.free(bin_basename);
@@ -2549,7 +2722,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
.target = target,
.root_name = root_name,
.root_pkg = &root_pkg,
.output_mode = output_mode,
.output_mode = fixed_output_mode,
.rand = comp.rand,
.libc_installation = comp.bin_file.options.libc_installation,
.emit_bin = emit_bin,
@@ -2563,6 +2736,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = comp.bin_file.options.is_native_os,
.is_native_abi = comp.bin_file.options.is_native_abi,
.self_exe_path = comp.self_exe_path,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
@@ -2621,6 +2795,11 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
defer man.deinit();
_ = try man.addFile(main_zig_file, null);
{
var local_arena = std.heap.ArenaAllocator.init(comp.gpa);
defer local_arena.deinit();
try addPackageTableToCacheHash(&man.hash, &local_arena, mod.root_pkg.table, .{ .files = &man });
}
man.hash.add(comp.bin_file.options.valgrind);
man.hash.add(comp.bin_file.options.single_threaded);
man.hash.add(target.os.getVersionRange());
@@ -2628,11 +2807,11 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
man.hash.add(comp.bin_file.options.function_sections);
man.hash.add(comp.bin_file.options.is_test);
man.hash.add(comp.bin_file.options.emit != null);
man.hash.add(comp.emit_h != null);
man.hash.add(comp.emit_asm != null);
man.hash.add(comp.emit_llvm_ir != null);
man.hash.add(comp.emit_analysis != null);
man.hash.add(comp.emit_docs != null);
man.hash.addOptionalEmitLoc(comp.emit_h);
man.hash.addOptionalEmitLoc(comp.emit_asm);
man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
man.hash.addOptionalEmitLoc(comp.emit_analysis);
man.hash.addOptionalEmitLoc(comp.emit_docs);
man.hash.addOptionalBytes(comp.test_filter);
man.hash.addOptionalBytes(comp.test_name_prefix);
@@ -2926,6 +3105,7 @@ pub fn build_crt_file(
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = comp.bin_file.options.is_native_os,
.is_native_abi = comp.bin_file.options.is_native_abi,
.self_exe_path = comp.self_exe_path,
.c_source_files = c_source_files,
.verbose_cc = comp.verbose_cc,
@@ -2955,6 +3135,11 @@ pub fn build_crt_file(
}
pub fn stage1AddLinkLib(comp: *Compilation, lib_name: []const u8) !void {
// Avoid deadlocking on building import libs such as kernel32.lib
// This can happen when the user uses `build-exe foo.obj -lkernel32` and then
// when we create a sub-Compilation for zig libc, it also tries to build kernel32.lib.
if (comp.bin_file.options.is_compiler_rt_or_libc) return;
// This happens when an `extern "foo"` function is referenced by the stage1 backend.
// If we haven't seen this library yet and we're targeting Windows, we need to queue up
// a work item to produce the DLL import library for this.

View File

@@ -911,13 +911,14 @@ fn buildSharedLib(
const tracy = trace(@src());
defer tracy.end();
const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover });
const emit_bin = Compilation.EmitLoc{
.directory = bin_directory,
.basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }),
.basename = basename,
};
const version: std.builtin.Version = .{ .major = lib.sover, .minor = 0, .patch = 0 };
const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?);
const override_soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else null;
const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename;
const map_file_path = try path.join(arena, &[_][]const u8{ bin_directory.path.?, all_map_basename });
const c_source_files = [1]Compilation.CSourceFile{
.{
@@ -943,6 +944,7 @@ fn buildSharedLib(
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = false,
.is_native_abi = false,
.self_exe_path = comp.self_exe_path,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
@@ -955,7 +957,7 @@ fn buildSharedLib(
.clang_passthrough_mode = comp.clang_passthrough_mode,
.version = version,
.version_script = map_file_path,
.override_soname = override_soname,
.soname = soname,
.c_source_files = &c_source_files,
.is_compiler_rt_or_libc = true,
});

View File

@@ -174,6 +174,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = comp.bin_file.options.is_native_os,
.is_native_abi = comp.bin_file.options.is_native_abi,
.self_exe_path = comp.self_exe_path,
.c_source_files = c_source_files.items,
.verbose_cc = comp.verbose_cc,
@@ -291,6 +292,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = comp.bin_file.options.is_native_os,
.is_native_abi = comp.bin_file.options.is_native_abi,
.self_exe_path = comp.self_exe_path,
.c_source_files = &c_source_files,
.verbose_cc = comp.verbose_cc,

View File

@@ -107,6 +107,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = comp.bin_file.options.is_native_os,
.is_native_abi = comp.bin_file.options.is_native_abi,
.self_exe_path = comp.self_exe_path,
.c_source_files = &c_source_files,
.verbose_cc = comp.verbose_cc,

View File

@@ -46,6 +46,7 @@ pub const Options = struct {
entry_addr: ?u64 = null,
stack_size_override: ?u64,
image_base_override: ?u64,
include_compiler_rt: bool,
/// Set to `true` to omit debug info.
strip: bool,
/// If this is true then this link code is responsible for outputting an object
@@ -70,6 +71,7 @@ pub const Options = struct {
z_defs: bool,
bind_global_refs_locally: bool,
is_native_os: bool,
is_native_abi: bool,
pic: bool,
valgrind: bool,
stack_check: bool,
@@ -87,7 +89,7 @@ pub const Options = struct {
subsystem: ?std.Target.SubSystem,
linker_script: ?[]const u8,
version_script: ?[]const u8,
override_soname: ?[]const u8,
soname: ?[]const u8,
llvm_cpu_features: ?[*:0]const u8,
/// Extra args passed directly to LLD. Ignored when not linking with LLD.
extra_lld_args: []const []const u8,
@@ -450,52 +452,65 @@ pub const File = struct {
break :blk full_obj_path;
} else null;
const compiler_rt_path: ?[]const u8 = if (base.options.include_compiler_rt)
comp.compiler_rt_obj.?.full_object_path
else
null;
// This function follows the same pattern as link.Elf.linkWithLLD so if you want some
// insight as to what's going on here you can read that function body which is more
// well-commented.
const id_symlink_basename = "llvm-ar.id";
base.releaseLock();
var man: Cache.Manifest = undefined;
defer if (!base.options.disable_lld_caching) man.deinit();
var ch = comp.cache_parent.obtain();
defer ch.deinit();
var digest: [Cache.hex_digest_len]u8 = undefined;
try ch.addListOfFiles(base.options.objects);
for (comp.c_object_table.items()) |entry| {
_ = try ch.addFile(entry.key.status.success.object_path, null);
if (!base.options.disable_lld_caching) {
man = comp.cache_parent.obtain();
// We are about to obtain this lock, so here we give other processes a chance first.
base.releaseLock();
try man.addListOfFiles(base.options.objects);
for (comp.c_object_table.items()) |entry| {
_ = try man.addFile(entry.key.status.success.object_path, null);
}
try man.addOptionalFile(module_obj_path);
try man.addOptionalFile(compiler_rt_path);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
digest = man.final();
var prev_digest_buf: [digest.len]u8 = undefined;
const prev_digest: []u8 = Cache.readSmallFile(
directory.handle,
id_symlink_basename,
&prev_digest_buf,
) catch |err| b: {
log.debug("archive new_digest={} readFile error: {}", .{ digest, @errorName(err) });
break :b prev_digest_buf[0..0];
};
if (mem.eql(u8, prev_digest, &digest)) {
log.debug("archive digest={} match - skipping invocation", .{digest});
base.lock = man.toOwnedLock();
return;
}
// We are about to change the output file to be different, so we invalidate the build hash now.
directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
error.FileNotFound => {},
else => |e| return e,
};
}
try ch.addOptionalFile(module_obj_path);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try ch.hit();
const digest = ch.final();
var prev_digest_buf: [digest.len]u8 = undefined;
const prev_digest: []u8 = Cache.readSmallFile(
directory.handle,
id_symlink_basename,
&prev_digest_buf,
) catch |err| b: {
log.debug("archive new_digest={} readFile error: {}", .{ digest, @errorName(err) });
break :b prev_digest_buf[0..0];
};
if (mem.eql(u8, prev_digest, &digest)) {
log.debug("archive digest={} match - skipping invocation", .{digest});
base.lock = ch.toOwnedLock();
return;
}
// We are about to change the output file to be different, so we invalidate the build hash now.
directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
error.FileNotFound => {},
else => |e| return e,
};
var object_files = std.ArrayList([*:0]const u8).init(base.allocator);
defer object_files.deinit();
try object_files.ensureCapacity(base.options.objects.len + comp.c_object_table.items().len + 1);
try object_files.ensureCapacity(base.options.objects.len + comp.c_object_table.items().len + 2);
for (base.options.objects) |obj_path| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj_path));
}
@@ -505,6 +520,9 @@ pub const File = struct {
if (module_obj_path) |p| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
}
if (compiler_rt_path) |p| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
}
const full_out_path = try directory.join(arena, &[_][]const u8{base.options.emit.?.sub_path});
const full_out_path_z = try arena.dupeZ(u8, full_out_path);
@@ -522,15 +540,17 @@ pub const File = struct {
const bad = llvm.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_type);
if (bad) return error.UnableToWriteArchive;
Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
std.log.warn("failed to save archive hash digest file: {}", .{@errorName(err)});
};
if (!base.options.disable_lld_caching) {
Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
std.log.warn("failed to save archive hash digest file: {}", .{@errorName(err)});
};
ch.writeManifest() catch |err| {
std.log.warn("failed to write cache manifest when archiving: {}", .{@errorName(err)});
};
man.writeManifest() catch |err| {
std.log.warn("failed to write cache manifest when archiving: {}", .{@errorName(err)});
};
base.lock = ch.toOwnedLock();
base.lock = man.toOwnedLock();
}
}
pub const Tag = enum {

View File

@@ -907,8 +907,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
// Create an LLD command line and invoke it.
var argv = std.ArrayList([]const u8).init(self.base.allocator);
defer argv.deinit();
// Even though we're calling LLD as a library it thinks the first argument is its own exe name.
try argv.append("lld");
// We will invoke ourselves as a child process to gain access to LLD.
// This is necessary because LLD does not behave properly as a library -
// it calls exit() and does not reset all global data between invocations.
try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "lld-link" });
try argv.append("-ERRORLIMIT:0");
try argv.append("-NOLOGO");
@@ -1146,45 +1148,65 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
}
if (self.base.options.verbose_link) {
Compilation.dump_argv(argv.items);
// Skip over our own name so that the LLD linker name is the first argv item.
Compilation.dump_argv(argv.items[1..]);
}
const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
for (argv.items) |arg, i| {
new_argv[i] = try arena.dupeZ(u8, arg);
}
// Sadly, we must run LLD as a child process because it does not behave
// properly as a library.
const child = try std.ChildProcess.init(argv.items, arena);
defer child.deinit();
var stderr_context: LLDContext = .{
.coff = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stderr_context.data.deinit();
var stdout_context: LLDContext = .{
.coff = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stdout_context.data.deinit();
const llvm = @import("../llvm.zig");
const ok = llvm.Link(
.COFF,
new_argv.ptr,
new_argv.len,
append_diagnostic,
@ptrToInt(&stdout_context),
@ptrToInt(&stderr_context),
);
if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
if (stdout_context.data.items.len != 0) {
std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
}
if (!ok) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{}", .{stderr_context.data.items});
return error.LLDReportedFailure;
}
if (stderr_context.data.items.len != 0) {
std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
if (comp.clang_passthrough_mode) {
child.stdin_behavior = .Inherit;
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
const term = child.spawnAndWait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO https://github.com/ziglang/zig/issues/6342
std.process.exit(1);
}
},
else => std.process.abort(),
}
} else {
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Ignore;
child.stderr_behavior = .Pipe;
try child.spawn();
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
const term = child.wait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{s}", .{stderr});
return error.LLDReportedFailure;
}
},
else => {
log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
return error.LLDCrashed;
},
}
if (stderr.len != 0) {
std.log.warn("unexpected LLD stderr:\n{s}", .{stderr});
}
}
}
@@ -1204,20 +1226,6 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
}
}
const LLDContext = struct {
data: std.ArrayList(u8),
coff: *Coff,
oom: bool = false,
};
fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
const lld_context = @intToPtr(*LLDContext, context);
const msg = ptr[0..len];
lld_context.data.appendSlice(msg) catch |err| switch (err) {
error.OutOfMemory => lld_context.oom = true,
};
}
pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {
return self.text_section_virtual_address + decl.link.coff.text_offset;
}

View File

@@ -1260,6 +1260,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
const gc_sections = self.base.options.gc_sections orelse !is_obj;
const stack_size = self.base.options.stack_size_override orelse 16777216;
const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt) blk: {
if (is_exe_or_dyn_lib) {
break :blk comp.compiler_rt_static_lib.?.full_object_path;
} else {
break :blk comp.compiler_rt_obj.?.full_object_path;
}
} else null;
// Here we want to determine whether we can save time by not invoking LLD when the
// output is unchanged. None of the linker options or the object files that are being
@@ -1289,6 +1296,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
_ = try man.addFile(entry.key.status.success.object_path, null);
}
try man.addOptionalFile(module_obj_path);
try man.addOptionalFile(compiler_rt_path);
// We can skip hashing libc and libc++ components that we are in charge of building from Zig
// installation sources because they are always a product of the compiler version + target information.
man.hash.add(stack_size);
@@ -1313,10 +1322,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
man.hash.addOptionalBytes(self.base.options.dynamic_linker);
}
}
if (is_dyn_lib) {
man.hash.addOptionalBytes(self.base.options.override_soname);
man.hash.addOptional(self.base.options.version);
}
man.hash.addOptionalBytes(self.base.options.soname);
man.hash.addOptional(self.base.options.version);
man.hash.addStringSet(self.base.options.system_libs);
man.hash.add(allow_shlib_undefined);
man.hash.add(self.base.options.bind_global_refs_locally);
@@ -1353,8 +1360,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
// Create an LLD command line and invoke it.
var argv = std.ArrayList([]const u8).init(self.base.allocator);
defer argv.deinit();
// Even though we're calling LLD as a library it thinks the first argument is its own exe name.
try argv.append("lld");
// We will invoke ourselves as a child process to gain access to LLD.
// This is necessary because LLD does not behave properly as a library -
// it calls exit() and does not reset all global data between invocations.
try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld.lld" });
if (is_obj) {
try argv.append("-r");
}
@@ -1505,13 +1514,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
}
if (is_dyn_lib) {
const soname = self.base.options.override_soname orelse if (self.base.options.version) |ver|
try std.fmt.allocPrint(arena, "lib{}.so.{}", .{ self.base.options.root_name, ver.major })
else
try std.fmt.allocPrint(arena, "lib{}.so", .{self.base.options.root_name});
try argv.append("-soname");
try argv.append(soname);
if (self.base.options.soname) |soname| {
try argv.append("-soname");
try argv.append(soname);
}
if (self.base.options.version_script) |version_script| {
try argv.append("-version-script");
try argv.append(version_script);
@@ -1529,25 +1535,29 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
try argv.append(p);
}
// compiler-rt and libc
if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
if (!self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
// libc
if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc and !self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
// compiler-rt
if (compiler_rt_path) |p| {
try argv.append(p);
}
// Shared libraries.
const system_libs = self.base.options.system_libs.items();
try argv.ensureCapacity(argv.items.len + system_libs.len);
for (system_libs) |entry| {
const link_lib = entry.key;
// By this time, we depend on these libs being dynamically linked libraries and not static libraries
// (the check for that needs to be earlier), but they could be full paths to .so files, in which
// case we want to avoid prepending "-l".
const ext = Compilation.classifyFileExt(link_lib);
const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
argv.appendAssumeCapacity(arg);
if (is_exe_or_dyn_lib) {
const system_libs = self.base.options.system_libs.items();
try argv.ensureCapacity(argv.items.len + system_libs.len);
for (system_libs) |entry| {
const link_lib = entry.key;
// By this time, we depend on these libs being dynamically linked libraries and not static libraries
// (the check for that needs to be earlier), but they could be full paths to .so files, in which
// case we want to avoid prepending "-l".
const ext = Compilation.classifyFileExt(link_lib);
const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
argv.appendAssumeCapacity(arg);
}
}
if (!is_obj) {
@@ -1584,7 +1594,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
} else if (target.isMusl()) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
.Static => "libc.a",
.Dynamic => "libc.so",
}));
} else if (self.base.options.link_libcpp) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
} else {
@@ -1613,46 +1626,65 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
}
if (self.base.options.verbose_link) {
Compilation.dump_argv(argv.items);
// Skip over our own name so that the LLD linker name is the first argv item.
Compilation.dump_argv(argv.items[1..]);
}
// Oh, snapplesauce! We need null terminated argv.
const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
for (argv.items) |arg, i| {
new_argv[i] = try arena.dupeZ(u8, arg);
}
// Sadly, we must run LLD as a child process because it does not behave
// properly as a library.
const child = try std.ChildProcess.init(argv.items, arena);
defer child.deinit();
var stderr_context: LLDContext = .{
.elf = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stderr_context.data.deinit();
var stdout_context: LLDContext = .{
.elf = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stdout_context.data.deinit();
const llvm = @import("../llvm.zig");
const ok = llvm.Link(
.ELF,
new_argv.ptr,
new_argv.len,
append_diagnostic,
@ptrToInt(&stdout_context),
@ptrToInt(&stderr_context),
);
if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
if (stdout_context.data.items.len != 0) {
std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
}
if (!ok) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{}", .{stderr_context.data.items});
return error.LLDReportedFailure;
}
if (stderr_context.data.items.len != 0) {
std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
if (comp.clang_passthrough_mode) {
child.stdin_behavior = .Inherit;
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
const term = child.spawnAndWait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO https://github.com/ziglang/zig/issues/6342
std.process.exit(1);
}
},
else => std.process.abort(),
}
} else {
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Ignore;
child.stderr_behavior = .Pipe;
try child.spawn();
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
const term = child.wait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{s}", .{stderr});
return error.LLDReportedFailure;
}
},
else => {
log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
return error.LLDCrashed;
},
}
if (stderr.len != 0) {
std.log.warn("unexpected LLD stderr:\n{s}", .{stderr});
}
}
if (!self.base.options.disable_lld_caching) {
@@ -1671,20 +1703,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
}
}
const LLDContext = struct {
data: std.ArrayList(u8),
elf: *Elf,
oom: bool = false,
};
fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
const lld_context = @intToPtr(*LLDContext, context);
const msg = ptr[0..len];
lld_context.data.appendSlice(msg) catch |err| switch (err) {
error.OutOfMemory => lld_context.oom = true,
};
}
fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
const target_endian = self.base.options.target.cpu.arch.endian();
switch (self.ptr_width) {

View File

@@ -256,7 +256,10 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
errdefer file.close();
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
errdefer {
self.base.file = null;
self.base.destroy();
}
self.base.file = file;
@@ -473,6 +476,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
man.hash.addStringSet(self.base.options.system_libs);
man.hash.add(allow_shlib_undefined);
man.hash.add(self.base.options.bind_global_refs_locally);
man.hash.add(self.base.options.system_linker_hack);
man.hash.addOptionalBytes(self.base.options.syslibroot);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@@ -539,8 +544,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
if (self.base.options.system_linker_hack) {
try argv.append("ld");
} else {
// Even though we're calling LLD as a library it thinks the first argument is its own exe name.
try argv.append("lld");
// We will invoke ourselves as a child process to gain access to LLD.
// This is necessary because LLD does not behave properly as a library -
// it calls exit() and does not reset all global data between invocations.
try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld64.lld" });
try argv.append("-error-limit");
try argv.append("0");
@@ -582,11 +589,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
try argv.append(cur_vers);
}
// TODO getting an error when running an executable when doing this rpath thing
//Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
// buf_ptr(g->root_out_name), g->version_major);
//try argv.append("-install_name");
//try argv.append(buf_ptr(dylib_install_name));
const dylib_install_name = try std.fmt.allocPrint(arena, "@rpath/{}", .{self.base.options.emit.?.sub_path});
try argv.append("-install_name");
try argv.append(dylib_install_name);
}
try argv.append("-arch");
@@ -708,7 +713,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
}
if (self.base.options.verbose_link) {
Compilation.dump_argv(argv.items);
// Potentially skip over our own name so that the LLD linker name is the first argv item.
const adjusted_argv = if (self.base.options.system_linker_hack) argv.items else argv.items[1..];
Compilation.dump_argv(adjusted_argv);
}
// TODO https://github.com/ziglang/zig/issues/6971
@@ -733,42 +740,61 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
return error.LDReportedFailure;
}
} else {
const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
for (argv.items) |arg, i| {
new_argv[i] = try arena.dupeZ(u8, arg);
}
// Sadly, we must run LLD as a child process because it does not behave
// properly as a library.
const child = try std.ChildProcess.init(argv.items, arena);
defer child.deinit();
var stderr_context: LLDContext = .{
.macho = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stderr_context.data.deinit();
var stdout_context: LLDContext = .{
.macho = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stdout_context.data.deinit();
const llvm = @import("../llvm.zig");
const ok = llvm.Link(
.MachO,
new_argv.ptr,
new_argv.len,
append_diagnostic,
@ptrToInt(&stdout_context),
@ptrToInt(&stderr_context),
);
if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
if (stdout_context.data.items.len != 0) {
std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
}
if (!ok) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{}", .{stderr_context.data.items});
return error.LLDReportedFailure;
}
if (stderr_context.data.items.len != 0) {
std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
if (comp.clang_passthrough_mode) {
child.stdin_behavior = .Inherit;
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
const term = child.spawnAndWait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO https://github.com/ziglang/zig/issues/6342
std.process.exit(1);
}
},
else => std.process.abort(),
}
} else {
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Ignore;
child.stderr_behavior = .Pipe;
try child.spawn();
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
const term = child.wait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{s}", .{stderr});
return error.LLDReportedFailure;
}
},
else => {
log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
return error.LLDCrashed;
},
}
if (stderr.len != 0) {
std.log.warn("unexpected LLD stderr:\n{s}", .{stderr});
}
}
}
}
@@ -789,20 +815,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
}
}
const LLDContext = struct {
data: std.ArrayList(u8),
macho: *MachO,
oom: bool = false,
};
fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
const lld_context = @intToPtr(*LLDContext, context);
const msg = ptr[0..len];
lld_context.data.appendSlice(msg) catch |err| switch (err) {
error.OutOfMemory => lld_context.oom = true,
};
}
fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
return switch (arch) {
.aarch64, .aarch64_be, .aarch64_32 => "arm64",

View File

@@ -282,6 +282,11 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
break :blk full_obj_path;
} else null;
const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt)
comp.compiler_rt_static_lib.?.full_object_path
else
null;
const target = self.base.options.target;
const id_symlink_basename = "lld.id";
@@ -302,6 +307,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
_ = try man.addFile(entry.key.status.success.object_path, null);
}
try man.addOptionalFile(module_obj_path);
try man.addOptionalFile(compiler_rt_path);
man.hash.addOptional(self.base.options.stack_size_override);
man.hash.addListOfBytes(self.base.options.extra_lld_args);
@@ -339,8 +345,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
// Create an LLD command line and invoke it.
var argv = std.ArrayList([]const u8).init(self.base.allocator);
defer argv.deinit();
// Even though we're calling LLD as a library it thinks the first argument is its own exe name.
try argv.append("lld");
// We will invoke ourselves as a child process to gain access to LLD.
// This is necessary because LLD does not behave properly as a library -
// it calls exit() and does not reset all global data between invocations.
try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "wasm-ld" });
if (is_obj) {
try argv.append("-r");
}
@@ -378,53 +386,77 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
try argv.append(p);
}
if (self.base.options.output_mode != .Obj and !self.base.options.is_compiler_rt_or_libc) {
if (!self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
if (self.base.options.output_mode != .Obj and
!self.base.options.is_compiler_rt_or_libc and
!self.base.options.link_libc)
{
try argv.append(comp.libc_static_lib.?.full_object_path);
}
if (compiler_rt_path) |p| {
try argv.append(p);
}
if (self.base.options.verbose_link) {
Compilation.dump_argv(argv.items);
// Skip over our own name so that the LLD linker name is the first argv item.
Compilation.dump_argv(argv.items[1..]);
}
const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
for (argv.items) |arg, i| {
new_argv[i] = try arena.dupeZ(u8, arg);
}
// Sadly, we must run LLD as a child process because it does not behave
// properly as a library.
const child = try std.ChildProcess.init(argv.items, arena);
defer child.deinit();
var stderr_context: LLDContext = .{
.wasm = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stderr_context.data.deinit();
var stdout_context: LLDContext = .{
.wasm = self,
.data = std.ArrayList(u8).init(self.base.allocator),
};
defer stdout_context.data.deinit();
const llvm = @import("../llvm.zig");
const ok = llvm.Link(
.Wasm,
new_argv.ptr,
new_argv.len,
append_diagnostic,
@ptrToInt(&stdout_context),
@ptrToInt(&stderr_context),
);
if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
if (stdout_context.data.items.len != 0) {
std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
}
if (!ok) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{}", .{stderr_context.data.items});
return error.LLDReportedFailure;
}
if (stderr_context.data.items.len != 0) {
std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
if (comp.clang_passthrough_mode) {
child.stdin_behavior = .Inherit;
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
const term = child.spawnAndWait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO https://github.com/ziglang/zig/issues/6342
std.process.exit(1);
}
},
else => std.process.abort(),
}
} else {
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Ignore;
child.stderr_behavior = .Pipe;
try child.spawn();
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
const term = child.wait() catch |err| {
log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
return error.UnableToSpawnSelf;
};
switch (term) {
.Exited => |code| {
if (code != 0) {
// TODO parse this output and surface with the Compilation API rather than
// directly outputting to stderr here.
std.debug.print("{s}", .{stderr});
return error.LLDReportedFailure;
}
},
else => {
log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
return error.LLDCrashed;
},
}
if (stderr.len != 0) {
std.log.warn("unexpected LLD stderr:\n{s}", .{stderr});
}
}
if (!self.base.options.disable_lld_caching) {
@@ -443,20 +475,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
}
}
const LLDContext = struct {
data: std.ArrayList(u8),
wasm: *Wasm,
oom: bool = false,
};
fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
const lld_context = @intToPtr(*LLDContext, context);
const msg = ptr[0..len];
lld_context.data.appendSlice(msg) catch |err| switch (err) {
error.OutOfMemory => lld_context.oom = true,
};
}
/// Get the current index of a given Decl in the function list
/// TODO: we could maintain a hash map to potentially make this
fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 {

View File

@@ -1,15 +1,15 @@
//! We do this instead of @cImport because the self-hosted compiler is easier
//! to bootstrap if it does not depend on translate-c.
pub const Link = ZigLLDLink;
extern fn ZigLLDLink(
oformat: ObjectFormatType,
args: [*:null]const ?[*:0]const u8,
arg_count: usize,
append_diagnostic: fn (context: usize, ptr: [*]const u8, len: usize) callconv(.C) void,
context_stdout: usize,
context_stderr: usize,
) bool;
extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
extern fn ZigLLDLinkMachO(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
pub const LinkCOFF = ZigLLDLinkCOFF;
pub const LinkELF = ZigLLDLinkELF;
pub const LinkMachO = ZigLLDLinkMachO;
pub const LinkWasm = ZigLLDLinkWasm;
pub const ObjectFormatType = extern enum(c_int) {
Unknown,

View File

@@ -41,11 +41,12 @@ const usage =
\\ build Build project from build.zig
\\ build-exe Create executable from source or object files
\\ build-lib Create library from source or object files
\\ build-obj Create object from source or assembly
\\ build-obj Create object from source or object files
\\ cc Use Zig as a drop-in C compiler
\\ c++ Use Zig as a drop-in C++ compiler
\\ env Print lib path, std path, compiler id and version
\\ fmt Parse file and render in canonical zig format
\\ env Print lib path, std path, cache directory, and version
\\ fmt Reformat Zig source into canonical form
\\ help Print this help and exit
\\ init-exe Initialize a `zig build` application in the cwd
\\ init-lib Initialize a `zig build` library in the cwd
\\ libc Display native libc paths file or validate one
@@ -54,11 +55,11 @@ const usage =
\\ targets List available compilation targets
\\ test Create and run a test build
\\ version Print version number and exit
\\ zen Print zen of zig and exit
\\ zen Print Zen of Zig and exit
\\
\\General Options:
\\
\\ --help Print command-specific usage
\\ -h, --help Print command-specific usage
\\
;
@@ -175,6 +176,12 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
{
return punt_to_clang(arena, args);
} else if (mem.eql(u8, cmd, "ld.lld") or
mem.eql(u8, cmd, "ld64.lld") or
mem.eql(u8, cmd, "lld-link") or
mem.eql(u8, cmd, "wasm-ld"))
{
return punt_to_lld(arena, args);
} else if (mem.eql(u8, cmd, "build")) {
return cmdBuild(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "fmt")) {
@@ -195,7 +202,7 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
try @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().outStream());
} else if (mem.eql(u8, cmd, "zen")) {
try io.getStdOut().writeAll(info_zen);
} else if (mem.eql(u8, cmd, "help")) {
} else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
try io.getStdOut().writeAll(usage);
} else {
std.log.info("{}", .{usage});
@@ -303,6 +310,12 @@ const usage_build_generic =
\\ --version-script [path] Provide a version .map file
\\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
\\ --version [ver] Dynamic library semver
\\ -fsoname[=name] (Linux) Override the default SONAME value
\\ -fno-soname (Linux) Disable emitting a SONAME
\\ -fLLD Force using LLD as the linker
\\ -fno-LLD Prevent using LLD as the linker
\\ -fcompiler-rt Always include compiler-rt symbols in output
\\ -fno-compiler-rt Prevent including compiler-rt symbols in output
\\ -rdynamic Add all symbols to the dynamic symbol table
\\ -rpath [path] Add directory to the runtime library search path
\\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
@@ -347,6 +360,12 @@ const repl_help =
\\
;
const SOName = union(enum) {
no,
yes_default_value,
yes: []const u8,
};
const Emit = union(enum) {
no,
yes_default_path,
@@ -449,6 +468,7 @@ fn buildOutputType(
var target_ofmt: ?[]const u8 = null;
var output_mode: std.builtin.OutputMode = undefined;
var emit_h: Emit = undefined;
var soname: SOName = undefined;
var ensure_libc_on_non_freestanding = false;
var ensure_libcpp_on_non_freestanding = false;
var link_libc = false;
@@ -459,11 +479,11 @@ fn buildOutputType(
var want_sanitize_c: ?bool = null;
var want_stack_check: ?bool = null;
var want_valgrind: ?bool = null;
var want_compiler_rt: ?bool = null;
var rdynamic: bool = false;
var linker_script: ?[]const u8 = null;
var version_script: ?[]const u8 = null;
var disable_c_depfile = false;
var override_soname: ?[]const u8 = null;
var linker_gc_sections: ?bool = null;
var linker_allow_shlib_undefined: ?bool = null;
var linker_bind_global_refs_locally: ?bool = null;
@@ -560,6 +580,8 @@ fn buildOutputType(
// .translate_c, .zig_test, .run => emit_h = .no,
// else => unreachable,
//}
soname = .yes_default_value;
const args = all_args[2..];
var i: usize = 0;
args_loop: while (i < args.len) : (i += 1) {
@@ -774,6 +796,10 @@ fn buildOutputType(
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
i += 1;
override_lib_dir = args[i];
} else if (mem.eql(u8, arg, "-fcompiler-rt")) {
want_compiler_rt = true;
} else if (mem.eql(u8, arg, "-fno-compiler-rt")) {
want_compiler_rt = false;
} else if (mem.eql(u8, arg, "-feach-lib-rpath")) {
each_lib_rpath = true;
} else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
@@ -820,6 +846,12 @@ fn buildOutputType(
use_clang = false;
} else if (mem.eql(u8, arg, "-rdynamic")) {
rdynamic = true;
} else if (mem.eql(u8, arg, "-fsoname")) {
soname = .yes_default_value;
} else if (mem.startsWith(u8, arg, "-fsoname=")) {
soname = .{ .yes = arg["-fsoname=".len..] };
} else if (mem.eql(u8, arg, "-fno-soname")) {
soname = .no;
} else if (mem.eql(u8, arg, "-femit-bin")) {
emit_bin = .yes_default_path;
} else if (mem.startsWith(u8, arg, "-femit-bin=")) {
@@ -947,6 +979,7 @@ fn buildOutputType(
},
.cc, .cpp => {
emit_h = .no;
soname = .no;
strip = true;
ensure_libc_on_non_freestanding = true;
ensure_libcpp_on_non_freestanding = arg_mode == .cpp;
@@ -1090,33 +1123,33 @@ fn buildOutputType(
if (i >= linker_args.items.len) {
fatal("expected linker arg after '{}'", .{arg});
}
const soname = linker_args.items[i];
override_soname = soname;
const name = linker_args.items[i];
soname = .{ .yes = name };
// Use it as --name.
// Example: libsoundio.so.2
var prefix: usize = 0;
if (mem.startsWith(u8, soname, "lib")) {
if (mem.startsWith(u8, name, "lib")) {
prefix = 3;
}
var end: usize = soname.len;
if (mem.endsWith(u8, soname, ".so")) {
var end: usize = name.len;
if (mem.endsWith(u8, name, ".so")) {
end -= 3;
} else {
var found_digit = false;
while (end > 0 and std.ascii.isDigit(soname[end - 1])) {
while (end > 0 and std.ascii.isDigit(name[end - 1])) {
found_digit = true;
end -= 1;
}
if (found_digit and end > 0 and soname[end - 1] == '.') {
if (found_digit and end > 0 and name[end - 1] == '.') {
end -= 1;
} else {
end = soname.len;
end = name.len;
}
if (mem.endsWith(u8, soname[prefix..end], ".so")) {
if (mem.endsWith(u8, name[prefix..end], ".so")) {
end -= 3;
}
}
provided_name = soname[prefix..end];
provided_name = name[prefix..end];
} else if (mem.eql(u8, arg, "-rpath")) {
i += 1;
if (i >= linker_args.items.len) {
@@ -1277,16 +1310,16 @@ fn buildOutputType(
break :blk "test";
} else if (root_src_file) |file| {
const basename = fs.path.basename(file);
break :blk mem.split(basename, ".").next().?;
} else if (c_source_files.items.len == 1) {
break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
} else if (c_source_files.items.len >= 1) {
const basename = fs.path.basename(c_source_files.items[0].src_path);
break :blk mem.split(basename, ".").next().?;
} else if (link_objects.items.len == 1) {
break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
} else if (link_objects.items.len >= 1) {
const basename = fs.path.basename(link_objects.items[0]);
break :blk mem.split(basename, ".").next().?;
break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
} else if (emit_bin == .yes) {
const basename = fs.path.basename(emit_bin.yes);
break :blk mem.split(basename, ".").next().?;
break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
} else if (show_builtin) {
break :blk "builtin";
} else if (arg_mode == .run) {
@@ -1356,6 +1389,9 @@ fn buildOutputType(
_ = system_libs.orderedRemove(i);
continue;
}
if (std.fs.path.isAbsolute(lib_name)) {
fatal("cannot use absolute path as a system library: {s}", .{lib_name});
}
i += 1;
}
}
@@ -1418,6 +1454,18 @@ fn buildOutputType(
const have_enable_cache = enable_cache orelse false;
const optional_version = if (have_version) version else null;
const resolved_soname: ?[]const u8 = switch (soname) {
.yes => |explicit| explicit,
.no => null,
.yes_default_value => switch (object_format) {
.elf => if (have_version)
try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
else
try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}),
else => null,
},
};
const emit_bin_loc: ?Compilation.EmitLoc = switch (emit_bin) {
.no => null,
.yes_default_path => Compilation.EmitLoc{
@@ -1576,21 +1624,18 @@ fn buildOutputType(
if (arg_mode == .run) {
break :l global_cache_directory;
}
const cache_dir_path = blk: {
if (root_pkg) |pkg| {
if (pkg.root_src_directory.path) |p| {
break :blk try fs.path.join(arena, &[_][]const u8{ p, "zig-cache" });
}
}
break :blk "zig-cache";
};
const cache_parent_dir = if (root_pkg) |pkg| pkg.root_src_directory.handle else fs.cwd();
const dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
cleanup_local_cache_dir = dir;
break :l .{
.handle = dir,
.path = cache_dir_path,
};
if (root_pkg) |pkg| {
const cache_dir_path = try pkg.root_src_directory.join(arena, &[_][]const u8{"zig-cache"});
const dir = try pkg.root_src_directory.handle.makeOpenPath("zig-cache", .{});
cleanup_local_cache_dir = dir;
break :l .{
.handle = dir,
.path = cache_dir_path,
};
}
// Otherwise we really don't have a reasonable place to put the local cache directory,
// so we utilize the global one.
break :l global_cache_directory;
};
if (build_options.have_llvm and emit_asm != .no) {
@@ -1608,6 +1653,7 @@ fn buildOutputType(
.root_name = root_name,
.target = target_info.target,
.is_native_os = cross_target.isNativeOs(),
.is_native_abi = cross_target.isNativeAbi(),
.dynamic_linker = target_info.dynamic_linker.get(),
.output_mode = output_mode,
.root_pkg = root_pkg,
@@ -1637,6 +1683,7 @@ fn buildOutputType(
.want_sanitize_c = want_sanitize_c,
.want_stack_check = want_stack_check,
.want_valgrind = want_valgrind,
.want_compiler_rt = want_compiler_rt,
.use_llvm = use_llvm,
.use_lld = use_lld,
.use_clang = use_clang,
@@ -1644,7 +1691,7 @@ fn buildOutputType(
.linker_script = linker_script,
.version_script = version_script,
.disable_c_depfile = disable_c_depfile,
.override_soname = override_soname,
.soname = resolved_soname,
.linker_gc_sections = linker_gc_sections,
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
@@ -1707,7 +1754,10 @@ fn buildOutputType(
}
};
try updateModule(gpa, comp, zir_out_path, hook);
updateModule(gpa, comp, zir_out_path, hook) catch |err| switch (err) {
error.SemanticAnalyzeFail => process.exit(1),
else => |e| return e,
};
if (build_options.is_stage1 and comp.stage1_lock != null and watch) {
warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{});
@@ -1819,7 +1869,10 @@ fn buildOutputType(
if (output_mode == .Exe) {
try comp.makeBinFileWritable();
}
try updateModule(gpa, comp, zir_out_path, hook);
updateModule(gpa, comp, zir_out_path, hook) catch |err| switch (err) {
error.SemanticAnalyzeFail => continue,
else => |e| return e,
};
} else if (mem.eql(u8, actual_line, "exit")) {
break;
} else if (mem.eql(u8, actual_line, "help")) {
@@ -1849,6 +1902,7 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,
for (errors.list) |full_err_msg| {
full_err_msg.renderToStdErr();
}
return error.SemanticAnalyzeFail;
} else switch (hook) {
.none => {},
.print => |bin_path| try io.getStdOut().writer().print("{s}\n", .{bin_path}),
@@ -2013,7 +2067,7 @@ pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void {
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--help")) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
const stdout = io.getStdOut().writer();
try stdout.writeAll(usage_libc);
return cleanExit();
@@ -2055,7 +2109,7 @@ pub const usage_init =
\\ directory.
\\
\\Options:
\\ --help Print this help and exit
\\ -h, --help Print this help and exit
\\
\\
;
@@ -2071,7 +2125,7 @@ pub fn cmdInit(
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--help")) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
try io.getStdOut().writeAll(usage_init);
return cleanExit();
} else {
@@ -2144,7 +2198,7 @@ pub const usage_build =
\\ Build a project from build.zig.
\\
\\Options:
\\ --help Print this help and exit
\\ -h, --help Print this help and exit
\\
\\
;
@@ -2152,7 +2206,7 @@ pub const usage_build =
pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {
// We want to release all the locks before executing the child process, so we make a nice
// big block here to ensure the cleanup gets run when we extract out our argv.
const lock_and_argv = lock_and_argv: {
const child_argv = argv: {
const self_exe_path = try fs.selfExePathAlloc(arena);
var build_file: ?[]const u8 = null;
@@ -2172,6 +2226,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
const argv_index_cache_dir = child_argv.items.len;
_ = try child_argv.addOne();
const argv_index_global_cache_dir = child_argv.items.len;
_ = try child_argv.addOne();
{
var i: usize = 0;
while (i < args.len) : (i += 1) {
@@ -2192,13 +2249,11 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
if (i + 1 >= args.len) fatal("expected argument after '{}'", .{arg});
i += 1;
override_local_cache_dir = args[i];
try child_argv.appendSlice(&[_][]const u8{ arg, args[i] });
continue;
} else if (mem.eql(u8, arg, "--global-cache-dir")) {
if (i + 1 >= args.len) fatal("expected argument after '{}'", .{arg});
i += 1;
override_global_cache_dir = args[i];
try child_argv.appendSlice(&[_][]const u8{ arg, args[i] });
continue;
}
}
@@ -2283,6 +2338,8 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
};
defer global_cache_directory.handle.close();
child_argv.items[argv_index_global_cache_dir] = global_cache_directory.path orelse cwd_path;
var local_cache_directory: Compilation.Directory = l: {
if (override_local_cache_dir) |local_cache_dir_path| {
break :l .{
@@ -2327,6 +2384,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
.root_name = "build",
.target = target_info.target,
.is_native_os = cross_target.isNativeOs(),
.is_native_abi = cross_target.isNativeAbi(),
.dynamic_linker = target_info.dynamic_linker.get(),
.output_mode = .Exe,
.root_pkg = &root_pkg,
@@ -2347,15 +2405,8 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
&[_][]const u8{exe_basename},
);
break :lock_and_argv .{
.child_argv = child_argv.items,
.lock = comp.bin_file.toOwnedLock(),
};
break :argv child_argv.items;
};
const child_argv = lock_and_argv.child_argv;
var lock = lock_and_argv.lock;
defer lock.release();
const child = try std.ChildProcess.init(child_argv, gpa);
defer child.deinit();
@@ -2396,7 +2447,7 @@ pub const usage_fmt =
\\ recursively.
\\
\\Options:
\\ --help Print this help and exit
\\ -h, --help Print this help and exit
\\ --color [auto|off|on] Enable or disable colored error messages
\\ --stdin Format code from stdin; output to stdout
\\ --check List non-conforming files and exit with an error
@@ -2428,7 +2479,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--help")) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
const stdout = io.getStdOut().outStream();
try stdout.writeAll(usage_fmt);
return cleanExit();
@@ -2566,6 +2617,9 @@ fn fmtPathDir(
var dir_it = dir.iterate();
while (try dir_it.next()) |entry| {
const is_dir = entry.kind == .Directory;
if (is_dir and std.mem.eql(u8, entry.name, "zig-cache")) continue;
if (is_dir or mem.endsWith(u8, entry.name, ".zig")) {
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
defer fmt.gpa.free(full_path);
@@ -2736,6 +2790,39 @@ fn punt_to_clang(arena: *Allocator, args: []const []const u8) error{OutOfMemory}
process.exit(@bitCast(u8, @truncate(i8, exit_code)));
}
/// The first argument determines which backend is invoked. The options are:
/// * `ld.lld` - ELF
/// * `ld64.lld` - Mach-O
/// * `lld-link` - COFF
/// * `wasm-ld` - WebAssembly
/// TODO https://github.com/ziglang/zig/issues/3257
pub fn punt_to_lld(arena: *Allocator, args: []const []const u8) error{OutOfMemory} {
if (!build_options.have_llvm)
fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]});
// Convert the args to the format LLD expects.
// We subtract 1 to shave off the zig binary from args[0].
const argv = try arena.allocSentinel(?[*:0]const u8, args.len - 1, null);
for (args[1..]) |arg, i| {
argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
}
const exit_code = rc: {
const llvm = @import("llvm.zig");
const argc = @intCast(c_int, argv.len);
if (mem.eql(u8, args[1], "ld.lld")) {
break :rc llvm.LinkELF(argc, argv.ptr, true);
} else if (mem.eql(u8, args[1], "ld64.lld")) {
break :rc llvm.LinkMachO(argc, argv.ptr, true);
} else if (mem.eql(u8, args[1], "lld-link")) {
break :rc llvm.LinkCOFF(argc, argv.ptr, true);
} else if (mem.eql(u8, args[1], "wasm-ld")) {
break :rc llvm.LinkWasm(argc, argv.ptr, true);
} else {
unreachable;
}
};
process.exit(@bitCast(u8, @truncate(i8, exit_code)));
}
const clang_args = @import("clang_options.zig").list;
pub const ClangArgIterator = struct {

View File

@@ -14,6 +14,7 @@ pub const CRTFile = enum {
crt1_o,
scrt1_o,
libc_a,
libc_so,
};
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
@@ -122,7 +123,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
const dirname = path.dirname(src_file).?;
const basename = path.basename(src_file);
const noextbasename = mem.split(basename, ".").next().?;
const noextbasename = basename[0 .. basename.len - std.fs.path.extension(basename).len];
const before_arch_dir = path.dirname(dirname).?;
const dirbasename = path.basename(dirname);
@@ -171,6 +172,59 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
}
return comp.build_crt_file("c", .Lib, c_source_files.items);
},
.libc_so => {
const sub_compilation = try Compilation.create(comp.gpa, .{
.local_cache_directory = comp.global_cache_directory,
.global_cache_directory = comp.global_cache_directory,
.zig_lib_directory = comp.zig_lib_directory,
.target = comp.getTarget(),
.root_name = "c",
.root_pkg = null,
.output_mode = .Lib,
.link_mode = .Dynamic,
.rand = comp.rand,
.libc_installation = comp.bin_file.options.libc_installation,
.emit_bin = Compilation.EmitLoc{ .directory = null, .basename = "libc.so" },
.optimize_mode = comp.bin_file.options.optimize_mode,
.want_sanitize_c = false,
.want_stack_check = false,
.want_valgrind = false,
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = false,
.is_native_abi = false,
.self_exe_path = comp.self_exe_path,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.verbose_tokenize = comp.verbose_tokenize,
.verbose_ast = comp.verbose_ast,
.verbose_ir = comp.verbose_ir,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.c_source_files = &[_]Compilation.CSourceFile{
.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "libc.s" }) },
},
.is_compiler_rt_or_libc = true,
.soname = "libc.so",
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
const basename = try comp.gpa.dupe(u8, "libc.so");
errdefer comp.gpa.free(basename);
comp.crt_files.putAssumeCapacityNoClobber(basename, .{
.full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{
sub_compilation.bin_file.options.emit.?.sub_path,
}),
.lock = sub_compilation.bin_file.toOwnedLock(),
});
},
}
}

View File

@@ -745,8 +745,14 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
return existing_entry->value;
}
Error err;
if ((err = type_resolve(g, err_set_type, ResolveStatusSizeKnown)))
return g->builtin_types.entry_invalid;
if ((err = type_resolve(g, payload_type, ResolveStatusSizeKnown)))
return g->builtin_types.entry_invalid;
ZigType *entry = new_type_table_entry(ZigTypeIdErrorUnion);
assert(type_is_resolved(payload_type, ResolveStatusSizeKnown));
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name));
@@ -1453,7 +1459,12 @@ Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *typ
case LazyValueIdArrayType: {
LazyValueArrayType *lazy_array_type =
reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
return type_val_resolve_abi_align(g, source_node, lazy_array_type->elem_type->value, abi_align);
if (lazy_array_type->length + (lazy_array_type->sentinel != nullptr) != 0)
return type_val_resolve_abi_align(g, source_node, lazy_array_type->elem_type->value, abi_align);
*abi_align = 0;
return ErrorNone;
}
case LazyValueIdErrUnionType: {
LazyValueErrUnionType *lazy_err_union_type =
@@ -3473,7 +3484,29 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
union_type->abi_size = SIZE_MAX;
union_type->size_in_bits = SIZE_MAX;
}
union_type->data.unionation.resolve_status = zero_bits ? ResolveStatusSizeKnown : ResolveStatusZeroBitsKnown;
if (zero_bits) {
// Don't forget to resolve the types for each union member even though
// the type is zero sized.
// XXX: Do it in a nicer way in stage2.
union_type->data.unionation.resolve_loop_flag_other = true;
for (uint32_t i = 0; i < field_count; i += 1) {
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
ZigType *field_type = resolve_union_field_type(g, union_field);
if (field_type == nullptr) {
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
}
union_type->data.unionation.resolve_loop_flag_other = false;
union_type->data.unionation.resolve_status = ResolveStatusSizeKnown;
return ErrorNone;
}
union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown;
return ErrorNone;
}
@@ -4375,7 +4408,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
}
}
Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope) {
// resolve all the using_namespace decls
for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
TldUsingNamespace *tld_using_namespace = decls_scope->use_decls.at(i);
@@ -4385,6 +4418,10 @@ Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
}
}
}
Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
resolve_container_usingnamespace_decls(g, decls_scope);
auto entry = decls_scope->decl_table.maybe_get(name);
return (entry == nullptr) ? nullptr : entry->value;
}
@@ -6017,7 +6054,7 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
TypeUnionField *only_field = &union_type->data.unionation.fields[0];
ZigType *field_type = resolve_union_field_type(g, only_field);
assert(field_type);
bigint_init_unsigned(&result->data.x_union.tag, 0);
bigint_init_bigint(&result->data.x_union.tag, &only_field->enum_field->value);
result->data.x_union.payload = g->pass1_arena->create<ZigValue>();
copy_const_val(g, result->data.x_union.payload,
get_the_one_possible_value(g, field_type));
@@ -6026,6 +6063,11 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
result->data.x_ptr.mut = ConstPtrMutComptimeConst;
result->data.x_ptr.special = ConstPtrSpecialRef;
result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type);
} else if (result->type->id == ZigTypeIdEnum) {
ZigType *enum_type = result->type;
assert(enum_type->data.enumeration.src_field_count == 1);
TypeEnumField *only_field = &result->type->data.enumeration.fields[0];
bigint_init_bigint(&result->data.x_enum_tag, &only_field->value);
}
g->one_possible_values.put(type_entry, result);
return result;
@@ -7079,8 +7121,6 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *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(g, 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);
}

View File

@@ -79,6 +79,7 @@ ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **c
Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name);
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy);
void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope);
ZigType *get_src_ptr_type(ZigType *type);
uint32_t get_ptr_align(CodeGen *g, ZigType *type);

View File

@@ -83,7 +83,7 @@ static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char
static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name);
static void generate_error_name_table(CodeGen *g);
static bool value_is_all_undef(CodeGen *g, ZigValue *const_val);
static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr);
static void gen_undef_init(CodeGen *g, ZigType *ptr_type, ZigType *value_type, LLVMValueRef ptr);
static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment);
static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstGen *source_instr,
LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type,
@@ -242,14 +242,24 @@ struct CalcLLVMFieldIndex {
static void calc_llvm_field_index_add(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *ty) {
if (!type_has_bits(g, ty)) return;
uint32_t ty_align = get_abi_alignment(g, ty);
if (calc->offset % ty_align != 0) {
uint32_t llvm_align = LLVMABIAlignmentOfType(g->target_data_ref, get_llvm_type(g, ty));
if (llvm_align >= ty_align) {
ty_align = llvm_align; // llvm's padding is sufficient
} else if (calc->offset) {
calc->field_index += 1; // zig will insert an extra padding field here
}
calc->offset += ty_align - (calc->offset % ty_align); // padding bytes
// Alignment according to Zig.
uint32_t adj_offset = calc->offset + (ty_align - (calc->offset % ty_align));
// Alignment according to LLVM.
uint32_t adj_llvm_offset = (calc->offset % llvm_align) ?
calc->offset + (llvm_align - (calc->offset % llvm_align)) :
calc->offset;
// Cannot under-align structure fields.
assert(adj_offset >= adj_llvm_offset);
// Zig will insert an extra padding field here.
if (adj_offset != adj_llvm_offset)
calc->field_index += 1;
calc->offset = adj_offset;
}
calc->offset += ty->abi_size;
calc->field_index += 1;
@@ -380,9 +390,36 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
LLVMTypeRef fn_llvm_type = fn->raw_type_ref;
LLVMValueRef llvm_fn = nullptr;
if (fn->body_node == nullptr) {
assert(fn->proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto;
const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref);
// The compiler tries to deduplicate extern definitions by looking up
// their name, this was introduced to allow the declaration of the same
// extern function with differing prototypes.
// When Wasm is targeted this check becomes a problem as the user may
// declare two (or more) extern functions sharing the same name but
// imported from different modules!
// To overcome this problem we generate a mangled identifier out of the
// import and the function name, this name is only visible within the
// compiler as we're telling LLVM (using 'wasm-import-name' and
// 'wasm-import-name') what the real function name is and where to find
// it.
const bool use_mangled_name = target_is_wasm(g->zig_target) &&
fn_proto->is_extern && fn_proto->lib_name != nullptr;
// Pick a weird name to avoid collisions...
// This whole function should be burned to the ground.
Buf *mangled_symbol_buf = use_mangled_name ?
buf_sprintf("%s|%s", unmangled_name, buf_ptr(fn_proto->lib_name)) :
nullptr;
symbol_name = use_mangled_name ?
buf_ptr(mangled_symbol_buf) : unmangled_name;
LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, symbol_name);
if (existing_llvm_fn) {
if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf);
return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, fn_addrspace));
} else {
Buf *buf_symbol_name = buf_create_from_str(symbol_name);
@@ -392,12 +429,9 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
if (entry == nullptr) {
llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type);
if (target_is_wasm(g->zig_target)) {
assert(fn->proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto;
if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {
addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name));
}
if (use_mangled_name) {
addLLVMFnAttrStr(llvm_fn, "wasm-import-name", unmangled_name);
addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name));
}
} else {
assert(entry->value->id == TldIdFn);
@@ -407,8 +441,11 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, symbol_name,
tld_fn->fn_entry->raw_type_ref);
llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, fn_addrspace));
if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf);
return llvm_fn;
}
if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf);
}
} else {
if (llvm_fn == nullptr) {
@@ -484,6 +521,12 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value);
}
if (g->build_mode == BuildModeSmallRelease) {
// Optimize for small code size.
addLLVMFnAttr(llvm_fn, "minsize");
addLLVMFnAttr(llvm_fn, "optsize");
}
addLLVMFnAttr(llvm_fn, "nounwind");
add_uwtable_attr(g, llvm_fn);
addLLVMFnAttr(llvm_fn, "nobuiltin");
@@ -1487,7 +1530,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
gen_safety_crash(g, actual_type->data.integral.is_signed ? PanicMsgIdCastNegativeToUnsigned : PanicMsgIdCastTruncatedData);
gen_safety_crash(g, scalar_actual_type->data.integral.is_signed ? PanicMsgIdCastNegativeToUnsigned : PanicMsgIdCastTruncatedData);
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
@@ -3306,9 +3349,9 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutableGen
LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand);
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
} else if (ir_want_runtime_safety(g, &instruction->base)) {
} else if (ir_want_runtime_safety(g, &instruction->base) && ptr_index != SIZE_MAX) {
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, ptr_index, "");
gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr);
gen_undef_init(g, slice_ptr_type, slice_ptr_type, ptr_field_ptr);
}
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, len_index, "");
@@ -3773,22 +3816,35 @@ static void gen_valgrind_undef(CodeGen *g, LLVMValueRef dest_ptr, LLVMValueRef b
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) {
static void gen_undef_init(CodeGen *g, ZigType *ptr_type, ZigType *value_type, LLVMValueRef ptr) {
assert(type_has_bits(g, value_type));
uint64_t ptr_align_bytes = get_ptr_align(g, ptr_type);
assert(ptr_align_bytes > 0);
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, value_type));
assert(size_bytes > 0);
assert(ptr_align_bytes > 0);
// memset uninitialized memory to 0xaa
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
ZigType *usize = g->builtin_types.entry_usize;
LLVMValueRef byte_count = LLVMConstInt(usize->llvm_type, size_bytes, false);
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 (g->valgrind_enabled) {
gen_valgrind_undef(g, dest_ptr, byte_count);
if (ptr_type->data.pointer.host_int_bytes == 0) {
// memset uninitialized memory to 0xaa
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
ZigType *usize = g->builtin_types.entry_usize;
LLVMValueRef byte_count = LLVMConstInt(usize->llvm_type, size_bytes, false);
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 (g->valgrind_enabled) {
gen_valgrind_undef(g, dest_ptr, byte_count);
}
return;
}
// This is a pointer into a packed struct, we can't use memset here.
// The jury is still out on what pattern should be written here so clear the
// old value and call it a day. Generating a 0xAA...AA mask for this n-bit
// value is left as an exercise for the (bored) reader.
LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, value_type));
gen_assign_raw(g, ptr, ptr_type, zero);
}
static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutableGen *executable, IrInstGenStorePtr *instruction) {
@@ -3817,7 +3873,7 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutableGen *executable,
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,
gen_undef_init(g, ptr_type, instruction->value->value->type,
ir_llvm_value(g, instruction->ptr));
}
return nullptr;
@@ -3837,15 +3893,30 @@ static LLVMValueRef ir_render_vector_store_elem(CodeGen *g, IrExecutableGen *exe
}
static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutableGen *executable, IrInstGenVarPtr *instruction) {
if (instruction->base.value->special != ConstValSpecialRuntime)
return ir_llvm_value(g, &instruction->base);
ZigVar *var = instruction->var;
if (type_has_bits(g, var->var_type)) {
assert(var->value_ref);
return var->value_ref;
} else {
Error err;
ZigType *ptr_type = instruction->base.value->type;
assert(ptr_type->id == ZigTypeIdPointer);
bool ptr_type_has_bits;
if ((err = type_has_bits2(g, ptr_type, &ptr_type_has_bits)))
codegen_report_errors_and_exit(g);
if (!ptr_type_has_bits) {
return nullptr;
}
// The extra bitcasts are needed in case the LLVM value is an unnamed
// struct, as it happens when rendering container types with extra alignment
// fields.
if (instruction->base.value->special != ConstValSpecialRuntime) {
return LLVMBuildBitCast(g->builder, ir_llvm_value(g, &instruction->base),
get_llvm_type(g, ptr_type), "");
}
ZigVar *var = instruction->var;
assert(var->value_ref);
return LLVMBuildBitCast(g->builder, var->value_ref,
get_llvm_type(g, ptr_type), "");
}
static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutableGen *executable,
@@ -4378,8 +4449,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
arg_calc = arg_calc_start;
for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
CalcLLVMFieldIndex prev = arg_calc;
// Use the declared argument type and not the value one to be
// consistent with the assignment operation below.
calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));
field_types[arg_calc.field_index - 1] = LLVMTypeOf(gen_param_values.at(arg_i));
field_types[arg_calc.field_index - 1] = get_llvm_type(g, gen_param_types.at(arg_i));
if (arg_calc.field_index - prev.field_index > 1) {
// Padding field
uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size;
@@ -4793,6 +4866,29 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I
}
}
// Add some architecture-specific clobbers.
const char *arch_clobbers = nullptr;
switch (g->zig_target->arch) {
case ZigLLVM_x86:
case ZigLLVM_x86_64:
arch_clobbers = "~{dirflag},~{fpsr},~{flags}";
break;
case ZigLLVM_mips:
case ZigLLVM_mipsel:
case ZigLLVM_mips64:
case ZigLLVM_mips64el:
arch_clobbers = "~{$1}";
break;
default:
break;
}
if (arch_clobbers != nullptr) {
if (buf_len(&constraint_buf))
buf_append_char(&constraint_buf, ',');
buf_append_str(&constraint_buf, arch_clobbers);
}
LLVMTypeRef ret_type;
if (instruction->return_count == 0) {
ret_type = LLVMVoidType();
@@ -5088,11 +5184,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutableGen *executable, IrIns
static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutableGen *executable, IrInstGenErrName *instruction) {
assert(g->generate_error_name_table);
if (g->errors_by_index.length == 1) {
LLVMBuildUnreachable(g->builder);
return nullptr;
}
assert(g->errors_by_index.length > 0);
LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
if (ir_want_runtime_safety(g, &instruction->base)) {
@@ -5817,7 +5909,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
if (slice_start_ptr != nullptr) {
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
} else if (want_runtime_safety) {
gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr);
gen_undef_init(g, slice_ptr_type, slice_ptr_type, ptr_field_ptr);
} else {
gen_store_untyped(g, LLVMGetUndef(get_llvm_type(g, slice_ptr_type)), ptr_field_ptr, 0, false);
}
@@ -6878,9 +6970,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ZigValue *val, ConstParent *paren
render_const_val(g, val, "");
render_const_val_global(g, val, "");
return val->llvm_global;
case ConstParentIdStruct:
return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val,
parent->data.p_struct.field_index);
case ConstParentIdStruct: {
ZigValue *struct_val = parent->data.p_struct.struct_val;
size_t src_field_index = parent->data.p_struct.field_index;
size_t gen_field_index = struct_val->type->data.structure.fields[src_field_index]->gen_index;
return gen_const_ptr_struct_recursive(g, struct_val, gen_field_index);
}
case ConstParentIdErrUnionCode:
return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val);
case ConstParentIdErrUnionPayload:
@@ -6934,7 +7029,14 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ZigValue *struct_
LLVMConstNull(get_llvm_type(g, u32)),
LLVMConstInt(get_llvm_type(g, u32), field_index, false),
};
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
// The structure pointed by base_ptr may include trailing padding for
// alignment purposes and have the following LLVM type: <{ %T, [N x i8] }>.
// Add an extra bitcast as we're only interested in the %T part.
assert(handle_is_ptr(g, struct_const_val->type));
LLVMValueRef casted_base_ptr = LLVMConstBitCast(base_ptr,
LLVMPointerType(get_llvm_type(g, struct_const_val->type), 0));
return LLVMConstInBoundsGEP(casted_base_ptr, indices, 2);
}
static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ZigValue *err_union_const_val) {
@@ -7764,7 +7866,7 @@ static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char
}
static void generate_error_name_table(CodeGen *g) {
if (g->err_name_table != nullptr || !g->generate_error_name_table || g->errors_by_index.length == 1) {
if (g->err_name_table != nullptr || !g->generate_error_name_table) {
return;
}
@@ -8485,7 +8587,60 @@ static void define_builtin_types(CodeGen *g) {
add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble);
switch (g->zig_target->arch) {
case ZigLLVM_x86:
case ZigLLVM_x86_64:
if (g->zig_target->abi != ZigLLVM_MSVC)
add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble);
else
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_arm:
case ZigLLVM_armeb:
case ZigLLVM_thumb:
case ZigLLVM_thumbeb:
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_aarch64:
case ZigLLVM_aarch64_be:
if (g->zig_target->os == OsWindows || target_os_is_darwin(g->zig_target->os))
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
else
add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_riscv32:
case ZigLLVM_riscv64:
add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_wasm32:
case ZigLLVM_wasm64:
add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_mips:
case ZigLLVM_mipsel:
// Assume o32 ABI
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_mips64:
case ZigLLVM_mips64el:
add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_ppc:
case ZigLLVM_ppc64:
case ZigLLVM_ppc64le:
add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_avr:
// It's either a float or a double, depending on a toolchain switch
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_msp430:
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
break;
default:
zig_panic("TODO implement mapping for c_longdouble");
}
{
ZigType *entry = new_type_table_entry(ZigTypeIdVoid);

View File

@@ -14123,6 +14123,18 @@ static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, AstNode *source_node,
}
}
static bool can_fold_enum_type(ZigType *ty) {
assert(ty->id == ZigTypeIdEnum);
// We can fold the enum type (and avoid any check, be it at runtime or at
// compile time) iff it has only a single element and its tag type is
// zero-sized.
ZigType *tag_int_type = ty->data.enumeration.tag_int_type;
return ty->data.enumeration.layout == ContainerLayoutAuto &&
ty->data.enumeration.src_field_count == 1 &&
!ty->data.enumeration.non_exhaustive &&
(tag_int_type->id == ZigTypeIdInt && tag_int_type->data.integral.bit_count == 0);
}
static IrInstGen *ir_analyze_enum_to_int(IrAnalyze *ira, IrInst *source_instr, IrInstGen *target) {
Error err;
@@ -14151,10 +14163,7 @@ static IrInstGen *ir_analyze_enum_to_int(IrAnalyze *ira, IrInst *source_instr, I
assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt);
// If there is only one possible tag, then we know at comptime what it is.
if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
enum_type->data.enumeration.src_field_count == 1 &&
!enum_type->data.enumeration.non_exhaustive)
{
if (can_fold_enum_type(enum_type)) {
IrInstGen *result = ir_const(ira, source_instr, tag_type);
init_const_bigint(result->value, tag_type,
&enum_type->data.enumeration.fields[0].value);
@@ -14192,10 +14201,7 @@ static IrInstGen *ir_analyze_union_to_tag(IrAnalyze *ira, IrInst* source_instr,
}
// If there is only 1 possible tag, then we know at comptime what it is.
if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
wanted_type->data.enumeration.src_field_count == 1 &&
!wanted_type->data.enumeration.non_exhaustive)
{
if (can_fold_enum_type(wanted_type)) {
IrInstGen *result = ir_const(ira, source_instr, wanted_type);
result->value->special = ConstValSpecialStatic;
result->value->type = wanted_type;
@@ -17778,7 +17784,7 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
return false;
switch (lhs_type->data.pointer.ptr_len) {
case PtrLenSingle:
return lhs_type->data.pointer.child_type->id == ZigTypeIdArray;
return false;
case PtrLenUnknown:
case PtrLenC:
return true;
@@ -23837,7 +23843,8 @@ static IrInstGen *ir_analyze_instruction_switch_target(IrAnalyze *ira,
bigint_init_bigint(&result->value->data.x_enum_tag, &pointee_val->data.x_union.tag);
return result;
}
if (tag_type->data.enumeration.src_field_count == 1 && !tag_type->data.enumeration.non_exhaustive) {
if (can_fold_enum_type(tag_type)) {
IrInstGen *result = ir_const(ira, &switch_target_instruction->base.base, tag_type);
TypeEnumField *only_field = &tag_type->data.enumeration.fields[0];
bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);
@@ -23852,7 +23859,8 @@ static IrInstGen *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case ZigTypeIdEnum: {
if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_inst_gen;
if (target_type->data.enumeration.src_field_count == 1 && !target_type->data.enumeration.non_exhaustive) {
if (can_fold_enum_type(target_type)) {
TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
IrInstGen *result = ir_const(ira, &switch_target_instruction->base.base, target_type);
bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);
@@ -24587,7 +24595,9 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_inst_gen;
if (target->value->type->id == ZigTypeIdEnumLiteral) {
ZigType *target_type = target->value->type;
if (target_type->id == ZigTypeIdEnumLiteral) {
IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
Buf *field_name = target->value->data.x_enum_literal;
ZigValue *array_val = create_const_str_lit(ira->codegen, field_name)->data.x_ptr.data.ref.pointee;
@@ -24595,21 +24605,21 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
return result;
}
if (target->value->type->id == ZigTypeIdUnion) {
if (target_type->id == ZigTypeIdUnion) {
target = ir_analyze_union_tag(ira, &instruction->base.base, target, instruction->base.is_gen);
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_inst_gen;
target_type = target->value->type;
}
if (target->value->type->id != ZigTypeIdEnum) {
if (target_type->id != ZigTypeIdEnum) {
ir_add_error(ira, &target->base,
buf_sprintf("expected enum tag, found '%s'", buf_ptr(&target->value->type->name)));
buf_sprintf("expected enum tag, found '%s'", buf_ptr(&target_type->name)));
return ira->codegen->invalid_inst_gen;
}
if (target->value->type->data.enumeration.src_field_count == 1 &&
!target->value->type->data.enumeration.non_exhaustive) {
TypeEnumField *only_field = &target->value->type->data.enumeration.fields[0];
if (can_fold_enum_type(target_type)) {
TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
ZigValue *array_val = create_const_str_lit(ira->codegen, only_field->name)->data.x_ptr.data.ref.pointee;
IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(only_field->name), true);
@@ -24617,9 +24627,9 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
}
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_inst_gen;
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
TypeEnumField *field = find_enum_field_by_tag(target_type, &target->value->data.x_bigint);
if (field == nullptr) {
Buf *int_buf = buf_alloc();
bigint_append_buf(int_buf, &target->value->data.x_bigint, 10);
@@ -24890,6 +24900,8 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa
if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown)))
return err;
resolve_container_usingnamespace_decls(ira->codegen, decls_scope);
// The unresolved declarations are collected in a separate queue to avoid
// modifying decl_table while iterating over it
ZigList<Tld*> resolve_decl_queue{};
@@ -25060,12 +25072,12 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa
0, 0, 0, false);
fn_decl_fields[5]->type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
if (fn_node->is_extern && fn_node->lib_name != nullptr && buf_len(fn_node->lib_name) > 0) {
fn_decl_fields[5]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>();
ZigValue *slice_val = ira->codegen->pass1_arena->create<ZigValue>();
ZigValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, fn_decl_fields[5]->data.x_optional, lib_name, 0,
buf_len(fn_node->lib_name), true);
init_const_slice(ira->codegen, slice_val, lib_name, 0, buf_len(fn_node->lib_name), true);
set_optional_payload(fn_decl_fields[5], slice_val);
} else {
fn_decl_fields[5]->data.x_optional = nullptr;
set_optional_payload(fn_decl_fields[5], nullptr);
}
// return_type: type
ensure_field_index(fn_decl_val->type, "return_type", 6);
@@ -25345,8 +25357,12 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
fields[1]->data.x_type = type_entry->data.array.child_type;
// sentinel: anytype
fields[2]->special = ConstValSpecialStatic;
fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type);
fields[2]->data.x_optional = type_entry->data.array.sentinel;
if (type_entry->data.array.child_type != nullptr) {
fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type);
set_optional_payload(fields[2], type_entry->data.array.sentinel);
} else {
fields[2]->type = ira->codegen->builtin_types.entry_null;
}
break;
}
case ZigTypeIdVector: {
@@ -26022,6 +26038,32 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
return ira->codegen->builtin_types.entry_bool;
case ZigTypeIdUnreachable:
return ira->codegen->builtin_types.entry_unreachable;
case ZigTypeIdComptimeFloat:
return ira->codegen->builtin_types.entry_num_lit_float;
case ZigTypeIdComptimeInt:
return ira->codegen->builtin_types.entry_num_lit_int;
case ZigTypeIdUndefined:
return ira->codegen->builtin_types.entry_undef;
case ZigTypeIdNull:
return ira->codegen->builtin_types.entry_null;
case ZigTypeIdEnumLiteral:
return ira->codegen->builtin_types.entry_enum_literal;
default:
if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_instr->source_node, payload, UndefBad)))
return ira->codegen->invalid_inst_gen->value->type;
}
switch (tagTypeId) {
case ZigTypeIdInvalid:
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
case ZigTypeIdBool:
case ZigTypeIdUnreachable:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdEnumLiteral:
zig_unreachable();
case ZigTypeIdInt: {
assert(payload->special == ConstValSpecialStatic);
assert(payload->type == ir_type_info_get_type(ira, "Int", nullptr));
@@ -26131,14 +26173,6 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
return ira->codegen->invalid_inst_gen->value->type;
return get_array_type(ira->codegen, elem_type, bigint_as_u64(bi), sentinel);
}
case ZigTypeIdComptimeFloat:
return ira->codegen->builtin_types.entry_num_lit_float;
case ZigTypeIdComptimeInt:
return ira->codegen->builtin_types.entry_num_lit_int;
case ZigTypeIdUndefined:
return ira->codegen->builtin_types.entry_undef;
case ZigTypeIdNull:
return ira->codegen->builtin_types.entry_null;
case ZigTypeIdOptional: {
assert(payload->special == ConstValSpecialStatic);
assert(payload->type == ir_type_info_get_type(ira, "Optional", nullptr));
@@ -26204,8 +26238,6 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
return get_any_frame_type(ira->codegen, child_type);
}
case ZigTypeIdEnumLiteral:
return ira->codegen->builtin_types.entry_enum_literal;
case ZigTypeIdFnFrame: {
assert(payload->special == ConstValSpecialStatic);
assert(payload->type == ir_type_info_get_type(ira, "Frame", nullptr));
@@ -26665,7 +26697,7 @@ static IrInstGen *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira,
IrInstSrcSetEvalBranchQuota *instruction)
{
uint64_t new_quota;
if (!ir_resolve_usize(ira, instruction->new_quota->child, &new_quota))
if (!ir_resolve_unsigned(ira, instruction->new_quota->child, ira->codegen->builtin_types.entry_u32, &new_quota))
return ira->codegen->invalid_inst_gen;
if (new_quota > *ira->new_irb.exec->backward_branch_quota) {
@@ -32970,8 +33002,13 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
break;
}
if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
return err;
// Avoid resolving the type if the total length is zero.
// Matches the logic in get_array_type and in the lazy alignment
// resolution routine.
if (lazy_array_type->length + (lazy_array_type->sentinel != nullptr) != 0) {
if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
return err;
}
ZigValue *sentinel_val = nullptr;
if (lazy_array_type->sentinel != nullptr) {

View File

@@ -682,19 +682,6 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) {
}
}
#if defined(ZIG_OS_WINDOWS)
static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) {
mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
mtime->nsec = 0;
}
static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) {
FILETIME result;
result.dwHighDateTime = mtime.sec >> 32;
result.dwLowDateTime = mtime.sec;
return result;
}
#endif
Error os_copy_file(Buf *src_path, Buf *dest_path) {
#if defined(ZIG_OS_WINDOWS)
PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path));

View File

@@ -10,6 +10,28 @@
#include <string.h>
#include <math.h>
// Every OSes seem to define endianness macros in different files.
#if defined(__APPLE__)
#include <machine/endian.h>
#define ZIG_BIG_ENDIAN BIG_ENDIAN
#define ZIG_LITTLE_ENDIAN LITTLE_ENDIAN
#define ZIG_BYTE_ORDER BYTE_ORDER
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/endian.h>
#define ZIG_BIG_ENDIAN _BIG_ENDIAN
#define ZIG_LITTLE_ENDIAN _LITTLE_ENDIAN
#define ZIG_BYTE_ORDER _BYTE_ORDER
#elif defined(_WIN32) || defined(_WIN64)
// Assume that Windows installations are always little endian.
#define ZIG_LITTLE_ENDIAN 1
#define ZIG_BYTE_ORDER ZIG_LITTLE_ENDIAN
#else // Linux
#include <endian.h>
#define ZIG_BIG_ENDIAN __BIG_ENDIAN
#define ZIG_LITTLE_ENDIAN __LITTLE_ENDIAN
#define ZIG_BYTE_ORDER __BYTE_ORDER
#endif
#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf))
#define shlim(f, lim) __shlim((f), (lim))
#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : __shgetc(f))
@@ -47,8 +69,7 @@
#define DECIMAL_DIG 36
#if __BYTE_ORDER == __LITTLE_ENDIAN
#if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN
union ldshape {
float128_t f;
struct {
@@ -62,7 +83,7 @@ union ldshape {
uint64_t hi;
} i2;
};
#elif __BYTE_ORDER == __BIG_ENDIAN
#elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN
union ldshape {
float128_t f;
struct {
@@ -76,6 +97,7 @@ union ldshape {
uint64_t lo;
} i2;
};
#else
#error Unsupported endian
#endif

View File

@@ -1146,8 +1146,6 @@ bool target_is_libc_lib_name(const ZigTarget *target, const char *name) {
return true;
if (equal(name, "dl"))
return true;
if (equal(name, "util"))
return true;
}
if (target_os_is_darwin(target->os) && equal(name, "System"))

View File

@@ -99,6 +99,7 @@ pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
.i386 => return "i386",
.x86_64 => return "x86_64",
.riscv64 => return "riscv64",
.wasm32, .wasm64 => return "wasm",
else => unreachable,
}
}
@@ -320,8 +321,6 @@ pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
return true;
if (eqlIgnoreCase(ignore_case, name, "dl"))
return true;
if (eqlIgnoreCase(ignore_case, name, "util"))
return true;
}
if (target.os.tag.isDarwin() and eqlIgnoreCase(ignore_case, name, "System"))

View File

@@ -513,6 +513,7 @@ pub const TestContext = struct {
.keep_source_files_loaded = true,
.object_format = ofmt,
.is_native_os = case.target.isNativeOs(),
.is_native_abi = case.target.isNativeAbi(),
});
defer comp.destroy();

View File

@@ -38,7 +38,6 @@ pub const Type = extern union {
.c_ulong,
.c_longlong,
.c_ulonglong,
.c_longdouble,
.int_signed,
.int_unsigned,
=> return .Int,
@@ -47,6 +46,7 @@ pub const Type = extern union {
.f32,
.f64,
.f128,
.c_longdouble,
=> return .Float,
.c_void => return .Opaque,

View File

@@ -221,6 +221,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
PMBuilder->DisableUnrollLoops = is_debug;
PMBuilder->SLPVectorize = !is_debug;
PMBuilder->LoopVectorize = !is_debug;
PMBuilder->LoopsInterleaved = !PMBuilder->DisableUnrollLoops;
PMBuilder->RerollLoops = !is_debug;
// Leaving NewGVN as default (off) because when on it caused issue #673
//PMBuilder->NewGVN = !is_debug;
@@ -1047,35 +1048,24 @@ bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size
return false;
}
int ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early) {
std::vector<const char *> args(argv, argv + argc);
return lld::coff::link(args, can_exit_early, llvm::outs(), llvm::errs());
}
bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
void (*append_diagnostic)(void *, const char *, size_t),
void *context_stdout, void *context_stderr)
{
ArrayRef<const char *> array_ref_args(args, arg_count);
int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early) {
std::vector<const char *> args(argv, argv + argc);
return lld::elf::link(args, can_exit_early, llvm::outs(), llvm::errs());
}
MyOStream diag_stdout(append_diagnostic, context_stdout);
MyOStream diag_stderr(append_diagnostic, context_stderr);
int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early) {
std::vector<const char *> args(argv, argv + argc);
return lld::mach_o::link(args, can_exit_early, llvm::outs(), llvm::errs());
}
switch (oformat) {
case ZigLLVM_UnknownObjectFormat:
case ZigLLVM_XCOFF:
assert(false); // unreachable
case ZigLLVM_COFF:
return lld::coff::link(array_ref_args, false, diag_stdout, diag_stderr);
case ZigLLVM_ELF:
return lld::elf::link(array_ref_args, false, diag_stdout, diag_stderr);
case ZigLLVM_MachO:
return lld::mach_o::link(array_ref_args, false, diag_stdout, diag_stderr);
case ZigLLVM_Wasm:
return lld::wasm::link(array_ref_args, false, diag_stdout, diag_stderr);
}
assert(false); // unreachable
abort();
int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early) {
std::vector<const char *> args(argv, argv + argc);
return lld::wasm::link(args, can_exit_early, llvm::outs(), llvm::errs());
}
static AtomicRMWInst::BinOp toLLVMRMWBinOp(enum ZigLLVM_AtomicRMWBinOp BinOp) {

View File

@@ -505,9 +505,10 @@ ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor
ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os);
ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType abi);
ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
void (*append_diagnostic)(void *, const char *, size_t),
void *context_stdout, void *context_stderr);
ZIG_EXTERN_C int ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early);
ZIG_EXTERN_C int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early);
ZIG_EXTERN_C int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early);
ZIG_EXTERN_C int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early);
ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
enum ZigLLVM_OSType os_type);

View File

@@ -92,13 +92,13 @@ fn exec(cwd: []const u8, expect_0: bool, argv: []const []const u8) !ChildProcess
fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void {
_ = try exec(dir_path, true, &[_][]const u8{ zig_exe, "init-lib" });
const test_result = try exec(dir_path, true, &[_][]const u8{ zig_exe, "build", "test" });
testing.expect(std.mem.endsWith(u8, test_result.stderr, "All 1 tests passed.\n"));
testing.expectStringEndsWith(test_result.stderr, "All 1 tests passed.\n");
}
fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
_ = try exec(dir_path, true, &[_][]const u8{ zig_exe, "init-exe" });
const run_result = try exec(dir_path, true, &[_][]const u8{ zig_exe, "build", "run" });
testing.expect(std.mem.eql(u8, run_result.stderr, "info: All your codebase are belong to us.\n"));
testing.expectEqualStrings("info: All your codebase are belong to us.\n", run_result.stderr);
}
fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {

View File

@@ -2,6 +2,25 @@ const tests = @import("tests.zig");
const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add("pointer arithmetic on pointer-to-array",
\\export fn foo() void {
\\ var x: [10]u8 = undefined;
\\ var y = &x;
\\ var z = y + 1;
\\}
, &[_][]const u8{
"tmp.zig:4:17: error: integer value 1 cannot be coerced to type '*[10]u8'",
});
cases.add("@Type() union payload is undefined",
\\const Foo = @Type(@import("std").builtin.TypeInfo{
\\ .Struct = undefined,
\\});
\\comptime { _ = Foo; }
, &[_][]const u8{
"tmp.zig:1:50: error: use of undefined value here causes undefined behavior",
});
cases.add("union with too small explicit signed tag type",
\\const U = union(enum(i2)) {
\\ A: u8,

View File

@@ -1,6 +1,85 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompareOutputContext) void {
{
const check_panic_msg =
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ if (std.mem.eql(u8, message, "reached unreachable code")) {
\\ std.process.exit(126); // good
\\ }
\\ std.process.exit(0); // test failed
\\}
;
cases.addRuntimeSafety("switch on corrupted enum value",
\\const std = @import("std");
++ check_panic_msg ++
\\const E = enum(u32) {
\\ X = 1,
\\};
\\pub fn main() void {
\\ var e: E = undefined;
\\ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
\\ switch (e) {
\\ .X => @breakpoint(),
\\ }
\\}
);
cases.addRuntimeSafety("switch on corrupted union value",
\\const std = @import("std");
++ check_panic_msg ++
\\const U = union(enum(u32)) {
\\ X: u8,
\\};
\\pub fn main() void {
\\ var u: U = undefined;
\\ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
\\ switch (u) {
\\ .X => @breakpoint(),
\\ }
\\}
);
}
{
const check_panic_msg =
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ if (std.mem.eql(u8, message, "invalid enum value")) {
\\ std.process.exit(126); // good
\\ }
\\ std.process.exit(0); // test failed
\\}
;
cases.addRuntimeSafety("@tagName on corrupted enum value",
\\const std = @import("std");
++ check_panic_msg ++
\\const E = enum(u32) {
\\ X = 1,
\\};
\\pub fn main() void {
\\ var e: E = undefined;
\\ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
\\ var n = @tagName(e);
\\}
);
cases.addRuntimeSafety("@tagName on corrupted union value",
\\const std = @import("std");
++ check_panic_msg ++
\\const U = union(enum(u32)) {
\\ X: u8,
\\};
\\pub fn main() void {
\\ var u: U = undefined;
\\ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
\\ var t: @TagType(U) = u;
\\ var n = @tagName(t);
\\}
);
}
{
const check_panic_msg =
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
@@ -89,7 +168,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const std = @import("std");
\\const V = @import("std").meta.Vector;
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
\\ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
\\ std.process.exit(126); // good
\\ }
\\ std.process.exit(0); // test failed
@@ -100,6 +179,21 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\}
);
cases.addRuntimeSafety("signed-unsigned vector cast",
\\const std = @import("std");
\\const V = @import("std").meta.Vector;
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
\\ std.process.exit(126); // good
\\ }
\\ std.process.exit(0); // test failed
\\}
\\pub fn main() void {
\\ var x = @splat(4, @as(i32, -2147483647));
\\ var y = @intCast(V(4, u32), x);
\\}
);
cases.addRuntimeSafety("shift left by huge amount",
\\const std = @import("std");
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {

View File

@@ -13,6 +13,7 @@ pub const RunTranslatedCContext = struct {
step: *build.Step,
test_index: usize,
test_filter: ?[]const u8,
target: std.zig.CrossTarget,
const TestCase = struct {
name: []const u8,
@@ -93,6 +94,7 @@ pub const RunTranslatedCContext = struct {
});
translate_c.step.name = b.fmt("{} translate-c", .{annotated_case_name});
const exe = translate_c.addExecutable();
exe.setTarget(self.target);
exe.step.name = b.fmt("{} build-exe", .{annotated_case_name});
exe.linkLibC();
const run = exe.run();

View File

@@ -50,12 +50,17 @@ comptime {
_ = @import("behavior/bugs/4769_b.zig");
_ = @import("behavior/bugs/4769_c.zig");
_ = @import("behavior/bugs/4954.zig");
_ = @import("behavior/bugs/5398.zig");
_ = @import("behavior/bugs/5413.zig");
_ = @import("behavior/bugs/5474.zig");
_ = @import("behavior/bugs/5487.zig");
_ = @import("behavior/bugs/6456.zig");
_ = @import("behavior/bugs/6781.zig");
_ = @import("behavior/bugs/6850.zig");
_ = @import("behavior/bugs/7027.zig");
_ = @import("behavior/bugs/7047.zig");
_ = @import("behavior/bugs/7003.zig");
_ = @import("behavior/bugs/7250.zig");
_ = @import("behavior/bugs/394.zig");
_ = @import("behavior/bugs/421.zig");
_ = @import("behavior/bugs/529.zig");

View File

@@ -413,3 +413,21 @@ test "sentinel element count towards the ABI size calculation" {
S.doTheTest();
comptime S.doTheTest();
}
test "zero-sized array with recursive type definition" {
const U = struct {
fn foo(comptime T: type, comptime n: usize) type {
return struct {
s: [n]T,
x: usize = n,
};
}
};
const S = struct {
list: U.foo(@This(), 0),
};
var t: S = .{ .list = .{ .s = undefined } };
expectEqual(@as(usize, 0), t.list.x);
}

View File

@@ -1559,3 +1559,52 @@ test "avoid forcing frame alignment resolution implicit cast to *c_void" {
resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x));
expect(nosuspend await frame);
}
test "@asyncCall with pass-by-value arguments" {
const F0: u64 = 0xbeefbeefbeefbeef;
const F1: u64 = 0xf00df00df00df00d;
const F2: u64 = 0xcafecafecafecafe;
const S = struct {
pub const ST = struct { f0: usize, f1: usize };
pub const AT = [5]u8;
pub fn f(_fill0: u64, s: ST, _fill1: u64, a: AT, _fill2: u64) callconv(.Async) void {
// Check that the array and struct arguments passed by value don't
// end up overflowing the adjacent fields in the frame structure.
expectEqual(F0, _fill0);
expectEqual(F1, _fill1);
expectEqual(F2, _fill2);
}
};
var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined;
// The function pointer must not be comptime-known.
var t = S.f;
var frame_ptr = @asyncCall(&buffer, {}, t, .{
F0,
.{ .f0 = 1, .f1 = 2 },
F1,
[_]u8{ 1, 2, 3, 4, 5 },
F2,
});
}
test "@asyncCall with arguments having non-standard alignment" {
const F0: u64 = 0xbeefbeef;
const F1: u64 = 0xf00df00df00df00d;
const S = struct {
pub fn f(_fill0: u32, s: struct { x: u64 align(16) }, _fill1: u64) callconv(.Async) void {
// The compiler inserts extra alignment for s, check that the
// generated code picks the right slot for fill1.
expectEqual(F0, _fill0);
expectEqual(F1, _fill1);
}
};
var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined;
// The function pointer must not be comptime-known.
var t = S.f;
var frame_ptr = @asyncCall(&buffer, {}, t, .{ F0, undefined, F1 });
}

View File

@@ -0,0 +1,31 @@
const std = @import("std");
const testing = std.testing;
pub const Mesh = struct {
id: u32,
};
pub const Material = struct {
transparent: bool = true,
emits_shadows: bool = true,
render_color: bool = true,
};
pub const Renderable = struct {
material: Material,
// The compiler inserts some padding here to ensure Mesh is correctly aligned.
mesh: Mesh,
};
var renderable: Renderable = undefined;
test "assignment of field with padding" {
renderable = Renderable{
.mesh = Mesh{ .id = 0 },
.material = Material{
.transparent = false,
.emits_shadows = false,
},
};
testing.expectEqual(false, renderable.material.transparent);
testing.expectEqual(false, renderable.material.emits_shadows);
testing.expectEqual(true, renderable.material.render_color);
}

View File

@@ -0,0 +1,8 @@
test "@Type should resolve its children types" {
const sparse = enum(u2) { a, b, c };
const dense = enum(u2) { a, b, c, d };
comptime var sparse_info = @typeInfo(anyerror!sparse);
sparse_info.ErrorUnion.payload = dense;
const B = @Type(sparse_info);
}

View File

@@ -0,0 +1,17 @@
const Foobar = struct {
myTypes: [128]type,
str: [1024]u8,
fn foo() @This() {
comptime var foobar: Foobar = undefined;
foobar.str = [_]u8{'a'} ** 1024;
return foobar;
}
};
fn foo(arg: anytype) void {}
test "" {
comptime var foobar = Foobar.foo();
foo(foobar.str[0..10]);
}

View File

@@ -0,0 +1,22 @@
const std = @import("std");
const U = union(enum) {
T: type,
N: void,
};
fn S(comptime query: U) type {
return struct {
fn tag() type {
return query.T;
}
};
}
test "compiler doesn't consider equal unions with different 'type' payload" {
const s1 = S(U{ .T = u32 }).tag();
std.testing.expectEqual(u32, s1);
const s2 = S(U{ .T = u64 }).tag();
std.testing.expectEqual(u64, s2);
}

View File

@@ -0,0 +1,15 @@
const nrfx_uart_t = extern struct {
p_reg: [*c]u32,
drv_inst_idx: u8,
};
pub fn nrfx_uart_rx(p_instance: [*c]const nrfx_uart_t) void {}
threadlocal var g_uart0 = nrfx_uart_t{
.p_reg = 0,
.drv_inst_idx = 0,
};
test "reference a global threadlocal variable" {
_ = nrfx_uart_rx(&g_uart0);
}

View File

@@ -908,3 +908,9 @@ test "cast from ?[*]T to ??[*]T" {
const a: ??[*]u8 = @as(?[*]u8, null);
expect(a != null and a.? == null);
}
test "cast between *[N]void and []void" {
var a: [4]void = undefined;
var b: []void = &a;
expect(b.len == 4);
}

View File

@@ -884,3 +884,28 @@ test "type coercion of anon struct literal to struct" {
S.doTheTest();
comptime S.doTheTest();
}
test "packed struct with undefined initializers" {
const S = struct {
const P = packed struct {
a: u3,
_a: u3 = undefined,
b: u3,
_b: u3 = undefined,
c: u3,
_c: u3 = undefined,
};
fn doTheTest() void {
var p: P = undefined;
p = P{ .a = 2, .b = 4, .c = 6 };
// Make sure the compiler doesn't touch the unprefixed fields.
expectEqual(@as(u3, 2), p.a);
expectEqual(@as(u3, 4), p.b);
expectEqual(@as(u3, 6), p.c);
}
};
S.doTheTest();
comptime S.doTheTest();
}

View File

@@ -82,9 +82,6 @@ fn testNullTerminatedPtr() void {
expect(ptr_info.Pointer.sentinel.? == 0);
expect(@typeInfo([:0]u8).Pointer.sentinel != null);
expect(@typeInfo([10:0]u8).Array.sentinel != null);
expect(@typeInfo([10:0]u8).Array.len == 10);
expect(@sizeOf([10:0]u8) == 11);
}
test "type info: C pointer type info" {
@@ -123,10 +120,21 @@ test "type info: array type info" {
}
fn testArray() void {
const arr_info = @typeInfo([42]bool);
expect(arr_info == .Array);
expect(arr_info.Array.len == 42);
expect(arr_info.Array.child == bool);
{
const info = @typeInfo([42]u8);
expect(info == .Array);
expect(info.Array.len == 42);
expect(info.Array.child == u8);
expect(info.Array.sentinel == null);
}
{
const info = @typeInfo([10:0]u8);
expect(info.Array.len == 10);
expect(info.Array.child == u8);
expect(info.Array.sentinel.? == @as(u8, 0));
expect(@sizeOf([10:0]u8) == info.Array.len + 1);
}
}
test "type info: optional type info" {
@@ -460,3 +468,17 @@ test "StructField.is_comptime" {
expect(!info.fields[0].is_comptime);
expect(info.fields[1].is_comptime);
}
test "typeInfo resolves usingnamespace declarations" {
const A = struct {
pub const f1 = 42;
};
const B = struct {
const f0 = 42;
usingnamespace A;
};
expect(@typeInfo(B).Struct.decls.len == 2);
//a
}

View File

@@ -15,10 +15,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
cases.addBuildFile("test/standalone/static_c_lib/build.zig");
cases.addBuildFile("test/standalone/issue_339/build.zig");
cases.addBuildFile("test/standalone/issue_794/build.zig");
cases.addBuildFile("test/standalone/issue_5825/build.zig");
cases.addBuildFile("test/standalone/pkg_import/build.zig");
cases.addBuildFile("test/standalone/use_alias/build.zig");
cases.addBuildFile("test/standalone/brace_expansion/build.zig");
cases.addBuildFile("test/standalone/empty_env/build.zig");
cases.addBuildFile("test/standalone/issue_7030/build.zig");
if (std.Target.current.os.tag != .wasi) {
cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
}

View File

@@ -3,37 +3,40 @@ const io = std.io;
const process = std.process;
const fs = std.fs;
const mem = std.mem;
const warn = std.debug.warn;
const allocator = std.testing.allocator;
const warn = std.log.warn;
pub fn main() !void {
var args_it = process.args();
const exe = try unwrapArg(args_it.next(allocator).?);
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_instance.deinit();
const arena = &arena_instance.allocator;
const args = try process.argsAlloc(arena);
const exe = args[0];
var catted_anything = false;
const stdout_file = io.getStdOut();
const cwd = fs.cwd();
while (args_it.next(allocator)) |arg_or_err| {
const arg = try unwrapArg(arg_or_err);
for (args[1..]) |arg| {
if (mem.eql(u8, arg, "-")) {
catted_anything = true;
try cat_file(stdout_file, io.getStdIn());
} else if (arg[0] == '-') {
try stdout_file.writeFileAll(io.getStdIn(), .{});
} else if (mem.startsWith(u8, arg, "-")) {
return usage(exe);
} else {
const file = cwd.openFile(arg, .{}) catch |err| {
warn("Unable to open file: {}\n", .{@errorName(err)});
warn("Unable to open file: {s}\n", .{@errorName(err)});
return err;
};
defer file.close();
catted_anything = true;
try cat_file(stdout_file, file);
try stdout_file.writeFileAll(file, .{});
}
}
if (!catted_anything) {
try cat_file(stdout_file, io.getStdIn());
try stdout_file.writeFileAll(io.getStdIn(), .{});
}
}
@@ -41,31 +44,3 @@ fn usage(exe: []const u8) !void {
warn("Usage: {} [FILE]...\n", .{exe});
return error.Invalid;
}
// TODO use copy_file_range
fn cat_file(stdout: fs.File, file: fs.File) !void {
var buf: [1024 * 4]u8 = undefined;
while (true) {
const bytes_read = file.read(buf[0..]) catch |err| {
warn("Unable to read from stream: {}\n", .{@errorName(err)});
return err;
};
if (bytes_read == 0) {
break;
}
stdout.writeAll(buf[0..bytes_read]) catch |err| {
warn("Unable to write to stdout: {}\n", .{@errorName(err)});
return err;
};
}
}
fn unwrapArg(arg: anyerror![]u8) ![]u8 {
return arg catch |err| {
warn("Unable to parse command line: {}\n", .{err});
return err;
};
}

View File

@@ -0,0 +1,24 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
const target = .{
.cpu_arch = .x86_64,
.os_tag = .windows,
.abi = .msvc,
};
const mode = b.standardReleaseOptions();
const obj = b.addObject("issue_5825", "main.zig");
obj.setTarget(target);
obj.setBuildMode(mode);
const exe = b.addExecutable("issue_5825", null);
exe.subsystem = .Console;
exe.linkSystemLibrary("kernel32");
exe.linkSystemLibrary("ntdll");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.addObject(obj);
const test_step = b.step("test", "Test the program");
test_step.dependOn(&exe.step);
}

View File

@@ -0,0 +1,5 @@
const std = @import("std");
pub fn main() anyerror!void {
std.log.info("All your codebase are belong to us.", .{});
}

View File

@@ -0,0 +1,14 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
const exe = b.addExecutable("issue_7030", "main.zig");
exe.setTarget(.{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
});
exe.install();
b.default_step.dependOn(&exe.step);
const test_step = b.step("test", "Test the program");
test_step.dependOn(&exe.step);
}

Some files were not shown because too many files have changed in this diff Show More