From 10236c840b91ce2269350a712d4305f2586b2c69 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Wed, 1 Dec 2010 16:04:01 -0500 Subject: [PATCH 01/19] Implemented tail-const for classes as "const(Object)ref". --- src/declaration.c | 12 +++++--- src/mtype.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ src/mtype.h | 14 +++++++++- src/parse.c | 13 +++++++++ 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/declaration.c b/src/declaration.c index e861de210d2f..d7e297f369cb 100644 --- a/src/declaration.c +++ b/src/declaration.c @@ -890,17 +890,21 @@ void VarDeclaration::semantic(Scope *sc) type = type->addStorageClass(storage_class); /* Adjust storage class to reflect type + * For classes, use the reference's storage class (if available) */ - if (type->isConst()) + Type *sctype = type; + if (type->ty == Tclass && ((TypeClass *)type)->ref) + sctype = ((TypeClass *)type)->ref; + if (sctype->isConst()) { storage_class |= STCconst; if (type->isShared()) storage_class |= STCshared; } - else if (type->isImmutable()) + else if (sctype->isImmutable()) storage_class |= STCimmutable; - else if (type->isShared()) + else if (sctype->isShared()) storage_class |= STCshared; - else if (type->isWild()) + else if (sctype->isWild()) storage_class |= STCwild; if (isSynchronized()) diff --git a/src/mtype.c b/src/mtype.c index b0ad68d37d37..9ee9ab490aed 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -241,6 +241,7 @@ void Type::init() mangleChar[Ttuple] = 'B'; mangleChar[Tslice] = '@'; mangleChar[Treturn] = '@'; + mangleChar[Trefsuffix] = '@'; for (i = 0; i < TMAX; i++) { if (!mangleChar[i]) @@ -4428,6 +4429,62 @@ int TypeReference::isZeroInit(Loc loc) } + +/***************************** TypeRefSuffix *****************************/ + +TypeRefSuffix::TypeRefSuffix(Type *t) + : TypeNext(Trefsuffix, t) +{ + // BUG: what about references to static arrays? +} + +Type *TypeRefSuffix::syntaxCopy() +{ + Type *t = next->syntaxCopy(); + if (t == next) + t = this; + else + { t = new TypeRefSuffix(t); + t->mod = mod; + } + return t; +} + +Type *TypeRefSuffix::semantic(Loc loc, Scope *sc) +{ + //printf("TypeReference::semantic()\n"); + Type *n = next->semantic(loc, sc); + if (n->ty != Tclass) + { error(loc, "ref suffix is only valid for class types"); + return n; + } + next = n; + transitive(); + ((TypeClass *)n)->ref = this; + return n; +} + +void TypeRefSuffix::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + if (mod != this->mod) + { toCBuffer3(buf, hgs, mod); + return; + } + next->toCBuffer2(buf, hgs, this->mod); + buf->writestring("ref"); +} + +Expression *TypeRefSuffix::dotExp(Scope *sc, Expression *e, Identifier *ident) +{ +#if LOGDOTEXP + printf("TypeRefSuffix::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); +#endif + + // References just forward things along + return next->dotExp(sc, e, ident); +} + + /***************************** TypeFunction *****************************/ TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc) @@ -7235,6 +7292,14 @@ TypeClass::TypeClass(ClassDeclaration *sym) : Type(Tclass) { this->sym = sym; + this->ref = NULL; +} + +Type *TypeClass::addMod(unsigned mod) +{ + if (ref) + ref = (TypeRefSuffix *)ref->addMod(mod); + return Type::addMod(mod); } char *TypeClass::toChars() @@ -7640,6 +7705,10 @@ MATCH TypeClass::constConv(Type *to) Type *TypeClass::toHeadMutable() { + if (!mod) + return this; + this->ref = new TypeRefSuffix(this); + // don't perform semantic on t->ref return this; } @@ -7666,6 +7735,7 @@ int TypeClass::hasPointers() return TRUE; } + /***************************** TypeTuple *****************************/ TypeTuple::TypeTuple(Parameters *arguments) diff --git a/src/mtype.h b/src/mtype.h index 091f614c265f..6bf9ed61964d 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -58,6 +58,7 @@ enum ENUMTY Taarray, // associative array, aka T[type] Tpointer, Treference, + Trefsuffix, // explicit ref suffix, aka Object ref Tfunction, Tident, Tclass, @@ -271,7 +272,7 @@ struct Type : Object void fixTo(Type *t); void check(); Type *castMod(unsigned mod); - Type *addMod(unsigned mod); + virtual Type *addMod(unsigned mod); Type *addStorageClass(StorageClass stc); Type *pointerTo(); Type *referenceTo(); @@ -538,6 +539,15 @@ struct TypeReference : TypeNext #endif }; +struct TypeRefSuffix : TypeNext +{ + TypeRefSuffix(Type *t); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); +}; + enum RET { RETregs = 1, // returned in registers @@ -820,8 +830,10 @@ struct TypeTypedef : Type struct TypeClass : Type { ClassDeclaration *sym; + TypeRefSuffix *ref; TypeClass(ClassDeclaration *sym); + Type *addMod(unsigned mod); d_uns64 size(Loc loc); char *toChars(); Type *syntaxCopy(); diff --git a/src/parse.c b/src/parse.c index 162fa851e2c0..679bbffd3545 100644 --- a/src/parse.c +++ b/src/parse.c @@ -2386,6 +2386,7 @@ Type *Parser::parseBasicType() * t [expression .. expression] * t function * t delegate + * t ref */ Type *Parser::parseBasicType2(Type *t) @@ -2399,6 +2400,14 @@ Type *Parser::parseBasicType2(Type *t) t = new TypePointer(t); nextToken(); continue; + + case TOKref: + // handle explicit reference marker for class: + // Object ref + // const(Object)ref + t = new TypeRefSuffix(t); + nextToken(); + continue; case TOKlbracket: // Handle []. Make sure things like @@ -4465,6 +4474,10 @@ int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) //case TOKand: t = peek(t); continue; + + case TOKref: + t = peek(t); + continue; case TOKlbracket: t = peek(t); From 11850ae027ac4b7dc997ee67024cb50f4a7e2f68 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sat, 4 Dec 2010 12:19:56 -0500 Subject: [PATCH 02/19] Finalized implementation of const(Object)ref syntax, now works with Unqual!. --- src/declaration.c | 15 +-- src/mtype.c | 296 +++++++++++++++++++++++++++++----------------- src/mtype.h | 20 +++- 3 files changed, 213 insertions(+), 118 deletions(-) diff --git a/src/declaration.c b/src/declaration.c index d7e297f369cb..622cb8f88373 100644 --- a/src/declaration.c +++ b/src/declaration.c @@ -890,21 +890,18 @@ void VarDeclaration::semantic(Scope *sc) type = type->addStorageClass(storage_class); /* Adjust storage class to reflect type - * For classes, use the reference's storage class (if available) */ - Type *sctype = type; - if (type->ty == Tclass && ((TypeClass *)type)->ref) - sctype = ((TypeClass *)type)->ref; - if (sctype->isConst()) + Type *thead = type->head(); + if (thead->isConst()) { storage_class |= STCconst; - if (type->isShared()) + if (thead->isShared()) storage_class |= STCshared; } - else if (sctype->isImmutable()) + else if (thead->isImmutable()) storage_class |= STCimmutable; - else if (sctype->isShared()) + else if (thead->isShared()) storage_class |= STCshared; - else if (sctype->isWild()) + else if (thead->isWild()) storage_class |= STCwild; if (isSynchronized()) diff --git a/src/mtype.c b/src/mtype.c index 9ee9ab490aed..8cb90e0acebc 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -122,6 +122,7 @@ Type::Type(TY ty) this->ty = ty; this->mod = 0; this->deco = NULL; + this->thead = NULL; #if DMDV2 this->cto = NULL; this->ito = NULL; @@ -199,6 +200,7 @@ void Type::init() mangleChar[Taarray] = 'H'; mangleChar[Tpointer] = 'P'; mangleChar[Treference] = 'R'; + mangleChar[Trefsuffix] = 'X'; mangleChar[Tfunction] = 'F'; mangleChar[Tident] = 'I'; mangleChar[Tclass] = 'C'; @@ -241,7 +243,6 @@ void Type::init() mangleChar[Ttuple] = 'B'; mangleChar[Tslice] = '@'; mangleChar[Treturn] = '@'; - mangleChar[Trefsuffix] = '@'; for (i = 0; i < TMAX; i++) { if (!mangleChar[i]) @@ -348,7 +349,7 @@ MATCH Type::constConv(Type *to) { if (equals(to)) return MATCHexact; - if (ty == to->ty && MODimplicitConv(mod, to->mod)) + if (ty == to->ty && MODimplicitConv(head()->mod, to->head()->mod)) return MATCHconst; return MATCHnomatch; } @@ -360,10 +361,10 @@ MATCH Type::constConv(Type *to) Type *Type::constOf() { //printf("Type::constOf() %p %s\n", this, toChars()); - if (mod == MODconst) + if (head()->mod == MODconst) return this; if (cto) - { assert(cto->mod == MODconst); + { assert(cto->head()->mod == MODconst); return cto; } Type *t = makeConst(); @@ -380,13 +381,13 @@ Type *Type::constOf() Type *Type::invariantOf() { //printf("Type::invariantOf() %p %s\n", this, toChars()); - if (isImmutable()) + if (head()->isImmutable()) { return this; } if (ito) { - assert(ito->isImmutable()); + assert(ito->head()->isImmutable()); return ito; } Type *t = makeInvariant(); @@ -404,24 +405,24 @@ Type *Type::mutableOf() { //printf("Type::mutableOf() %p, %s\n", this, toChars()); Type *t = this; - if (isConst()) - { if (isShared()) + if (head()->isConst()) + { if (head()->isShared()) t = sto; // shared const => shared else t = cto; // const => naked - assert(!t || t->isMutable()); + assert(!t || t->head()->isMutable()); } - else if (isImmutable()) + else if (head()->isImmutable()) { t = ito; // immutable => naked - assert(!t || (t->isMutable() && !t->isShared())); + assert(!t || (t->head()->isMutable() && !t->head()->isShared())); } - else if (isWild()) + else if (head()->isWild()) { - if (isShared()) + if (head()->isShared()) t = sto; // shared wild => shared else t = wto; // wild => naked - assert(!t || t->isMutable()); + assert(!t || t->head()->isMutable()); } if (!t) { @@ -429,20 +430,20 @@ Type *Type::mutableOf() t = t->merge(); t->fixTo(this); } - assert(t->isMutable()); + assert(t->head()->isMutable()); return t; } Type *Type::sharedOf() { //printf("Type::sharedOf() %p, %s\n", this, toChars()); - if (mod == MODshared) + if (head()->mod == MODshared) { return this; } if (sto) { - assert(sto->isShared()); + assert(sto->head()->isShared()); return sto; } Type *t = makeShared(); @@ -455,13 +456,13 @@ Type *Type::sharedOf() Type *Type::sharedConstOf() { //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); - if (mod == (MODshared | MODconst)) + if (head()->mod == (MODshared | MODconst)) { return this; } if (scto) { - assert(scto->mod == (MODshared | MODconst)); + assert(scto->head()->mod == (MODshared | MODconst)); return scto; } Type *t = makeSharedConst(); @@ -488,39 +489,25 @@ Type *Type::unSharedOf() //printf("Type::unSharedOf() %p, %s\n", this, toChars()); Type *t = this; - if (isShared()) + if (head()->isShared()) { - if (isConst()) + if (head()->isConst()) t = cto; // shared const => const - else if (isWild()) + else if (head()->isWild()) t = wto; // shared wild => wild else t = sto; - assert(!t || !t->isShared()); + assert(!t || !t->head()->isShared()); } if (!t) { - unsigned sz = sizeTy[ty]; - t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = mod & ~MODshared; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; + t = makeUnShared(); t = t->merge(); t->fixTo(this); } - assert(!t->isShared()); + assert(!t->head()->isShared()); return t; } @@ -531,13 +518,13 @@ Type *Type::unSharedOf() Type *Type::wildOf() { //printf("Type::wildOf() %p %s\n", this, toChars()); - if (mod == MODwild) + if (head()->mod == MODwild) { return this; } if (wto) { - assert(wto->isWild()); + assert(wto->head()->isWild()); return wto; } Type *t = makeWild(); @@ -550,13 +537,13 @@ Type *Type::wildOf() Type *Type::sharedWildOf() { //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); - if (mod == (MODshared | MODwild)) + if (head()->mod == (MODshared | MODwild)) { return this; } if (swto) { - assert(swto->mod == (MODshared | MODwild)); + assert(swto->head()->mod == (MODshared | MODwild)); return swto; } Type *t = makeSharedWild(); @@ -584,9 +571,9 @@ void Type::fixTo(Type *t) scto = t->scto; #endif - assert(mod != t->mod); + assert(head()->mod != t->head()->mod); #define X(m, n) (((m) << 4) | (n)) - switch (X(mod, t->mod)) + switch (X(head()->mod, t->head()->mod)) { case X(0, MODconst): cto = t; @@ -796,69 +783,69 @@ void Type::fixTo(Type *t) void Type::check() { - switch (mod) + switch (head()->mod) { case 0: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); + if (cto) assert(cto->head()->mod == MODconst); + if (ito) assert(ito->head()->mod == MODimmutable); + if (sto) assert(sto->head()->mod == MODshared); + if (scto) assert(scto->head()->mod == (MODshared | MODconst)); + if (wto) assert(wto->head()->mod == MODwild); + if (swto) assert(swto->head()->mod == (MODshared | MODwild)); break; case MODconst: - if (cto) assert(cto->mod == 0); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); + if (cto) assert(cto->head()->mod == 0); + if (ito) assert(ito->head()->mod == MODimmutable); + if (sto) assert(sto->head()->mod == MODshared); + if (scto) assert(scto->head()->mod == (MODshared | MODconst)); + if (wto) assert(wto->head()->mod == MODwild); + if (swto) assert(swto->head()->mod == (MODshared | MODwild)); break; case MODimmutable: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == 0); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); + if (cto) assert(cto->head()->mod == MODconst); + if (ito) assert(ito->head()->mod == 0); + if (sto) assert(sto->head()->mod == MODshared); + if (scto) assert(scto->head()->mod == (MODshared | MODconst)); + if (wto) assert(wto->head()->mod == MODwild); + if (swto) assert(swto->head()->mod == (MODshared | MODwild)); break; case MODshared: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == 0); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); + if (cto) assert(cto->head()->mod == MODconst); + if (ito) assert(ito->head()->mod == MODimmutable); + if (sto) assert(sto->head()->mod == 0); + if (scto) assert(scto->head()->mod == (MODshared | MODconst)); + if (wto) assert(wto->head()->mod == MODwild); + if (swto) assert(swto->head()->mod == (MODshared | MODwild)); break; case MODshared | MODconst: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == 0); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); + if (cto) assert(cto->head()->mod == MODconst); + if (ito) assert(ito->head()->mod == MODimmutable); + if (sto) assert(sto->head()->mod == MODshared); + if (scto) assert(scto->head()->mod == 0); + if (wto) assert(wto->head()->mod == MODwild); + if (swto) assert(swto->head()->mod == (MODshared | MODwild)); break; case MODwild: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == 0); - if (swto) assert(swto->mod == (MODshared | MODwild)); + if (cto) assert(cto->head()->mod == MODconst); + if (ito) assert(ito->head()->mod == MODimmutable); + if (sto) assert(sto->head()->mod == MODshared); + if (scto) assert(scto->head()->mod == (MODshared | MODconst)); + if (wto) assert(wto->head()->mod == 0); + if (swto) assert(swto->head()->mod == (MODshared | MODwild)); break; case MODshared | MODwild: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == 0); + if (cto) assert(cto->head()->mod == MODconst); + if (ito) assert(ito->head()->mod == MODimmutable); + if (sto) assert(sto->head()->mod == MODshared); + if (scto) assert(scto->head()->mod == (MODshared | MODconst)); + if (wto) assert(wto->head()->mod == MODwild); + if (swto) assert(swto->head()->mod == 0); break; default: @@ -994,6 +981,26 @@ Type *Type::makeSharedConst() return t; } +Type *Type::makeUnShared() +{ + unsigned sz = sizeTy[ty]; + Type *t = (Type *)mem.malloc(sz); + memcpy(t, this, sz); + t->mod = mod & ~MODshared; + t->deco = NULL; + t->arrayof = NULL; + t->pto = NULL; + t->rto = NULL; + t->cto = NULL; + t->ito = NULL; + t->sto = NULL; + t->scto = NULL; + t->wto = NULL; + t->swto = NULL; + t->vtinfo = NULL; + return t; +} + Type *Type::makeWild() { if (wto) @@ -1112,7 +1119,7 @@ Type *Type::addMod(unsigned mod) /* Add anything to immutable, and it remains immutable */ - if (!t->isImmutable()) + if (!t->head()->isImmutable()) { //printf("addMod(%x) %s\n", mod, toChars()); switch (mod) @@ -1121,7 +1128,7 @@ Type *Type::addMod(unsigned mod) break; case MODconst: - if (isShared()) + if (head()->isShared()) t = sharedConstOf(); else t = constOf(); @@ -1132,9 +1139,9 @@ Type *Type::addMod(unsigned mod) break; case MODshared: - if (isConst()) + if (head()->isConst()) t = sharedConstOf(); - else if (isWild()) + else if (head()->isWild()) t = sharedWildOf(); else t = sharedOf(); @@ -1145,9 +1152,9 @@ Type *Type::addMod(unsigned mod) break; case MODwild: - if (isConst()) + if (head()->isConst()) ; - else if (isShared()) + else if (head()->isShared()) t = sharedWildOf(); else t = wildOf(); @@ -4454,14 +4461,18 @@ Type *TypeRefSuffix::semantic(Loc loc, Scope *sc) { //printf("TypeReference::semantic()\n"); Type *n = next->semantic(loc, sc); - if (n->ty != Tclass) + if (n->ty != Tclass || next->ty != Tident /* block double ref */) { error(loc, "ref suffix is only valid for class types"); return n; } next = n; transitive(); - ((TypeClass *)n)->ref = this; - return n; + if (next->mod != mod) + { /* apply ref suffix modifiers. + */ + return next->castMod(mod); + } + return next; } void TypeRefSuffix::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -7292,14 +7303,27 @@ TypeClass::TypeClass(ClassDeclaration *sym) : Type(Tclass) { this->sym = sym; - this->ref = NULL; } -Type *TypeClass::addMod(unsigned mod) +TypeClass::TypeClass(TypeClass* tc, unsigned char headmod) + : Type(Tclass) { - if (ref) - ref = (TypeRefSuffix *)ref->addMod(mod); - return Type::addMod(mod); + this->sym = tc->sym; + this->mod = tc->mod; + + // Fix class modifiers + if (headmod & MODimmutable) + this->mod = MODimmutable; + else if (!isImmutable()) + this->mod |= headmod; + + if (headmod != this->mod) + { + thead = new TypeRefSuffix(this); + thead->mod = headmod; + ((TypeRefSuffix *)thead)->next = this; + thead->check(); + } } char *TypeClass::toChars() @@ -7335,6 +7359,17 @@ Dsymbol *TypeClass::toDsymbol(Scope *sc) void TypeClass::toDecoBuffer(OutBuffer *buf, int flag) { + if (thead && thead->mod != this->mod) + { /* Only print thead's deco if thead->mod differs from this->mod. + * Avoiding infinite recurtion by temporarily detatching ref member. + */ + assert(thead->ty == Trefsuffix && ((TypeRefSuffix *)thead)->next == this); + Type *savedhead = thead; + thead = NULL; + savedhead->toDecoBuffer(buf, flag); + thead = savedhead; + return; + } const char *name = sym->mangle(); //printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name); Type::toDecoBuffer(buf, flag); @@ -7343,6 +7378,17 @@ void TypeClass::toDecoBuffer(OutBuffer *buf, int flag) void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { + if (thead && thead->mod != this->mod) + { /* Only print 'ref' marker if thead->mod differs from this->mod. + * Avoiding infinite recurtion by temporarily detatching ref member. + */ + assert(thead->ty == Trefsuffix && ((TypeRefSuffix *)thead)->next == this); + Type *savedhead = thead; + thead = NULL; + savedhead->toCBuffer2(buf, hgs, mod); + thead = savedhead; + return; + } if (mod != this->mod) { toCBuffer3(buf, hgs, mod); return; @@ -7703,15 +7749,53 @@ MATCH TypeClass::constConv(Type *to) return MATCHnomatch; } +Type *TypeClass::makeConst() +{ + return new TypeClass(this, MODconst); +} + +Type *TypeClass::makeInvariant() +{ + return new TypeClass(this, MODimmutable); +} + +Type *TypeClass::makeShared() +{ + return new TypeClass(this, MODshared); +} + +Type *TypeClass::makeSharedConst() +{ + return new TypeClass(this, MODshared | MODconst); +} +Type *TypeClass::makeWild() +{ + return new TypeClass(this, MODwild); +} + +Type *TypeClass::makeSharedWild() +{ + return new TypeClass(this, MODshared | MODwild); +} + +Type *TypeClass::makeUnShared() +{ + return new TypeClass(this, head()->mod & ~MODshared); +} + +Type *TypeClass::makeMutable() +{ + return new TypeClass(this, head()->mod & MODshared); +} + Type *TypeClass::toHeadMutable() { - if (!mod) + if (!head()->mod) return this; - this->ref = new TypeRefSuffix(this); - // don't perform semantic on t->ref - return this; + return mutableOf(); } + Expression *TypeClass::defaultInit(Loc loc) { #if LOGDEFAULTINIT diff --git a/src/mtype.h b/src/mtype.h index 6bf9ed61964d..b35bb8e291b1 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -122,6 +122,11 @@ struct Type : Object #define MODwild 8 // type is wild #define MODmutable 0x10 // type is mutable (only used in wildcard matching) char *deco; + + /* Head type which holds reference modifiers for class type. + * Points to 'this' for other types. + */ + Type *thead; /* These are cached values that are lazily evaluated by constOf(), invariantOf(), etc. * They should not be referenced by anybody but mtype.c. @@ -222,6 +227,7 @@ struct Type : Object virtual Type *syntaxCopy(); int equals(Object *o); int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() + Type *head() { return thead ? thead : this; } int covariant(Type *t); char *toChars(); static char needThisPrefix(); @@ -272,7 +278,7 @@ struct Type : Object void fixTo(Type *t); void check(); Type *castMod(unsigned mod); - virtual Type *addMod(unsigned mod); + Type *addMod(unsigned mod); Type *addStorageClass(StorageClass stc); Type *pointerTo(); Type *referenceTo(); @@ -281,6 +287,7 @@ struct Type : Object virtual Type *makeInvariant(); virtual Type *makeShared(); virtual Type *makeSharedConst(); + virtual Type *makeUnShared(); virtual Type *makeWild(); virtual Type *makeSharedWild(); virtual Type *makeMutable(); @@ -830,14 +837,21 @@ struct TypeTypedef : Type struct TypeClass : Type { ClassDeclaration *sym; - TypeRefSuffix *ref; TypeClass(ClassDeclaration *sym); - Type *addMod(unsigned mod); + TypeClass(TypeClass* tc, unsigned char headmod); d_uns64 size(Loc loc); char *toChars(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); + Type *makeConst(); + Type *makeInvariant(); + Type *makeShared(); + Type *makeSharedConst(); + Type *makeUnShared(); + Type *makeWild(); + Type *makeSharedWild(); + Type *makeMutable(); Dsymbol *toDsymbol(Scope *sc); void toDecoBuffer(OutBuffer *buf, int flag); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); From e5385fad1a156f1561c956294a337d5ff277bf8d Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sat, 4 Dec 2010 16:29:20 -0500 Subject: [PATCH 03/19] Now checking head-const in some expressions. --- src/declaration.c | 2 +- src/expression.c | 10 +++++----- src/func.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/declaration.c b/src/declaration.c index 622cb8f88373..fdbaa10e4284 100644 --- a/src/declaration.c +++ b/src/declaration.c @@ -91,7 +91,7 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t) if (sc->incontract && isResult()) error(loc, "cannot modify result '%s' in contract", toChars()); - if (isCtorinit() && !t->isMutable()) + if (isCtorinit() && !t->head()->isMutable()) { // It's only modifiable if inside the right constructor Dsymbol *s = sc->func; while (1) diff --git a/src/expression.c b/src/expression.c index 9ec74d04ad37..b33ebb6891aa 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1095,7 +1095,7 @@ Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) // See if this expression is a modifiable lvalue (i.e. not const) #if DMDV2 - if (type && (!type->isMutable() || !type->isAssignable())) + if (type && (!type->head()->isMutable() || !type->isAssignable())) error("%s is not mutable", e->toChars()); #endif return toLvalue(sc, e); @@ -6234,9 +6234,9 @@ Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) Type *t1 = e1->type->toBasetype(); - if (!t1->isMutable() || - (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || - !var->type->isMutable() || + if (!t1->head()->isMutable() || + (t1->ty == Tpointer && !t1->nextOf()->head()->isMutable()) || + !var->type->head()->isMutable() || !var->type->isAssignable() || var->storage_class & STCmanifest ) @@ -8695,7 +8695,7 @@ Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) modifiable = 1; if (e1->op == TOKstring) error("string literals are immutable"); - if (type && !type->isMutable()) + if (type && !type->head()->isMutable()) error("%s isn't mutable", e->toChars()); Type *t1 = e1->type->toBasetype(); if (t1->ty == Taarray) diff --git a/src/func.c b/src/func.c index 1ed8a0061565..4ba6938be954 100644 --- a/src/func.c +++ b/src/func.c @@ -1281,7 +1281,7 @@ void FuncDeclaration::semantic3(Scope *sc) for (int i = 0; i < cd->fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - if (v->ctorinit == 0 && v->isCtorinit() && !v->type->isMutable()) + if (v->ctorinit == 0 && v->isCtorinit() && !v->type->head()->isMutable()) error("missing initializer for final field %s", v->toChars()); } } From a7986e8c28dc12f0fa7281b5f39431b1ce2ea52e Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sat, 4 Dec 2010 17:17:06 -0500 Subject: [PATCH 04/19] Fix for typeinfo generation. --- src/typinf.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/typinf.c b/src/typinf.c index 860e9a7a83dc..7fdb1aa2a254 100644 --- a/src/typinf.c +++ b/src/typinf.c @@ -239,8 +239,13 @@ void TypeInfoConstDeclaration::toDt(dt_t **pdt) //printf("TypeInfoConstDeclaration::toDt() %s\n", toChars()); dtxoff(pdt, Type::typeinfoconst->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Const dtsize_t(pdt, 0); // monitor - Type *tm = tinfo->mutableOf(); - tm = tm->merge(); + Type *tm; + if (tinfo->ty == Tclass) + tm = ((TypeClass *)tinfo)->sym->type; + else + { tm = tinfo->mutableOf(); + tm = tm->merge(); + } tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } @@ -250,8 +255,13 @@ void TypeInfoInvariantDeclaration::toDt(dt_t **pdt) //printf("TypeInfoInvariantDeclaration::toDt() %s\n", toChars()); dtxoff(pdt, Type::typeinfoinvariant->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Invariant dtsize_t(pdt, 0); // monitor - Type *tm = tinfo->mutableOf(); - tm = tm->merge(); + Type *tm; + if (tinfo->ty == Tclass) + tm = ((TypeClass *)tinfo)->sym->type; + else + { tm = tinfo->mutableOf(); + tm = tm->merge(); + } tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } @@ -261,8 +271,16 @@ void TypeInfoSharedDeclaration::toDt(dt_t **pdt) //printf("TypeInfoSharedDeclaration::toDt() %s\n", toChars()); dtxoff(pdt, Type::typeinfoshared->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Shared dtsize_t(pdt, 0); // monitor - Type *tm = tinfo->unSharedOf(); - tm = tm->merge(); + Type *tm; + if (tinfo->ty == Tclass) + { tm = ((TypeClass *)tinfo)->sym->type; + if (tinfo->mod != MODshared) // other modifiers + tm = tm->addMod(tinfo->mod & ~MODshared); + } + else + { tm = tinfo->mutableOf(); + tm = tm->merge(); + } tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } @@ -272,8 +290,13 @@ void TypeInfoWildDeclaration::toDt(dt_t **pdt) //printf("TypeInfoWildDeclaration::toDt() %s\n", toChars()); dtxoff(pdt, Type::typeinfowild->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Wild dtsize_t(pdt, 0); // monitor - Type *tm = tinfo->mutableOf(); - tm = tm->merge(); + Type *tm; + if (tinfo->ty == Tclass) + tm = ((TypeClass *)tinfo)->sym->type; + else + { tm = tinfo->mutableOf(); + tm = tm->merge(); + } tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } From d23d1e5249c0a316273f9c49a6a25bc212953f9b Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 5 Dec 2010 08:04:14 -0500 Subject: [PATCH 05/19] Adjustments for foreach and array ops with const(Object)ref. --- src/expression.c | 2 +- src/osx.mak | 4 ++-- src/statement.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/expression.c b/src/expression.c index b33ebb6891aa..9ad03f70e996 100644 --- a/src/expression.c +++ b/src/expression.c @@ -9104,7 +9104,7 @@ Expression *AssignExp::semantic(Scope *sc) else if (e1->op == TOKslice) { Type *tn = e1->type->nextOf(); - if (tn && !tn->isMutable() && op != TOKconstruct) + if (tn && !tn->head()->isMutable() && op != TOKconstruct) { error("slice %s is not mutable", e1->toChars()); return new ErrorExp(); } diff --git a/src/osx.mak b/src/osx.mak index a7c7241360bd..2302d786ca86 100644 --- a/src/osx.mak +++ b/src/osx.mak @@ -20,8 +20,8 @@ CC=g++ -m32 -isysroot $(SDK) WARNINGS=-Wno-deprecated -Wstrict-aliasing -#GFLAGS = $(WARNINGS) -D__near= -D__pascal= -fno-exceptions -g -DDEBUG=1 -DUNITTEST $(COV) -GFLAGS = $(WARNINGS) -D__near= -D__pascal= -fno-exceptions -O2 +GFLAGS = $(WARNINGS) -D__near= -D__pascal= -fno-exceptions -g -DDEBUG=1 -DUNITTEST $(COV) +#GFLAGS = $(WARNINGS) -D__near= -D__pascal= -fno-exceptions -O2 CFLAGS = $(GFLAGS) -I$(ROOT) -D__I86__=1 -DMARS=1 -DTARGET_OSX=1 -D_DH MFLAGS = $(GFLAGS) -I$C -I$(TK) -D__I86__=1 -DMARS=1 -DTARGET_OSX=1 -D_DH diff --git a/src/statement.c b/src/statement.c index 98c62a63ff5b..7d65cbe96435 100644 --- a/src/statement.c +++ b/src/statement.c @@ -1536,7 +1536,7 @@ Statement *ForeachStatement::semantic(Scope *sc) value = var; /* Reference to immutable data should be marked as const */ - if (var->storage_class & STCref && !tn->isMutable()) + if (var->storage_class & STCref && !tn->head()->isMutable()) { var->storage_class |= STCconst; } @@ -3534,7 +3534,7 @@ Statement *ReturnStatement::semantic(Scope *sc) if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration()) { // Function returns a reference - if (tbret->isMutable()) + if (tbret->head()->isMutable()) exp = exp->modifiableLvalue(sc, exp); else exp = exp->toLvalue(sc, exp); From ad046d3bc38b72d35a0570bca0529d17e11684e6 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 5 Dec 2010 16:29:28 -0500 Subject: [PATCH 06/19] Fixed small mistake introduced in TypeInfo_Shared by last commit.. --- src/typinf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typinf.c b/src/typinf.c index 7fdb1aa2a254..4fe15bbe2504 100644 --- a/src/typinf.c +++ b/src/typinf.c @@ -278,7 +278,7 @@ void TypeInfoSharedDeclaration::toDt(dt_t **pdt) tm = tm->addMod(tinfo->mod & ~MODshared); } else - { tm = tinfo->mutableOf(); + { tm = tinfo->unSharedOf(); tm = tm->merge(); } tm->getTypeInfo(NULL); From 8eb9b1707b04f30544480379e501bb74faf0db5d Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 5 Dec 2010 16:30:59 -0500 Subject: [PATCH 07/19] Added const(Object)ref related tests. --- test/compilable/objconst1.d | 7 +++ test/compilable/objconst2.d | 7 +++ test/compilable/objconst3.d | 10 ++++ test/compilable/objconst4.d | 11 +++++ test/compilable/objconst5.d | 6 +++ test/fail_compilation/objconst1fail.d | 7 +++ test/fail_compilation/objconst2fail.d | 7 +++ test/runnable/objconst1unqual.d | 66 +++++++++++++++++++++++++++ test/runnable/objconst2typeinfo.d | 14 ++++++ 9 files changed, 135 insertions(+) create mode 100644 test/compilable/objconst1.d create mode 100644 test/compilable/objconst2.d create mode 100644 test/compilable/objconst3.d create mode 100644 test/compilable/objconst4.d create mode 100644 test/compilable/objconst5.d create mode 100644 test/fail_compilation/objconst1fail.d create mode 100644 test/fail_compilation/objconst2fail.d create mode 100644 test/runnable/objconst1unqual.d create mode 100644 test/runnable/objconst2typeinfo.d diff --git a/test/compilable/objconst1.d b/test/compilable/objconst1.d new file mode 100644 index 000000000000..bfa54b5bd6cc --- /dev/null +++ b/test/compilable/objconst1.d @@ -0,0 +1,7 @@ + +void main() +{ + const(Object)ref copy = new const(Object)ref; + const(Object) value = new const(Object)ref; + copy = value; +} \ No newline at end of file diff --git a/test/compilable/objconst2.d b/test/compilable/objconst2.d new file mode 100644 index 000000000000..b29181859a33 --- /dev/null +++ b/test/compilable/objconst2.d @@ -0,0 +1,7 @@ + +void main() +{ + const(Object)ref[] copy = new const(Object)ref[12]; + const(Object)[] value = new const(Object)ref[12]; + copy[] = value[]; +} \ No newline at end of file diff --git a/test/compilable/objconst3.d b/test/compilable/objconst3.d new file mode 100644 index 000000000000..77ecc74752e9 --- /dev/null +++ b/test/compilable/objconst3.d @@ -0,0 +1,10 @@ + +void main() +{ + const(Object)ref[] objects = new const(Object)ref[12]; + foreach (ref object; objects) + { + static assert(is(typeof(object) == const(Object)ref)); + object = new Object; + } +} \ No newline at end of file diff --git a/test/compilable/objconst4.d b/test/compilable/objconst4.d new file mode 100644 index 000000000000..c987ce0ffd40 --- /dev/null +++ b/test/compilable/objconst4.d @@ -0,0 +1,11 @@ + +struct S +{ + const(Object)ref o; +} + +void main() +{ + S s; + s.o = new Object; +} \ No newline at end of file diff --git a/test/compilable/objconst5.d b/test/compilable/objconst5.d new file mode 100644 index 000000000000..45435910d7d8 --- /dev/null +++ b/test/compilable/objconst5.d @@ -0,0 +1,6 @@ + +void main() +{ + auto o = cast(const(Object)ref)(new const(Object)); + static assert(is(typeof(o) == const(Object)ref)); +} \ No newline at end of file diff --git a/test/fail_compilation/objconst1fail.d b/test/fail_compilation/objconst1fail.d new file mode 100644 index 000000000000..5a8d4cb97133 --- /dev/null +++ b/test/fail_compilation/objconst1fail.d @@ -0,0 +1,7 @@ + +void main() +{ + const(Object) copy; + const(Object) value; + copy = value; +} \ No newline at end of file diff --git a/test/fail_compilation/objconst2fail.d b/test/fail_compilation/objconst2fail.d new file mode 100644 index 000000000000..ffe0901411f4 --- /dev/null +++ b/test/fail_compilation/objconst2fail.d @@ -0,0 +1,7 @@ + +void main() +{ + const(Object)[] copy = new const(Object)ref[12]; + const(Object)[] value = new const(Object)ref[12]; + copy[] = value[]; +} \ No newline at end of file diff --git a/test/runnable/objconst1unqual.d b/test/runnable/objconst1unqual.d new file mode 100644 index 000000000000..f0acd1e61250 --- /dev/null +++ b/test/runnable/objconst1unqual.d @@ -0,0 +1,66 @@ +template Unqual(T) +{ + version (none) // Error: recursive alias declaration @@@BUG1308@@@ + { + static if (is(T U == const U)) alias Unqual!U Unqual; + else static if (is(T U == immutable U)) alias Unqual!U Unqual; + else static if (is(T U == shared U)) alias Unqual!U Unqual; + else alias T Unqual; + } + else // workaround + { + static if (is(T U == shared(const U))) alias U Unqual; + else static if (is(T U == const U )) alias U Unqual; + else static if (is(T U == immutable U )) alias U Unqual; + else static if (is(T U == shared U )) alias U Unqual; + else alias T Unqual; + } +} + +//unittest +//{ +// static assert(is(Unqual!(int) == int)); +// static assert(is(Unqual!(const int) == int)); +// static assert(is(Unqual!(immutable int) == int)); +// static assert(is(Unqual!(shared int) == int)); +// static assert(is(Unqual!(shared(const int)) == int)); +// alias immutable(int[]) ImmIntArr; +// static assert(is(Unqual!(ImmIntArr) == immutable(int)[])); + + static assert(is(Unqual!(const(Object)) == const(Object)ref)); + static assert(is(Unqual!(const(Object ref)) == const(Object)ref)); + static assert(is(Unqual!(const(immutable(Object)ref)) == immutable(Object)ref)); + static assert(!is(Unqual!(const(Object)) == const(Object))); + static assert(!is(Unqual!(const(Object)) == Object)); +//} + +import std.stdio; + +alias const(Object)ref OO; + +void test(const(OO)ref o) {} + +int main() +{ + writeln((&test).mangleof); + + writeln((const(Object)ref).stringof); + writeln((immutable(Object)ref).stringof); + writeln((shared(Object)ref).stringof); + writeln((const(Object)ref).mangleof); + writeln((immutable(Object)ref).mangleof); + writeln((shared(Object)ref).mangleof); + writeln(Object.mangleof); + assert((const(Object)ref).stringof == "const(Object)ref"); + assert((immutable(Object)ref).stringof == "immutable(Object)ref"); + assert((shared(Object)ref).stringof == "shared(Object)ref"); + assert((const(Object)).stringof == "const(Object)"); + assert((immutable(Object)).stringof == "immutable(Object)"); + assert((shared(Object)).stringof == "shared(Object)"); +// writeln((immutable(Object)ref).mangleof ~ " hello"); + //writeln((shared(const(Object)ref)).stringof); + //writeln((shared(const(Object)ref[])*).stringof); + //assert((shared(const(Object)ref)).stringof == "shared(const(Object)ref)"); + //assert((shared(const(Object)ref[])*).stringof == "shared(const(Object)ref[])*"); + return 0; +} diff --git a/test/runnable/objconst2typeinfo.d b/test/runnable/objconst2typeinfo.d new file mode 100644 index 000000000000..c89fc3e46130 --- /dev/null +++ b/test/runnable/objconst2typeinfo.d @@ -0,0 +1,14 @@ + +void main() +{ + // This tests wehther typeinfo was generated correctly. + typeid(const(Object)ref).toString(); + typeid(immutable(Object)ref).toString(); + typeid(shared(Object)ref).toString(); + typeid(shared(const(Object))ref).toString(); + typeid(inout(Object)ref).toString(); + typeid(inout(shared(Object))ref).toString(); + typeid(inout(shared(Object)ref)).toString(); + typeid(const(shared(Object)ref)).toString(); + typeid(shared(immutable(Object)ref)).toString(); +} \ No newline at end of file From e5a3a7b4b79a7768ebc90a3840daee0638160d2a Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sat, 18 Dec 2010 12:49:56 -0500 Subject: [PATCH 08/19] Improved error messages around ref suffix. --- src/mtype.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/mtype.c b/src/mtype.c index 8cb90e0acebc..838d69b4920a 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -4461,8 +4461,14 @@ Type *TypeRefSuffix::semantic(Loc loc, Scope *sc) { //printf("TypeReference::semantic()\n"); Type *n = next->semantic(loc, sc); - if (n->ty != Tclass || next->ty != Tident /* block double ref */) - { error(loc, "ref suffix is only valid for class types"); + if (next->ty == Trefsuffix) + { error(loc, "double ref suffix"); + return n; + } + if (n->ty != Tclass) + { if (sc->parameterSpecialization) + return this; + error(loc, "ref suffix is only valid for class types"); return n; } next = n; @@ -4482,6 +4488,9 @@ void TypeRefSuffix::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) return; } next->toCBuffer2(buf, hgs, this->mod); + // skip the space if last character in buffer is a closing parenthesis + if (buf->offset && buf->data[buf->offset-1] != ')') + buf->writeByte(' '); buf->writestring("ref"); } From 613a7f7d02c9cb14a3c801e702b1acf723f5445e Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sat, 18 Dec 2010 12:51:46 -0500 Subject: [PATCH 09/19] Call tm->merge() for class type in constness typeinfo declarations (was original behaviour). --- src/typinf.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/typinf.c b/src/typinf.c index 4fe15bbe2504..6014e4ce073c 100644 --- a/src/typinf.c +++ b/src/typinf.c @@ -243,9 +243,8 @@ void TypeInfoConstDeclaration::toDt(dt_t **pdt) if (tinfo->ty == Tclass) tm = ((TypeClass *)tinfo)->sym->type; else - { tm = tinfo->mutableOf(); - tm = tm->merge(); - } + tm = tinfo->mutableOf(); + tm = tm->merge(); tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } @@ -259,9 +258,8 @@ void TypeInfoInvariantDeclaration::toDt(dt_t **pdt) if (tinfo->ty == Tclass) tm = ((TypeClass *)tinfo)->sym->type; else - { tm = tinfo->mutableOf(); - tm = tm->merge(); - } + tm = tinfo->mutableOf(); + tm = tm->merge(); tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } @@ -274,13 +272,11 @@ void TypeInfoSharedDeclaration::toDt(dt_t **pdt) Type *tm; if (tinfo->ty == Tclass) { tm = ((TypeClass *)tinfo)->sym->type; - if (tinfo->mod != MODshared) // other modifiers - tm = tm->addMod(tinfo->mod & ~MODshared); + tm = tm->addMod(tinfo->mod & ~MODshared); // propagate other modifiers } else - { tm = tinfo->unSharedOf(); - tm = tm->merge(); - } + tm = tinfo->unSharedOf(); + tm = tm->merge(); tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } @@ -294,9 +290,8 @@ void TypeInfoWildDeclaration::toDt(dt_t **pdt) if (tinfo->ty == Tclass) tm = ((TypeClass *)tinfo)->sym->type; else - { tm = tinfo->mutableOf(); - tm = tm->merge(); - } + tm = tinfo->mutableOf(); + tm = tm->merge(); tm->getTypeInfo(NULL); dtxoff(pdt, tm->vtinfo->toSymbol(), 0, TYnptr); } From ccd1ced3102be3f7c42656719e4900e4e6e24f35 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sat, 18 Dec 2010 12:55:10 -0500 Subject: [PATCH 10/19] Handle ref suffix in template type deduction by ignoring it (for now) --- src/template.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/template.c b/src/template.c index 8464420528bc..874a8fec3fa7 100644 --- a/src/template.c +++ b/src/template.c @@ -1755,7 +1755,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, if (this == tparam) goto Lexact; - + if (tparam->ty == Tident) { // Determine which parameter tparam is @@ -2572,6 +2572,14 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet { //printf("TypeClass::deduceType(this = %s)\n", toChars()); + // Handle class ref suffix by ignoring it + TypeRefSuffix *refsuffix = NULL; + if (tparam->ty == Trefsuffix) + { + refsuffix = (TypeRefSuffix *)tparam; + tparam = refsuffix->next; + } + /* If this class is a template class, and we're matching * it against a template instance, convert the class type * to a template instance, too, and try again. @@ -2661,6 +2669,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet //printf("\t%d\n", (MATCH) implicitConvTo(tp)); return implicitConvTo(tp); } + return Type::deduceType(sc, tparam, parameters, dedtypes); } From 841e81a7c717290ffabec8427e92a1e02b6bfce5 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Thu, 30 Dec 2010 12:00:23 -0500 Subject: [PATCH 11/19] Type deduction now takes into account the modifiers for explicit 'ref' suffixes. --- src/template.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/template.c b/src/template.c index 874a8fec3fa7..300f080091a0 100644 --- a/src/template.c +++ b/src/template.c @@ -2571,12 +2571,20 @@ void deduceBaseClassParameters(BaseClass *b, MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) { //printf("TypeClass::deduceType(this = %s)\n", toChars()); - - // Handle class ref suffix by ignoring it - TypeRefSuffix *refsuffix = NULL; + + /* If we have an explicit 'ref' suffix, we need to check + * that our head modifiers are compatible with those of that + * suffix. In the abscence of an explicit 'ref' suffix, we let + * normal type deduction choose what the ref's mod should + * be and thus don't have to check anything. + */ if (tparam->ty == Trefsuffix) { - refsuffix = (TypeRefSuffix *)tparam; + TypeRefSuffix *refsuffix = (TypeRefSuffix *)tparam; + if (head()->mod != refsuffix->mod && !MODimplicitConv(head()->mod, refsuffix->mod)) + return MATCHnomatch; + + // now skip ref suffix tparam = refsuffix->next; } From 031c32b0982c0447bfccb69216765277e4c875a5 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 23 Jan 2011 14:51:35 -0500 Subject: [PATCH 12/19] Implemented "correct" behaviour for head modifiers in type deduction. --- src/mtype.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/src/mtype.c b/src/mtype.c index 838d69b4920a..2739133e1555 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -7320,12 +7320,65 @@ TypeClass::TypeClass(TypeClass* tc, unsigned char headmod) this->sym = tc->sym; this->mod = tc->mod; - // Fix class modifiers - if (headmod & MODimmutable) - this->mod = MODimmutable; - else if (!isImmutable()) - this->mod |= headmod; + // Apply head modifiers to class (transitivity) + if (headmod != 0) { + if (this->mod == 0) + this->mod = headmod; + else if (headmod == MODimmutable || this->mod == MODimmutable) + this->mod = MODimmutable; + else + { + // remaining cases combining shared, const, and wild + #define X(m, n) (((m) << 4) | (n)) + switch (X(headmod, this->mod)) + { + case X(MODshared, MODshared): + this->mod = MODshared; + break; + + case X(MODconst, MODwild): + case X(MODconst, MODconst): + case X(MODwild, MODconst): + this->mod = MODconst; + break; + + case X(MODconst, MODshared): + case X(MODconst | MODshared, MODshared): + case X(MODconst | MODshared, MODwild): + case X(MODshared, MODconst): + case X(MODconst | MODshared, MODconst): + case X(MODwild | MODshared, MODconst): + case X(MODconst, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODshared, MODconst | MODshared): + case X(MODconst, MODconst | MODshared): + case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + this->mod = MODconst | MODshared; + break; + + case X(MODwild, MODwild): + this->mod = MODwild; + break; + + case X(MODwild, MODshared): + case X(MODwild | MODshared, MODshared): + case X(MODshared, MODwild): + case X(MODwild | MODshared, MODwild): + case X(MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): + case X(MODwild | MODshared, MODwild | MODshared): + this->mod = MODwild | MODshared; + break; + + default: + assert(0); + } + } + } + // Create type to hold head-modifiers (if they are different) if (headmod != this->mod) { thead = new TypeRefSuffix(this); From 239c013ddffdef5d1bfa01f498147224a9fd2441 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 23 Jan 2011 14:52:02 -0500 Subject: [PATCH 13/19] Added a few tests. --- test/compilable/objconst10.d | 43 ++++++++ test/compilable/objconst6.d | 10 ++ test/compilable/objconst7mangleof.d | 19 ++++ test/compilable/objconst8ptr.d | 6 ++ test/compilable/objconst9tmpl.d | 156 ++++++++++++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100644 test/compilable/objconst10.d create mode 100644 test/compilable/objconst6.d create mode 100644 test/compilable/objconst7mangleof.d create mode 100644 test/compilable/objconst8ptr.d create mode 100644 test/compilable/objconst9tmpl.d diff --git a/test/compilable/objconst10.d b/test/compilable/objconst10.d new file mode 100644 index 000000000000..dd9240a84c81 --- /dev/null +++ b/test/compilable/objconst10.d @@ -0,0 +1,43 @@ + +class C { + + const(C) constTest() const { return this; } + immutable(C) immutableTest() immutable { return this; } + shared(C) sharedTest() shared { return this; } + shared(const(C)) sharedConstTest() shared const { return this; } + inout(C) inoutTest() inout { return this; } + + const(C)ref constTestRef() const { return this; } + immutable(C)ref immutableTestRef() immutable { return this; } + shared(C)ref sharedTestRef() shared { return this; } + shared(const(C))ref sharedConstTestRef() shared const { return this; } + inout(C)ref inoutTestRef() inout { return this; } + +} + +void main() { + C a = new C; + const(C) ac; + ac = a.constTest(); + ac = a.constTestRef(); + a = a.inoutTest(); + a = a.inoutTestRef(); + + immutable(C)ref b = new immutable(C); + const(C)ref bc; + bc = b.constTest(); + bc = b.constTestRef(); + b = b.inoutTest(); + b = b.inoutTestRef(); + b = b.immutableTest(); + b = b.immutableTestRef(); + + shared(C)ref c = new shared(C); + const(C)ref cc; + cc = c.sharedConstTest(); + cc = c.sharedConstTestRef(); + c = c.inoutTest(); + c = c.inoutTestRef(); + c = c.sharedTest(); + c = c.sharedTestRef(); +} diff --git a/test/compilable/objconst6.d b/test/compilable/objconst6.d new file mode 100644 index 000000000000..3d23917e34fb --- /dev/null +++ b/test/compilable/objconst6.d @@ -0,0 +1,10 @@ + +const(Object)ref test() { + return new Object; +} + +void main() { + auto obj = test(); + static assert(is(typeof(obj) == const(Object)ref)); + static assert(!is(typeof(obj) == const(Object))); +} \ No newline at end of file diff --git a/test/compilable/objconst7mangleof.d b/test/compilable/objconst7mangleof.d new file mode 100644 index 000000000000..592c7e963130 --- /dev/null +++ b/test/compilable/objconst7mangleof.d @@ -0,0 +1,19 @@ + +// Mangling with no 'ref' suffix is be preserved +static assert((shared(Object)).mangleof == "OC6Object"); +static assert((const(Object)).mangleof == "xC6Object"); +static assert((immutable(Object)).mangleof == "yC6Object"); +static assert((shared(const(Object))).mangleof == "OxC6Object"); +static assert((inout(Object)).mangleof == "NgC6Object"); +static assert((shared(inout(Object))).mangleof == "ONgC6Object"); + +// Mangling with 'ref' suffix: the 'X' represents the suffix and is only present +// when the reference's modifiers is different from those of the class. +static assert((const(Object)ref).mangleof == "XxC6Object"); +static assert((const(immutable(Object)ref)).mangleof == "xXyC6Object"); +static assert((shared(inout(Object)ref)).mangleof == "OXOxC6Object"); + +// Reference suffix is not mangled when it has the same modifiers +static assert((const(Object ref))).mangleof == "xC6Object"); +static assert((inout(Object ref))).mangleof == "NgC6Object"); + diff --git a/test/compilable/objconst8ptr.d b/test/compilable/objconst8ptr.d new file mode 100644 index 000000000000..cf4ed123dc39 --- /dev/null +++ b/test/compilable/objconst8ptr.d @@ -0,0 +1,6 @@ + +void main() +{ + const(Object)ref* p = (new const(Object)ref[1]).ptr; // hard to get a new "const(Object)ref*" + *p = new Object; +} \ No newline at end of file diff --git a/test/compilable/objconst9tmpl.d b/test/compilable/objconst9tmpl.d new file mode 100644 index 000000000000..3450c56f25ea --- /dev/null +++ b/test/compilable/objconst9tmpl.d @@ -0,0 +1,156 @@ + +// Template matching + +template a(T : Object) { + enum a = 1; +} + +static assert(a!(Object)); +static assert(!is(typeof(a!(const(Object))))); // no match +static assert(!is(typeof(a!(const(Object)ref)))); // no match +static assert(!is(typeof(a!(immutable(Object))))); // no match +static assert(!is(typeof(a!(immutable(Object)ref)))); // no match +static assert(!is(typeof(a!(shared(Object))))); // no match +static assert(!is(typeof(a!(shared(Object)ref)))); // no match + +template ap(T : int*) { + enum ap = 1; +} + +static assert(ap!(int*)); +static assert(ap!(const(int*))); // FIXME: should not match +static assert(ap!(const(int)*)); // FIXME: should not match +static assert(ap!(immutable(int*))); // FIXME: should not match +static assert(ap!(immutable(int)*)); // FIXME: should not match +static assert(ap!(shared(int*))); // FIXME: should not match +static assert(ap!(shared(int)*)); // FIXME: should not match + + +template b(T : const(Object)) { + enum b = 1; +} + +static assert(b!(Object)); +static assert(b!(const(Object))); +static assert(b!(const(Object)ref)); +static assert(b!(immutable(Object))); +static assert(b!(immutable(Object)ref)); +static assert(!is(typeof(b!(shared(Object))))); // no match +static assert(!is(typeof(b!(shared(Object)ref)))); // no match + +template bp(T : const(int*)) { + enum bp = 1; +} + +static assert(bp!(int*)); +static assert(bp!(const(int*))); +static assert(bp!(const(int)*)); +static assert(bp!(immutable(int*))); +static assert(bp!(immutable(int)*)); +static assert(bp!(shared(int*))); // FIXME: should not match +static assert(bp!(shared(int)*)); // FIXME: should not match + + +template c(T : const(Object)ref) { + enum c = 1; +} + +static assert(c!(Object)); +static assert(c!(const(Object))); // FIXME: should not match (const ref) +static assert(c!(const(Object)ref)); +static assert(c!(immutable(Object))); // FIXME: should not match (immutable ref) +static assert(c!(immutable(Object)ref)); +static assert(!is(typeof(c!(shared(Object))))); // no match +static assert(!is(typeof(c!(shared(Object)ref)))); // no match + +template cp(T : const(int)*) { + enum cp = 1; +} + +static assert(cp!(int*)); +static assert(cp!(const(int*))); // FIXME: should not match (const ptr) +static assert(cp!(const(int)*)); +static assert(cp!(immutable(int*))); // FIXME: should not match (immutable ptr) +static assert(cp!(immutable(int)*)); +static assert(cp!(shared(int*))); // FIXME: should not match +static assert(cp!(shared(int)*)); // FIXME: should not match + + +// Type deduction + +template d(T : U ref, U) { + alias U d; +} + +static assert(is(d!(Object) == Object)); +static assert(!is(d!(const(Object)))); // no match (const ref) +static assert(is(d!(const(Object)ref) == const(Object)ref)); +static assert(!is(d!(immutable(Object)))); // no match (immutable ref) +static assert(is(d!(immutable(Object)ref) == immutable(Object)ref)); +static assert(!is(d!(shared(Object)))); // no match (shared ref) +static assert(is(d!(shared(Object)ref) == shared(Object)ref)); + +static assert(!is(d!(int))); // no match: 'ref' prevents matching non-class + +template dp(T : U*, U) { + alias U dp; +} + +static assert(is(dp!(int*) == int)); +static assert(is(dp!(const(int*)) == const(int))); // FIXME: should not match (const ptr) +static assert(is(dp!(const(int)*) == const(int))); +static assert(is(dp!(immutable(int*)) == immutable(int))); // FIXME: should not match (immutable ptr) +static assert(is(dp!(immutable(int)*) == immutable(int))); +static assert(is(dp!(shared(int*)) == shared(int))); // FIXME: should not match (shared ptr) +static assert(is(dp!(shared(int)*) == shared(int))); + + +template e(T : const(U), U) { + alias U e; +} + +static assert(is(e!(Object) == Object)); +static assert(is(e!(const(Object)) == const(Object)ref)); // FIXME: should == Object +static assert(is(e!(const(Object)ref) == const(Object)ref)); // FIXME: should == Object +static assert(is(e!(immutable(Object)) == immutable(Object)ref)); // FIXME: should == Object +static assert(is(e!(immutable(Object)ref) == immutable(Object)ref)); // FIXME: should == Object +static assert(!is(e!(shared(Object)))); // no match +static assert(!is(e!(shared(Object)ref))); // no match + +template ep(T : const(U*), U) { + alias U ep; +} + +static assert(is(ep!(int*) == int)); +static assert(is(ep!(const(int*)) == int)); +static assert(is(ep!(const(int)*) == int)); +static assert(is(ep!(immutable(int*)) == int)); +static assert(is(ep!(immutable(int)*) == int)); +static assert(!is(ep!(shared(int*)))); // no match +static assert(!is(ep!(shared(int)*))); // no match + + +template f(T : const(U)ref, U) { + alias U f; +} + +static assert(is(f!(Object) == Object)); +static assert(!is(f!(const(Object)))); // no match (const ref) +static assert(is(f!(const(Object)ref) == const(Object)ref)); // FIXME: should == Object +static assert(!is(f!(immutable(Object)))); // no match (immutable ref) +static assert(is(f!(immutable(Object)ref) == immutable(Object)ref)); // FIXME: should == Object +static assert(!is(f!(shared(Object)))); // no match +static assert(!is(f!(shared(Object)ref))); // no match + +template fp(T : const(U)*, U) { + alias U fp; +} + +static assert(is(fp!(int*) == int)); +static assert(is(fp!(const(int*)) == int)); // FIXME: should not match (const ptr) +static assert(is(fp!(const(int)*) == int)); +static assert(is(fp!(immutable(int*)) == int)); // FIXME: should not match (immutable ref) +static assert(is(fp!(immutable(int)*) == int)); +static assert(!is(fp!(shared(int*)))); // no match +static assert(!is(fp!(shared(int)*))); // no match + From af3acbcc0e8583d9056998ce31db7cf6dec6292a Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 23 Jan 2011 15:04:31 -0500 Subject: [PATCH 14/19] Disabled some failing inout tests. --- test/compilable/objconst10.d | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/compilable/objconst10.d b/test/compilable/objconst10.d index dd9240a84c81..5252cfda9b28 100644 --- a/test/compilable/objconst10.d +++ b/test/compilable/objconst10.d @@ -5,39 +5,39 @@ class C { immutable(C) immutableTest() immutable { return this; } shared(C) sharedTest() shared { return this; } shared(const(C)) sharedConstTest() shared const { return this; } - inout(C) inoutTest() inout { return this; } + inout(C) inoutTest(inout(C) a) { return a; } const(C)ref constTestRef() const { return this; } immutable(C)ref immutableTestRef() immutable { return this; } shared(C)ref sharedTestRef() shared { return this; } shared(const(C))ref sharedConstTestRef() shared const { return this; } - inout(C)ref inoutTestRef() inout { return this; } + inout(C)ref inoutTestRef(inout(C)ref a) { return a; } } void main() { C a = new C; - const(C) ac; + const(C)ref ac; ac = a.constTest(); ac = a.constTestRef(); - a = a.inoutTest(); - a = a.inoutTestRef(); +// a = a.inoutTest(a); +// a = a.inoutTestRef(a); immutable(C)ref b = new immutable(C); const(C)ref bc; bc = b.constTest(); bc = b.constTestRef(); - b = b.inoutTest(); - b = b.inoutTestRef(); +// b = b.inoutTest(b); +// b = b.inoutTestRef(b); b = b.immutableTest(); b = b.immutableTestRef(); shared(C)ref c = new shared(C); - const(C)ref cc; + shared(const(C))ref cc; cc = c.sharedConstTest(); cc = c.sharedConstTestRef(); - c = c.inoutTest(); - c = c.inoutTestRef(); +// c = c.inoutTest(c); +// c = c.inoutTestRef(c); c = c.sharedTest(); c = c.sharedTestRef(); } From bb5a775f5ef231d55573b9febd4bf3583f9e4ccc Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 30 Jan 2011 12:08:00 -0500 Subject: [PATCH 15/19] Fixed infinite loop in type merge. --- src/cast.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cast.c b/src/cast.c index dcd61dd97028..1f58a1fe29e0 100644 --- a/src/cast.c +++ b/src/cast.c @@ -1707,8 +1707,8 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression } else if (t1->ty == Tclass || t2->ty == Tclass) { - if (t1->mod != t2->mod) - { unsigned char mod = MODmerge(t1->mod, t2->mod); + if (t1->head()->mod != t2->head()->mod) + { unsigned char mod = MODmerge(t1->head()->mod, t2->head()->mod); t1 = t1->castMod(mod); t2 = t2->castMod(mod); t = t1; From 5e807bed50e3b71872e0730991d23d194c7ec873 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 6 Feb 2011 11:02:21 -0500 Subject: [PATCH 16/19] Spacing issues --- src/mtype.c | 2 -- src/template.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mtype.c b/src/mtype.c index 2739133e1555..8956b24df525 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -7857,7 +7857,6 @@ Type *TypeClass::toHeadMutable() return mutableOf(); } - Expression *TypeClass::defaultInit(Loc loc) { #if LOGDEFAULTINIT @@ -7881,7 +7880,6 @@ int TypeClass::hasPointers() return TRUE; } - /***************************** TypeTuple *****************************/ TypeTuple::TypeTuple(Parameters *arguments) diff --git a/src/template.c b/src/template.c index 300f080091a0..f2795ebec86e 100644 --- a/src/template.c +++ b/src/template.c @@ -1755,7 +1755,7 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, if (this == tparam) goto Lexact; - + if (tparam->ty == Tident) { // Determine which parameter tparam is From a20424c73c4901fe4c84119bff41bdfbc225ae16 Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 6 Feb 2011 11:15:15 -0500 Subject: [PATCH 17/19] Fix for testaa; cast()(x) now makes mutable only the head reference. --- test/runnable/testaa.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runnable/testaa.d b/test/runnable/testaa.d index b3d1fc1f555a..99b79900d971 100644 --- a/test/runnable/testaa.d +++ b/test/runnable/testaa.d @@ -173,7 +173,7 @@ void test10() { auto key = new immutable(A10)[2]; - cast()(key[0]) = new A10(); + cast()(key[0]) = new immutable(A10)(); foo10[key] = 0; assert(key in foo10); assert(!(key !in foo10)); From 7380ce7082ccdc497d397ca10b159265afcf0cbf Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 6 Feb 2011 13:23:43 -0500 Subject: [PATCH 18/19] Cleanup of some tests. --- test/compilable/objconst11unqual.d | 15 +++++++ test/compilable/objconst7mangleof.d | 4 +- test/runnable/objconst1stringof.d | 7 +++ test/runnable/objconst1unqual.d | 66 ----------------------------- 4 files changed, 24 insertions(+), 68 deletions(-) create mode 100644 test/compilable/objconst11unqual.d create mode 100644 test/runnable/objconst1stringof.d delete mode 100644 test/runnable/objconst1unqual.d diff --git a/test/compilable/objconst11unqual.d b/test/compilable/objconst11unqual.d new file mode 100644 index 000000000000..be664855d1ed --- /dev/null +++ b/test/compilable/objconst11unqual.d @@ -0,0 +1,15 @@ + +template Unqual(T) +{ + static if (is(T U == shared(const U))) alias U Unqual; + else static if (is(T U == const U )) alias U Unqual; + else static if (is(T U == immutable U )) alias U Unqual; + else static if (is(T U == shared U )) alias U Unqual; + else alias T Unqual; +} + +static assert(is(Unqual!(const(Object)) == const(Object)ref)); +static assert(is(Unqual!(const(Object ref)) == const(Object)ref)); +static assert(is(Unqual!(const(immutable(Object)ref)) == immutable(Object)ref)); +static assert(!is(Unqual!(const(Object)) == const(Object))); +static assert(!is(Unqual!(const(Object)) == Object)); diff --git a/test/compilable/objconst7mangleof.d b/test/compilable/objconst7mangleof.d index 592c7e963130..38142d058dbd 100644 --- a/test/compilable/objconst7mangleof.d +++ b/test/compilable/objconst7mangleof.d @@ -14,6 +14,6 @@ static assert((const(immutable(Object)ref)).mangleof == "xXyC6Object"); static assert((shared(inout(Object)ref)).mangleof == "OXOxC6Object"); // Reference suffix is not mangled when it has the same modifiers -static assert((const(Object ref))).mangleof == "xC6Object"); -static assert((inout(Object ref))).mangleof == "NgC6Object"); +static assert((const(Object ref)).mangleof == "xC6Object"); +static assert((inout(Object ref)).mangleof == "NgC6Object"); diff --git a/test/runnable/objconst1stringof.d b/test/runnable/objconst1stringof.d new file mode 100644 index 000000000000..ba9a856411d7 --- /dev/null +++ b/test/runnable/objconst1stringof.d @@ -0,0 +1,7 @@ + +void main() +{ + assert((const(Object)ref).stringof == "const(Object)ref"); + assert((const(Object ref)).stringof == "const(Object)"); + assert((const(Object)).stringof == "const(Object)"); +} \ No newline at end of file diff --git a/test/runnable/objconst1unqual.d b/test/runnable/objconst1unqual.d deleted file mode 100644 index f0acd1e61250..000000000000 --- a/test/runnable/objconst1unqual.d +++ /dev/null @@ -1,66 +0,0 @@ -template Unqual(T) -{ - version (none) // Error: recursive alias declaration @@@BUG1308@@@ - { - static if (is(T U == const U)) alias Unqual!U Unqual; - else static if (is(T U == immutable U)) alias Unqual!U Unqual; - else static if (is(T U == shared U)) alias Unqual!U Unqual; - else alias T Unqual; - } - else // workaround - { - static if (is(T U == shared(const U))) alias U Unqual; - else static if (is(T U == const U )) alias U Unqual; - else static if (is(T U == immutable U )) alias U Unqual; - else static if (is(T U == shared U )) alias U Unqual; - else alias T Unqual; - } -} - -//unittest -//{ -// static assert(is(Unqual!(int) == int)); -// static assert(is(Unqual!(const int) == int)); -// static assert(is(Unqual!(immutable int) == int)); -// static assert(is(Unqual!(shared int) == int)); -// static assert(is(Unqual!(shared(const int)) == int)); -// alias immutable(int[]) ImmIntArr; -// static assert(is(Unqual!(ImmIntArr) == immutable(int)[])); - - static assert(is(Unqual!(const(Object)) == const(Object)ref)); - static assert(is(Unqual!(const(Object ref)) == const(Object)ref)); - static assert(is(Unqual!(const(immutable(Object)ref)) == immutable(Object)ref)); - static assert(!is(Unqual!(const(Object)) == const(Object))); - static assert(!is(Unqual!(const(Object)) == Object)); -//} - -import std.stdio; - -alias const(Object)ref OO; - -void test(const(OO)ref o) {} - -int main() -{ - writeln((&test).mangleof); - - writeln((const(Object)ref).stringof); - writeln((immutable(Object)ref).stringof); - writeln((shared(Object)ref).stringof); - writeln((const(Object)ref).mangleof); - writeln((immutable(Object)ref).mangleof); - writeln((shared(Object)ref).mangleof); - writeln(Object.mangleof); - assert((const(Object)ref).stringof == "const(Object)ref"); - assert((immutable(Object)ref).stringof == "immutable(Object)ref"); - assert((shared(Object)ref).stringof == "shared(Object)ref"); - assert((const(Object)).stringof == "const(Object)"); - assert((immutable(Object)).stringof == "immutable(Object)"); - assert((shared(Object)).stringof == "shared(Object)"); -// writeln((immutable(Object)ref).mangleof ~ " hello"); - //writeln((shared(const(Object)ref)).stringof); - //writeln((shared(const(Object)ref[])*).stringof); - //assert((shared(const(Object)ref)).stringof == "shared(const(Object)ref)"); - //assert((shared(const(Object)ref[])*).stringof == "shared(const(Object)ref[])*"); - return 0; -} From 42e7f2399faedf4e8a4e90f8937803d431f0ba7c Mon Sep 17 00:00:00 2001 From: Michel Fortin Date: Sun, 17 Jul 2011 11:37:02 -0400 Subject: [PATCH 19/19] Fix test suite since const(Object)ref changes cast(modifier). --- test/runnable/testsafe.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runnable/testsafe.d b/test/runnable/testsafe.d index dd17e35e4e7a..55a431c72717 100644 --- a/test/runnable/testsafe.d +++ b/test/runnable/testsafe.d @@ -237,11 +237,11 @@ void sharedcast() shared(Object) xshared; immutable(Object) ishared; - static assert(!__traits(compiles, cast()xshared)); - static assert(!__traits(compiles, cast(shared)local)); + static assert(!__traits(compiles, cast(Object)xshared)); + static assert(!__traits(compiles, cast(shared(Object)ref)local)); - static assert(!__traits(compiles, cast(immutable)xshared)); - static assert(!__traits(compiles, cast(shared)ishared)); + static assert(!__traits(compiles, cast(immutable(Object)ref)xshared)); + static assert(!__traits(compiles, cast(shared(Object)ref)ishared)); } int threadlocalvar;