From 6a1a928814594a9f47a030815da6a83e0c91f443 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 7 Mar 2014 01:54:49 -0800 Subject: [PATCH] DIP29: make dup functions pure --- src/cast.c | 74 +++++++++++++++++++++++++--------------- src/declaration.h | 4 +-- src/func.c | 10 +++--- src/mtype.c | 3 +- test/runnable/implicit.d | 21 ++++++++++++ 5 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/cast.c b/src/cast.c index 87d5167c6a5d..72400f4da344 100644 --- a/src/cast.c +++ b/src/cast.c @@ -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 @@ -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(); @@ -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 diff --git a/src/declaration.h b/src/declaration.h index 51e32ad666b8..9b25382acc6a 100644 --- a/src/declaration.h +++ b/src/declaration.h @@ -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 diff --git a/src/func.c b/src/func.c index 1bf04b25af44..d8811e37e630 100644 --- a/src/func.c +++ b/src/func.c @@ -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; @@ -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; diff --git a/src/mtype.c b/src/mtype.c index a280b22e7202..836735d4f105 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -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 { diff --git a/test/runnable/implicit.d b/test/runnable/implicit.d index a8326b3b1091..6f59bb372728 100644 --- a/test/runnable/implicit.d +++ b/test/runnable/implicit.d @@ -161,6 +161,26 @@ void testDIP29_4() /***********************************/ +int[] test6(int[] a) pure @safe nothrow +{ + 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(); @@ -172,6 +192,7 @@ void main() testDIP29_2(); testDIP29_3(); testDIP29_4(); + testDIP29_5(); writefln("Success"); }