mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-20 06:43:14 +01:00
[svn r131] Fixed #11
All associative array properties now work as they should. Fixed problems with some cases of array.length and array.ptr. Fixed some problems with array properties. Fixed 'in' contracts.
This commit is contained in:
@@ -259,11 +259,11 @@ int main(int argc, char *argv[])
|
||||
global.params.link = 1;
|
||||
global.params.useAssert = 0;
|
||||
global.params.useInvariants = 0;
|
||||
global.params.useIn = 0;
|
||||
global.params.useIn = 1;
|
||||
global.params.useOut = 0;
|
||||
global.params.useArrayBounds = 0;
|
||||
global.params.useSwitchError = 0;
|
||||
global.params.useInline = 0;
|
||||
global.params.useInline = 0; // this one messes things up to a point where codegen breaks
|
||||
global.params.obj = 1;
|
||||
global.params.Dversion = 2;
|
||||
|
||||
|
||||
24
dmd/mtype.c
24
dmd/mtype.c
@@ -1513,9 +1513,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
static char *name[2] = { "_adReverseChar", "_adReverseWchar" };
|
||||
|
||||
nm = name[n->ty == Twchar];
|
||||
fd = FuncDeclaration::genCfunc(Type::tindex, nm);
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm);
|
||||
fd->llvmRunTimeHack = true;
|
||||
((TypeFunction*)fd->type)->llvmRetInPtr = true;
|
||||
ec = new VarExp(0, fd);
|
||||
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
|
||||
arguments = new Expressions();
|
||||
@@ -1532,9 +1531,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
static char *name[2] = { "_adSortChar", "_adSortWchar" };
|
||||
|
||||
nm = name[n->ty == Twchar];
|
||||
fd = FuncDeclaration::genCfunc(Type::tindex, nm);
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm);
|
||||
fd->llvmRunTimeHack = true;
|
||||
((TypeFunction*)fd->type)->llvmRetInPtr = true;
|
||||
ec = new VarExp(0, fd);
|
||||
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
|
||||
arguments = new Expressions();
|
||||
@@ -1552,9 +1550,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
|
||||
assert(size);
|
||||
dup = (ident == Id::dup);
|
||||
fd = FuncDeclaration::genCfunc(Type::tindex, dup ? Id::adDup : Id::adReverse);
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), dup ? Id::adDup : Id::adReverse);
|
||||
fd->llvmRunTimeHack = true;
|
||||
((TypeFunction*)fd->type)->llvmRetInPtr = true;
|
||||
ec = new VarExp(0, fd);
|
||||
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
|
||||
arguments = new Expressions();
|
||||
@@ -1572,10 +1569,9 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
FuncDeclaration *fd;
|
||||
Expressions *arguments;
|
||||
|
||||
fd = FuncDeclaration::genCfunc(tint32->arrayOf(),
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(),
|
||||
(char*)(n->ty == Tbit ? "_adSortBit" : "_adSort"));
|
||||
fd->llvmRunTimeHack = true;
|
||||
((TypeFunction*)fd->type)->llvmRetInPtr = true;
|
||||
ec = new VarExp(0, fd);
|
||||
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
|
||||
arguments = new Expressions();
|
||||
@@ -2277,6 +2273,7 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
Expressions *arguments;
|
||||
|
||||
fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen);
|
||||
fd->llvmRunTimeHack = true;
|
||||
ec = new VarExp(0, fd);
|
||||
arguments = new Expressions();
|
||||
arguments->push(e);
|
||||
@@ -2291,7 +2288,8 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
int size = key->size(e->loc);
|
||||
|
||||
assert(size);
|
||||
fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaKeys);
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaKeys);
|
||||
fd->llvmRunTimeHack = true;
|
||||
ec = new VarExp(0, fd);
|
||||
arguments = new Expressions();
|
||||
arguments->push(e);
|
||||
@@ -2305,12 +2303,13 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
FuncDeclaration *fd;
|
||||
Expressions *arguments;
|
||||
|
||||
fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaValues);
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaValues);
|
||||
fd->llvmRunTimeHack = true;
|
||||
ec = new VarExp(0, fd);
|
||||
arguments = new Expressions();
|
||||
arguments->push(e);
|
||||
size_t keysize = key->size(e->loc);
|
||||
keysize = (keysize + 3) & ~3; // BUG: 64 bit pointers?
|
||||
keysize = (keysize + 4 - 1) & ~(4 - 1);
|
||||
arguments->push(new IntegerExp(0, keysize, Type::tsize_t));
|
||||
arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t));
|
||||
e = new CallExp(e->loc, ec, arguments);
|
||||
@@ -2322,7 +2321,8 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
FuncDeclaration *fd;
|
||||
Expressions *arguments;
|
||||
|
||||
fd = FuncDeclaration::genCfunc(Type::tint64, Id::aaRehash);
|
||||
fd = FuncDeclaration::genCfunc(Type::tvoid->pointerTo(), Id::aaRehash);
|
||||
fd->llvmRunTimeHack = true;
|
||||
ec = new VarExp(0, fd);
|
||||
arguments = new Expressions();
|
||||
arguments->push(e->addressOf(sc));
|
||||
|
||||
71
gen/aa.cpp
71
gen/aa.cpp
@@ -48,6 +48,20 @@ static llvm::Value* to_pkey(DValue* key)
|
||||
return pkey;
|
||||
}
|
||||
|
||||
// returns the keytype typeinfo
|
||||
static llvm::Value* to_keyti(DValue* key)
|
||||
{
|
||||
// keyti param
|
||||
Type* keytype = key->getType();
|
||||
keytype->getTypeInfo(NULL);
|
||||
TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration();
|
||||
assert(tid);
|
||||
DtoResolveDsymbol(Type::typeinfo);
|
||||
DtoForceDeclareDsymbol(tid);
|
||||
assert(tid->llvmValue);
|
||||
return tid->llvmValue;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key)
|
||||
@@ -64,14 +78,7 @@ DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key)
|
||||
aaval = DtoBitCast(aaval, funcTy->getParamType(0));
|
||||
|
||||
// keyti param
|
||||
Type* keytype = key->getType();
|
||||
keytype->getTypeInfo(NULL);
|
||||
TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration();
|
||||
assert(tid);
|
||||
DtoResolveDsymbol(Type::typeinfo);
|
||||
DtoForceDeclareDsymbol(tid);
|
||||
assert(tid->llvmValue);
|
||||
llvm::Value* keyti = tid->llvmValue;
|
||||
llvm::Value* keyti = to_keyti(key);
|
||||
keyti = DtoBitCast(keyti, funcTy->getParamType(1));
|
||||
|
||||
// pkey param
|
||||
@@ -89,7 +96,7 @@ DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key)
|
||||
args.push_back(valsize);
|
||||
|
||||
// call runtime
|
||||
llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aaGet");
|
||||
llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aa.index");
|
||||
|
||||
// cast return value
|
||||
const llvm::Type* targettype = llvm::PointerType::get(DtoType(type));
|
||||
@@ -119,14 +126,7 @@ DValue* DtoAAIn(Type* type, DValue* aa, DValue* key)
|
||||
aaval = DtoBitCast(aaval, funcTy->getParamType(0));
|
||||
|
||||
// keyti param
|
||||
Type* keytype = key->getType();
|
||||
keytype->getTypeInfo(NULL);
|
||||
TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration();
|
||||
assert(tid);
|
||||
DtoResolveDsymbol(Type::typeinfo);
|
||||
DtoForceDeclareDsymbol(tid);
|
||||
assert(tid->llvmValue);
|
||||
llvm::Value* keyti = tid->llvmValue;
|
||||
llvm::Value* keyti = to_keyti(key);
|
||||
keyti = DtoBitCast(keyti, funcTy->getParamType(1));
|
||||
|
||||
// pkey param
|
||||
@@ -140,7 +140,7 @@ DValue* DtoAAIn(Type* type, DValue* aa, DValue* key)
|
||||
args.push_back(pkey);
|
||||
|
||||
// call runtime
|
||||
llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aaIn");
|
||||
llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aa.in");
|
||||
|
||||
// cast return value
|
||||
const llvm::Type* targettype = DtoType(type);
|
||||
@@ -151,3 +151,38 @@ DValue* DtoAAIn(Type* type, DValue* aa, DValue* key)
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoAARemove(DValue* aa, DValue* key)
|
||||
{
|
||||
// call:
|
||||
// extern(C) void _aaDel(AA aa, TypeInfo keyti, void* pkey)
|
||||
|
||||
// first get the runtime function
|
||||
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDel");
|
||||
const llvm::FunctionType* funcTy = func->getFunctionType();
|
||||
|
||||
Logger::cout() << "_aaDel = " << *func << '\n';
|
||||
|
||||
// aa param
|
||||
llvm::Value* aaval = aa->getRVal();
|
||||
Logger::cout() << "aaval: " << *aaval << '\n';
|
||||
Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n';
|
||||
aaval = DtoBitCast(aaval, funcTy->getParamType(0));
|
||||
|
||||
// keyti param
|
||||
llvm::Value* keyti = to_keyti(key);
|
||||
keyti = DtoBitCast(keyti, funcTy->getParamType(1));
|
||||
|
||||
// pkey param
|
||||
llvm::Value* pkey = to_pkey(key);
|
||||
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
|
||||
|
||||
// build arg vector
|
||||
std::vector<llvm::Value*> args;
|
||||
args.push_back(aaval);
|
||||
args.push_back(keyti);
|
||||
args.push_back(pkey);
|
||||
|
||||
// call runtime
|
||||
gIR->ir->CreateCall(func, args.begin(), args.end(),"");
|
||||
}
|
||||
|
||||
1
gen/aa.h
1
gen/aa.h
@@ -3,5 +3,6 @@
|
||||
|
||||
DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key);
|
||||
DValue* DtoAAIn(Type* type, DValue* aa, DValue* key);
|
||||
void DtoAARemove(DValue* aa, DValue* key);
|
||||
|
||||
#endif // LLVMDC_GEN_AA_H
|
||||
|
||||
@@ -808,8 +808,10 @@ llvm::Value* DtoArrayLen(DValue* v)
|
||||
return s->len;
|
||||
}
|
||||
const llvm::ArrayType* arrTy = isaArray(s->ptr->getType()->getContainedType(0));
|
||||
assert(arrTy);
|
||||
return DtoConstSize_t(arrTy->getNumElements());
|
||||
if (arrTy)
|
||||
return DtoConstSize_t(arrTy->getNumElements());
|
||||
else
|
||||
return DtoLoad(DtoGEPi(s->ptr, 0,0, "tmp"));
|
||||
}
|
||||
return DtoLoad(DtoGEPi(v->getRVal(), 0,0, "tmp"));
|
||||
}
|
||||
@@ -831,9 +833,13 @@ llvm::Value* DtoArrayPtr(DValue* v)
|
||||
if (t->ty == Tarray) {
|
||||
if (DSliceValue* s = v->isSlice()) {
|
||||
if (s->len) return s->ptr;
|
||||
const llvm::Type* t = s->ptr->getType()->getContainedType(0);
|
||||
Logger::cout() << "ptr of full slice: " << *s->ptr << '\n';
|
||||
const llvm::ArrayType* arrTy = isaArray(s->ptr->getType()->getContainedType(0));
|
||||
assert(arrTy);
|
||||
return DtoGEPi(s->ptr, 0,0, "tmp");
|
||||
if (arrTy)
|
||||
return DtoGEPi(s->ptr, 0,0, "tmp");
|
||||
else
|
||||
return DtoLoad(DtoGEPi(s->ptr, 0,1, "tmp"));
|
||||
}
|
||||
return DtoLoad(DtoGEPi(v->getRVal(), 0,1, "tmp"));
|
||||
}
|
||||
|
||||
@@ -256,6 +256,8 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
|
||||
|
||||
if (fdecl->llvmRunTimeHack) {
|
||||
gIR->declareList.push_back(fdecl);
|
||||
TypeFunction* tf = (TypeFunction*)fdecl->type;
|
||||
tf->llvmRetInPtr = DtoIsPassedByRef(tf->next);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
41
gen/toir.cpp
41
gen/toir.cpp
@@ -904,7 +904,7 @@ DValue* CallExp::toElem(IRState* p)
|
||||
Logger::cout() << "what are we calling? : " << *funcval << '\n';
|
||||
}
|
||||
assert(llfnty);
|
||||
//Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
|
||||
Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
|
||||
|
||||
// argument handling
|
||||
llvm::FunctionType::param_iterator argiter = llfnty->param_begin();
|
||||
@@ -2572,6 +2572,19 @@ DValue* InExp::toElem(IRState* p)
|
||||
return DtoAAIn(type, aa, key);
|
||||
}
|
||||
|
||||
DValue* RemoveExp::toElem(IRState* p)
|
||||
{
|
||||
Logger::print("RemoveExp::toElem: %s\n", toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
DValue* aa = e1->toElem(p);
|
||||
DValue* key = e2->toElem(p);
|
||||
|
||||
DtoAARemove(aa, key);
|
||||
|
||||
return NULL; // does not produce anything useful
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DValue* AssocArrayLiteralExp::toElem(IRState* p)
|
||||
@@ -2583,6 +2596,20 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p)
|
||||
assert(values);
|
||||
assert(keys->dim == values->dim);
|
||||
|
||||
Type* aatype = DtoDType(type);
|
||||
Type* vtype = aatype->next;
|
||||
|
||||
DValue* aa;
|
||||
if (p->topexp() && p->topexp()->e2 == this)
|
||||
{
|
||||
aa = p->topexp()->v;
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm::Value* tmp = new llvm::AllocaInst(DtoType(type),"aaliteral",p->topallocapoint());
|
||||
aa = new DVarValue(type, tmp, true);
|
||||
}
|
||||
|
||||
const size_t n = keys->dim;
|
||||
for (size_t i=0; i<n; ++i)
|
||||
{
|
||||
@@ -2590,9 +2617,17 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p)
|
||||
Expression* eval = (Expression*)values->data[i];
|
||||
|
||||
Logger::println("(%u) aa[%s] = %s", i, ekey->toChars(), eval->toChars());
|
||||
|
||||
// index
|
||||
DValue* key = ekey->toElem(p);
|
||||
DValue* mem = DtoAAIndex(vtype, aa, key);
|
||||
|
||||
// store
|
||||
DValue* val = eval->toElem(p);
|
||||
DtoAssign(mem, val);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return aa;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2666,7 +2701,7 @@ STUB(BoolExp);
|
||||
//STUB(CommaExp);
|
||||
//STUB(ArrayLengthExp);
|
||||
//STUB(HaltExp);
|
||||
STUB(RemoveExp);
|
||||
//STUB(RemoveExp);
|
||||
//STUB(ArrayLiteralExp);
|
||||
//STUB(AssocArrayLiteralExp);
|
||||
//STUB(StructLiteralExp);
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<projectname>llvmdc</projectname>
|
||||
<projectdirectory>.</projectdirectory>
|
||||
<absoluteprojectpath>false</absoluteprojectpath>
|
||||
<description></description>
|
||||
<defaultencoding></defaultencoding>
|
||||
<description/>
|
||||
<defaultencoding/>
|
||||
</general>
|
||||
<kdevautoproject>
|
||||
<general/>
|
||||
@@ -156,7 +156,7 @@
|
||||
<includePaths>.;</includePaths>
|
||||
</codecompletion>
|
||||
<creategettersetter>
|
||||
<prefixGet></prefixGet>
|
||||
<prefixGet/>
|
||||
<prefixSet>set</prefixSet>
|
||||
<prefixVariable>m_,_</prefixVariable>
|
||||
<parameterName>theValue</parameterName>
|
||||
@@ -168,14 +168,16 @@
|
||||
<synchronize>true</synchronize>
|
||||
<orientation>Vertical</orientation>
|
||||
</splitheadersource>
|
||||
<references/>
|
||||
<references>
|
||||
<pcs>LLVM</pcs>
|
||||
</references>
|
||||
</kdevcppsupport>
|
||||
<kdevcustomproject>
|
||||
<run>
|
||||
<directoryradio>executable</directoryradio>
|
||||
<mainprogram>/home/tomas/kdevprojects/llvmdc</mainprogram>
|
||||
<programargs></programargs>
|
||||
<globaldebugarguments></globaldebugarguments>
|
||||
<programargs/>
|
||||
<globaldebugarguments/>
|
||||
<globalcwd>/home/tomas/kdevprojects/llvmdc</globalcwd>
|
||||
<useglobalprogram>false</useglobalprogram>
|
||||
<terminal>false</terminal>
|
||||
@@ -398,13 +400,13 @@
|
||||
</blacklist>
|
||||
<build>
|
||||
<buildtool>make</buildtool>
|
||||
<builddir></builddir>
|
||||
<builddir/>
|
||||
</build>
|
||||
<other>
|
||||
<prio>0</prio>
|
||||
<otherbin></otherbin>
|
||||
<defaulttarget></defaulttarget>
|
||||
<otheroptions></otheroptions>
|
||||
<otherbin/>
|
||||
<defaulttarget/>
|
||||
<otheroptions/>
|
||||
<selectedenvironment>default</selectedenvironment>
|
||||
<environments>
|
||||
<default/>
|
||||
@@ -415,9 +417,9 @@
|
||||
<numberofjobs>0</numberofjobs>
|
||||
<prio>0</prio>
|
||||
<dontact>false</dontact>
|
||||
<makebin></makebin>
|
||||
<defaulttarget></defaulttarget>
|
||||
<makeoptions></makeoptions>
|
||||
<makebin/>
|
||||
<defaulttarget/>
|
||||
<makeoptions/>
|
||||
<selectedenvironment>default</selectedenvironment>
|
||||
<environments>
|
||||
<default/>
|
||||
@@ -432,11 +434,11 @@
|
||||
</cppsupportpart>
|
||||
<kdevdebugger>
|
||||
<general>
|
||||
<gdbpath></gdbpath>
|
||||
<dbgshell></dbgshell>
|
||||
<configGdbScript></configGdbScript>
|
||||
<runShellScript></runShellScript>
|
||||
<runGdbScript></runGdbScript>
|
||||
<gdbpath/>
|
||||
<dbgshell/>
|
||||
<configGdbScript/>
|
||||
<runShellScript/>
|
||||
<runGdbScript/>
|
||||
<breakonloadinglibs>true</breakonloadinglibs>
|
||||
<separatetty>false</separatetty>
|
||||
<floatingtoolbar>false</floatingtoolbar>
|
||||
|
||||
@@ -98,8 +98,9 @@ alias BB* AA;
|
||||
|
||||
size_t aligntsize(size_t tsize)
|
||||
{
|
||||
// Is pointer alignment on the x64 4 bytes or 8?
|
||||
return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
|
||||
// Is pointer alignment on the x86-64 4 bytes or 8?
|
||||
//return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
|
||||
return (tsize + 3) & (~3);
|
||||
}
|
||||
|
||||
extern (C):
|
||||
@@ -742,7 +743,8 @@ body
|
||||
* length pairs of key/value pairs.
|
||||
*/
|
||||
|
||||
extern (C)
|
||||
version(none) // not used, C variadics can't be implemented in LLVM on x86-64
|
||||
{
|
||||
BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
|
||||
{
|
||||
auto valuesize = ti.next.tsize(); // value size
|
||||
@@ -819,5 +821,5 @@ BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
25
test/aa6.d
Normal file
25
test/aa6.d
Normal file
@@ -0,0 +1,25 @@
|
||||
module aa6;
|
||||
|
||||
void main()
|
||||
{
|
||||
int[int] aa;
|
||||
aa = [1:1, 2:4, 3:9, 4:16];
|
||||
printf("---\n");
|
||||
foreach(int k, int v; aa)
|
||||
printf("aa[%d] = %d\n", k, v);
|
||||
aa.rehash;
|
||||
printf("---\n");
|
||||
foreach(int k, int v; aa)
|
||||
printf("aa[%d] = %d\n", k, v);
|
||||
size_t n = aa.length;
|
||||
assert(n == 4);
|
||||
int[] keys = aa.keys;
|
||||
assert(keys[] == [1,2,3,4][]);
|
||||
int[] vals = aa.values;
|
||||
assert(vals[] == [1,4,9,16][]);
|
||||
aa.remove(3);
|
||||
printf("---\n");
|
||||
foreach(int k, int v; aa)
|
||||
printf("aa[%d] = %d\n", k, v);
|
||||
assert(aa.length == 3);
|
||||
}
|
||||
Reference in New Issue
Block a user