Commit graph

1278 commits

Author SHA1 Message Date
mlugg
37a9a4e0f1
compiler: refactor Zcu.File and path representation
This commit makes some big changes to how we track state for Zig source
files. In particular, it changes:

* How `File` tracks its path on-disk
* How AstGen discovers files
* How file-level errors are tracked
* How `builtin.zig` files and modules are created

The original motivation here was to address incremental compilation bugs
with the handling of files, such as #22696. To fix this, a few changes
are necessary.

Just like declarations may become unreferenced on an incremental update,
meaning we suppress analysis errors associated with them, it is also
possible for all imports of a file to be removed on an incremental
update, in which case file-level errors for that file should be
suppressed. As such, after AstGen, the compiler must traverse files
(starting from analysis roots) and discover the set of "live files" for
this update.

Additionally, the compiler's previous handling of retryable file errors
was not very good; the source location the error was reported as was
based only on the first discovered import of that file. This source
location also disappeared on future incremental updates. So, as a part
of the file traversal above, we also need to figure out the source
locations of imports which errors should be reported against.

Another observation I made is that the "file exists in multiple modules"
error was not implemented in a particularly good way (I get to say that
because I wrote it!). It was subject to races, where the order in which
different imports of a file were discovered affects both how errors are
printed, and which module the file is arbitrarily assigned, with the
latter in turn affecting which other files are considered for import.
The thing I realised here is that while the AstGen worker pool is
running, we cannot know for sure which module(s) a file is in; we could
always discover an import later which changes the answer.

So, here's how the AstGen workers have changed. We initially ensure that
`zcu.import_table` contains the root files for all modules in this Zcu,
even if we don't know any imports for them yet. Then, the AstGen
workers do not need to be aware of modules. Instead, they simply ignore
module imports, and only spin off more workers when they see a by-path
import.

During AstGen, we can't use module-root-relative paths, since we don't
know which modules files are in; but we don't want to unnecessarily use
absolute files either, because those are non-portable and can make
`error.NameTooLong` more likely. As such, I have introduced a new
abstraction, `Compilation.Path`. This type is a way of representing a
filesystem path which has a *canonical form*. The path is represented
relative to one of a few special directories: the lib directory, the
global cache directory, or the local cache directory. As a fallback, we
use absolute (or cwd-relative on WASI) paths. This is kind of similar to
`std.Build.Cache.Path` with a pre-defined list of possible
`std.Build.Cache.Directory`, but has stricter canonicalization rules
based on path resolution to make sure deduplicating files works
properly. A `Compilation.Path` can be trivially converted to a
`std.Build.Cache.Path` from a `Compilation`, but is smaller, has a
canonical form, and has a digest which will be consistent across
different compiler processes with the same lib and cache directories
(important when we serialize incremental compilation state in the
future). `Zcu.File` and `Zcu.EmbedFile` both contain a
`Compilation.Path`, which is used to access the file on-disk;
module-relative sub paths are used quite rarely (`EmbedFile` doesn't
even have one now for simplicity).

After the AstGen workers all complete, we know that any file which might
be imported is definitely in `import_table` and up-to-date. So, we
perform a single-threaded graph traversal; similar to what
`resolveReferences` plays for `AnalUnit`s, but for files instead. We
figure out which files are alive, and which module each file is in. If a
file turns out to be in multiple modules, we set a field on `Zcu` to
indicate this error. If a file is in a different module to a prior
update, we set a flag instructing `updateZirRefs` to invalidate all
dependencies on the file. This traversal also discovers "import errors";
these are errors associated with a specific `@import`. With Zig's
current design, there is only one possible error here: "import outside
of module root". This must be identified during this traversal instead
of during AstGen, because it depends on which module the file is in. I
tried also representing "module not found" errors in this same way, but
it turns out to be much more useful to report those in Sema, because of
use cases like optional dependencies where a module import is behind a
comptime-known build option.

For simplicity, `failed_files` now just maps to `?[]u8`, since the
source location is always the whole file. In fact, this allows removing
`LazySrcLoc.Offset.entire_file` completely, slightly simplifying some
error reporting logic. File-level errors are now directly built in the
`std.zig.ErrorBundle.Wip`. If the payload is not `null`, it is the
message for a retryable error (i.e. an error loading the source file),
and will be reported with a "file imported here" note pointing to the
import site discovered during the single-threaded file traversal.

The last piece of fallout here is how `Builtin` works. Rather than
constructing "builtin" modules when creating `Package.Module`s, they are
now constructed on-the-fly by `Zcu`. The map `Zcu.builtin_modules` maps
from digests to `*Package.Module`s. These digests are abstract hashes of
the `Builtin` value; i.e. all of the options which are placed into
"builtin.zig". During the file traversal, we populate `builtin_modules`
as needed, so that when we see this imports in Sema, we just grab the
relevant entry from this map. This eliminates a bunch of awkward state
tracking during construction of the module graph. It's also now clearer
exactly what options the builtin module has, since previously it
inherited some options arbitrarily from the first-created module with
that "builtin" module!

