Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstracted pointers cannot be used at comptime #2487

Open
tgschultz opened this issue May 14, 2019 · 1 comment
Open

Abstracted pointers cannot be used at comptime #2487

tgschultz opened this issue May 14, 2019 · 1 comment
Labels
use case Describes a real use case that is difficult or impossible, but does not propose a solution.
Milestone

Comments

@tgschultz
Copy link
Contributor

tgschultz commented May 14, 2019

const Any = *@OpaqueType();

const Iface = struct
{
    impl: Any,
    funcFn: fn(Any)u32,
    
    pub fn func(self: *Iface) u32
    {
        return self.funcFn(self.impl);
    }
};

const Impl = struct
{
    val: u32,
    
    pub fn func(self: *Impl) u32
    {
        return self.val;
    }
};

test "comptime type erasure failure"
{
    comptime
    {
        var impl = Impl{ .val = 123, };
        var iface = Iface
        {
            .impl = @ptrCast(Any, &impl),
            .funcFn = @ptrCast(fn(Any)u32, Impl.func),
        };
        var x = iface.func();
    }
}
: error: expected type '*Impl', found '*Any'
        return self.funcFn(self.impl);
                               ^
: note: called from here
        var x = iface.func();
                          ^
: note: pointer type child 'Any' cannot cast into pointer type child 'Impl'
        return self.funcFn(self.impl);
                               ^
: note: Impl declared here
const Impl = struct
             ^

Removing comptime allows the test to pass.

This affects my experiments with new std interface patterns somewhat, but I'm not actually sure it should work.

@andrewrk andrewrk added this to the 0.5.0 milestone May 15, 2019
@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Sep 20, 2019
@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Jan 5, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 30, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@SpexGuy
Copy link
Contributor

SpexGuy commented Mar 20, 2021

I think this is UB, so the compiler is right to reject this. It's not technically specified that you should be able to cast from (a function with unspecified calling convention accepting a pointer) to (a function accepting a different pointer type) and call the result. But if you generate a function that does a ptrCast and then calls the implementation, it seems to work correctly:

const Any = *opaque{};

const Iface = struct
{
    impl: Any,
    funcFn: fn(Any)u32,
    
    pub fn func(self: *Iface) u32
    {
        return self.funcFn(self.impl);
    }
};

const Impl = struct
{
    val: u32,
    
    pub fn func(self: *Impl) u32
    {
        return self.val;
    }

    pub fn iface(self: *Impl) Iface
    {
        return Iface
        {
            .impl = @ptrCast(Any, self),
            .funcFn = struct
            {
                pub fn f(i: Any) u32
                {
                    return func(@ptrCast(*Impl, @alignCast(@alignOf(Impl), i)));
                }
            }.f,
        };
    }
};

test "comptime type erasure success"
{
    comptime
    {
        var impl = Impl{ .val = 123 };
        var iface = impl.iface();
        var x = iface.func();
    }
}

@SpexGuy SpexGuy added the use case Describes a real use case that is difficult or impossible, but does not propose a solution. label Mar 20, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
use case Describes a real use case that is difficult or impossible, but does not propose a solution.
Projects
None yet
Development

No branches or pull requests

3 participants