Jump to page: 1 2
Thread overview
Extra .tupleof field in structs with disabled postblit blocks non-GC-allocation trait
May 09, 2018
Per Nordlöw
May 09, 2018
Per Nordlöw
May 09, 2018
Per Nordlöw
May 09, 2018
Per Nordlöw
May 09, 2018
Per Nordlöw
May 09, 2018
Per Nordlöw
May 09, 2018
Meta
May 09, 2018
Per Nordlöw
May 09, 2018
Meta
May 10, 2018
Per Nordlöw
May 10, 2018
Uknown
May 10, 2018
Meta
May 11, 2018
Johan Engelen
May 09, 2018
Why (on earth) does

    struct S
    {
        @disable this(this);
        int* _ptr;
    }
    pragma(msg, typeof(S.tupleof));

prints

(int*, void*)

when

    struct S
    {
        int* _ptr;
    }
    pragma(msg, typeof(S.tupleof));

prints

(int*)

?!!!

This prevents the trait `mustAddGCRangeOfStructOrUnion` [1] from detecting when a container with manual memory management doesn't have to be scanned by the GC as in, for instance,

    enum NoGc;
    struct S
    {
        @disable this(this); // disable S postlib
        @NoGc int* _ptr;
    }
    static assert(!mustAddGCRangeOfStructOrUnion!S); // is false when postblit of `S` is disabled

[1] https://github.com/nordlow/phobos-next/blob/master/src/gc_traits.d#L81
May 09, 2018
On Wednesday, 9 May 2018 at 14:07:37 UTC, Per Nordlöw wrote:
> This prevents the trait `mustAddGCRangeOfStructOrUnion` [1] from detecting when a container with manual memory management doesn't have to be scanned by the GC as in, for instance,
>
>     enum NoGc;
>     struct S
>     {
>         @disable this(this); // disable S postlib
>         @NoGc int* _ptr;
>     }
>     static assert(!mustAddGCRangeOfStructOrUnion!S); // is false when postblit of `S` is disabled
>
> [1] https://github.com/nordlow/phobos-next/blob/master/src/gc_traits.d#L81

Can we statically check if the postblit has been disabled via

@disable this(this);

?

If so, we can temporarily modify the trait to exclude the last `void*` member of the `S.tuple`. Given that it's always added as the last member.
May 09, 2018
On Wednesday, 9 May 2018 at 14:20:41 UTC, Per Nordlöw wrote:
> If so, we can temporarily modify the trait to exclude the last `void*` member of the `S.tuple`. Given that it's always added as the last member.