The user-visible effects of this commit are:
* retryable file errors are now consistently reported against the whole
  file, with a note pointing to a live import of that file
* some theoretical bugs where imports are wrongly considered distinct
  (when the import path moves out of the cwd and then back in) are fixed
* some consistency issues with how file-level errors are reported are
  fixed; these errors will now always be printed in the same order
  regardless of how the AstGen pass assigns file indices
* incremental updates do not print retryable file errors differently
  between updates or depending on file structure/contents
* incremental updates support files changing modules
* incremental updates support files becoming unreferenced

Resolves: #22696
2025-05-18 17:37:02 +01:00
mlugg
16481c8ef3
cases: update to new "called from here" notes 2025-05-16 13:29:55 +01:00
wooster0
56fad6a195 make error messages prettier
Error messages never contain periods or grave accents.
Get rid of the periods and use apostrophes instead in
probably the only two error messages that had them.
2025-05-15 16:39:15 +01:00
xdBronch
10bf6964ed translate-c: fix callconv attribute in macro 2025-05-07 16:15:51 +03:00
Matthew Lugg
f4e9846bca
Merge pull request #23263 from mlugg/comptime-field-ptr
Sema: fix pointers to comptime fields of comptime-known aggregate pointers
2025-05-03 20:10:42 +01:00
Alex Rønne Petersen
bf9b15ee67 std.Target: Add Cpu.Arch.or1k and basic target info. 2025-05-03 11:22:27 +02:00
Andrew Kelley
8facd99d41
Merge pull request #23708 from ziglang/memmove-followups
`@memmove` followups
2025-04-28 15:06:18 -04:00
mlugg
d038676a1f Sema: fix a few indexing bugs
* Indexing zero-bit types should not produce AIR indexing instructions
* Getting a runtime-known element pointer from a many-pointer should
  check that the many-pointer is not comptime-only

Resolves: #23405
2025-04-28 19:43:58 +01:00
dweiller
365ed0ed68 sema: do checked cast when resolving aggregate size 2025-04-28 16:48:45 +01:00
Andrew Kelley
7bd3207921 make @memcpy and @memmove share panic handlers 2025-04-27 23:30:00 -07:00
mlugg
d4c5396646
Sema: fix pointers to comptime fields of comptime-known aggregate pointers
Resolves: #23190
2025-04-28 01:14:22 +01:00
dweiller
4e78836d29 test: add tests for @memmove 2025-04-26 13:34:17 +10:00
dweiller
898ca82458 compiler: add @memmove builtin 2025-04-26 13:34:16 +10:00
dweiller
b9f440620d test: add error return to memcpy_len_mismatch and memcpy_alias 2025-04-26 13:34:16 +10:00
Matthew Roush
fb1d4990cb
Make translate-c more robust in handling macro functions.
Translate-c didn't properly account for C macro functions having parameter names that are C keywords. So something like `#define FOO(float) ((float) + 10)` would've been interpreted as casting `+10` to a `float` type, instead of adding `10` to the parameter `float`.

An example of a real-world macro function like this is SDL3's `SDL_DEFINE_AUDIO_FORMAT` from `SDL_audio.h`, which uses `signed` as a parameter.
2025-04-07 20:53:38 +00:00
Mason Remaley
06ee383da9
compiler: allow @import of ZON without a result type
In particular, this allows importing `build.zig.zon` at comptime.
2025-04-02 05:53:22 +01:00
Parker Liu
0bdc0bb534
translate-c: fix referencing extern locals from nested blocks 2025-03-31 20:22:03 +03:00
mlugg
eee752ea5a compiler: "illegal behavior", not "undefined behavior", in errors 2025-03-29 18:40:23 -04:00
Jacob Young
c5c1c8538d x86_64: rewrite wrapping multiplication 2025-03-21 21:51:08 -04:00
Ali Cheraghi
c1977bf0fb Sema: error on illegal code when targeting spirv 2025-03-17 21:56:14 +03:30
mlugg
2a4e06bcb3 Sema: rewrite comptime arithmetic
This commit reworks how Sema handles arithmetic on comptime-known
values, fixing many bugs in the process.

The general pattern is that arithmetic on comptime-known values is now
handled by the new namespace `Sema.arith`. Functions handling comptime
arithmetic no longer live on `Value`; this is because some of them can
emit compile errors, so some *can't* go on `Value`. Only semantic
analysis should really be doing arithmetic on `Value`s anyway, so it
makes sense for it to integrate more tightly with `Sema`.

