remove @ptrCast. add @elemCast
Right now, @ptrCast can change the pointer element, but it gives a compile error if you try to change the alignment or const-ness. We already have @alignCast to change the alignment only. Really, this cast is only meant to change the underlying element. So let's make that explicit by having the built-in function only accept the child element type as a parameter, and then it's obvious that the other pointer attributes are unmodified.
I will work on this one if you don't mind.
How would we handle:
*T->[*]T->*T*T->fn(...) ...->*Tfn(...) ...->fn(...) ...
*T -> [*]T currently does not work even with explicit casting, *T -> *[1]T -> [*]T is required.
The rest do not explicitly cast either.
I'm leaving this up here and will update with further work, will close if the proposal is significantly changed/not approved.
@alexnask What? I mean the use-cases that the current @ptrCast does just fine:
fn q() void {}
test "" {
const a: u8 = 0;
const b = &a;
const c = @ptrCast([*]const u8, b);
const d = @ptrCast(*const u8, c);
// This should work, but I think I hit some compiler bug
//zig: zig/src/codegen.cpp:5338: LLVMOpaqueValue* gen_const_val(CodeGen*, ConstExprValue*, const char*): Assertion `const_val->data.x_ptr.special == ConstPtrSpecialFunction' failed.
//[1] 6043 abort (core dumped) zig test test.zig
//const e = @ptrCast(fn()u8, b);
// This should also work...
//Stored value type does not match pointer operand type!
// store void ()* @q, i8 ()** %f, align 8, !dbg !647
// i8 ()*LLVM ERROR: Broken module found, compilation aborted!
//const f = @ptrCast(fn()u8, q);
}
@Hejsil
Right, I was saying those cases do not work without @ptrCast, since you can't "just" cast from one of those types to another, I'm not disagreeing :)
How would we handle:
*T->[*]T->*T
To get from *T to [*]T I propose a userland solution, that does *T -> *[1]T -> [*]T (these are all implicit casts)
To get from [*]T to *T, do this: &foo[0]
*T->fn(...) ...->*Tfn(...) ...->fn(...) ...
maybe @fnCast? but it wouldn't do fn(...) ... -> *T.
I guess that could be @intToPtr(*T, @ptrToInt(func)). I think fn -> *T is really rare, while *T -> fn is more "common".
Edit: Wait no. If you got a *T which is a function, then somewhere, a function was casted to *T.
Discarding attributes is a very unsafe operations. You can easily discard attributes you don't want to discard with @ptrCast when you refactor code. It's to powerful. That is probably why @ptrCast actually can't discard all pointer attributes (like const).
@elemCast (or just change @ptrCasts behavior but not it's name) is a safer more controlled function. When you really want to do your unsafe operations, you always have the @ptrToInt @intToPtr pair. They can do everything.
Re-opening for reconsideration in light of two new developments:
- The destination type parameter is eliminated (#5909)
- Function pointers now use uniform syntax with pointers
When you really want to do your unsafe operations, you always have the
@ptrToInt@intToPtrpair. They can do everything.
It would be nice if you didn't need two casts for that.