Bug 19966 – [DIP1000] DIP1000 with a template behaves differently

Status
RESOLVED
Resolution
INVALID
Severity
critical
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2019-06-14T12:17:35Z
Last change time
2020-03-13T10:21:07Z
Keywords
safe
Assigned to
No Owner
Creator
Jacob Carlborg

Comments

Comment #0 by doob — 2019-06-14T12:17:35Z
The following code compile successfully with DIP1000 enabled: struct Foo() { int* bar; int* foo() @safe return { return bar; } } int* a; void main() @safe { Foo!() f; a = f.foo; } But if `Foo` is not a template it fails to compile, complaining that the return value of `foo` outlives `f`. I think there are two errors here: 1. `Foo` as a template and as a non-template struct behaves differently 2. I think the above code is actually valid because it's not provable that `foo` escapes a pointer to the internal state of `Foo`
Comment #1 by bugzilla — 2020-03-13T09:18:06Z
> 2. I think the above code is actually valid because it's not provable that `foo` escapes a pointer to the internal state of `Foo` It's not valid because foo() is defined as returning a pointer that is equivalent to foo()'s `this` pointer. Then, `a = f.foo;` is treated as assigning the address of `f` to `a`, a global, which is an error. The compiler is behaving correctly for this point.
Comment #2 by doob — 2020-03-13T09:26:47Z
(In reply to Walter Bright from comment #1) > > 2. I think the above code is actually valid because it's not provable that `foo` escapes a pointer to the internal state of `Foo` > > It's not valid because foo() is defined as returning a pointer that is > equivalent to foo()'s `this` pointer. Then, `a = f.foo;` is treated as > assigning the address of `f` to `a`, a global, which is an error. The > compiler is behaving correctly for this point. So it doesn't matter if "foo" is returning something else, like a global variable?
Comment #3 by bugzilla — 2020-03-13T09:28:12Z
> 1. `Foo` as a template and as a non-template struct behaves differently What's happening is that when `Foo` is a template, then inference happens with `foo()`, which infers that `this.bar` is being returned, not `this`. You can verify this by removing the function body for `foo()` so inference cannot happen, and then the error appears, because without inference the `return` applies to `this`, not `this.bar`. Not a bug.
Comment #4 by bugzilla — 2020-03-13T09:29:47Z
> So it doesn't matter if "foo" is returning something else, like a global variable? If inference is not happening, then the compiler believes you when you say it is returning the `this` pointer. This is a feature, not a bug, as it enables you to attach the checking to the `this` pointer.
Comment #5 by doob — 2020-03-13T09:39:00Z
(In reply to Walter Bright from comment #3) > > 1. `Foo` as a template and as a non-template struct behaves differently > > What's happening is that when `Foo` is a template, then inference happens > with `foo()`, which infers that `this.bar` is being returned, not `this`. > You can verify this by removing the function body for `foo()` so inference > cannot happen, and then the error appears, because without inference the > `return` applies to `this`, not `this.bar`. > > Not a bug. Is it possible to somehow get the behavior I want? To make sure that some internal state of "f" cannot outlive "f" itself.
Comment #6 by doob — 2020-03-13T09:47:36Z
(In reply to Walter Bright from comment #3) > > 1. `Foo` as a template and as a non-template struct behaves differently > > What's happening is that when `Foo` is a template, then inference happens > with `foo()`, which infers that `this.bar` is being returned, not `this`. > You can verify this by removing the function body for `foo()` so inference > cannot happen, and then the error appears, because without inference the > `return` applies to `this`, not `this.bar`. > > Not a bug. But is it possible to get what I want somehow? To make sure no internal state of "f" outlives "f" itself.
Comment #7 by bugzilla — 2020-03-13T10:21:07Z
That's what @live is for.