This commit also implements more coherent rules surrounding how
`undefined` interacts with comptime and mixed-comptime-runtime
arithmetic. The rules are as follows.

* If an operation cannot trigger Illegal Behavior, and any operand is
  `undefined`, the result is `undefined`. This includes operations like
  `0 *| undef`, where the LHS logically *could* be used to determine a
  defined result. This is partly to simplify the language, but mostly to
  permit codegen backends to represent `undefined` values as completely
  invalid states.

* If an operation *can* trigger Illegal Behvaior, and any operand is
  `undefined`, then Illegal Behavior results. This occurs even if the
  operand in question isn't the one that "decides" illegal behavior; for
  instance, `undef / 1` is undefined. This is for the same reasons as
  described above.

* An operation which would trigger Illegal Behavior, when evaluated at
  comptime, instead triggers a compile error. Additionally, if one
  operand is comptime-known undef, such that the other (runtime-known)
  operand isn't needed to determine that Illegal Behavior would occur,
  the compile error is triggered.

* The only situation in which an operation with one comptime-known
  operand has a comptime-known result is if that operand is undefined,
  in which case the result is either undefined or a compile error per
  the above rules. This could potentially be loosened in future (for
  instance, `0 * rt` could be comptime-known 0 with a runtime assertion
  that `rt` is not undefined), but at least for now, defining it more
  conservatively simplifies the language and allows us to easily change
  this in future if desired.

This commit fixes many bugs regarding the handling of `undefined`,
particularly in vectors. Along with a collection of smaller tests, two
very large test cases are added to check arithmetic on `undefined`.

The operations which have been rewritten in this PR are:

* `+`, `+%`, `+|`, `@addWithOverflow`
* `-`, `-%`, `-|`, `@subWithOverflow`
* `*`, `*%`, `*|`, `@mulWithOverflow`
* `/`, `@divFloor`, `@divTrunc`, `@divExact`
* `%`, `@rem`, `@mod`

Other arithmetic operations are currently unchanged.

Resolves: #22743
Resolves: #22745
Resolves: #22748
Resolves: #22749
Resolves: #22914
2025-03-16 08:17:50 +00:00
Matthew Lugg
d0911786c9
Merge pull request #22397 from Techatrix/type-safe-ast
improve type safety of std.zig.Ast
2025-03-12 02:22:41 +00:00
Ian Johnson
0bce4a4e05 Sema: handle generated tag enums in union field order check
Fixes #23059

The "note: enum field here" now references the field in the base union type rather than crashing.
2025-03-08 14:29:20 -05:00
Techatrix
de9c889a0e
aro_translate_c: fix ast lowering of continue node
fixes #22601
2025-03-07 22:20:35 +01:00
Linus Groh
79460d4a3e Remove uses of deprecated callconv aliases 2025-03-05 03:01:43 +00:00
mlugg
3aaf394249
test: remove dependencies on legacy coercion 2025-02-26 00:17:09 +00:00
mlugg
84da520c44
Sema: remove legacy coercion
This was meant to be removed in #21817, but was somehow missed.
2025-02-26 00:17:09 +00:00
mlugg
3fcb4408a5 AstGen: improve 'file cannot be a tuple' source location
Instead of just reporting this on token 0, report it on the first
tuple-like field.
2025-02-25 22:28:47 +00:00
mlugg
5e20e9b449 Sema: allow @ptrCast of slices changing the length
Also, refactor `Sema.ptrCastFull` to not be a horrifying hellscape.
2025-02-23 08:28:58 +00:00
David Rubin
36fc2d2607 AstGen: make layout specifiers on opaque containers a compile error 2025-02-22 17:21:34 -05:00
Benjamin Thompson
a8d3760c5b
added compile_error test coverage for issue 17166 2025-02-21 07:00:37 +01:00
Alex Rønne Petersen
faccd79ca5
test: Update some compiler-internal type names in expected output. 2025-02-17 19:18:20 +01:00
Alex Rønne Petersen
9c015e6c2b
std.builtin: Remove CallingConvention.arm_(apcs,aapcs16_vfp).
* arm_apcs is the long dead "OABI" which we never had working support for.
* arm_aapcs16_vfp is for arm-watchos-none which is a dead target that we've
  dropped support for.
2025-02-17 19:17:56 +01:00
Tw
d7b93c7876 Sema: make source location in checkCallConvSupportsVarArgs more meaningful
As calling convention may not be specified explicitly in the source,
so use va_arg's location instead.

Signed-off-by: Tw <tw19881113@gmail.com>
2025-02-17 05:28:11 +01:00
Jacob Young
f6bcc9dbcb x86_64: rewrite scalar and vector int @rem 2025-02-15 03:45:21 -05:00
Jacob Young
8c48376d64 x86_64: rewrite scalar and vector int @divTrunc 2025-02-15 03:45:21 -05:00
Jacob Young
8159ff8b81 x86_64: implement error set and enum safety
This is all of the expected 0.14.0 progress on #21530, which can now be
postponed once this commit is merged.

