Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 47 additions & 27 deletions src/cast.c
Original file line number Diff line number Diff line change
Expand Up @@ -768,33 +768,6 @@ MATCH implicitConvTo(Expression *e, Type *t)
return;
}

/* The result of arr.dup and arr.idup can be unique essentially.
* So deal with this case specially.
*/
if (!e->f && e->e1->op == TOKvar && ((VarExp *)e->e1)->var->ident == Id::adDup &&
t->toBasetype()->ty == Tarray)
{
assert(e->type->toBasetype()->ty == Tarray);
assert(e->arguments->dim == 2);
Expression *eorg = (*e->arguments)[1];
Type *tn = t->nextOf();
if (e->type->nextOf()->implicitConvTo(tn) < MATCHconst)
{
/* If the operand is an unique array literal, then allow conversion.
*/
if (eorg->op != TOKarrayliteral)
return;
Expressions *elements = ((ArrayLiteralExp *)eorg)->elements;
for (size_t i = 0; i < elements->dim; i++)
{
if (!(*elements)[i]->implicitConvTo(tn))
return;
}
}
result = e->type->immutableOf()->implicitConvTo(t);
return;
}

/* Conversion is 'const' conversion if:
* 1. function is pure (weakly pure is ok)
* 2. implicit conversion only fails because of mod bits
Expand All @@ -814,6 +787,51 @@ MATCH implicitConvTo(Expression *e, Type *t)
if (e->type->immutableOf()->implicitConvTo(t->immutableOf()) == MATCHnomatch)
return;

/* adDup() is called to implement arr.dup or arr.idup
* We know that it makes a copy of an array. So it is not necessary
* to check first level, only second level, to see if convertible, because
* we know the first level of the return value will be unique.
*/
bool isdup = false;
if (!e->f && e->e1->op == TOKvar && ((VarExp *)e->e1)->var->ident == Id::adDup &&
t->toBasetype()->ty == Tarray)
{
assert(e->type->toBasetype()->ty == Tarray);
assert(e->arguments->dim == 2);
isdup = true; // so we only check eorg later

Expression *eorg = (*e->arguments)[1];
Type *tnb = t->nextOf()->toBasetype();

Type *typen = e->type->nextOf();

/* If the operand is an array literal, then we can look at the
* array literal elements to do second level conversion check.
*/
if (eorg->op == TOKarrayliteral)
{
Expressions *elements = ((ArrayLiteralExp *)eorg)->elements;
for (size_t i = 0; i < elements->dim; i++)
{
if ((*elements)[i]->implicitConvTo(tnb) == MATCHnomatch)
return;
}
result = MATCHconst;
return;
}

if (typen->implicitConvTo(tnb) >= MATCHconst)
{
result = MATCHconst;
return;
}

/* Treat as regular pure function, i.e. if arguments are unique we can
* allow the conversion. But only check second arg, since we know that
* first arg won't be part of the return value.
*/
}

/* Get mod bits of what we're converting to
*/
Type *tb = t->toBasetype();
Expand Down Expand Up @@ -855,6 +873,8 @@ MATCH implicitConvTo(Expression *e, Type *t)
}
continue;
}
if (isdup)
i = 1; // for adDup, only check eorg for uniqueness
Expression *earg = (*e->arguments)[i];
Type *targ = earg->type->toBasetype();
#if LOG
Expand Down
4 changes: 2 additions & 2 deletions src/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,8 +674,8 @@ class FuncDeclaration : public Declaration
Statement *mergeFensure(Statement *, Identifier *oid);
Parameters *getParameters(int *pvarargs);

static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name);
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id);
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc = 0);
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc = 0);

Symbol *toThunkSymbol(int offset); // thunk version
void toObjFile(int multiobj); // compile to .obj file
Expand Down
10 changes: 6 additions & 4 deletions src/func.c
Original file line number Diff line number Diff line change
Expand Up @@ -3684,12 +3684,14 @@ bool FuncDeclaration::addPostInvariant()
* Generate a FuncDeclaration for a runtime library function.
*/

FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name)
FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name,
StorageClass stc)
{
return genCfunc(args, treturn, Lexer::idPool(name));
return genCfunc(args, treturn, Lexer::idPool(name), stc);
}

FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id)
FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id,
StorageClass stc)
{
FuncDeclaration *fd;
TypeFunction *tf;
Expand All @@ -3711,7 +3713,7 @@ FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Iden
}
else
{
tf = new TypeFunction(args, treturn, 0, LINKc);
tf = new TypeFunction(args, treturn, 0, LINKc, stc);
fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf);
fd->protection = PROTpublic;
fd->linkage = LINKc;
Expand Down
3 changes: 2 additions & 1 deletion src/mtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -3802,7 +3802,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f
Parameters* args = new Parameters;
args->push(new Parameter(STCin, Type::dtypeinfo->type, NULL, NULL));
args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL));
adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup);
adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup,
STCpure | STCtrusted);
}
fd = adDup_fd;
} else {
Expand Down
21 changes: 21 additions & 0 deletions test/runnable/implicit.d
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,26 @@ void testDIP29_4()

/***********************************/

int[] test6(int[] a) pure @safe nothrow
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothrow seems to fail here

{
return a.dup;
}

/***********************************/

int*[] pureFoo() pure { return null; }


void testDIP29_5() pure
{
{ char[] s; immutable x = s.dup; }
{ immutable x = (cast(int*[])null).dup; }
{ immutable x = pureFoo(); }
{ immutable x = pureFoo().dup; }
}

/***********************************/

void main()
{
test1();
Expand All @@ -172,6 +192,7 @@ void main()
testDIP29_2();
testDIP29_3();
testDIP29_4();
testDIP29_5();

writefln("Success");
}