Skip to content

Commit 22021c7

Browse files
committed
Fix capturing NRVO variables
Fixes #3883 by capturing NRVO vars by ref - unless the nested context is a heap closure.
1 parent 63d18b4 commit 22021c7

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

gen/nested.cpp

+31-14
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,22 @@
2222
#include "ir/irtypeaggr.h"
2323
#include "llvm/Analysis/ValueTracking.h"
2424

25-
static unsigned getVthisIdx(AggregateDeclaration *ad) {
25+
namespace {
26+
unsigned getVthisIdx(AggregateDeclaration *ad) {
2627
return getFieldGEPIndex(ad, ad->vthis);
2728
}
2829

30+
bool isNRVOVar(VarDeclaration *vd) {
31+
if (auto fd = vd->toParent2()->isFuncDeclaration())
32+
return fd->nrvo_can && vd == fd->nrvo_var && !fd->needsClosure();
33+
return false;
34+
}
35+
36+
bool captureByRef(VarDeclaration *vd) {
37+
return vd->isReference() || isNRVOVar(vd);
38+
}
39+
} // anonymous namespace
40+
2941
static void DtoCreateNestedContextType(FuncDeclaration *fd);
3042

3143
DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
@@ -153,15 +165,14 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
153165
Logger::cout() << "Addr: " << *val << '\n';
154166
Logger::cout() << "of type: " << *val->getType() << '\n';
155167
}
156-
const bool isRefOrOut = vd->isRef() || vd->isOut();
157168
if (isSpecialRefVar(vd)) {
158169
// Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass
159170
// storage of pointer (reference lvalue).
160-
} else if (byref || isRefOrOut) {
171+
} else if (byref || captureByRef(vd)) {
161172
val = DtoAlignedLoad(val);
162173
// ref/out variables get a reference-debuginfo-type in EmitLocalVariable()
163174
// => don't dereference, use reference lvalue as address
164-
if (!isRefOrOut)
175+
if (!vd->isReference())
165176
gIR->DBuilder.OpDeref(dwarfAddrOps);
166177
IF_LOG {
167178
Logger::cout() << "Was byref, now: " << *irLocal->value << '\n';
@@ -396,7 +407,7 @@ static void DtoCreateNestedContextType(FuncDeclaration *fd) {
396407
irLocal.nestedDepth = depth;
397408

398409
LLType *t = nullptr;
399-
if (vd->isRef() || vd->isOut()) {
410+
if (captureByRef(vd)) {
400411
t = DtoType(vd->type->pointerTo());
401412
} else if (isParam && (vd->storage_class & STClazy)) {
402413
// the type is a delegate (LL struct)
@@ -494,31 +505,37 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
494505
assert(parm->value);
495506
assert(parm->value->getType()->isPointerTy());
496507

497-
if (vd->isRef() || vd->isOut()) {
508+
if (vd->isReference()) {
498509
Logger::println(
499510
"Captured by reference, copying pointer to nested frame");
500511
DtoAlignedStore(parm->value, gep);
501512
// pass GEP as reference lvalue to EmitLocalVariable()
502513
} else {
503-
Logger::println("Copying to nested frame");
514+
Logger::println("Moving to nested frame");
504515
// The parameter value is an alloca'd stack slot.
505516
// Copy to the nesting frame and leave the alloca for
506517
// the optimizers to clean up.
507518
DtoMemCpy(gep, parm->value);
508519
gep->takeName(parm->value);
509-
parm->value = gep;
520+
parm->value = gep; // update variable lvalue
510521
}
522+
} else if (isNRVOVar(vd)) {
523+
IF_LOG Logger::println(
524+
"nested NRVO var: %s, copying pointer to nested frame",
525+
vd->toChars());
526+
assert(irFunc.sretArg);
527+
DtoAlignedStore(irFunc.sretArg, gep);
528+
assert(!irLocal->value);
529+
irLocal->value = irFunc.sretArg;
530+
gep = irFunc.sretArg; // lvalue for debuginfo
511531
} else {
512-
IF_LOG Logger::println("nested var: %s", vd->toChars());
532+
IF_LOG Logger::println("nested var: %s, allocating in nested frame",
533+
vd->toChars());
513534
assert(!irLocal->value);
514535
irLocal->value = gep;
515536
}
516537

517-
if (global.params.symdebug) {
518-
LLSmallVector<int64_t, 1> dwarfAddrOps;
519-
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, false, false,
520-
dwarfAddrOps);
521-
}
538+
gIR->DBuilder.EmitLocalVariable(gep, vd);
522539
}
523540
}
524541
}

tests/codegen/nested_nrvo_gh3883.d

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// https://github.com/ldc-developers/ldc/issues/3883
2+
// RUN: %ldc -run %s
3+
4+
struct S {
5+
int x;
6+
~this() {}
7+
}
8+
9+
__gshared S* ptr;
10+
11+
S foo() {
12+
auto result = S(123);
13+
(() @trusted { result.x++; ptr = &result; })();
14+
return result;
15+
}
16+
17+
void main() {
18+
auto r = foo();
19+
assert(r.x == 124);
20+
assert(&r == ptr);
21+
}

0 commit comments

Comments
 (0)