This required rewriting the (un)wrap operations since the original
implementations were extremely buggy.

Also adds an easy way to retrigger Sema OPV bugs so that I don't have to
keep updating #22419 all the time.
2025-02-15 03:45:21 -05:00
mlugg
75ec7d863e
Sema: add missing validateRuntimeValue calls
Resolves: #13791
2025-02-06 01:11:10 +00:00
mlugg
456f3c026b
Sema: fix crash on @tagName of undefined enum literal
Resolves: #20826
2025-02-05 19:08:05 +00:00
mlugg
3ce857d054
Sema: fix incorrectly succeeding type resolution
Resolves: #21436
2025-02-05 18:31:39 +00:00
Matthew Lugg
f01f1e33c9
Merge pull request #22754 from mlugg/files-and-stuff
ZON and incremental bits
2025-02-05 12:17:13 +00:00
Will Lillis
cf059ee087
AstGen: improve error for invalid bytes in strings and comments 2025-02-05 11:10:11 +02:00
mlugg
bebfa036ba
test: remove failing case
Unfortunately, now that this error is more in line with other `@import`
errors, it isn't so easy to have a test case for.
2025-02-04 18:30:50 +00:00
Mason Remaley
13c6eb0d71
compiler,std: implement ZON support
This commit allows using ZON (Zig Object Notation) in a few ways.

* `@import` can be used to load ZON at comptime and convert it to a
  normal Zig value. In this case, `@import` must have a result type.
* `std.zon.parse` can be used to parse ZON at runtime, akin to the
  parsing logic in `std.json`.
* `std.zon.stringify` can be used to convert arbitrary data structures
  to ZON at runtime, again akin to `std.json`.
2025-02-03 09:14:37 +00:00
Will Lillis
953355ebea
fix: error on non-exhaustive enums with zero width backing type (#21374)
Co-authored-by: WillLillis <wlillis@umass.edu>
2025-02-02 03:36:16 +00:00
Andrew Kelley
963651bbf2
Merge pull request #22672 from jacobly0/x86_64-rewrite
x86_64: rewrite float conversions
2025-02-01 14:32:43 -08:00
mlugg
3924f173af compiler: do not propagate result type to try operand
This commit effectively reverts 9e683f0, and hence un-accepts #19777.
While nice in theory, this proposal turned out to have a few problems.

Firstly, supplying a result type implicitly coerces the operand to this
type -- that's the main point of result types! But for `try`, this is
actually a bad idea; we want a redundant `try` to be a compile error,
not to silently coerce the non-error value to an error union. In
practice, this didn't always happen, because the implementation was
buggy anyway; but when it did, it was really quite silly. For instance,
`try try ... try .{ ... }` was an accepted expression, with the inner
initializer being initially coerced to `E!E!...E!T`.

Secondly, the result type inference here didn't play nicely with
`return`. If you write `return try`, the operand would actually receive
a result type of `E!E!T`, since the `return` gave a result type of `E!T`
and the `try` wrapped it in *another* error union. More generally, the
problem here is that `try` doesn't know when it should or shouldn't
nest error unions. This occasionally broke code which looked like it
should work.

So, this commit prevents `try` from propagating result types through to
its operand. A key motivation for the original proposal here was decl
literals; so, as a special case, `try .foo(...)` is still an allowed
syntax form, caught by AstGen and specially lowered. This does open the
doors to allowing other special cases for decl literals in future, such
as `.foo(...) catch ...`, but those proposals are for another time.

Resolves: #21991
Resolves: #22633
2025-02-01 15:48:45 +00:00
Jacob Young
b9531f5de6 x86_64: rewrite float vector conversions 2025-01-31 23:00:34 -05:00
mlugg
b01d6b156c compiler: add intcast_safe AIR instruction
This instruction is like `intcast`, but includes two safety checks:

* Checks that the int is in range of the destination type
* If the destination type is an exhaustive enum, checks that the int
  is a named enum value

This instruction is locked behind the `safety_checked_instructions`
backend feature; if unsupported, Sema will emit a fallback, as with
other safety-checked instructions.

This instruction is used to add a missing safety check for `@enumFromInt`
truncating bits. This check also has a fallback for backends which do
not yet support `safety_checked_instructions`.

Resolves: #21946
2025-01-30 14:47:59 +00:00
mlugg
107b65ec5d Sema: explain why we tried to call an extern fn at comptime
I recently saw a user hit the "comptime call of extern function" error,
and get confused because they didn't know why the scope was `comptime`.
So, use `explainWhyBlockIsComptime` on this and related errors to add
all the relevant notes.

The added test case shows the motivating situation.
2025-01-29 18:43:24 +00:00