Bug 12936 – Some more @nogc cases for immediately iterated array literal
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-06-16T16:59:06Z
Last change time
2022-08-25T10:59:31Z
Keywords
pull
Assigned to
No Owner
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2014-06-16T16:59:06Z
This is a spinoff of Issue 12932
See this code:
struct F { int x; }
void main() @nogc {
foreach ( a; [F(1)]) {} // Case#1 OK
foreach (int[1] a; [[1]]) {} // Case#2 Error
foreach (const ref int[1] a; [[1]]) {} // Case#3 Error
foreach ( a; [[1]]) {} // Case#4 Error
}
With dmd2.066alpha gives:
test.d(4,25): Error: array literal in @nogc function main may cause GC allocation
test.d(5,5): Error: argument type mismatch, int[] to ref const(int[1])
test.d(6,25): Error: array literal in @nogc function main may cause GC allocation
Currently the Case#1 works. I think Case#2 could work because it's supposed to be a dynamic array of int[1] values.
I am not sure we can also support the Case#4, this is more complex, and perhaps needs escape analisys. So not supporting Case#4 is acceptable for now.
Case#4 currently doesn't even compile even without @nogc, but perhaps it should without @nogc.
Comment #1 by bearophile_hugs — 2015-03-11T09:53:40Z
A different case where the compiler should avoid heap allocations and allow @nogc:
void main() @nogc {
int[3] a;
a[] = [1, 2, 3];
a[0 .. 2] = [1, 2];
}
temp.d(3,11): Error: array literal in @nogc function main may cause GC allocation
temp.d(4,17): Error: array literal in @nogc function main may cause GC allocation
Comment #2 by k.hara.pg — 2016-05-19T13:05:57Z
(In reply to bearophile_hugs from comment #0)
>
> struct F { int x; }
> void main() @nogc {
> foreach ( a; [F(1)]) {} // Case#1 OK
> foreach (int[1] a; [[1]]) {} // Case#2 Error
> foreach (const ref int[1] a; [[1]]) {} // Case#3 Error
> foreach ( a; [[1]]) {} // Case#4 Error
> }
For case#2, it's possible enhancement because int[1] a is a copy of iterated array literal element.
For case#3, it's not safe because an address of stack allocated array literal can escape out of the lifetime.
const(int)* p;
foreach (const ref int[1] a; [[1]]) { p = &a[0]; }
// After the foreach, p wold point invalid stack address.
Note that similar situation is properly rejected.
void foo(ref int[1] sa) {}
void main() {
foo([1]); // array literal never become stack allocated because
// its address can escape out via the ref parameter.
}
For case#4 supporting it would cause inconsistent type inference result.
void foo() {
foreach (a; [[1]]) { pragma(msg, typeof(a)); } // prints int[]
}
void bar() @nogc {
foreach (a; [[1]]) { pragma(msg, typeof(a)); } // prints int[] or int[1]?
}
I opened a compiler improvement for case#2:
https://github.com/dlang/dmd/pull/5795
Comment #3 by github-bugzilla — 2016-08-10T17:52:31Z