The LLVM backend was calculating the amount of padding solely based
on the payload size. However, in the case where there is no union
tag, this fails to take into account alignment.
Closes#11857
This includes various fixes/improvements to the C backend to improve
error/union support. It also fixes up our handling of decls, where some
decls were not correctly marked alive.
Adds 2 new AIR instructions:
* dbg_var_ptr
* dbg_var_val
Sema no longer emits dbg_stmt AIR instructions when strip=true.
LLVM backend: fixed lowerPtrToVoid when calling ptrAlignment on
the element type is problematic.
LLVM backend: fixed alloca instructions improperly getting debug
location annotated, causing chaotic debug info behavior.
zig_llvm.cpp: fixed incorrect bindings for a function that should use
unsigned integers for line and column.
A bunch of C test cases regressed because the new dbg_var AIR
instructions caused their operands to be alive, exposing latent bugs.
Mostly it's just a problem that the C backend lowers mutable
and const slices to the same C type, so we need to represent that in the
C backend instead of printing two duplicate typedefs.
Several issues with pointer types are fixed:
Prior to this commit, Zig would not canonicalize a pointer type with
an explicit alignment to alignment=0 if it matched the pointee ABI
alignment. In order to fix this, `Type.ptr` now takes a Target
parameter. I also moved the host_size canonicalization to `Type.ptr`
since target is now available. Similarly, is_allowzero in the case of
C pointers is now treated as a canonicalization done by the function
rather than a precondition.
in-memory coercion for pointers now properly checks ABI alignment
of pointee types instead of incorrectly treating the 0 value as an
alignment.
Type equality is completely reworked based on the tag() rather than the
zigTypeTag(). It's still semantically based on zigTypeTag() but that
knowledge is implied rather than dictating the control flow of the
logic. Importantly, this fixes cases for opaques, structs, tuples,
enums, and unions, where type equality was incorrectly returning based
on whether the tag() values were equal.
Additionally, pointer type equality now takes into account alignment.
Because we canonicalize non-zero alignment which equals pointee type ABI
alignment to alignment=0, this now can be a simple integer comparison.
Type hashing is implemented for pointers and floats. Array types now
additionally hash their sentinels.
This regressed some behavior tests that were passing but only because
of bugs regarding type equality.
The C backend has a noticeable problem with lowering differently-aligned
pointers (particularly slices) as the same type, causing C compilation
errors due to duplicate declarations.
The ZIR instruction `union_init_ptr` is renamed to `union_init`.
I made it always use by-value semantics for now, not taking the time to
invest in result location semantics, in case we decide to change the
rules for unions. This way is much simpler.
There is a new AIR instruction: union_init. This is for a comptime known
tag, runtime-known field value.
vector_init is renamed to aggregate_init, which solves a TODO comment.
* fix alignment issues for consts with natural ABI alignment not
matching that of the `ldr` instruction in `aarch64` - solved by
preceeding the `ldr` with an additional `add` instruction to form
the full address before dereferencing the pointer.
* redo selection of segment/section for decls and consts based on
combined type and value
The mechanism behind initializing a union's tag is a bit complicated,
depending on whether the union is initialized at runtime,
forced comptime, or implicit comptime.
`coerce_result_ptr` now does not force a block to be a runtime context;
instead of adding runtime instructions directly, it forwards analysis to
the respective functions for initializing optionals and error unions.
`validateUnionInit` now has logic to still emit a runtime
`set_union_tag` instruction even if the union pointer is comptime-known,
for the case of a pointer that is not comptime mutable, such as a
variable or the result of `@intToPtr`.
`validateStructInit` looks for a completely different pattern now; it
now handles the possibility of the corresponding AIR instruction for
the `field_ptr` to be missing or the corresponding `store` to be missing.
See the new comment added to the function for more details. An
equivalent change should probably be made to `validateArrayInit`.
`analyzeOptionalPayloadPtr` and `analyzeErrUnionPayloadPtr` functions now
emit a `optional_payload_ptr_set` or `errunion_payload_ptr_set`
instruction respectively if `initializing` is true and the pointer value
is not comptime-mutable.
`storePtr2` now tries the comptime pointer store before checking if the
element type has one possible value because the comptime pointer store
can have side effects of setting a union tag, setting an optional payload
non-null, or setting an error union to be non-error.
The LLVM backend `lowerParentPtr` function is improved to take into
account the differences in how the LLVM values are lowered depending on
the Zig type. It now handles unions correctly as well as additionally
handling optionals and error unions.
In the LLVM backend, the instructions `optional_payload_ptr_set` and
`errunion_payload_ptr_set` check liveness analysis and only do the side
effects in the case the result of the instruction is unused.
A few wasm and C backend test cases regressed, but they are due to TODOs
in lowering of constants, so this is progress.
LLVM union globals have to be lowered as unnamed structs if the
non-most-aligned field is the active tag. In this case it bubbles up so
that structs containing unions have the same restriction.
This fix needs to be applied to optionals and other callsites of
createNamedStruct.
The bug fixed in this commit was revealed in searching for
the cause of #10837.
This makes all union test cases succeed.
`rem` was also implemented as all we had to do is enable the instruction.
Loading and storing values based on ABI-size was simplified to a direct abiSize() call.
We also enabled all the newly passing test cases and disable them for all non-passing backends.
All of those test cases were verified to see if they perhaps already pass for the c-backend.
This commit updates stage2 to enforce the property that the syntax
`fn()void` is a function *body* not a *pointer*. To get a pointer, the
syntax `*const fn()void` is required.
ZIR puts function alignment into the func instruction rather than the
decl because this way it makes it into function types. LLVM backend
respects function alignments.
Struct and Union have methods `fieldSrcLoc` to help look up source
locations of their fields. These trigger full loading, tokenization, and
parsing of source files, so should only be called once it is confirmed
that an error message needs to be printed.
There are some nice new error hints for explaining why a type is
required to be comptime, particularly for structs that contain function
body types.
`Type.requiresComptime` is now moved into Sema because it can fail and
might need to trigger field type resolution. Comptime pointer loading
takes into account types that do not have a well-defined memory layout
and does not try to compute a byte offset for them.
`fn()void` syntax no longer secretly makes a pointer. You get a function
body type, which requires comptime. However a pointer to a function body
can be runtime known (obviously).
Compile errors that report "expected pointer, found ..." are factored
out into convenience functions `checkPtrOperand` and `checkPtrType` and
have a note about function pointers.
Implemented `Value.hash` for functions, enum literals, and undefined values.
stage1 is not updated to this (yet?), so some workarounds and disabled
tests are needed to keep everything working. Should we update stage1 to
these new type semantics? Yes probably because I don't want to add too
much conditional compilation logic in the std lib for the different
backends.
* `Module.Union.getLayout`: fixes to support components of the union
being 0 bits.
* Implement `@typeInfo` for unions.
* Add missing calls to `resolveTypeFields`.
* Fix explicitly-provided union tag types passing a `Zir.Inst.Ref`
where an `Air.Inst.Ref` was expected. We don't have any type safety
for this; these typess are aliases.
* Fix explicitly-provided `union(enum)` tag Values allocated to the
wrong arena.
* reduce number of branches in zirCmpEq
* implement equality comparison for enums and unions
* fix coercion from union to its tag type resulting in the wrong type
* fix method calls of unions
* implement peer type resolution for unions, enums, and enum literals
* fix union tag type memory in the wrong arena
Comment from this commit reproduced here:
LLVM does not allow us to change the type of globals. So we must
create a new global with the correct type, copy all its attributes,
and then update all references to point to the new global,
delete the original, and rename the new one to the old one's name.
This is necessary because LLVM does not support const bitcasting
a struct with padding bytes, which is needed to lower a const union value
to LLVM, when a field other than the most-aligned is active. Instead,
we must lower to an unnamed struct, and pointer cast at usage sites
of the global. Such an unnamed struct is the cause of the global type
mismatch, because we don't have the LLVM type until the *value* is created,
whereas the global needs to be created based on the type alone, because
lowering the value may reference the global as a pointer.