mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 00:20:40 +03:00
Properly handle DMD-internal "reference variables".
Previously, we just had a hack to make ref foreach statements work. This commit enables them to work in other cases as well, like the implicit __result variable for functions with out-contracts (which is such a magic ref variable for ref-returning functions). Fixes DMD testcase 'testcontracts'.
This commit is contained in:
parent
6b1b84a28d
commit
ee4285f934
8 changed files with 173 additions and 172 deletions
|
@ -16,6 +16,8 @@ DVarValue::DVarValue(Type* t, VarDeclaration* vd, LLValue* llvmValue)
|
||||||
: DValue(t), var(vd), val(llvmValue)
|
: DValue(t), var(vd), val(llvmValue)
|
||||||
{
|
{
|
||||||
assert(isaPointer(llvmValue));
|
assert(isaPointer(llvmValue));
|
||||||
|
assert(!isSpecialRefVar(vd) ||
|
||||||
|
isaPointer(isaPointer(llvmValue)->getElementType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
DVarValue::DVarValue(Type* t, LLValue* llvmValue)
|
DVarValue::DVarValue(Type* t, LLValue* llvmValue)
|
||||||
|
@ -27,6 +29,8 @@ DVarValue::DVarValue(Type* t, LLValue* llvmValue)
|
||||||
LLValue* DVarValue::getLVal()
|
LLValue* DVarValue::getLVal()
|
||||||
{
|
{
|
||||||
assert(val);
|
assert(val);
|
||||||
|
if (var && isSpecialRefVar(var))
|
||||||
|
return DtoLoad(val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +38,14 @@ LLValue* DVarValue::getRVal()
|
||||||
{
|
{
|
||||||
assert(val);
|
assert(val);
|
||||||
Type* bt = type->toBasetype();
|
Type* bt = type->toBasetype();
|
||||||
|
|
||||||
|
LLValue* tmp = val;
|
||||||
|
if (var && isSpecialRefVar(var))
|
||||||
|
tmp = DtoLoad(tmp);
|
||||||
|
|
||||||
if (DtoIsPassedByRef(bt))
|
if (DtoIsPassedByRef(bt))
|
||||||
return val;
|
return tmp;
|
||||||
return DtoLoad(val);
|
return DtoLoad(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -815,8 +815,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
{
|
{
|
||||||
DtoNestedInit(fd->vresult);
|
DtoNestedInit(fd->vresult);
|
||||||
} else if (fd->vresult) {
|
} else if (fd->vresult) {
|
||||||
fd->vresult->ir.irLocal = new IrLocal(fd->vresult);
|
DtoVarDeclaration(fd->vresult);
|
||||||
fd->vresult->ir.irLocal->value = DtoAlloca(fd->vresult->type, fd->vresult->toChars());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy _argptr and _arguments to a memory location
|
// copy _argptr and _arguments to a memory location
|
||||||
|
|
|
@ -1013,6 +1013,110 @@ void DtoConstInitGlobal(VarDeclaration* vd)
|
||||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// DECLARATION EXP HELPER
|
// DECLARATION EXP HELPER
|
||||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
// TODO: Merge with DtoRawVarDeclaration!
|
||||||
|
void DtoVarDeclaration(VarDeclaration* vd)
|
||||||
|
{
|
||||||
|
assert(!vd->isDataseg() && "Statics/globals are handled in DtoDeclarationExp.");
|
||||||
|
assert(!vd->aliassym && "Aliases are handled in DtoDeclarationExp.");
|
||||||
|
|
||||||
|
Logger::println("vdtype = %s", vd->type->toChars());
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
if (vd->nestedrefs.dim)
|
||||||
|
#else
|
||||||
|
if (vd->nestedref)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Logger::println("has nestedref set (referenced by nested function/delegate)");
|
||||||
|
assert(vd->ir.irLocal);
|
||||||
|
DtoNestedInit(vd);
|
||||||
|
}
|
||||||
|
else if(vd->ir.irLocal)
|
||||||
|
{
|
||||||
|
// Nothing to do if it has already been allocated.
|
||||||
|
}
|
||||||
|
#if DMDV2
|
||||||
|
/* Named Return Value Optimization (NRVO):
|
||||||
|
T f(){
|
||||||
|
T ret; // &ret == hidden pointer
|
||||||
|
ret = ...
|
||||||
|
return ret; // NRVO.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) {
|
||||||
|
assert(!isSpecialRefVar(vd) && "Can this happen?");
|
||||||
|
vd->ir.irLocal = new IrLocal(vd);
|
||||||
|
vd->ir.irLocal->value = gIR->func()->retArg;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// normal stack variable, allocate storage on the stack if it has not already been done
|
||||||
|
else {
|
||||||
|
vd->ir.irLocal = new IrLocal(vd);
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
/* NRVO again:
|
||||||
|
T t = f(); // t's memory address is taken hidden pointer
|
||||||
|
*/
|
||||||
|
ExpInitializer *ei = 0;
|
||||||
|
if (vd->type->toBasetype()->ty == Tstruct && vd->init &&
|
||||||
|
!!(ei = vd->init->isExpInitializer()))
|
||||||
|
{
|
||||||
|
if (ei->exp->op == TOKconstruct) {
|
||||||
|
AssignExp *ae = static_cast<AssignExp*>(ei->exp);
|
||||||
|
if (ae->e2->op == TOKcall) {
|
||||||
|
CallExp *ce = static_cast<CallExp *>(ae->e2);
|
||||||
|
TypeFunction *tf = static_cast<TypeFunction *>(ce->e1->type->toBasetype());
|
||||||
|
if (tf->ty == Tfunction && tf->fty.arg_sret) {
|
||||||
|
LLValue* const val = ce->toElem(gIR)->getLVal();
|
||||||
|
if (isSpecialRefVar(vd))
|
||||||
|
{
|
||||||
|
vd->ir.irLocal->value = DtoAlloca(
|
||||||
|
vd->type->pointerTo(), vd->toChars());
|
||||||
|
DtoStore(val, vd->ir.irLocal->value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vd->ir.irLocal->value = val;
|
||||||
|
}
|
||||||
|
goto Lexit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type;
|
||||||
|
LLType* lltype = DtoType(type);
|
||||||
|
|
||||||
|
llvm::Value* allocainst;
|
||||||
|
if(gTargetData->getTypeSizeInBits(lltype) == 0)
|
||||||
|
allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype));
|
||||||
|
else
|
||||||
|
allocainst = DtoAlloca(type, vd->toChars());
|
||||||
|
|
||||||
|
vd->ir.irLocal->value = allocainst;
|
||||||
|
|
||||||
|
DtoDwarfLocalVariable(allocainst, vd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Logger::enabled())
|
||||||
|
Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n';
|
||||||
|
|
||||||
|
DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether?
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
Lexit:
|
||||||
|
/* Mark the point of construction of a variable that needs to be destructed.
|
||||||
|
*/
|
||||||
|
if (vd->edtor && !vd->noscope)
|
||||||
|
{
|
||||||
|
// Put vd on list of things needing destruction
|
||||||
|
gIR->varsInScope().push_back(vd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
DValue* DtoDeclarationExp(Dsymbol* declaration)
|
DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||||
{
|
{
|
||||||
Logger::print("DtoDeclarationExp: %s\n", declaration->toChars());
|
Logger::print("DtoDeclarationExp: %s\n", declaration->toChars());
|
||||||
|
@ -1036,123 +1140,8 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (global.params.llvmAnnotate)
|
DtoVarDeclaration(vd);
|
||||||
DtoAnnotation(declaration->toChars());
|
|
||||||
|
|
||||||
Logger::println("vdtype = %s", vd->type->toChars());
|
|
||||||
|
|
||||||
// ref vardecls are generated when DMD lowers foreach to a for statement,
|
|
||||||
// and this is a hack to support them for this case only
|
|
||||||
if(vd->isRef())
|
|
||||||
{
|
|
||||||
if (!vd->ir.irLocal)
|
|
||||||
vd->ir.irLocal = new IrLocal(vd);
|
|
||||||
|
|
||||||
ExpInitializer* ex = vd->init->isExpInitializer();
|
|
||||||
assert(ex && "ref vars must have expression initializer");
|
|
||||||
assert(ex->exp);
|
|
||||||
AssignExp* as = ex->exp->isAssignExp();
|
|
||||||
assert(as && "ref vars must be initialized by an assign exp");
|
|
||||||
DValue *val = as->e2->toElem(gIR);
|
|
||||||
if (val->isLVal())
|
|
||||||
{
|
|
||||||
vd->ir.irLocal->value = val->getLVal();
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
LLValue *newVal = DtoAlloca(val->type);
|
|
||||||
DtoStore(val->getRVal(), newVal);
|
|
||||||
vd->ir.irLocal->value = newVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// referenced by nested delegate?
|
|
||||||
#if DMDV2
|
|
||||||
if (vd->nestedrefs.dim) {
|
|
||||||
#else
|
|
||||||
if (vd->nestedref) {
|
|
||||||
#endif
|
|
||||||
Logger::println("has nestedref set");
|
|
||||||
assert(vd->ir.irLocal);
|
|
||||||
DtoNestedInit(vd);
|
|
||||||
// is it already allocated?
|
|
||||||
} else if(vd->ir.irLocal) {
|
|
||||||
// nothing to do...
|
|
||||||
}
|
|
||||||
#if DMDV2
|
|
||||||
/* Named Return Value Optimization (NRVO):
|
|
||||||
T f(){
|
|
||||||
T ret; // &ret == hidden pointer
|
|
||||||
ret = ...
|
|
||||||
return ret; // NRVO.
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) {
|
|
||||||
vd->ir.irLocal = new IrLocal(vd);
|
|
||||||
vd->ir.irLocal->value = gIR->func()->retArg;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// normal stack variable, allocate storage on the stack if it has not already been done
|
|
||||||
else if(!vd->isRef()) {
|
|
||||||
vd->ir.irLocal = new IrLocal(vd);
|
|
||||||
|
|
||||||
#if DMDV2
|
|
||||||
/* NRVO again:
|
|
||||||
T t = f(); // t's memory address is taken hidden pointer
|
|
||||||
*/
|
|
||||||
ExpInitializer *ei = 0;
|
|
||||||
if (vd->type->toBasetype()->ty == Tstruct && vd->init &&
|
|
||||||
!!(ei = vd->init->isExpInitializer()))
|
|
||||||
{
|
|
||||||
if (ei->exp->op == TOKconstruct) {
|
|
||||||
AssignExp *ae = static_cast<AssignExp*>(ei->exp);
|
|
||||||
if (ae->e2->op == TOKcall) {
|
|
||||||
CallExp *ce = static_cast<CallExp *>(ae->e2);
|
|
||||||
TypeFunction *tf = static_cast<TypeFunction *>(ce->e1->type->toBasetype());
|
|
||||||
if (tf->ty == Tfunction && tf->fty.arg_sret) {
|
|
||||||
vd->ir.irLocal->value = ce->toElem(gIR)->getLVal();
|
|
||||||
goto Lexit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LLType* lltype = DtoType(vd->type);
|
|
||||||
|
|
||||||
llvm::Value* allocainst;
|
|
||||||
if(gTargetData->getTypeSizeInBits(lltype) == 0)
|
|
||||||
allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype));
|
|
||||||
else
|
|
||||||
allocainst = DtoAlloca(vd->type, vd->toChars());
|
|
||||||
|
|
||||||
//allocainst->setAlignment(vd->type->alignsize()); // TODO
|
|
||||||
vd->ir.irLocal->value = allocainst;
|
|
||||||
|
|
||||||
DtoDwarfLocalVariable(allocainst, vd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(vd->ir.irLocal->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Logger::enabled())
|
|
||||||
Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n';
|
|
||||||
if (!vd->isRef())
|
|
||||||
DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether?
|
|
||||||
|
|
||||||
#if DMDV2
|
|
||||||
Lexit:
|
|
||||||
/* Mark the point of construction of a variable that needs to be destructed.
|
|
||||||
*/
|
|
||||||
if (vd->edtor && !vd->noscope)
|
|
||||||
{
|
|
||||||
// Put vd on list of things needing destruction
|
|
||||||
gIR->varsInScope().push_back(vd);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DVarValue(vd->type, vd, vd->ir.getIrValue());
|
return new DVarValue(vd->type, vd, vd->ir.getIrValue());
|
||||||
}
|
}
|
||||||
// struct declaration
|
// struct declaration
|
||||||
|
@ -1921,6 +1910,13 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool isSpecialRefVar(VarDeclaration* vd)
|
||||||
|
{
|
||||||
|
return (vd->storage_class & STCref) && (vd->storage_class & STCforeach);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void printLabelName(std::ostream& target, const char* func_mangle, const char* label_name)
|
void printLabelName(std::ostream& target, const char* func_mangle, const char* label_name)
|
||||||
{
|
{
|
||||||
target << gTargetMachine->getMCAsmInfo()->getPrivateGlobalPrefix() <<
|
target << gTargetMachine->getMCAsmInfo()->getPrivateGlobalPrefix() <<
|
||||||
|
|
|
@ -98,6 +98,7 @@ void DtoResolveDsymbol(Dsymbol* dsym);
|
||||||
void DtoConstInitGlobal(VarDeclaration* vd);
|
void DtoConstInitGlobal(VarDeclaration* vd);
|
||||||
|
|
||||||
// declaration inside a declarationexp
|
// declaration inside a declarationexp
|
||||||
|
void DtoVarDeclaration(VarDeclaration* var);
|
||||||
DValue* DtoDeclarationExp(Dsymbol* declaration);
|
DValue* DtoDeclarationExp(Dsymbol* declaration);
|
||||||
LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr = 0);
|
LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr = 0);
|
||||||
|
|
||||||
|
@ -158,6 +159,14 @@ LLValue* makeLValue(Loc& loc, DValue* value);
|
||||||
void callPostblit(Loc &loc, Expression *exp, LLValue *val);
|
void callPostblit(Loc &loc, Expression *exp, LLValue *val);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Returns whether the given variable is a DMD-internal "ref variable".
|
||||||
|
///
|
||||||
|
/// D doesn't have reference variables (the ref keyword is only usable in
|
||||||
|
/// function signatures and foreach headers), but the DMD frontend internally
|
||||||
|
/// creates them in cases like lowering a ref foreach to a for loop or the
|
||||||
|
/// implicit __result variable for ref-return functions with out contracts.
|
||||||
|
bool isSpecialRefVar(VarDeclaration* vd);
|
||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// gen/tocall.cpp stuff below
|
// gen/tocall.cpp stuff below
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
|
|
|
@ -211,7 +211,7 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
|
||||||
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
|
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
|
||||||
Logger::cout() << "Addr: " << *val << '\n';
|
Logger::cout() << "Addr: " << *val << '\n';
|
||||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||||
if (vd->ir.irLocal->byref || byref) {
|
if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) {
|
||||||
val = DtoAlignedLoad(val);
|
val = DtoAlignedLoad(val);
|
||||||
//dwarfOpDeref(dwarfAddr);
|
//dwarfOpDeref(dwarfAddr);
|
||||||
Logger::cout() << "Was byref, now: " << *val << '\n';
|
Logger::cout() << "Was byref, now: " << *val << '\n';
|
||||||
|
@ -251,27 +251,7 @@ void DtoNestedInit(VarDeclaration* vd)
|
||||||
DtoAlignedStore(val, gep);
|
DtoAlignedStore(val, gep);
|
||||||
}
|
}
|
||||||
else if (nestedCtx == NCHybrid) {
|
else if (nestedCtx == NCHybrid) {
|
||||||
assert(vd->ir.irLocal->value && "Nested variable without storage?");
|
// Already initialized in DtoCreateNestedContext.
|
||||||
|
|
||||||
if (!vd->isParameter() && (vd->isRef() || vd->isOut())) {
|
|
||||||
unsigned vardepth = vd->ir.irLocal->nestedDepth;
|
|
||||||
|
|
||||||
LLValue* val = NULL;
|
|
||||||
// Retrieve frame pointer
|
|
||||||
if (vardepth == irfunc->depth) {
|
|
||||||
val = nestedVar;
|
|
||||||
} else {
|
|
||||||
FuncDeclaration *parentfunc = getParentFunc(vd, true);
|
|
||||||
assert(parentfunc && "No parent function for nested variable?");
|
|
||||||
|
|
||||||
val = DtoGEPi(nestedVar, 0, vardepth);
|
|
||||||
val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str());
|
|
||||||
}
|
|
||||||
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
|
|
||||||
storeVariable(vd, val);
|
|
||||||
} else {
|
|
||||||
// Already initialized in DtoCreateNestedContext
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(0 && "Not implemented yet");
|
assert(0 && "Not implemented yet");
|
||||||
|
@ -492,18 +472,13 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
||||||
type = type->getContainedType(0);
|
type = type->getContainedType(0);
|
||||||
else
|
else
|
||||||
type = DtoType(vd->type);
|
type = DtoType(vd->type);
|
||||||
vd->ir.irParam->byref = false;
|
|
||||||
} else {
|
} else {
|
||||||
vd->ir.irParam->byref = true;
|
|
||||||
}
|
}
|
||||||
types.push_back(type);
|
types.push_back(type);
|
||||||
} else if (vd->isRef() || vd->isOut()) {
|
} else if (isSpecialRefVar(vd)) {
|
||||||
// Foreach variables can also be by reference, for instance.
|
|
||||||
types.push_back(DtoType(vd->type->pointerTo()));
|
types.push_back(DtoType(vd->type->pointerTo()));
|
||||||
vd->ir.irLocal->byref = true;
|
|
||||||
} else {
|
} else {
|
||||||
types.push_back(DtoType(vd->type));
|
types.push_back(DtoType(vd->type));
|
||||||
vd->ir.irLocal->byref = false;
|
|
||||||
}
|
}
|
||||||
if (Logger::enabled()) {
|
if (Logger::enabled()) {
|
||||||
Logger::println("Nested var: %s", vd->toChars());
|
Logger::println("Nested var: %s", vd->toChars());
|
||||||
|
@ -692,36 +667,26 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||||
if (vd->isParameter()) {
|
if (vd->isParameter()) {
|
||||||
Logger::println("nested param: %s", vd->toChars());
|
Logger::println("nested param: %s", vd->toChars());
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
LLValue* value = vd->ir.irLocal->value;
|
IrParameter* parm = vd->ir.irParam;
|
||||||
if (llvm::isa<llvm::AllocaInst>(llvm::GetUnderlyingObject(value))) {
|
|
||||||
|
if (parm->arg->byref)
|
||||||
|
{
|
||||||
|
storeVariable(vd, gep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Logger::println("Copying to nested frame");
|
Logger::println("Copying to nested frame");
|
||||||
// The parameter value is an alloca'd stack slot.
|
// The parameter value is an alloca'd stack slot.
|
||||||
// Copy to the nesting frame and leave the alloca for
|
// Copy to the nesting frame and leave the alloca for
|
||||||
// the optimizers to clean up.
|
// the optimizers to clean up.
|
||||||
assert(!vd->ir.irLocal->byref);
|
DtoStore(DtoLoad(parm->value), gep);
|
||||||
DtoStore(DtoLoad(value), gep);
|
gep->takeName(parm->value);
|
||||||
gep->takeName(value);
|
parm->value = gep;
|
||||||
vd->ir.irLocal->value = gep;
|
|
||||||
} else {
|
|
||||||
Logger::println("Adding pointer to nested frame");
|
|
||||||
// The parameter value is something else, such as a
|
|
||||||
// passed-in pointer (for 'ref' or 'out' parameters) or
|
|
||||||
// a pointer arg with byval attribute.
|
|
||||||
// Store the address into the frame.
|
|
||||||
assert(vd->ir.irLocal->byref);
|
|
||||||
storeVariable(vd, gep);
|
|
||||||
}
|
}
|
||||||
} else if (vd->isRef() || vd->isOut()) {
|
|
||||||
// This slot is initialized in DtoNestedInit, to handle things like byref foreach variables
|
|
||||||
// which move around in memory.
|
|
||||||
assert(vd->ir.irLocal->byref);
|
|
||||||
} else {
|
} else {
|
||||||
Logger::println("nested var: %s", vd->toChars());
|
Logger::println("nested var: %s", vd->toChars());
|
||||||
if (vd->ir.irLocal->value)
|
|
||||||
Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n';
|
|
||||||
assert(!vd->ir.irLocal->value);
|
assert(!vd->ir.irLocal->value);
|
||||||
vd->ir.irLocal->value = gep;
|
vd->ir.irLocal->value = gep;
|
||||||
assert(!vd->ir.irLocal->byref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.params.symdebug) {
|
if (global.params.symdebug) {
|
||||||
|
|
24
gen/toir.cpp
24
gen/toir.cpp
|
@ -583,6 +583,30 @@ DValue* AssignExp::toElem(IRState* p)
|
||||||
return newlen;
|
return newlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can't just override ConstructExp::toElem because not all TOKconstruct
|
||||||
|
// operations are actually instances of ConstructExp... Long live the DMD
|
||||||
|
// coding style!
|
||||||
|
if (op == TOKconstruct)
|
||||||
|
{
|
||||||
|
if (e1->op == TOKvar)
|
||||||
|
{
|
||||||
|
VarExp* ve = (VarExp*)e1;
|
||||||
|
if (ve->var->storage_class & STCref)
|
||||||
|
{
|
||||||
|
// Note that the variable value is accessed directly (instead
|
||||||
|
// of via getLValue(), which would perform a load from the
|
||||||
|
// uninitialized location), and that rhs is stored as an l-value!
|
||||||
|
|
||||||
|
IrLocal* const local = ve->var->ir.irLocal;
|
||||||
|
assert(local && "ref var must be local and already initialized");
|
||||||
|
|
||||||
|
DValue* rhs = e2->toElem(p);
|
||||||
|
DtoStore(rhs->getLVal(), local->value);
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Logger::println("performing normal assignment");
|
Logger::println("performing normal assignment");
|
||||||
|
|
||||||
DValue* l = e1->toElem(p);
|
DValue* l = e1->toElem(p);
|
||||||
|
|
|
@ -31,7 +31,6 @@ IrGlobal::IrGlobal(VarDeclaration* v): IrVar(v)
|
||||||
IrLocal::IrLocal(VarDeclaration* v) : IrVar(v)
|
IrLocal::IrLocal(VarDeclaration* v) : IrVar(v)
|
||||||
{
|
{
|
||||||
nestedIndex = -1;
|
nestedIndex = -1;
|
||||||
byref = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -28,8 +28,8 @@ struct IrLocal : IrVar
|
||||||
{
|
{
|
||||||
IrLocal(VarDeclaration* v);
|
IrLocal(VarDeclaration* v);
|
||||||
|
|
||||||
bool byref; // Not used for -nested-ctx=array
|
// Used for hybrid nested context creation.
|
||||||
int nestedDepth; // ditto
|
int nestedDepth;
|
||||||
int nestedIndex;
|
int nestedIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue