zig icon indicating copy to clipboard operation
zig copied to clipboard

remove @ptrCast. add @elemCast

Open andrewrk opened this issue 7 years ago • 10 comments

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.

andrewrk avatar Jun 13 '18 14:06 andrewrk

I will work on this one if you don't mind.

alexnask avatar Jun 15 '18 06:06 alexnask

How would we handle:

  • *T -> [*]T -> *T
  • *T -> fn(...) ... -> *T
  • fn(...) ... -> fn(...) ...

Hejsil avatar Jun 15 '18 15:06 Hejsil

*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 avatar Jun 15 '18 16:06 alexnask

@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 avatar Jun 15 '18 16:06 Hejsil

@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 :)

alexnask avatar Jun 15 '18 16:06 alexnask

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(...) ... -> *T
  • fn(...) ... -> fn(...) ...

maybe @fnCast? but it wouldn't do fn(...) ... -> *T.

andrewrk avatar Jun 15 '18 17:06 andrewrk

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.

Hejsil avatar Jun 15 '18 18:06 Hejsil

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.

Hejsil avatar Jun 05 '19 07:06 Hejsil

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

andrewrk avatar Jul 06 '23 00:07 andrewrk

When you really want to do your unsafe operations, you always have the @ptrToInt @intToPtr pair. They can do everything.

It would be nice if you didn't need two casts for that.

kocsis1david avatar Jul 16 '24 20:07 kocsis1david