Skip to content

Commit 6832231

Browse files
committed
Speculatively call copy constructor when returning in foreach
1 parent edc93a7 commit 6832231

5 files changed

Lines changed: 102 additions & 1 deletion

File tree

compiler/src/dmd/funcsem.d

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,15 @@ extern (D) void declareThis(FuncDeclaration fd, Scope* sc)
16871687
fd.vthis.parent = fd;
16881688
if (ad)
16891689
fd.objc.selectorParameter = .objc.createSelectorParameter(fd, sc);
1690+
1691+
if (fd.fes && !fd.vthis._scope)
1692+
{
1693+
/* If foreach nested function, save the scope to allow outer semantic
1694+
* to access internal context pointer.
1695+
*/
1696+
fd.vthis._scope = sc.copy();
1697+
fd.vthis._scope.setNoFree();
1698+
}
16901699
}
16911700

16921701
/****************************************************

compiler/src/dmd/semantic3.d

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,14 @@ private extern(C++) final class Semantic3Visitor : Visitor
975975

976976
if (funcdecl.vresult)
977977
{
978-
Scope* scret = rs.fesFunc ? rs.fesFunc._scope : sc2;
978+
Scope* scret = sc2;
979+
980+
if (rs.fesFunc)
981+
{
982+
// Borrow context pointer's scope for vresult.
983+
assert(rs.fesFunc.vthis);
984+
scret = rs.fesFunc.vthis._scope;
985+
}
979986

980987
// Create: return (vresult = exp, vresult);
981988
exp = new ConstructExp(rs.loc, funcdecl.vresult, exp);

compiler/src/dmd/statementsem.d

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2774,6 +2774,21 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
27742774
* return x; return 3; // ok, x can be a value
27752775
*/
27762776
}
2777+
2778+
if (rs.fesFunc &&
2779+
(!tf.isRef || (fd.storage_class & STC.auto_)))
2780+
{
2781+
/* In foreach inside non-ref or auto ref functions,
2782+
* invoke copy/move constructor but ignore errors.
2783+
* This relaxes attributes for the nested function and
2784+
* allows semantic3 to generate the copy.
2785+
* If the parent's attributes reject such a copy,
2786+
* semantic3 would still error out.
2787+
*/
2788+
const olderrors = global.startGagging();
2789+
doCopyOrMove(sc, rs.exp, rs.exp.type, false, true);
2790+
global.endGagging(olderrors);
2791+
}
27772792
}
27782793
else
27792794
{
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
TEST_OUTPUT:
3+
---
4+
fail_compilation/issue22666.d(25): Error: function `issue22666.V4.opApply(int delegate(Object) @safe dg)` is not callable using argument types `(int delegate(Object _) nothrow @system)`
5+
fail_compilation/issue22666.d(25): cannot pass argument `int(Object _) => s` of type `int delegate(Object _) nothrow @system` to parameter `int delegate(Object) @safe dg`
6+
7+
---
8+
*/
9+
struct S4
10+
{
11+
this(ref inout S4) @system {}
12+
}
13+
14+
struct V4
15+
{
16+
int opApply(int delegate(Object) @safe dg)
17+
{
18+
return dg(null);
19+
}
20+
}
21+
22+
S4 h4()
23+
{
24+
S4 s = S4();
25+
foreach (_; V4())
26+
{
27+
return s;
28+
}
29+
return S4();
30+
}
31+
32+
void main()
33+
{
34+
h4();
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// REQUIRED_ARGS: -betterC
2+
3+
struct Arr(T, int CAPACITY)
4+
{
5+
int count = 0;
6+
T[CAPACITY] items;
7+
int opApply(scope int delegate(T) dg)
8+
{
9+
int result;
10+
for (int i = 0; i < count; i++)
11+
if ((result = dg(items[i])) != 0)
12+
break;
13+
return result;
14+
}
15+
}
16+
17+
struct Foo {}
18+
struct Bar {
19+
Arr!(Foo*, 32) array;
20+
Foo* get()
21+
{
22+
foreach(Foo* it; array)
23+
{
24+
return it;
25+
}
26+
return null;
27+
}
28+
}
29+
30+
Foo* foo;
31+
Bar bar;
32+
extern(C) void main()
33+
{
34+
foo = bar.get();
35+
}

0 commit comments

Comments
 (0)