mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-08-13 18:00:05 +02:00
Fixed bug #191 by rewriting DtoConstArrayInitializer, patch unfortunately caused regressions, hopefully this doesn't :P
This commit is contained in:
175
gen/arrays.cpp
175
gen/arrays.cpp
@@ -216,141 +216,114 @@ void DtoSetArray(LLValue* arr, LLValue* dim, LLValue* ptr)
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// FIXME: this looks like it could use a cleanup
|
|
||||||
|
|
||||||
LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||||
{
|
{
|
||||||
Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars());
|
Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
Type* arrinittype = arrinit->type->toBasetype();
|
assert(arrinit->value.dim == arrinit->index.dim);
|
||||||
|
|
||||||
Type* t;
|
// get base array type
|
||||||
integer_t tdim;
|
Type* arrty = arrinit->type->toBasetype();
|
||||||
if (arrinittype->ty == Tsarray) {
|
size_t arrlen = arrinit->dim;
|
||||||
Logger::println("static array");
|
|
||||||
TypeSArray* tsa = (TypeSArray*)arrinittype;
|
// for statis arrays, dmd does not include any trailing default
|
||||||
tdim = tsa->dim->toInteger();
|
// initialized elements in the value/index lists
|
||||||
t = tsa;
|
if (arrty->ty == Tsarray)
|
||||||
|
{
|
||||||
|
TypeSArray* tsa = (TypeSArray*)arrty;
|
||||||
|
arrlen = (size_t)tsa->dim->toInteger();
|
||||||
}
|
}
|
||||||
else if (arrinittype->ty == Tarray) {
|
|
||||||
Logger::println("dynamic array");
|
// make sure the number of initializers is sane
|
||||||
t = arrinittype;
|
if (arrinit->index.dim > arrlen || arrinit->dim > arrlen)
|
||||||
tdim = arrinit->dim;
|
{
|
||||||
|
error(arrinit->loc, "too many initializers, %d, for array[%d]", arrinit->index.dim, arrlen);
|
||||||
|
fatal();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
assert(0);
|
|
||||||
|
|
||||||
if(arrinit->dim > tdim)
|
// get elem type
|
||||||
error(arrinit->loc, "array initializer for %s is too long (%d)", arrinit->type->toChars(), arrinit->dim);
|
Type* elemty = arrty->nextOf();
|
||||||
|
const LLType* llelemty = DtoType(elemty);
|
||||||
|
|
||||||
Logger::println("dim = %u", tdim);
|
// true if array elements differ in type, can happen with array of unions
|
||||||
|
|
||||||
std::vector<LLConstant*> inits(tdim, NULL);
|
|
||||||
|
|
||||||
Type* arrnext = arrinittype->nextOf();
|
|
||||||
const LLType* elemty = DtoType(arrinittype->nextOf());
|
|
||||||
|
|
||||||
// true if there is a mismatch with one of the initializers
|
|
||||||
bool mismatch = false;
|
bool mismatch = false;
|
||||||
|
|
||||||
assert(arrinit->index.dim == arrinit->value.dim);
|
// allocate room for initializers
|
||||||
for (unsigned i=0,j=0; i < tdim; ++i)
|
std::vector<LLConstant*> initvals(arrlen, NULL);
|
||||||
|
|
||||||
|
// go through each initializer, they're not sorted by index by the frontend
|
||||||
|
size_t j = 0;
|
||||||
|
for (size_t i = 0; i < arrinit->index.dim; i++)
|
||||||
{
|
{
|
||||||
Initializer* init = 0;
|
// get index
|
||||||
Expression* idx;
|
Expression* idx = (Expression*)arrinit->index.data[i];
|
||||||
|
|
||||||
if (j < arrinit->index.dim)
|
|
||||||
idx = (Expression*)arrinit->index.data[j];
|
|
||||||
else
|
|
||||||
idx = NULL;
|
|
||||||
|
|
||||||
LLConstant* v = NULL;
|
|
||||||
|
|
||||||
|
// idx can be null, then it's just the next element
|
||||||
if (idx)
|
if (idx)
|
||||||
|
j = idx->toInteger();
|
||||||
|
assert(j < arrlen);
|
||||||
|
|
||||||
|
// get value
|
||||||
|
Initializer* val = (Initializer*)arrinit->value.data[i];
|
||||||
|
assert(val);
|
||||||
|
|
||||||
|
// error check from dmd
|
||||||
|
if (initvals[j] != NULL)
|
||||||
{
|
{
|
||||||
Logger::println("%d has idx", i);
|
error(arrinit->loc, "duplicate initialization for index %d", j);
|
||||||
// this is pretty weird :/ idx->type turned out NULL for the initializer:
|
|
||||||
// const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
|
|
||||||
// in std.c.linux.socket
|
|
||||||
if (idx->type) {
|
|
||||||
Logger::println("has idx->type", i);
|
|
||||||
//integer_t k = idx->toInteger();
|
|
||||||
//Logger::println("getting value for exp: %s | %s", idx->toChars(), arrnext->toChars());
|
|
||||||
LLConstant* cc = idx->toConstElem(gIR);
|
|
||||||
Logger::println("value gotten");
|
|
||||||
assert(cc != NULL);
|
|
||||||
LLConstantInt* ci = llvm::dyn_cast<LLConstantInt>(cc);
|
|
||||||
assert(ci != NULL);
|
|
||||||
uint64_t k = ci->getZExtValue();
|
|
||||||
if (i == k)
|
|
||||||
{
|
|
||||||
init = (Initializer*)arrinit->value.data[j];
|
|
||||||
assert(init);
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (j < arrinit->value.dim) {
|
|
||||||
init = (Initializer*)arrinit->value.data[j];
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
v = arrnext->defaultInit()->toConstElem(gIR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!v)
|
LLConstant* c = DtoConstInitializer(val->loc, elemty, val);
|
||||||
v = DtoConstInitializer(arrinit->loc, t->nextOf(), init);
|
assert(c);
|
||||||
assert(v);
|
if (c->getType() != llelemty)
|
||||||
|
|
||||||
// global arrays of unions might have type mismatch for each element
|
|
||||||
// if there is any mismatch at all, we need to use a struct instead :/
|
|
||||||
if (v->getType() != elemty)
|
|
||||||
mismatch = true;
|
mismatch = true;
|
||||||
|
|
||||||
inits[i] = v;
|
initvals[j] = c;
|
||||||
if (Logger::enabled())
|
j++;
|
||||||
Logger::cout() << "llval: " << *v << '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::println("building constant array");
|
// die now if there was errors
|
||||||
|
if (global.errors)
|
||||||
|
fatal();
|
||||||
|
|
||||||
|
// fill out any null entries still left with default values
|
||||||
|
|
||||||
|
// element default initializer
|
||||||
|
LLConstant* defelem = elemty->defaultInit(arrinit->loc)->toConstElem(gIR);
|
||||||
|
bool mismatch2 = (defelem->getType() != llelemty);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arrlen; i++)
|
||||||
|
{
|
||||||
|
if (initvals[i] != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
initvals[i] = defelem;
|
||||||
|
|
||||||
|
if (mismatch2)
|
||||||
|
mismatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
LLConstant* constarr;
|
LLConstant* constarr;
|
||||||
const LLArrayType* arrty = LLArrayType::get(elemty,tdim);
|
|
||||||
|
|
||||||
if (mismatch)
|
if (mismatch)
|
||||||
{
|
constarr = LLConstantStruct::get(initvals);
|
||||||
constarr = LLConstantStruct::get(inits);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
constarr = LLConstantArray::get(LLArrayType::get(llelemty, arrlen), initvals);
|
||||||
constarr = LLConstantArray::get(arrty, inits);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
// std::cout << "constarr: " << *constarr << std::endl;
|
||||||
if (Logger::enabled())
|
|
||||||
{
|
|
||||||
Logger::cout() << "array type: " << *arrty << '\n';
|
|
||||||
size_t n = inits.size();
|
|
||||||
for (size_t i=0; i<n; i++)
|
|
||||||
Logger::cout() << " init " << i << " = " << *inits[i] << '\n';
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (arrinittype->ty == Tsarray)
|
// if the type is a static array, we're done
|
||||||
|
if (arrty->ty == Tsarray)
|
||||||
return constarr;
|
return constarr;
|
||||||
else
|
|
||||||
assert(arrinittype->ty == Tarray);
|
|
||||||
|
|
||||||
LLGlobalVariable* gvar = new LLGlobalVariable(constarr->getType(),true,LLGlobalValue::InternalLinkage,constarr,".constarray",gIR->module);
|
// for dynamic array we need to make a global with the data, so we have a pointer for the dynamic array
|
||||||
|
LLGlobalVariable* gvar = new LLGlobalVariable(constarr->getType(), true, LLGlobalValue::InternalLinkage, constarr, ".constarray", gIR->module);
|
||||||
LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
|
LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
|
||||||
|
|
||||||
LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
|
LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
|
||||||
gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(elemty));
|
gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(llelemty));
|
||||||
|
|
||||||
return DtoConstSlice(DtoConstSize_t(tdim),gep);
|
return DtoConstSlice(DtoConstSize_t(arrlen),gep);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
10
tests/mini/arrayinit2.d
Normal file
10
tests/mini/arrayinit2.d
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// bug #191
|
||||||
|
|
||||||
|
int[3] a = [0: 0, 2: 42, 1: 1];
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
assert(a[0] == 0);
|
||||||
|
assert(a[1] == 1); // fails!
|
||||||
|
assert(a[2] == 42);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user