Thread overview
Why is my @pure function @system when placed in a struct?
Feb 27, 2019
Q. Schroll
Feb 27, 2019
Stefan Koch
Feb 27, 2019
Dukc
Feb 27, 2019
Dukc
Feb 27, 2019
ag0aep6g
February 27, 2019
I have a template function `fImpl` I whish to instantiate manually using the new name `f`. Reason is simple: `f` should not be a template, but overloading it makes it easier that way.
Nothing's more simple in D:

    int fImpl(T)(T value) { return cast(int) value; }
    alias f = fImpl!int;
    alias f = fImpl!long;

It works perfectly used like that.

In my case, `T` isn't just a simple type, it's a delegate type. So it's rather like this:

    alias BaseDG = int delegate(ref int);
    int fImpl(DG : BaseDG)(scope DG callback)
    {
        // NB: this is @safe iff callback is @safe
        int x = 0;
        return callback(x);
    }

    alias myDG = int delegate(ref int) @safe;
    alias f = fImpl!myDG;

When I ask the compiler, if `f` is @safe, it tells me: Hurray, it is!

    pragma(msg, __traits(getFunctionAttributes, f)); // tells me: `f` is @safe

For whatever reason, when I put the code in a struct, the @safe testing line tells me, it's @system now.

    struct S
    {
        // static: // static or not does not matter

        alias BaseDG = int delegate(ref int);
        int fImpl(DG : BaseDG)(scope DG callback) { return 0; }

        alias myDG = int delegate(ref int) @system;
        alias f = fImpl!myDG;

        pragma(msg, __traits(getFunctionAttributes, f)); // tells me: `f` is @system
    }

I have no idea why. It is irrelevant if the function template is `static` or even does not call the callback.
February 27, 2019
On Wednesday, 27 February 2019 at 17:23:21 UTC, Q. Schroll wrote:
> I have a template function `fImpl` I whish to instantiate manually using the new name `f`. Reason is simple: `f` should not be a template, but overloading it makes it easier that way.
> Nothing's more simple in D:
>
> [...]

the struct gets drawn into your delegate-context.
and I guess that taints  the function.
February 27, 2019
On Wednesday, 27 February 2019 at 17:23:21 UTC, Q. Schroll wrote:
> For whatever reason, when I put the code in a struct, the @safe testing line tells me, it's @system now.

I tested a bit, and it appears that attribute inference is not done at all for templates inside structs -the attribute need not be a delegate:

struct S
    {
        static int fImpl(Ret)() { return Ret.init; }

        pragma(msg, __traits(getFunctionAttributes, fImpl!int)); // still tells us: `f` is @system
    }

void main(){}

A bug, unless I'm overlooking something.
February 27, 2019
On Wednesday, 27 February 2019 at 18:06:49 UTC, Stefan Koch wrote:
>
> the struct gets drawn into your delegate-context.
> and I guess that taints  the function.

Even if it did, it should not make the delegate @system. And it does not, since this manifest with static functions and function pointers too.
February 27, 2019
On 27.02.19 19:10, Dukc wrote:
> I tested a bit, and it appears that attribute inference is not done at all for templates inside structs -the attribute need not be a delegate:
> 
> struct S
>      {
>          static int fImpl(Ret)() { return Ret.init; }
> 
>          pragma(msg, __traits(getFunctionAttributes, fImpl!int)); // still tells us: `f` is @system
>      }
> 
> void main(){}
> 
> A bug, unless I'm overlooking something.

It's not quite as simple as that. When you put the pragma in a function, the inferred attributes show up:

----
struct S
{
    void f()() {}
}

pragma(msg, __traits(getFunctionAttributes, S.f!())); /* @system */

void g()
{
    pragma(msg, __traits(getFunctionAttributes, S.f!()));
        /* Same line now says @safe. */
}
----

But I agree that this can't be right.