Note that `std.traits.isCopyable!S` cannot be used, because it will return true when `S` has uncopyable members regardless of whether S.tupleof have any extra void* element or not (because of S's disabled postblit).
May 09, 2018
On Wednesday, 9 May 2018 at 14:20:41 UTC, Per Nordlöw wrote:
> If so, we can temporarily modify the trait to exclude the last `void*` member of the `S.tuple`. Given that it's always added as the last member.

Also note that

    pragma(msg, __traits(isDisabled, S.this(this)));

fails to compile as

    Error: identifier expected following `.`, not `this`
May 09, 2018
On Wednesday, 9 May 2018 at 14:34:02 UTC, Per Nordlöw wrote:
> On Wednesday, 9 May 2018 at 14:20:41 UTC, Per Nordlöw wrote:
>> If so, we can temporarily modify the trait to exclude the last `void*` member of the `S.tuple`. Given that it's always added as the last member.
>
> Also note that
>
>     pragma(msg, __traits(isDisabled, S.this(this)));
>
> fails to compile as
>
>     Error: identifier expected following `.`, not `this`

Ahh, but both

    pragma(msg, __traits(isDisabled, S.__postblit));
    pragma(msg, __traits(isDisabled, S.__xpostblit));

prints true for a struct with `@disable this(this);`

Which one should I pick to check if last element of `S.tupleof` should be discarded?
May 09, 2018
On Wednesday, 9 May 2018 at 14:36:38 UTC, Per Nordlöw wrote:
> On Wednesday, 9 May 2018 at 14:34:02 UTC, Per Nordlöw wrote:
>> On Wednesday, 9 May 2018 at 14:20:41 UTC, Per Nordlöw wrote:
>>> If so, we can temporarily modify the trait to exclude the last `void*` member of the `S.tuple`. Given that it's always added as the last member.
>>
>> Also note that
>>
>>     pragma(msg, __traits(isDisabled, S.this(this)));
>>
>> fails to compile as
>>
>>     Error: identifier expected following `.`, not `this`
>
> Ahh, but both
>
>     pragma(msg, __traits(isDisabled, S.__postblit));
>     pragma(msg, __traits(isDisabled, S.__xpostblit));
>
> prints true for a struct with `@disable this(this);`
>
> Which one should I pick to check if last element of `S.tupleof` should be discarded?

Managed to put together the hack

private template mustAddGCRangeOfStructOrUnion(T)
if (is(T == struct) ||
    is(T == union))
{
    import std.traits : hasUDA;
    import std.meta : anySatisfy;
    static if (__traits(hasMember, T, "__postblit"))
    {
        static if (__traits(isDisabled, T.__postblit))
        {
            enum mustAddGCRangeOfStructOrUnion = anySatisfy!(mustAddGCRangeOfMember, T.tupleof[0 .. $ - 1]);
        }
        else
        {
            enum mustAddGCRangeOfStructOrUnion = anySatisfy!(mustAddGCRangeOfMember, T.tupleof);
        }
    }
    else
    {
        enum mustAddGCRangeOfStructOrUnion = anySatisfy!(mustAddGCRangeOfMember, T.tupleof);
    }
}

defined here

https://github.com/nordlow/phobos-next/blob/master/src/gc_traits.d#L81

Destroy.
May 09, 2018
On Wednesday, 9 May 2018 at 14:07:37 UTC, Per Nordlöw wrote:
> Why (on earth) does
>
>     struct S
>     {
>         @disable this(this);
>         int* _ptr;
>     }
>     pragma(msg, typeof(S.tupleof));
>
> prints
>
> (int*, void*)
>
> when
>
>     struct S
>     {
>         int* _ptr;
>     }
>     pragma(msg, typeof(S.tupleof));
>
> prints
>
> (int*)
>
> ?!!!

I wasn't able to reproduce it on dmd-nightly: https://run.dlang.io/is/9wT8tH

What version of the compiler are you using?
May 09, 2018
On Wednesday, 9 May 2018 at 17:52:48 UTC, Meta wrote:
> I wasn't able to reproduce it on dmd-nightly: https://run.dlang.io/is/9wT8tH
>
> What version of the compiler are you using?

Ahh, the struct needs to be in a unittest block for it to happen:

struct R
{
    @disable this(this);
    int* _ptr;
}
unittest
{
    struct S
    {
        @disable this(this);
        int* _ptr;
    }
    struct T
    {
        int* _ptr;
    }
    pragma(msg, "R: ", typeof(R.tupleof));
    pragma(msg, "S: ", typeof(S.tupleof));
    pragma(msg, "T: ", typeof(T.tupleof));
}

prints

R: (int*)
S: (int*, void*)
T: (int*)

Why is that?
May 09, 2018
On Wednesday, 9 May 2018 at 18:04:40 UTC, Per Nordlöw wrote:
> On Wednesday, 9 May 2018 at 17:52:48 UTC, Meta wrote:
>> I wasn't able to reproduce it on dmd-nightly: https://run.dlang.io/is/9wT8tH
>>
>> What version of the compiler are you using?
>
> Ahh, the struct needs to be in a unittest block for it to happen:
>
> struct R
> {
>     @disable this(this);
>     int* _ptr;
> }
> unittest
> {
>     struct S
>     {
>         @disable this(this);
>         int* _ptr;
>     }
>     struct T
>     {
>         int* _ptr;
>     }
>     pragma(msg, "R: ", typeof(R.tupleof));
>     pragma(msg, "S: ", typeof(S.tupleof));
>     pragma(msg, "T: ", typeof(T.tupleof));
> }
>
> prints
>
> R: (int*)
> S: (int*, void*)
> T: (int*)
>
> Why is that?

It's a context pointer to the enclosing function/object/struct. Mark the struct as static to get rid of it.
May 10, 2018
On Wednesday, 9 May 2018 at 21:09:12 UTC, Meta wrote:
> It's a context pointer to the enclosing function/object/struct. Mark the struct as static to get rid of it.

Ok, but why an extra void* for `S.tupleof` and not for `T.tupleof` which is also scoped inside a unittest?
« First   ‹ Prev
1 2