Instead of adding 3 fields to every `Block`, this adds just one. The
function-level information is saved in the `Sema` struct instead,
which is created/copied more rarely.
This change extends the "lifetime" of the error return trace associated
with an error to continue throughout the block of a `const` variable
that it is assigned to.
This is necessary to support patterns like this one in test_runner.zig:
```zig
const result = foo();
if (result) |_| {
// ... success logic
} else |err| {
// `foo()` should be included in the error trace here
return error.TestFailed;
}
```
To make this happen, the majority of the error return trace popping logic
needed to move into Sema, since `const x = foo();` cannot be examined
syntactically to determine whether it modifies the error return trace. We
also have to make sure not to delete pertinent block information before it
makes it to Sema, so that Sema can pop/restore around blocks correctly.
* Why do this only for `const` and not `var`? *
There is room to relax things for `var`, but only a little bit. We could
do the same thing we do for const and keep the error trace alive for the
remainder of the block where the *assignment* happens. Any wider scope
would violate the stack discipline for traces, so it's not viable.
In the end, I decided the most consistent behavior for the user is just
to kill all error return traces assigned to a mutable `var`.
Despite the old doc-comment, this function cannot be valid for all types
since it operates with only a value and Error (Union) types have
overlapping Value representations with other Types.
This change extends the "lifetime" of the error return trace associated
with an error to include the duration of a function call it is passed
to.
This means that if a function returns an error, its return trace will
include the error return trace for any error inputs. This is needed to
support `testing.expectError` and similar functions.
If a function returns a non-error, we have to clean up any error return
traces created by error-able call arguments.
This re-factor is intended to make it easier to track what kind of
operator/expression consumes a result location, without overloading the
ResultLoc union for this purpose.
This is used in the following commit to keep track of initializer
expressions of `const` variables to avoid popping error traces
pre-maturely. Hopefully this will also be useful for implementing
RLS temporaries in the future.
This is encoded as a primitive AIR instruction to resolve one corner
case: A function may include a `catch { ... }` or `else |err| { ... }`
block but not call any errorable fn. In that case, there is no error
return trace to save the index of and codegen needs to avoid
interacting with the non-existing error trace.
By using a primitive AIR op, we can depend on Liveness to mark this
unused in this corner case.
In order to enforce a strict stack discipline for error return traces,
we cannot track error return traces that are stored in variables:
```zig
const x = errorable(); // errorable()'s error return trace is killed here
// v-- error trace starts here instead
return x catch error.UnknownError;
```
In order to propagate error return traces, function calls need to be passed
directly to an error-handling expression (`if`, `catch`, `try` or `return`):
```zig
// When passed directly to `catch`, the return trace is propagated
return errorable() catch error.UnknownError;
// Using a break also works
return blk: {
// code here
break :blk errorable();
} catch error.UnknownError;
```
Why do we need this restriction? Without it, multiple errors can co-exist
with their own error traces. Handling that situation correctly means either:
a. Dynamically allocating trace memory and tracking lifetimes, OR
b. Allowing the production of one error to interfere with the trace of another
(which is the current status quo)
This is piece (3/3) of https://github.com/ziglang/zig/issues/1923#issuecomment-1218495574
This allows for errors to be "re-thrown" by yielding any error as the
result of a catch block. For example:
```zig
fn errorable() !void {
return error.FallingOutOfPlane;
}
fn foo(have_parachute: bool) !void {
return errorable() catch |err| b: {
if (have_parachute) {
// error trace will include the call to errorable()
break :b error.NoParachute;
} else {
return;
}
};
}
pub fn main() !void {
// Anything that returns a non-error does not pollute the error trace.
try foo(true);
// This error trace will still include errorable(), whose error was "re-thrown" by foo()
try foo(false);
}
```
This is piece (2/3) of https://github.com/ziglang/zig/issues/1923#issuecomment-1218495574
This implement trace "popping" for correctly handled errors within
`catch { ... }` and `else { ... }` blocks.
When breaking from these blocks with any non-error, we pop the error
trace frames corresponding to the operand. When breaking with an error,
we preserve the frames so that error traces "chain" together as usual.
```zig
fn foo(cond1: bool, cond2: bool) !void {
bar() catch {
if (cond1) {
// If baz() result is a non-error, pop the error trace frames from bar()
// If baz() result is an error, leave the bar() frames on the error trace
return baz();
} else if (cond2) {
// If we break/return an error, then leave the error frames from bar() on the error trace
return error.Foo;
}
};
// An error returned from here does not include bar()'s error frames in the trace
return error.Bar;
}
```
Notice that if foo() does not return an error it, it leaves no extra
frames on the error trace.
This is piece (1/3) of https://github.com/ziglang/zig/issues/1923#issuecomment-1218495574
It is possible to get comptime-known values from runtime-known values
for example the length of array. Allowing runtime only instructions to
be emitted outside function bodies allows these operations to happen.
In places where comptime-known values are required we have other methods
to ensure that and they usually result in more specific compile errors too.
Closes#12240
Windows gives AccessDenied if you delete a directory which contains open
file handles. This could be triggered when using CacheMode.whole when
cross compiling macho test binaries.
build.zig: add a 'compile' step to compile the self-hosted compiler
without installing it.
Compilation: set cache mode to whole when using the LLVM backend and
--enable-cache is passed.
This makes `zig build` act the same as it does with stage1. Upside is
that a second invocation of `zig build` on an unmodified source tree
will avoid redoing the compilation again. Downside is that it will
proliferate more garbage in the project-local cache (same as stage1).
This can eventually be fixed when Zig's incremental compilation is more
robust; we can go back to having LLVM use CacheMode.incremental and rely
on it detecting no changes and avoiding doing the flush() step.
enums so that we can branch to set `link_mode` properly when we iterate
over the clang arguments. also replaced `dynamic` flag in
clang_options_data.zig with proper definition similarly to `static`."
This reverts commit 6af0eeb58d1d220d407ce4c463eaeb25b35f2761.
This change needs more careful consideration. It regressed
zig-bootstrap due to cmake passing `-static -lkernel32` and zig failing
with error.UnableToStaticLink.
See https://github.com/ziglang/zig-bootstrap/issues/134
I did not fully wire it up in main.zig when I originally implemented
`-z nocopyreloc` in #11679 (440f5249f1a). Finish it.
If we strictly follow the rules, we should bump the cache has version,
since the field was technically added only now. But since nobody
complained thus far, I don't think many users care that much about it
and we can omit it.
* Sema: implement linksection on functions
* Implement function linksection in Sema.
* Don't clobber function linksection/align/addrspace in Sema.
* Fix copy-paste typo in tests.
* Add a bunch of missing test_step.dependOn.
* Fix checkInSymtab match.
Closes#12546
It is not yet determined whether the Zig language will land on
text-based string concatenation for inline assembly, as Zig 0.9.1
allows, and as this commit allows, or whether it will introduce a new
assembly syntax more integrated with the rest of the language. Until
this decision is made, this commit relaxes the restriction which was
preventing inline assembly expressions from using comptime expressions
for the assembly source code.