Thread overview
Current limitations of -dip1000
Oct 09, 2017
Per Nordlöw
Oct 10, 2017
Walter Bright
Oct 10, 2017
meppl
Oct 10, 2017
meppl
Oct 10, 2017
12345swordy
Oct 10, 2017
Nordlöw
Oct 10, 2017
Nordlöw
Oct 11, 2017
Walter Bright
Oct 11, 2017
Per Nordlöw
October 09, 2017
I'm trying to figure out how to make my manually written containers have scope-aware element(s)-accessing functions. I've come up with 5 different situations as follows

@safe pure nothrow @nogc:

struct S(T)
{
    static private struct Range
    {
        S!T* _parent;
    }

    scope inout(Range) range() inout return
    {
        return typeof(return)(&this);
    }

    scope inout(T)[] opSlice() inout return
    {
        return x[];
    }

    scope inout(T)[] slice() inout return
    {
        return x[];
    }

    scope ref inout(T) front() inout return
    {
        return x[0];
    }

    scope inout(T)* pointer() inout return
    {
        return &x[0];
    }

    T[128] x;
}

/// this correctly fails
int[] testOpSlice()
{
    S!int s;
    return s[];                 // errors with -dip1000
}

/// this correctly fails
int[] testSlice()
{
    S!int s;
    return s.slice;             // errors with -dip1000
}

/// this correctly fails
auto testRange()
{
    S!int s;
    return s.range;             // errors with -dip1000
}

/// TODO this should fail
ref int testFront()
{
    S!int s;
    return s.front;             // should error with -dip1000
}

/// TODO this should fail
int* testPointer()
{
    S!int s;
    return s.pointer;           // should error with -dip1000
}

Compiling this with dmd version 2.076.0-b1 along with -dip25 and -dip1000 flags gives three errors:

test_scope.d(42,13): Error: returning `s.opSlice()` escapes a reference to local variable `s`
test_scope.d(49,12): Error: returning `s.slice()` escapes a reference to local variable `s`
test_scope.d(56,12): Error: returning `s.range()` escapes a reference to local variable `s`

It's very nice that the scope-analysis figures out that even the `range` member function contains an escaping pointer to the owning struct.

However, the other two `testFront` and `testPointer` don't error. Why are these two simpler cases allowed to escape a scoped reference and pointer which both outlive the lifetime of the owning struct `S`?
October 09, 2017
On 10/9/2017 8:04 AM, Per Nordlöw wrote:
> I'm trying to figure out how to make my manually written containers have scope-aware element(s)-accessing functions. I've come up with 5 different situations as follows

I find it is hopeless to explain how this works with refs, arrays, member functions, etc. It's much simpler to rewrite anything you're unsure of as using nothing but pointers and free functions. (After all, the compiler lowers all that reference stuff to pointers and free functions anyway.)

Making it explicit where all the pointers and parameters are makes it a LOT easier to reason about how dip1000 works.

For example, replace:

  int[]
  a[0]

with:

  int*
  *a

Get rid of the templates, too. Replace T with int. Get rid of any of the layers of confusing complexity. Think "what does the compiler lower this construct to" and do that.

Once it is clear how the pointers works, then start adding the complexity back in.
October 10, 2017
On Tuesday, 10 October 2017 at 02:37:21 UTC, Walter Bright wrote:
> On 10/9/2017 8:04 AM, Per Nordlöw wrote:
>> ...
>
> Get rid of the templates, too. Replace T with int. Get rid of any of the layers of confusing complexity.
> ...

this looks like an issue to me. If its a template the pointer can escape. The non-template-version doesnt let the pointer escape

@safe:
struct ST( T) {
	@safe:
	T[ 128] x;
	scope ref T front() return {
		return x[ 0];
	}
	scope T* pointer() return {
		return &x[ 0];
	}
}
ref int testFrontT() {
	ST!int s;
	return s.front(); // pointer escapes
}
int* testPointerT() {
	ST!int s;
	return s.pointer(); // pointer escapes
}

struct S {
	@safe:
	int[ 128] x;
	scope ref int front() return {
		return x[ 0];
	}
	scope int* pointer() return {
		return &x[ 0];
	}
}
ref int testFront() {
	S s;
	return s.front(); // error
}
int* testPointer() {
	S s;
	return s.pointer(); // error
}
October 10, 2017
On Tuesday, 10 October 2017 at 09:55:13 UTC, meppl wrote:
> ...

also, these differ:
(with dmd v2.076.0)

@safe:
struct S {
	@safe:
	int* x;
	scope int* pointer() return {
		return x;
	}
}
int* testPointer() {
	S s;
	return s.pointer(); // no error
}
struct SA {
	@safe:
	int[ 128] x;
	scope int* pointer() return {
		return &x[ 0];
	}
}
int* testPointerA() {
	SA s;
	return s.pointer(); // error
}
October 10, 2017
On Tuesday, 10 October 2017 at 10:49:54 UTC, meppl wrote:
> On Tuesday, 10 October 2017 at 09:55:13 UTC, meppl wrote:
>> ...
>
> also, these differ:
> (with dmd v2.076.0)
>
> @safe:
> struct S {
> 	@safe:
> 	int* x;
> 	scope int* pointer() return {
> 		return x;
> 	}
> }
> int* testPointer() {
> 	S s;
> 	return s.pointer(); // no error
> }
> struct SA {
> 	@safe:
> 	int[ 128] x;
> 	scope int* pointer() return {
> 		return &x[ 0];
> 	}
> }
> int* testPointerA() {
> 	SA s;
> 	return s.pointer(); // error
> }

Report any bugs to the official bug tracker here: https://issues.dlang.org/
October 10, 2017
On Tuesday, 10 October 2017 at 14:12:04 UTC, 12345swordy wrote:
> Report any bugs to the official bug tracker here: https://issues.dlang.org/

Shall I file the bug?
October 10, 2017
On Tuesday, 10 October 2017 at 18:58:42 UTC, Nordlöw wrote:
> On Tuesday, 10 October 2017 at 14:12:04 UTC, 12345swordy wrote:
>> Report any bugs to the official bug tracker here: https://issues.dlang.org/
>
> Shall I file the bug?

I did it: https://issues.dlang.org/show_bug.cgi?id=17892
October 10, 2017
On 10/10/2017 3:31 PM, Nordlöw wrote:
> I did it: https://issues.dlang.org/show_bug.cgi?id=17892

Thank you!
October 11, 2017
On Wednesday, 11 October 2017 at 03:32:41 UTC, Walter Bright wrote:
> Thank you!

You're very welcome!