Thread overview
cannot take address of scope local in safe function
Jun 13, 2021
vit
Jun 13, 2021
ag0aep6g
Jun 13, 2021
vit
Jun 13, 2021
Paul Backus
Jun 14, 2021
ag0aep6g
June 13, 2021

Why I can take address of Foo variable but not Bar?

//-dip1000

struct Foo{
    private double d;
}

struct Bar{
    private void* ptr;
}



void main()@safe{
    ///this is OK:
    {
        scope Foo x;
        scope ptr = &x;
    }

    ///Error: cannot take address of `scope` local `x` in `@safe` function `main`:
    {
        scope Bar x;
        scope ptr = &x;
    }
}
June 13, 2021

On Sunday, 13 June 2021 at 16:27:18 UTC, vit wrote:

>

Why I can take address of Foo variable but not Bar?

//-dip1000

struct Foo{
    private double d;
}

struct Bar{
    private void* ptr;
}



void main()@safe{
    ///this is OK:
    {
        scope Foo x;
        scope ptr = &x;
    }

    ///Error: cannot take address of `scope` local `x` in `@safe` function `main`:
    {
        scope Bar x;
        scope ptr = &x;
    }
}

scope affects indirections (i.e. pointers). Foo doesn't contain any indirections, so scope doesn't mean anything for it. The compiler just ignores it. It's like you wrote Foo x; without scope.

Bar does contain an indirection, so scope actually matters and you get the error.

June 13, 2021

On Sunday, 13 June 2021 at 17:18:46 UTC, ag0aep6g wrote:

>

On Sunday, 13 June 2021 at 16:27:18 UTC, vit wrote:

>

Why I can take address of Foo variable but not Bar?

//-dip1000

struct Foo{
    private double d;
}

struct Bar{
    private void* ptr;
}



void main()@safe{
    ///this is OK:
    {
        scope Foo x;
        scope ptr = &x;
    }

    ///Error: cannot take address of `scope` local `x` in `@safe` function `main`:
    {
        scope Bar x;
        scope ptr = &x;
    }
}

scope affects indirections (i.e. pointers). Foo doesn't contain any indirections, so scope doesn't mean anything for it. The compiler just ignores it. It's like you wrote Foo x; without scope.

Bar does contain an indirection, so scope actually matters and you get the error.

Thanks.

Is possible create and use scope output range allocated on stack in @safe code?

Example:

//-dip1000

    struct OutputRange{
        private bool valid = true;
        private void* ptr;
    	int count = 0;

        void put(Val)(auto ref scope Val val){
            assert(this.valid == true);
        	this.count += 1;
        }


        ~this()scope pure nothrow @safe @nogc{
        	this.valid = false;
        }


    }

    void main()@safe pure nothrow @nogc{
        import std.algorithm : copy;
        import std.range : only;

        scope OutputRange or;

        only(1, 2, 3, 4).copy(&or);   ///Error: cannot take address of `scope` local `or` in `@safe` function `main`
        assert(or.count == 4);
    }

June 13, 2021

On Sunday, 13 June 2021 at 17:49:50 UTC, vit wrote:

>

Is possible create and use scope output range allocated on stack in @safe code?

Example:

//-dip1000

    struct OutputRange{
        private bool valid = true;
        private void* ptr;
    	int count = 0;

        void put(Val)(auto ref scope Val val){
            assert(this.valid == true);
        	this.count += 1;
        }


        ~this()scope pure nothrow @safe @nogc{
        	this.valid = false;
        }


    }

    void main()@safe pure nothrow @nogc{
        import std.algorithm : copy;
        import std.range : only;

        scope OutputRange or;

        only(1, 2, 3, 4).copy(&or);   ///Error: cannot take address of `scope` local `or` in `@safe` function `main`
        assert(or.count == 4);
    }

Simply remove the scope annotation from or and from the destructor and it works:

https://run.dlang.io/is/hElNYf

Because OutputRange is a struct, it will still be allocated on the stack even if you don't annotate it as scope.

June 14, 2021
On 13.06.21 19:49, vit wrote:
> Is possible create and use scope output range allocated on stack in @safe code?
> 
> Example:
> ```d
> //-dip1000
> 
>      struct OutputRange{
>          private bool valid = true;
>          private void* ptr;
>          int count = 0;
> 
>          void put(Val)(auto ref scope Val val){
>              assert(this.valid == true);
>              this.count += 1;
>          }
> 
> 
>          ~this()scope pure nothrow @safe @nogc{
>              this.valid = false;
>          }
> 
> 
>      }
> 
>      void main()@safe pure nothrow @nogc{
>          import std.algorithm : copy;
>          import std.range : only;
> 
>          scope OutputRange or;
> 
>          only(1, 2, 3, 4).copy(&or);   ///Error: cannot take address of `scope` local `or` in `@safe` function `main`
>          assert(or.count == 4);
>      }
> 
> ```

You're trying to create a `scope` pointer that points to another `scope` pointer. That's not supported. You can only have one level of `scope`.

The first level of `scope` is explicit in `scope OutputRange or;`. The second level is implicit in `&or`, because the address of a local variable is necessarily a `scope` pointer.

As it's written, the first level isn't actually needed in your code. So maybe you can just remove `scope` from `or` be done. But let's assume that it really is needed for some reason.

The second level you do need. Without it, the assert fails. But you wouldn't need the pointer if `copy` took the argument by `ref`, because `ref` has a sort of implied `scope` that can be combined with an actual `scope` to give two levels of protection. So you could write your own `copy` with a `ref` parameter.

Or you can just write out what `copy` does in `main`, sidestepping the issue:

----
foreach (e; only(1, 2, 3, 4))
{
    or.put(e);
}
----

None of this is ideal, of course.