prevent pointer casts that allow writing invalid values
Closes #15874
At first I tried to block this kind of coercion for all types, but I ran into a case where the compiler coerces [][:0]u8 to [][:0]const u8 which was disallowed, and I had trouble allowing that while disallowing the problematic cases, so I tried making it specific to errors as @mlugg suggested in the issue.
As far as I can tell, this works for both error sets and error unions and I'm not aware of any other problematic cases.
I don't know how to add a test for a compile error. I see the tests in test/cases/compile_errors, but I don't know they work because they don't seem to be referenced from anywhere and I don't know how to run them.
I don't know how to add a test for a compile error. I see the tests in test/cases/compile_errors, but I don't know they work because they don't seem to be referenced from anywhere and I don't know how to run them.
Usually you have a function called export fn entry() void {} (or multiple entry1, entry2, etc.) that contains the code that is supposed to error. The expected errors go at the end. Example: test/cases/compile_errors/@intCast_on_vec.zig
To test, run zig-out/bin/zig build test-cases where zig-out/bin/zig is the compiler containing your changes. IIRC there is a way to run only a single test case by building an executable of test/src/Cases.zig but I don't remember an easy way to do that. zig build test-cases doesn't take long though (maybe 2-3 mins).
Finally,
// backend=stage2
// target=native
is more or less optional because those are the defaults anyway as far as I can tell.
Done! Added test and the suite passed.
This suffers from the issue described in https://github.com/ziglang/zig/issues/13586.
Do you mean the type names are reversed? I think it makes sense. It's assigning to a value of type *error{Bar,Foo}, so it's expecting *error{Bar,Foo}, but found *error{Foo}.
Do you mean the type names are reversed? I think it makes sense. It's assigning to a value of type
*error{Bar,Foo}, so it's expecting*error{Bar,Foo}, but found*error{Foo}.
Yes but the error notes say that error.Bar is not a member of destination error set when that is the only error set it is a member of:
//:3:35: error: expected type '*error{Bar,Foo}', found '*error{Foo}'
//:3:35: note: pointer type child 'error{Foo}' cannot cast into pointer type child 'error{Bar,Foo}'
//:3:35: note: 'error.Bar' not a member of destination error set
Oh, I see. I'll see if I can fix it.
I understand the cause of the problem, I think, but it's not obvious how to fix it.
So, the InMemoryCoercionResult returned is .ptr_child, containing an inner InMemoryCoercionResult that is .missing_error. .missing_error results don't contain information about which direction the coercion was going (probably because this is the only cause where it's reversed), and where they're stringified, there's no information about whether it was caused by this reversed comparison.
Well. I thought of a solution and it works. It's not pretty, but I'll go ahead and update the PR so you can see what you think.
Fixed merge conflicts.
I see this has been broken by intermediate changes. Oh well. I'm not putting in the work to figure out how to fix it just for it to be left to sit for 2 more weeks and then need to be rebased again.
Thanks for taking a stab at it. Who knows, maybe the person who ends up solving the issue in the future will get a head start based on your commits.