aboutsummaryrefslogtreecommitdiff
path: root/src/Sema/comptime_ptr_access.zig
AgeCommit message (Collapse)Author
2025-11-12compiler: spring cleaningMatthew Lugg
I started this diff trying to remove a little dead code from the C backend, but ended up finding a bunch of dead code sprinkled all over the place: * `packed` handling in the C backend which was made dead by `Legalize` * Representation of pointers to runtime-known vector indices * Handling for the `vector_store_elem` AIR instruction (now removed) * Old tuple handling from when they used the InternPool repr of structs * Straightforward unused functions * TODOs in the LLVM backend for features which Zig just does not support
2025-08-12replace even more aggregate internsJustus Klausecker
2025-05-16compiler: include inline calls in the reference tracemlugg
Inline calls which happened in the erroring `AnalUnit` still show as error notes, because they tend to make very important context (e.g. to see how comptime values propagate through them). However, "earlier" inline calls are still useful to see to understand how something is being referenced, so we should include them in the reference trace.
2025-05-03compiler: fix comptime memory store bugsmlugg
* When storing a zero-bit type, we should short-circuit almost immediately. Zero-bit stores do not need to do any work. * The bit size computation for arrays is incorrect; the `abiSize` will already be appropriately aligned, but the logic to do so here incorrectly assumes that zero-bit types have an alignment of 0. They don't; their alignment is 1. Resolves: #21202 Resolves: #21508 Resolves: #23307
2024-12-24compiler: analyze type and value of global declaration separatelymlugg
This commit separates semantic analysis of the annotated type vs value of a global declaration, therefore allowing recursive and mutually recursive values to be declared. Every `Nav` which undergoes analysis now has *two* corresponding `AnalUnit`s: `.{ .nav_val = n }` and `.{ .nav_ty = n }`. The `nav_val` unit is responsible for *fully resolving* the `Nav`: determining its value, linksection, addrspace, etc. The `nav_ty` unit, on the other hand, resolves only the information necessary to construct a *pointer* to the `Nav`: its type, addrspace, etc. (It does also analyze its linksection, but that could be moved to `nav_val` I think; it doesn't make any difference). Analyzing a `nav_ty` for a declaration with no type annotation will just mark a dependency on the `nav_val`, analyze it, and finish. Conversely, analyzing a `nav_val` for a declaration *with* a type annotation will first mark a dependency on the `nav_ty` and analyze it, using this as the result type when evaluating the value body. The `nav_val` and `nav_ty` units always have references to one another: so, if a `Nav`'s type is referenced, its value implicitly is too, and vice versa. However, these dependencies are trivial, so, to save memory, are only known implicitly by logic in `resolveReferences`. In general, analyzing ZIR `decl_val` will only analyze `nav_ty` of the corresponding `Nav`. There are two exceptions to this. If the declaration is an `extern` declaration, then we immediately ensure the `Nav` value is resolved (which doesn't actually require any more analysis, since such a declaration has no value body anyway). Additionally, if the resolved type has type tag `.@"fn"`, we again immediately resolve the `Nav` value. The latter restriction is in place for two reasons: * Functions are special, in that their externs are allowed to trivially alias; i.e. with a declaration `extern fn foo(...)`, you can write `const bar = foo;`. This is not allowed for non-function externs, and it means that function types are the only place where it is possible for a declaration `Nav` to have a `.@"extern"` value without actually being declared `extern`. We need to identify this situation immediately so that the `decl_ref` can create a pointer to the *real* extern `Nav`, not this alias. * In certain situations, such as taking a pointer to a `Nav`, Sema needs to queue analysis of a runtime function if the value is a function. To do this, the function value needs to be known, so we need to resolve the value immediately upon `&foo` where `foo` is a function. This restriction is simple to codify into the eventual language specification, and doesn't limit the utility of this feature in practice. A consequence of this commit is that codegen and linking logic needs to be more careful when looking at `Nav`s. In general: * When `updateNav` or `updateFunc` is called, it is safe to assume that the `Nav` being updated (the owner `Nav` for `updateFunc`) is fully resolved. * Any `Nav` whose value is/will be an `@"extern"` or a function is fully resolved; see `Nav.getExtern` for a helper for a common case here. * Any other `Nav` may only have its type resolved. This didn't seem to be too tricky to satisfy in any of the existing codegen/linker backends. Resolves: #131
2024-08-28std: update `std.builtin.Type` fields to follow naming conventionsmlugg
The compiler actually doesn't need any functional changes for this: Sema does reification based on the tag indices of `std.builtin.Type` already! So, no zig1.wasm update is necessary. This change is necessary to disallow name clashes between fields and decls on a type, which is a prerequisite of #9938.
2024-08-25sema: clean-up `{union,struct}FieldAlignment` and friendsDavid Rubin
My main gripes with this design were that it was incorrectly namespaced, the naming was inconsistent and a bit wrong (`fooAlign` vs `fooAlignment`). This commit moves all the logic from `PerThread.zig` to use the zcu + tid system that the previous couple commits introduce. I've organized and merged the functions to be a bit more specific to their own purpose. - `fieldAlignment` takes a struct or union type, an index, and a Zcu (or the Sema version which takes a Pt), and gives you the alignment of the field at the index. - `structFieldAlignment` takes the field type itself, and provides the logic to handle special cases, such as externs. A design goal I had in mind was to avoid using the word 'struct' in the function name, when it worked for things that aren't structs, such as unions.
2024-08-25sema: rework type resolution to use Zcu when possibleDavid Rubin
2024-08-11compiler: split Decl into Nav and Caumlugg
The type `Zcu.Decl` in the compiler is problematic: over time it has gained many responsibilities. Every source declaration, container type, generic instantiation, and `@extern` has a `Decl`. The functions of these `Decl`s are in some cases entirely disjoint. After careful analysis, I determined that the two main responsibilities of `Decl` are as follows: * A `Decl` acts as the "subject" of semantic analysis at comptime. A single unit of analysis is either a runtime function body, or a `Decl`. It registers incremental dependencies, tracks analysis errors, etc. * A `Decl` acts as a "global variable": a pointer to it is consistent, and it may be lowered to a specific symbol by the codegen backend. This commit eliminates `Decl` and introduces new types to model these responsibilities: `Cau` (Comptime Analysis Unit) and `Nav` (Named Addressable Value). Every source declaration, and every container type requiring resolution (so *not* including `opaque`), has a `Cau`. For a source declaration, this `Cau` performs the resolution of its value. (When #131 is implemented, it is unsolved whether type and value resolution will share a `Cau` or have two distinct `Cau`s.) For a type, this `Cau` is the context in which type resolution occurs. Every non-`comptime` source declaration, every generic instantiation, and every distinct `extern` has a `Nav`. These are sent to codegen/link: the backends by definition do not care about `Cau`s. This commit has some minor technically-breaking changes surrounding `usingnamespace`. I don't think they'll impact anyone, since the changes are fixes around semantics which were previously inconsistent (the behavior changed depending on hashmap iteration order!). Aside from that, this changeset has no significant user-facing changes. Instead, it is an internal refactor which makes it easier to correctly model the responsibilities of different objects, particularly regarding incremental compilation. The performance impact should be negligible, but I will take measurements before merging this work into `master`. Co-authored-by: Jacob Young <jacobly0@users.noreply.github.com> Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
2024-07-16Sema: add error note for failed coercions to optional types and error unionsWill Lillis
2024-07-07Zcu: introduce `PerThread` and pass to all the functionsJacob Young
2024-07-04compiler: type.zig -> Type.zigmlugg
2024-06-22rename src/Module.zig to src/Zcu.zigAndrew Kelley
This patch is a pure rename plus only changing the file path in `@import` sites, so it is expected to not create version control conflicts, even when rebasing.
2024-06-15Zcu: rework source locationsmlugg
`LazySrcLoc` now stores a reference to the "base AST node" to which it is relative. The previous tagged union is `LazySrcLoc.Offset`. To make working with this structure convenient, `Sema.Block` contains a convenience `src` method which takes an `Offset` and returns a `LazySrcLoc`. The "base node" of a source location is no longer given by a `Decl`, but rather a `TrackedInst` representing either a `declaration`, `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl`. This is a more appropriate model, and removes an unnecessary responsibility from `Decl` in preparation for the upcoming refactor which will split it into `Nav` and `Cau`. As a part of these `Decl` reworks, the `src_node` field is eliminated. This change aids incremental compilation, and simplifies `Decl`. In some cases -- particularly in backends -- the source location of a declaration is desired. This was previously `Decl.srcLoc` and worked for any `Decl`. Now, it is `Decl.navSrcLoc` in reference to the upcoming refactor, since the set of `Decl`s this works for precisely corresponds to what will in future become a `Nav` -- that is, source-level declarations and generic function instantiations, but *not* type owner Decls. This commit introduces more tags to `LazySrcLoc.Offset` so as to eliminate the concept of `error.NeededSourceLocation`. Now, `.unneeded` should only be used to assert that an error path is unreachable. In the future, uses of `.unneeded` can probably be replaced with `undefined`. The `src_decl` field of `Sema.Block` no longer has a role in type resolution. Its main remaining purpose is to handle namespacing of type names. It will be eliminated entirely in a future commit to remove another undue responsibility from `Decl`. It is worth noting that in future, the `Zcu.SrcLoc` type should probably be eliminated entirely in favour of storing `Zcu.LazySrcLoc` values. This is because `Zcu.SrcLoc` is not valid across incremental updates, and we want to be able to reuse error messages from previous updates even if the source file in question changed. The error reporting logic should instead simply resolve the location from the `LazySrcLoc` on the fly.
2024-06-15compiler: move LazySrcLoc out of stdmlugg
This is in preparation for some upcoming changes to how we represent source locations in the compiler. The bulk of the change here is dealing with the removal of `src()` methods from `Zir` types.
2024-04-17compiler: rework comptime pointer representation and accessmlugg
We've got a big one here! This commit reworks how we represent pointers in the InternPool, and rewrites the logic for loading and storing from them at comptime. Firstly, the pointer representation. Previously, pointers were represented in a highly structured manner: pointers to fields, array elements, etc, were explicitly represented. This works well for simple cases, but is quite difficult to handle in the cases of unusual reinterpretations, pointer casts, offsets, etc. Therefore, pointers are now represented in a more "flat" manner. For types without well-defined layouts -- such as comptime-only types, automatic-layout aggregates, and so on -- we still use this "hierarchical" structure. However, for types with well-defined layouts, we use a byte offset associated with the pointer. This allows the comptime pointer access logic to deal with reinterpreted pointers far more gracefully, because the "base address" of a pointer -- for instance a `field` -- is a single value which pointer accesses cannot exceed since the parent has undefined layout. This strategy is also more useful to most backends -- see the updated logic in `codegen.zig` and `codegen/llvm.zig`. For backends which do prefer a chain of field and elements accesses for lowering pointer values, such as SPIR-V, there is a helpful function in `Value` which creates a strategy to derive a pointer value using ideally only field and element accesses. This is actually more correct than the previous logic, since it correctly handles pointer casts which, after the dust has settled, end up referring exactly to an aggregate field or array element. In terms of the pointer access code, it has been rewritten from the ground up. The old logic had become rather a mess of special cases being added whenever bugs were hit, and was still riddled with bugs. The new logic was written to handle the "difficult" cases correctly, the most notable of which is restructuring of a comptime-only array (for instance, converting a `[3][2]comptime_int` to a `[2][3]comptime_int`. Currently, the logic for loading and storing work somewhat differently, but a future change will likely improve the loading logic to bring it more in line with the store strategy. As far as I can tell, the rewrite has fixed all bugs exposed by #19414. As a part of this, the comptime bitcast logic has also been rewritten. Previously, bitcasts simply worked by serializing the entire value into an in-memory buffer, then deserializing it. This strategy has two key weaknesses: pointers, and undefined values. Representations of these values at comptime cannot be easily serialized/deserialized whilst preserving data, which means many bitcasts would become runtime-known if pointers were involved, or would turn `undefined` values into `0xAA`. The new logic works by "flattening" the datastructure to be cast into a sequence of bit-packed atomic values, and then "unflattening" it; using serialization when necessary, but with special handling for `undefined` values and for pointers which align in virtual memory. The resulting code is definitely slower -- more on this later -- but it is correct. The pointer access and bitcast logic required some helper functions and types which are not generally useful elsewhere, so I opted to split them into separate files `Sema/comptime_ptr_access.zig` and `Sema/bitcast.zig`, with simple re-exports in `Sema.zig` for their small public APIs. Whilst working on this branch, I caught various unrelated bugs with transitive Sema errors, and with the handling of `undefined` values. These bugs have been fixed, and corresponding behavior test added. In terms of performance, I do anticipate that this commit will regress performance somewhat, because the new pointer access and bitcast logic is necessarily more complex. I have not yet taken performance measurements, but will do shortly, and post the results in this PR. If the performance regression is severe, I will do work to to optimize the new logic before merge. Resolves: #19452 Resolves: #19460