Bug 19743 – [dip1000] unclear error message when escaping variable through foreach `ref`

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2019-03-16T06:49:54Z
Last change time
2024-12-13T19:02:35Z
Keywords
diagnostic, safe
Assigned to
No Owner
Creator
Meta
Moved to GitHub: dmd#19542 →

Comments

Comment #0 by monkeyworks12 — 2019-03-16T06:49:54Z
I have the following code: Needle* find(Haystack, Needle)(return scope Haystack haystack, scope Needle needle) @safe { foreach (ref val; haystack) if (val == needle) return &val; //Error: scope variable __r2 may not be returned return null; } void main() @safe { int[9] haystack = [0, 10, 5, 6, 2, 3, 9, 4, 5]; int* foundVal = haystack.find(3); } From my understanding of `return scope` parameters, this should compile. However, the foreach loop desugars into the following: { int[] __r2 = haystack[]; ulong __key3 = 0LU; for (; __key3 < __r2.length; __key3 += 1LU) { ref int val = __r2[__key3]; if (val == needle) return &val; } } The slicing of the static array obscures the knowledge that `haystack` is `return scope` from the compiler. Furthermore, as `__r2` is inferred as `scope`, the compiler thinks that I am escaping a reference to a local `scope` variable, and does not allow this code to compile. Unfortunately, due to https://issues.dlang.org/show_bug.cgi?id=19742, writing a manually-desugared version does not quite work: for (auto i = 0; i < haystack.length; i++) if (haystack[i] == needle) return &haystack[i]; //Error: returning &haystack[cast(ulong)i] escapes a reference to parameter haystack, perhaps annotate with return
Comment #1 by dkorpel — 2022-11-04T21:08:10Z
Haystack in your example is an `int[9]`, a value type without pointers, so (return) scope doesn't apply to it. When you `return &val;`, you're escaping a pointer to the expired stack frame containing your `haystack` parameter, so an error is in place. To make `find` valid, your haystack should be passed by `ref`, and then it compiles: ``` int* find(return ref int[9] haystack, int needle) @safe { foreach (ref val; haystack) if (val == needle) return &val; return null; } void main() @safe { int[9] haystack = [0, 10, 5, 6, 2, 3, 9, 4, 5]; int* foundVal = haystack.find(3); } ``` However, "scope variable __r2 may not be returned" is not a good diagnostic, so I'm changing this issue to be about that.
Comment #2 by robert.schadek — 2024-12-13T19:02:35Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19542 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB