mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 19:06:02 +03:00
Call postblit on a struct when appending it to an array. Use _d_arraycatnT to concatenate multiple arrays.
Before, _d_arraycatT was used to concatenate multiple arrays. That caused an issue when postblit was called on a struct multiple times. The next code asserted due to the issue: void main() { static struct S { int x; int pad; this(this) { ++x; } } auto sarr = new S[1]; auto sarr2 = sarr ~ sarr ~ sarr; assert(sarr2[0].x == 1); assert(sarr2[1].x == 1); assert(sarr2[2].x == 1); assert(sarr[0].x == 0); }
This commit is contained in:
parent
9864129fb8
commit
0caba6672d
5 changed files with 98 additions and 40 deletions
|
@ -23,7 +23,7 @@
|
|||
static LLValue *DtoSlice(DValue *dval)
|
||||
{
|
||||
LLValue *val = dval->getRVal();
|
||||
if (dval->isVar() && dval->isVar()->type->ty == Tsarray) {
|
||||
if (dval->getType()->toBasetype()->ty == Tsarray) {
|
||||
// Convert static array to slice
|
||||
const LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context()));
|
||||
LLValue *array = DtoRawAlloca(type, 0, ".array");
|
||||
|
@ -36,6 +36,25 @@ static LLValue *DtoSlice(DValue *dval)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static LLValue *DtoSlicePtr(DValue *dval)
|
||||
{
|
||||
Loc loc;
|
||||
const LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context()));
|
||||
Type *vt = dval->getType()->toBasetype();
|
||||
if (vt->ty == Tarray)
|
||||
return makeLValue(loc, dval);
|
||||
|
||||
bool isStaticArray = vt->ty == Tsarray;
|
||||
LLValue *val = isStaticArray ? dval->getRVal() : makeLValue(loc, dval);
|
||||
LLValue *array = DtoRawAlloca(type, 0, ".array");
|
||||
LLValue *len = isStaticArray ? DtoArrayLen(dval) : DtoConstSize_t(1);
|
||||
DtoStore(len, DtoGEPi(array, 0, 0, ".len"));
|
||||
DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEPi(array, 0, 1, ".ptr"));
|
||||
return array;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const LLStructType* DtoArrayType(Type* arrayTy)
|
||||
{
|
||||
assert(arrayTy->nextOf());
|
||||
|
@ -751,6 +770,7 @@ void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* e
|
|||
val = DtoGEP1(val, oldLength, "lastElem");
|
||||
val = DtoBitCast(val, DtoType(arrayType->nextOf()->pointerTo()));
|
||||
DtoAssign(loc, new DVarValue(arrayType->nextOf(), val), expVal);
|
||||
callPostblit(loc, exp, val);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -846,23 +866,46 @@ DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2)
|
|||
Logger::println("DtoCatAssignArray");
|
||||
LOG_SCOPE;
|
||||
|
||||
// Prepare arguments
|
||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arraycatT");
|
||||
LLSmallVector<LLValue*,3> args;
|
||||
// TypeInfo ti
|
||||
args.push_back(DtoTypeInfoOf(arrayType));
|
||||
// byte[] x
|
||||
LLValue *val = DtoSlice(exp1->toElem(gIR));
|
||||
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1));
|
||||
args.push_back(val);
|
||||
// byte[] y
|
||||
val = DtoSlice(exp2->toElem(gIR));
|
||||
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2));
|
||||
args.push_back(val);
|
||||
std::vector<LLValue*> args;
|
||||
LLFunction* fn = 0;
|
||||
|
||||
// Call _d_arraycatT
|
||||
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".appendedArray").getInstruction();
|
||||
if (exp1->op == TOKcat)
|
||||
{ // handle multiple concat
|
||||
fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arraycatnT");
|
||||
|
||||
args.push_back(DtoSlicePtr(exp2->toElem(gIR)));
|
||||
CatExp *ce = (CatExp*)exp1;
|
||||
do
|
||||
{
|
||||
args.push_back(DtoSlicePtr(ce->e2->toElem(gIR)));
|
||||
ce = (CatExp *)ce->e1;
|
||||
|
||||
} while (ce->op == TOKcat);
|
||||
args.push_back(DtoSlicePtr(ce->toElem(gIR)));
|
||||
// uint n
|
||||
args.push_back(DtoConstUint(args.size()));
|
||||
// TypeInfo ti
|
||||
args.push_back(DtoTypeInfoOf(arrayType));
|
||||
|
||||
std::reverse(args.begin(), args.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arraycatT");
|
||||
|
||||
// TypeInfo ti
|
||||
args.push_back(DtoTypeInfoOf(arrayType));
|
||||
// byte[] x
|
||||
LLValue *val = DtoSlice(exp1->toElem(gIR));
|
||||
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1));
|
||||
args.push_back(val);
|
||||
// byte[] y
|
||||
val = DtoSlice(exp2->toElem(gIR));
|
||||
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2));
|
||||
args.push_back(val);
|
||||
}
|
||||
|
||||
LLValue *newArray = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".appendedArray").getInstruction();
|
||||
return getSlice(arrayType, newArray);
|
||||
}
|
||||
|
||||
|
|
|
@ -1733,3 +1733,28 @@ LLValue* makeLValue(Loc& loc, DValue* value)
|
|||
|
||||
return valuePointer;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if DMDV2
|
||||
void callPostblit(Loc &loc, Expression *exp, LLValue *val)
|
||||
{
|
||||
|
||||
Type *tb = exp->type->toBasetype();
|
||||
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) &&
|
||||
tb->ty == Tstruct)
|
||||
{ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
|
||||
if (sd->postblit)
|
||||
{
|
||||
FuncDeclaration *fd = sd->postblit;
|
||||
if (fd->storage_class & STCdisable)
|
||||
fd->toParent()->error(loc, "is not copyable because it is annotated with @disable");
|
||||
fd->codegen(Type::sir);
|
||||
Expressions args;
|
||||
DFuncValue dfn(fd, fd->ir.irFunc->func, val);
|
||||
DtoCallFunction(loc, Type::basic[Tvoid], &dfn, &args);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -152,6 +152,10 @@ size_t realignOffset(size_t offset, Type* type);
|
|||
/// functions without problems.
|
||||
LLValue* makeLValue(Loc& loc, DValue* value);
|
||||
|
||||
#if DMDV2
|
||||
void callPostblit(Loc &loc, Expression *exp, LLValue *val);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////
|
||||
// gen/tocall.cpp stuff below
|
||||
////////////////////////////////////////////
|
||||
|
|
|
@ -439,6 +439,14 @@ static void LLVM_D_BuildRuntimeModule()
|
|||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
// byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
|
||||
{
|
||||
llvm::StringRef fname("_d_arraycatnT");
|
||||
std::vector<const LLType*> types;
|
||||
types.push_back(typeInfoTy);
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, true);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
#else // DMDV1
|
||||
// byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element)
|
||||
{
|
||||
|
|
|
@ -47,28 +47,6 @@ void CompoundStatement::toIR(IRState* p)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if DMDV2
|
||||
static void callPostblitHelper(Loc &loc, Expression *exp, LLValue *val)
|
||||
{
|
||||
|
||||
Type *tb = exp->type->toBasetype();
|
||||
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) &&
|
||||
tb->ty == Tstruct)
|
||||
{ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
|
||||
if (sd->postblit)
|
||||
{
|
||||
FuncDeclaration *fd = sd->postblit;
|
||||
if (fd->storage_class & STCdisable)
|
||||
fd->toParent()->error(loc, "is not copyable because it is annotated with @disable");
|
||||
fd->codegen(Type::sir);
|
||||
Expressions args;
|
||||
DFuncValue dfn(fd, fd->ir.irFunc->func, val);
|
||||
DtoCallFunction(loc, Type::basic[Tvoid], &dfn, &args);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ReturnStatement::toIR(IRState* p)
|
||||
{
|
||||
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
|
||||
|
@ -101,7 +79,7 @@ void ReturnStatement::toIR(IRState* p)
|
|||
#if DMDV2
|
||||
// call postblit if necessary
|
||||
if (!p->func()->type->isref)
|
||||
callPostblitHelper(loc, exp, rvar->getLVal());
|
||||
callPostblit(loc, exp, rvar->getLVal());
|
||||
#endif
|
||||
|
||||
// emit scopes
|
||||
|
@ -127,7 +105,7 @@ void ReturnStatement::toIR(IRState* p)
|
|||
#if DMDV2
|
||||
// call postblit if necessary
|
||||
if (!p->func()->type->isref)
|
||||
callPostblitHelper(loc, exp, dval->getRVal());
|
||||
callPostblit(loc, exp, dval->getRVal());
|
||||
// do abi specific transformations on the return value
|
||||
v = p->func()->type->fty.putRet(exp->type, dval, p->func()->type->isref);
|
||||
#else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue