From 5c75bb31dd99a33b921f6038e3d1c1d7eb0333cd Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 17 Feb 2012 00:12:49 -0800 Subject: [PATCH] implement const/purity/nothrow/@safe inheritance --- src/expression.c | 2 +- src/func.c | 18 ++++++++++-- src/mars.c | 2 +- src/mtype.c | 65 ++++++++++++++++++++++++++++++++--------- src/mtype.h | 5 ++-- test/runnable/xtest46.d | 19 ++++++++++++ 6 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/expression.c b/src/expression.c index 3b41fd35710e..09a16ceb7988 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1547,7 +1547,7 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) break; if (ff->setImpure() && !msg) { error("pure function '%s' cannot access mutable static data '%s'", - sc->func->toChars(), v->toChars()); + sc->func->toPrettyChars(), v->toChars()); msg = TRUE; // only need the innermost message } } diff --git a/src/func.c b/src/func.c index 39ba3aba1ab3..f0478ae5b15c 100644 --- a/src/func.c +++ b/src/func.c @@ -1983,6 +1983,8 @@ int FuncDeclaration::overrides(FuncDeclaration *fd) int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) { FuncDeclaration *mismatch = NULL; + StorageClass mismatchstc = 0; + int mismatchvi = -1; int bestvi = -1; for (int vi = 0; vi < dim; vi++) { @@ -1992,7 +1994,8 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) if (type->equals(fdv->type)) // if exact match return vi; // no need to look further - int cov = type->covariant(fdv->type); + StorageClass stc = 0; + int cov = type->covariant(fdv->type, &stc); //printf("\tbaseclass cov = %d\n", cov); switch (cov) { @@ -2004,6 +2007,8 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) break; // keep looking for an exact match case 2: + mismatchvi = vi; + mismatchstc = stc; mismatch = fdv; // overrides, but is not covariant break; // keep looking for an exact match @@ -2020,8 +2025,15 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) //type->print(); //mismatch->type->print(); //printf("%s %s\n", type->deco, mismatch->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); + //printf("stc = %llx\n", mismatchstc); + if (mismatchstc) + { // Fix it by modifying the type to add the storage classes + type = type->addStorageClass(mismatchstc); + bestvi = mismatchvi; + } + else + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); } return bestvi; } diff --git a/src/mars.c b/src/mars.c index 5c7f38eba0f0..c30d5f95197a 100644 --- a/src/mars.c +++ b/src/mars.c @@ -94,7 +94,7 @@ Global::Global() "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; #endif ; - version = "v2.058"; + version = "v2.059"; global.structalign = 8; memset(¶ms, 0, sizeof(Param)); diff --git a/src/mtype.c b/src/mtype.c index c7f224122f09..93ceb24b77f3 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -4910,9 +4910,10 @@ Type *TypeFunction::syntaxCopy() * 2 arguments match as far as overloading goes, * but types are not covariant * 3 cannot determine covariance because of forward references + * *pstc STCxxxx which would make it covariant */ -int Type::covariant(Type *t) +int Type::covariant(Type *t, StorageClass *pstc) { #if 0 printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars()); @@ -4921,6 +4922,10 @@ int Type::covariant(Type *t) printf("mod = %x, %x\n", mod, t->mod); #endif + if (pstc) + *pstc = 0; + StorageClass stc = 0; + int inoutmismatch = 0; TypeFunction *t1; @@ -5024,35 +5029,39 @@ int Type::covariant(Type *t) goto Lnotcovariant; Lcovariant: + if (t1->isref != t2->isref) + goto Lnotcovariant; + /* Can convert mutable to const */ if (!MODimplicitConv(t2->mod, t1->mod)) - goto Lnotcovariant; -#if 0 - if (t1->mod != t2->mod) { - if (!(t1->mod & MODconst) && (t2->mod & MODconst)) - goto Lnotcovariant; - if (!(t1->mod & MODshared) && (t2->mod & MODshared)) + // If adding 'const' will make it covariant + if (MODimplicitConv(t2->mod, MODmerge(t1->mod, MODconst))) + stc |= STCconst; + else goto Lnotcovariant; } -#endif /* Can convert pure to impure, and nothrow to throw */ if (!t1->purity && t2->purity) - goto Lnotcovariant; + stc |= STCpure; if (!t1->isnothrow && t2->isnothrow) - goto Lnotcovariant; - - if (t1->isref != t2->isref) - goto Lnotcovariant; + stc |= STCnothrow; /* Can convert safe/trusted to system */ if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted) + // Should we infer trusted or safe? Go with safe. + stc |= STCsafe; + + if (stc) + { if (pstc) + *pstc = stc; goto Lnotcovariant; + } //printf("\tcovaraint: 1\n"); return 1; @@ -5908,6 +5917,36 @@ Expression *TypeFunction::defaultInit(Loc loc) return new ErrorExp(); } +Type *TypeFunction::addStorageClass(StorageClass stc) +{ + TypeFunction *t = (TypeFunction *)Type::addStorageClass(stc); + if ((stc & STCpure && !t->purity) || + (stc & STCnothrow && !t->isnothrow) || + (stc & STCsafe && t->trust < TRUSTtrusted)) + { + // Klunky to change these + TypeFunction *tf = new TypeFunction(t->parameters, t->next, t->varargs, t->linkage, 0); + tf->mod = t->mod; + tf->fargs = fargs; + tf->purity = t->purity; + tf->isnothrow = t->isnothrow; + tf->isproperty = t->isproperty; + tf->isref = t->isref; + tf->trust = t->trust; + + if (stc & STCpure) + tf->purity = PUREfwdref; + if (stc & STCnothrow) + tf->isnothrow = true; + if (stc & STCsafe) + tf->trust = TRUSTsafe; + + tf->deco = tf->merge()->deco; + t = tf; + } + return t; +} + /***************************** TypeDelegate *****************************/ TypeDelegate::TypeDelegate(Type *t) diff --git a/src/mtype.h b/src/mtype.h index b5bedf9ef514..e6c0705eaab8 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -223,7 +223,7 @@ struct Type : Object virtual Type *syntaxCopy(); int equals(Object *o); int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() - int covariant(Type *t); + int covariant(Type *t, StorageClass *pstc = NULL); char *toChars(); static char needThisPrefix(); static void init(); @@ -275,7 +275,7 @@ struct Type : Object Type *addSTC(StorageClass stc); Type *castMod(unsigned mod); Type *addMod(unsigned mod); - Type *addStorageClass(StorageClass stc); + virtual Type *addStorageClass(StorageClass stc); Type *pointerTo(); Type *referenceTo(); Type *arrayOf(); @@ -633,6 +633,7 @@ struct TypeFunction : TypeNext void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif bool parameterEscapes(Parameter *p); + Type *addStorageClass(StorageClass stc); int callMatch(Expression *ethis, Expressions *toargs, int flag = 0); type *toCtype(); diff --git a/test/runnable/xtest46.d b/test/runnable/xtest46.d index d35265f87b22..97e111b16aae 100644 --- a/test/runnable/xtest46.d +++ b/test/runnable/xtest46.d @@ -4458,6 +4458,25 @@ void test7321() static assert(is(typeof((){return;})==void function()pure nothrow @safe)); // fail } +/***************************************************/ + +class A158 +{ + pure void foo1() { } + const void foo2() { } + nothrow void foo3() { } + @safe void foo4() { } +} + +class B158 : A158 +{ + override void foo1() { } + override void foo2() { } + override void foo3() { } + override void foo4() { } +} + + /***************************************************/ int main()