diff --git a/src/aggregate.h b/src/aggregate.h index 674440bf1f26..859d8614af4f 100644 --- a/src/aggregate.h +++ b/src/aggregate.h @@ -51,7 +51,6 @@ class AggregateDeclaration : public ScopeDsymbol Type *handle; // 'this' type unsigned structsize; // size of struct unsigned alignsize; // size of struct for alignment purposes - int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields Sizeok sizeok; // set when structsize contains valid data Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol @@ -166,6 +165,7 @@ class StructDeclaration : public AggregateDeclaration const char *mangle(bool isv = false); const char *kind(); void finalizeSize(Scope *sc); + bool fill(Loc loc, Expressions *elements, bool ctorinit); bool isPOD(); int needOpAssign(); int needOpEquals(); diff --git a/src/declaration.c b/src/declaration.c index c85186467c75..56ea267e9512 100644 --- a/src/declaration.c +++ b/src/declaration.c @@ -733,6 +733,7 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer aliassym = NULL; onstack = 0; canassign = 0; + overlapped = false; lastVar = NULL; ctfeAdrOnStack = -1; rundtor = NULL; @@ -899,7 +900,7 @@ void VarDeclaration::semantic(Scope *sc) //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", storage_class); - // Safety checks + // Calculate type size + safety checks if (sc->func && !sc->intypeof) { if (storage_class & STCgshared) @@ -907,22 +908,12 @@ void VarDeclaration::semantic(Scope *sc) if (sc->func->setUnsafe()) error("__gshared not allowed in safe functions; use shared"); } - if (init && init->isVoidInitializer() && type->hasPointers()) + if (type->hasPointers()) // get type size { - if (sc->func->setUnsafe()) - error("void initializers for pointers not allowed in safe functions"); - } - if (type->hasPointers() && type->toDsymbol(sc)) - { - Dsymbol *s = type->toDsymbol(sc); - if (s) + if (init && init->isVoidInitializer()) { - AggregateDeclaration *ad2 = s->isAggregateDeclaration(); - if (ad2 && ad2->hasUnions) - { - if (sc->func->setUnsafe()) - error("unions containing pointers are not allowed in @safe functions"); - } + if (sc->func->setUnsafe()) + error("void initializers for pointers not allowed in safe functions"); } } } diff --git a/src/declaration.h b/src/declaration.h index fa45ab944a36..a779851ae18f 100644 --- a/src/declaration.h +++ b/src/declaration.h @@ -265,6 +265,7 @@ class VarDeclaration : public Declaration short onstack; // 1: it has been allocated on the stack // 2: on stack, run destructor anyway int canassign; // it can be assigned to + bool overlapped; // if it is a field and has overlapping Dsymbol *aliassym; // if redone as alias to another symbol VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection diff --git a/src/expression.c b/src/expression.c index 0634734cece2..8072e1a35350 100644 --- a/src/expression.c +++ b/src/expression.c @@ -485,6 +485,23 @@ Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL) return e->semantic(sc); } } + else if (e1->op == TOKdotvar) + { + // Check for reading overlapped pointer field in @safe code. + VarDeclaration *v = ((DotVarExp *)e1)->var->isVarDeclaration(); + if (v && v->overlapped && + sc->func && !sc->intypeof) + { + AggregateDeclaration *ad = v->toParent2()->isAggregateDeclaration(); + if (ad && e1->type->hasPointers() && + sc->func->setUnsafe()) + { + e1->error("field %s.%s cannot be accessed in @safe code because it overlaps with a pointer", + ad->toChars(), v->toChars()); + return new ErrorExp(); + } + } + } else if (e1->op == TOKdotexp) { e1->error("expression has no value"); @@ -4606,17 +4623,15 @@ Expression *StructLiteralExp::semantic(Scope *sc) /* Fill out remainder of elements[] with default initializers for fields[] */ - Expression *e = fill(false); - if (e->op == TOKerror) + if (!sd->fill(loc, elements, false)) { /* An error in the initializer needs to be recorded as an error * in the enclosing function or template, since the initializer * will be part of the stuct declaration. */ global.increaseErrorCount(); - return e; + return new ErrorExp(); } - assert(e == this); type = stype ? stype : sd->type; return this; } @@ -4640,115 +4655,6 @@ Expression *StructLiteralExp::addDtorHook(Scope *sc) return this; } -Expression *StructLiteralExp::fill(bool ctorinit) -{ - assert(sd && sd->sizeok == SIZEOKdone); - size_t nfields = sd->fields.dim - sd->isNested(); - - size_t dim = elements->dim; - elements->setDim(nfields); - for (size_t i = dim; i < nfields; i++) - (*elements)[i] = NULL; - - // Fill in missing any elements with default initializers - for (size_t i = 0; i < nfields; i++) - { - if ((*elements)[i]) - continue; - VarDeclaration *vd = sd->fields[i]; - VarDeclaration *vx = vd; - if (vd->init && vd->init->isVoidInitializer()) - vx = NULL; - // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. - size_t fieldi = i; - for (size_t j = 0; j < nfields; j++) - { - if (i == j) - continue; - VarDeclaration *v2 = sd->fields[j]; - if (v2->init && v2->init->isVoidInitializer()) - continue; - - bool overlap = (vd->offset < v2->offset + v2->type->size() && - v2->offset < vd->offset + vd->type->size()); - if (!overlap) - continue; - - sd->hasUnions = 1; // note that directly unrelated... - - if ((*elements)[j]) - { - vx = NULL; - break; - } - -#if 1 - /* Prefer first found non-void-initialized field - * union U { int a; int b = 2; } - * U u; // Error: overlapping initialization for field a and b - */ - if (!vx) - vx = v2, fieldi = j; - else if (v2->init) - { - error("overlapping initialization for field %s and %s", - v2->toChars(), vd->toChars()); - } -#else // fix Bugzilla 1432 - /* Prefer explicitly initialized field - * union U { int a; int b = 2; } - * U u; // OK (u.b == 2) - */ - if (!vx || !vx->init && v2->init) - vx = v2, fieldi = j; - else if (vx != vd && - !(vx->offset < v2->offset + v2->type->size() && - v2->offset < vx->offset + vx->type->size())) - { - // Both vx and v2 fills vd, but vx and v2 does not overlap - } - else if (vx->init && v2->init) - { - error("overlapping default initialization for field %s and %s", - v2->toChars(), vd->toChars()); - } - else - assert(vx->init || !vx->init && !v2->init); -#endif - } - if (vx) - { - Expression *e; - if (vx->init) - { - assert(!vx->init->isVoidInitializer()); - e = vx->getConstInitializer(false); - } - else - { - if ((vx->storage_class & STCnodefaultctor) && !ctorinit) - { - error("field %s.%s must be initialized because it has no default constructor", - sd->type->toChars(), vx->toChars()); - } - if (vx->type->needsNested() && ctorinit) - e = vx->type->defaultInit(loc); - else - e = vx->type->defaultInitLiteral(loc); - } - (*elements)[fieldi] = e; - } - } - - for (size_t i = 0; i < elements->dim; i++) - { - Expression *e = (*elements)[i]; - if (e && e->op == TOKerror) - return e; - } - return this; -} - /************************************** * Gets expression at offset of type. * Returns NULL if not found. @@ -7925,19 +7831,6 @@ Expression *DotVarExp::semantic(Scope *sc) return e; } } - Dsymbol *s; - if (sc->func && !sc->intypeof && t1->hasPointers() && - (s = t1->toDsymbol(sc)) != NULL) - { - AggregateDeclaration *ad = s->isAggregateDeclaration(); - if (ad && ad->hasUnions) - { - if (sc->func->setUnsafe()) - { error("union %s containing pointers are not allowed in @safe functions", t1->toChars()); - goto Lerr; - } - } - } } //printf("-DotVarExp::semantic('%s')\n", toChars()); @@ -8705,10 +8598,10 @@ Expression *CallExp::semantic(Scope *sc) ExpInitializer *ei = NULL; if (t1->needsNested()) { - StructLiteralExp *sle = new StructLiteralExp(loc, (StructDeclaration *)ad, NULL, e1->type); - Expression *e = sle->fill(true); - if (e->op == TOKerror) - return e; + StructDeclaration *sd = (StructDeclaration *)ad; + StructLiteralExp *sle = new StructLiteralExp(loc, sd, NULL, e1->type); + if (!sd->fill(loc, sle->elements, true)) + return new ErrorExp(); sle->type = type; ei = new ExpInitializer(loc, sle); } diff --git a/src/expression.h b/src/expression.h index 7c1794b07b44..562b3d558ca3 100644 --- a/src/expression.h +++ b/src/expression.h @@ -561,7 +561,6 @@ class StructLiteralExp : public Expression Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); - Expression *fill(bool ctorinit); Expression *getField(Type *type, unsigned offset); int getFieldIndex(Type *type, unsigned offset); elem *toElem(IRState *irs); diff --git a/src/init.c b/src/init.c index e5039b0a86e3..3108fad3133d 100644 --- a/src/init.c +++ b/src/init.c @@ -278,13 +278,11 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needI return new ErrorInitializer(); StructLiteralExp *sle = new StructLiteralExp(loc, sd, elements, t); - Expression *e = sle->fill(false); - if (e->op == TOKerror) + if (!sd->fill(loc, elements, false)) return new ErrorInitializer(); + sle->type = t; - e->type = t; - - ExpInitializer *ie = new ExpInitializer(loc, e); + ExpInitializer *ie = new ExpInitializer(loc, sle); return ie->semantic(sc, t, needInterpret); } else if ((t->ty == Tdelegate || t->ty == Tpointer && t->nextOf()->ty == Tfunction) && value.dim == 0) diff --git a/src/interpret.c b/src/interpret.c index 2cd1d824f016..084ff9b983f7 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -5882,41 +5882,56 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) #endif if (ex->op == TOKaddress) ex = ((AddrExp *)ex)->e1; + VarDeclaration *v = var->isVarDeclaration(); if (!v) { error("CTFE internal error: %s", toChars()); return EXP_CANT_INTERPRET; } - if (ex->op == TOKnull && ex->type->toBasetype()->ty == Tclass) - { error("class '%s' is null and cannot be dereferenced", e1->toChars()); - return EXP_CANT_INTERPRET; - } if (ex->op == TOKnull) - { error("dereference of null pointer '%s'", e1->toChars()); + { + if (ex->type->toBasetype()->ty == Tclass) + error("class '%s' is null and cannot be dereferenced", e1->toChars()); + else + error("dereference of null pointer '%s'", e1->toChars()); return EXP_CANT_INTERPRET; } if (ex->op == TOKstructliteral || ex->op == TOKclassreference) { - StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; - /* We don't know how to deal with overlapping fields - */ - if (se->sd->hasUnions) - { error("Unions with overlapping fields are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } + StructLiteralExp *se; + int i; + // We can't use getField, because it makes a copy - int i = -1; if (ex->op == TOKclassreference) - i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v); + { + se = ((ClassReferenceExp *)ex)->value; + i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v); + } else - i = findFieldIndexByName(se->sd, v); + { + se = (StructLiteralExp *)ex; + i = findFieldIndexByName(se->sd, v); + } +#if DMDV1 + if (se->sd->hasUnions) + { + error("Unions with overlapping fields are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } +#endif if (i == -1) { error("couldn't find field %s of type %s in %s", v->toChars(), type->toChars(), se->toChars()); return EXP_CANT_INTERPRET; } e = (*se->elements)[i]; + if (!e) + { + error("Internal Compiler Error: Null field %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) { // If it is an lvalue literal, return it... @@ -5939,11 +5954,6 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) e->type = type; return e; } - if (!e) - { - error("Internal Compiler Error: Null field %s", v->toChars()); - return EXP_CANT_INTERPRET; - } // If it is an rvalue literal, return it... if (e->op == TOKstructliteral || e->op == TOKarrayliteral || e->op == TOKassocarrayliteral || e->op == TOKstring) @@ -5951,15 +5961,24 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) if (e->op == TOKvoid) { VoidInitExp *ve = (VoidInitExp *)e; - error("cannot read uninitialized variable %s in CTFE", ve->var->toChars()); + const char *s = ve->var->toChars(); +#if DMDV2 + if (v->overlapped) + { + error("Reinterpretation through overlapped field %s is not allowed in CTFE", s); + return EXP_CANT_INTERPRET; + } +#endif + error("cannot read uninitialized variable %s in CTFE", s); return EXP_CANT_INTERPRET; } - if ( isPointer(type) ) + if (isPointer(type)) { return paintTypeOntoLiteral(type, e); } if (e->op == TOKvar) - { // Don't typepaint twice, since that might cause an erroneous copy + { + // Don't typepaint twice, since that might cause an erroneous copy e = getVarExp(loc, istate, ((VarExp *)e)->var, goal); if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) e = paintTypeOntoLiteral(type, e); diff --git a/src/struct.c b/src/struct.c index 18192eba92c0..8a1dfcf7e279 100644 --- a/src/struct.c +++ b/src/struct.c @@ -15,6 +15,7 @@ #include "aggregate.h" #include "scope.h" #include "mtype.h" +#include "init.h" #include "declaration.h" #include "module.h" #include "id.h" @@ -105,7 +106,6 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) handle = NULL; structsize = 0; // size of struct alignsize = 0; // size of struct for alignment purposes - hasUnions = 0; sizeok = SIZEOKnone; // size not determined yet deferred = NULL; isdeprecated = false; @@ -846,6 +846,133 @@ void StructDeclaration::finalizeSize(Scope *sc) structsize = (structsize + alignment - 1) & ~(alignment - 1); sizeok = SIZEOKdone; + + // Calculate fields[i]->overlapped + fill(loc, NULL, true); +} + +bool StructDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit) +{ + assert(sizeok == SIZEOKdone); + size_t nfields = fields.dim - isNested(); + + if (elements) + { + size_t dim = elements->dim; + elements->setDim(nfields); + for (size_t i = dim; i < nfields; i++) + (*elements)[i] = NULL; + } + + // Fill in missing any elements with default initializers + for (size_t i = 0; i < nfields; i++) + { + if (elements && (*elements)[i]) + continue; + VarDeclaration *vd = fields[i]; + VarDeclaration *vx = vd; + if (vd->init && vd->init->isVoidInitializer()) + vx = NULL; + // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. + size_t fieldi = i; + for (size_t j = 0; j < nfields; j++) + { + if (i == j) + continue; + VarDeclaration *v2 = fields[j]; + bool overlap = (vd->offset < v2->offset + v2->type->size() && + v2->offset < vd->offset + vd->type->size()); + if (!overlap) + continue; + + if (elements) + { + if ((*elements)[j]) + { + vx = NULL; + break; + } + } + else + { + vd->overlapped = true; + } + if (v2->init && v2->init->isVoidInitializer()) + continue; + + if (elements) + { + /* Prefer first found non-void-initialized field + * union U { int a; int b = 2; } + * U u; // Error: overlapping initialization for field a and b + */ + if (!vx) + vx = v2, fieldi = j; + else if (v2->init) + { + ::error(loc, "overlapping initialization for field %s and %s", + v2->toChars(), vd->toChars()); + } + } + else + { + // Will fix Bugzilla 1432 by enabling this path always + + /* Prefer explicitly initialized field + * union U { int a; int b = 2; } + * U u; // OK (u.b == 2) + */ + if (!vx || !vx->init && v2->init) + vx = v2, fieldi = j; + else if (vx != vd && + !(vx->offset < v2->offset + v2->type->size() && + v2->offset < vx->offset + vx->type->size())) + { + // Both vx and v2 fills vd, but vx and v2 does not overlap + } + else if (vx->init && v2->init) + { + ::error(loc, "overlapping default initialization for field %s and %s", + v2->toChars(), vd->toChars()); + } + else + assert(vx->init || !vx->init && !v2->init); + } + } + if (elements && vx) + { + Expression *e; + if (vx->init) + { + assert(!vx->init->isVoidInitializer()); + e = vx->getConstInitializer(false); + } + else + { + if ((vx->storage_class & STCnodefaultctor) && !ctorinit) + { + ::error(loc, "field %s.%s must be initialized because it has no default constructor", + type->toChars(), vx->toChars()); + } + if (vx->type->needsNested() && ctorinit) + e = vx->type->defaultInit(loc); + else + e = vx->type->defaultInitLiteral(loc); + } + (*elements)[fieldi] = e; + } + } + + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { + Expression *e = (*elements)[i]; + if (e && e->op == TOKerror) + return false; + } + } + return true; } /*************************************** @@ -921,7 +1048,6 @@ const char *StructDeclaration::kind() UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) : StructDeclaration(loc, id) { - hasUnions = 1; } Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) diff --git a/src/todt.c b/src/todt.c index 1778e55bf7d5..cb4216b0c305 100644 --- a/src/todt.c +++ b/src/todt.c @@ -649,13 +649,12 @@ void StructDeclaration::toDt(dt_t **pdt) { //printf("StructDeclaration::toDt(), this='%s'\n", toChars()); StructLiteralExp *sle = new StructLiteralExp(loc, this, NULL); - Expression *e = sle->fill(true); - if (e == sle) - { - //printf("sd->toDt sle = %s\n", sle->toChars()); - sle->type = type; - sle->toDt(pdt); - } + if (!fill(loc, sle->elements, true)) + assert(0); + + //printf("sd->toDt sle = %s\n", sle->toChars()); + sle->type = type; + sle->toDt(pdt); } /* ================================================================= */ diff --git a/test/compilable/interpret3.d b/test/compilable/interpret3.d index 652c091d12f6..64569e89048a 100644 --- a/test/compilable/interpret3.d +++ b/test/compilable/interpret3.d @@ -5865,6 +5865,33 @@ string f10782() } mixin(f10782()); +/************************************************** + 11510 support overlapped field access in CTFE +**************************************************/ + +struct S11510 +{ + union + { + size_t x; + int* y; // pointer field + } +} +bool test11510() +{ + S11510 s; + + s.y = [1,2,3].ptr; // writing overlapped pointer field is OK + assert(s.y[0..3] == [1,2,3]); // reading valid field is OK + + s.x = 10; + assert(s.x == 10); + + // There's no reinterpretation between S.x and S.y + return true; +} +static assert(test11510()); + /************************************************** 11534 - subtitude inout **************************************************/ diff --git a/test/fail_compilation/fail11510.d b/test/fail_compilation/fail11510.d new file mode 100644 index 000000000000..0f5d5aec9027 --- /dev/null +++ b/test/fail_compilation/fail11510.d @@ -0,0 +1,40 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11510.d(25): Error: Reinterpretation through overlapped field y is not allowed in CTFE +fail_compilation/fail11510.d(29): called from here: test11510a() +fail_compilation/fail11510.d(36): Error: Reinterpretation through overlapped field y is not allowed in CTFE +fail_compilation/fail11510.d(40): called from here: test11510b() +--- +*/ + +struct S11510 +{ + union + { + size_t x; + int* y; // pointer field + } +} + +bool test11510a() +{ + S11510 s; + + s.y = [1,2,3].ptr; + auto x = s.x; // reinterpretation + + return true; +} +enum a = test11510a(); + +bool test11510b() +{ + S11510 s; + + s.x = 10; + auto y = s.y; // reinterpretation + + return true; +} +enum b = test11510b(); diff --git a/test/runnable/structlit.d b/test/runnable/structlit.d index c989d3bf9c9f..e8eb52a080c3 100644 --- a/test/runnable/structlit.d +++ b/test/runnable/structlit.d @@ -1239,6 +1239,26 @@ void test11269() Atom a2 = {i:1, rest:10, b:2}; } +/********************************************/ +// 11427 + +struct S11427 +{ + union + { + ubyte a; + int x; + } + void[] arr; +} + +int foo11427() @safe +{ + S11427 s1 = S11427(); + S11427 s2; + return 0; +} + /********************************************/ int main() diff --git a/test/runnable/testsafe.d b/test/runnable/testsafe.d index f7231bf1c141..247524d99c2b 100644 --- a/test/runnable/testsafe.d +++ b/test/runnable/testsafe.d @@ -1,48 +1,48 @@ -// PERMUTE_ARGS: - -//http://d.puremagic.com/issues/show_bug.cgi?id=5415 - -@safe -void pointercast() -{ - int* a; - void* b; - - static assert( __traits(compiles, cast(void*)a)); - static assert(!__traits(compiles, cast(int*)b)); - static assert(!__traits(compiles, cast(int*)b)); - static assert(!__traits(compiles, cast(short*)b)); - static assert( __traits(compiles, cast(byte*)b)); - static assert( __traits(compiles, cast(short*)a)); - static assert( __traits(compiles, cast(byte*)a)); -} - -@safe -void pointercast2() -{ - size_t a; - int b; - Object c; - - static assert(!__traits(compiles, cast(void*)a)); - static assert(!__traits(compiles, cast(void*)b)); - static assert(!__traits(compiles, cast(void*)c)); -} - -@safe -void pointerarithmetic() -{//http://d.puremagic.com/issues/show_bug.cgi?id=4132 - void* a; - int b; - - static assert(!__traits(compiles, a + b)); - static assert(!__traits(compiles, a - b)); - static assert(!__traits(compiles, a += b)); - static assert(!__traits(compiles, a -= b)); - static assert(!__traits(compiles, a++)); - static assert(!__traits(compiles, a--)); - static assert(!__traits(compiles, ++a)); - static assert(!__traits(compiles, --a)); +// PERMUTE_ARGS: + +//http://d.puremagic.com/issues/show_bug.cgi?id=5415 + +@safe +void pointercast() +{ + int* a; + void* b; + + static assert( __traits(compiles, cast(void*)a)); + static assert(!__traits(compiles, cast(int*)b)); + static assert(!__traits(compiles, cast(int*)b)); + static assert(!__traits(compiles, cast(short*)b)); + static assert( __traits(compiles, cast(byte*)b)); + static assert( __traits(compiles, cast(short*)a)); + static assert( __traits(compiles, cast(byte*)a)); +} + +@safe +void pointercast2() +{ + size_t a; + int b; + Object c; + + static assert(!__traits(compiles, cast(void*)a)); + static assert(!__traits(compiles, cast(void*)b)); + static assert(!__traits(compiles, cast(void*)c)); +} + +@safe +void pointerarithmetic() +{//http://d.puremagic.com/issues/show_bug.cgi?id=4132 + void* a; + int b; + + static assert(!__traits(compiles, a + b)); + static assert(!__traits(compiles, a - b)); + static assert(!__traits(compiles, a += b)); + static assert(!__traits(compiles, a -= b)); + static assert(!__traits(compiles, a++)); + static assert(!__traits(compiles, a--)); + static assert(!__traits(compiles, ++a)); + static assert(!__traits(compiles, --a)); static assert( __traits(compiles, a + 0)); static assert( __traits(compiles, a - 0)); static assert( __traits(compiles, 0 + a)); @@ -53,230 +53,242 @@ void pointerarithmetic() static assert( __traits(compiles, a -= 0)); static assert(!__traits(compiles, a += 1)); static assert(!__traits(compiles, a -= 1)); -} - - - -union SafeUnion1 -{ - int a; - struct - { - int b; - int* c; - } -} -union SafeUnion2 -{ - int a; - struct - { - int b; - int c; - } -} -union UnsafeUnion1 -{ - int a; - int* c; -} -union UnsafeUnion2 -{ - int a; - align(1) - struct - { - byte b; - int* c; - } -} -union UnsafeUnion3 -{ - int a; - Object c; -} -union UnsafeUnion4 -{ - int a; - align(1) - struct - { - byte b; - Object c; - } -} -struct pwrapper -{ - int* a; -} -union UnsafeUnion5 -{ - SafeUnion2 x; - pwrapper b; -} - -SafeUnion1 su1; -SafeUnion2 su2; -UnsafeUnion1 uu1; -UnsafeUnion2 uu2; -UnsafeUnion3 uu3; -UnsafeUnion4 uu4; -UnsafeUnion5 uu5; - -union uA -{ - struct - { - int* a; - void* b; - } -} -struct uB -{ - uA a; -} -struct uC -{ - uB a; -} -struct uD -{ - uC a; -} -uD uud; - -@safe -void safeunions() -{ - //static assert( __traits(compiles, { SafeUnion1 x; x.a = 7; })); - static assert( __traits(compiles, { SafeUnion2 x; x.a = 7; })); - static assert(!__traits(compiles, { UnsafeUnion1 x; x.a = 7; })); - static assert(!__traits(compiles, { UnsafeUnion2 x; x.a = 7; })); - static assert(!__traits(compiles, { UnsafeUnion3 x; x.a = 7; })); - static assert(!__traits(compiles, { UnsafeUnion4 x; x.a = 7; })); - static assert(!__traits(compiles, { UnsafeUnion5 x; })); - - typeof(uu1.a) f; - - //static assert( __traits(compiles, { su1.a = 7; })); - static assert( __traits(compiles, { su2.a = 7; })); - static assert(!__traits(compiles, { uu1.a = 7; })); - static assert(!__traits(compiles, { uu2.a = 7; })); - static assert(!__traits(compiles, { uu3.a = 7; })); - static assert(!__traits(compiles, { uu4.a = 7; })); - static assert(!__traits(compiles, { uu5.x.a = null; })); - static assert(!__traits(compiles, { uud.a.a.a.a = null; })); -} - - - -@safe -void safeexception() -{ - try {} - catch(Exception e) {} - - static assert(!__traits(compiles, { - try {} - catch(Error e) {} - })); - - static assert(!__traits(compiles, { - try {} - catch(Throwable e) {} - })); - - static assert(!__traits(compiles, { - try {} - catch {} - })); -} - -@safe -void inlineasm() -{ - static assert(!__traits(compiles, { asm { int 3; } }() )); -} - -@safe -void multablecast() -{ - Object m; - const(Object) c; - immutable(Object) i; - - static assert( __traits(compiles, cast(const(Object))m)); - static assert( __traits(compiles, cast(const(Object))i)); - - static assert(!__traits(compiles, cast(immutable(Object))m)); - static assert(!__traits(compiles, cast(immutable(Object))c)); - - static assert(!__traits(compiles, cast(Object)c)); - static assert(!__traits(compiles, cast(Object)i)); - - void* mp; - const(void)* cp; - immutable(void)* ip; - - static assert( __traits(compiles, cast(const(void)*)mp)); - static assert( __traits(compiles, cast(const(void)*)ip)); - - static assert(!__traits(compiles, cast(immutable(void)*)mp)); - static assert(!__traits(compiles, cast(immutable(void)*)cp)); - - static assert(!__traits(compiles, cast(void*)cp)); - static assert(!__traits(compiles, cast(void*)ip)); -} - -@safe -void sharedcast() -{ - Object local; - shared(Object) xshared; - immutable(Object) ishared; - - static assert(!__traits(compiles, cast()xshared)); - static assert(!__traits(compiles, cast(shared)local)); - - static assert(!__traits(compiles, cast(immutable)xshared)); - static assert(!__traits(compiles, cast(shared)ishared)); -} - -int threadlocalvar; - -@safe -void takeaddr() -{ - static assert(!__traits(compiles, (int x) { auto y = &x; } )); - static assert(!__traits(compiles, { int x; auto y = &x; } )); - static assert( __traits(compiles, { static int x; auto y = &x; } )); - static assert( __traits(compiles, { auto y = &threadlocalvar; } )); -} - -__gshared int gsharedvar; - -@safe -void use__gshared() -{ - static assert(!__traits(compiles, { int x = gsharedvar; } )); -} - -@safe -void voidinitializers() -{//http://d.puremagic.com/issues/show_bug.cgi?id=4885 - static assert(!__traits(compiles, { uint* ptr = void; } )); - static assert( __traits(compiles, { uint i = void; } )); - static assert( __traits(compiles, { uint[2] a = void; } )); - - struct ValueStruct { int a; } - struct NonValueStruct { int* a; } - static assert( __traits(compiles, { ValueStruct a = void; } )); - static assert(!__traits(compiles, { NonValueStruct a = void; } )); - - static assert(!__traits(compiles, { uint[] a = void; } )); - static assert(!__traits(compiles, { int** a = void; } )); - static assert(!__traits(compiles, { int[int] a = void; } )); -} +} + + + +union SafeUnion1 +{ + int a; + struct + { + int b; + int* c; + } +} +union SafeUnion2 +{ + int a; + struct + { + int b; + int c; + } +} +union UnsafeUnion1 +{ + int a; + int* c; +} +union UnsafeUnion2 +{ + int a; + align(1) + struct + { + byte b; + int* c; + } +} +union UnsafeUnion3 +{ + int a; + Object c; +} +union UnsafeUnion4 +{ + int a; + align(1) + struct + { + byte b; + Object c; + } +} +struct pwrapper +{ + int* a; +} +union UnsafeUnion5 +{ + SafeUnion2 x; + pwrapper b; +} + +union uA +{ + struct + { + int* a; + void* b; + } +} +struct uB +{ + uA a; +} +struct uC +{ + uB a; +} +struct uD +{ + uC a; +} + +@safe +void safeunions() // improved for issue 11510 +{ + SafeUnion1 su1; + SafeUnion2 su2; + UnsafeUnion1 uu1; + UnsafeUnion2 uu2; + UnsafeUnion3 uu3; + UnsafeUnion4 uu4; + UnsafeUnion5 uu5; + uD uud; + + int n; + void* p; + Object o; + + // Writing field is always allowed, even if it is overlapped. + su1.a = 7, su1.b = 8, su1.c = null; + su2.a = 7, su2.b = 8, su2.c = 9; + uu1.a = 7, uu1.c = null; + uu2.a = 7; uu2.b = 8, uu2.c = null; + uu3.a = 7; uu3.c = null; + uu4.a = 7; uu4.b = 8, uu4.c = null; + uu5.x.a = 7; uu5.x.b = 8, uu5.x.c = 9; + uud.a.a.a.a = null, uud.a.a.a.b = null; + + // Reading field is allowed, if it is not overlapped or has no pointers. + n = su1.a, n = su1.b, p = su1.c; + n = su2.a, n = su2.b, n = su2.c; + n = uu1.a; + n = uu2.a, n = uu2.b; + n = uu3.a; + n = uu4.a, n = uu4.b; + n = uu5.x.a, n = uu5.x.b, n = uu5.x.c; + p = uud.a.a.a.a, p = uud.a.a.a.b; + + // Reading overlapped pointer field is not allowed. + static assert(!__traits(compiles, { auto p = uu1.c; })); + static assert(!__traits(compiles, { auto p = uu2.c; })); + static assert(!__traits(compiles, { auto c = uu3.c; })); + static assert(!__traits(compiles, { auto c = uu4.c; })); + static assert(!__traits(compiles, { auto p = uu5.b.a; })); +} + + + +@safe +void safeexception() +{ + try {} + catch(Exception e) {} + + static assert(!__traits(compiles, { + try {} + catch(Error e) {} + })); + + static assert(!__traits(compiles, { + try {} + catch(Throwable e) {} + })); + + static assert(!__traits(compiles, { + try {} + catch {} + })); +} + +@safe +void inlineasm() +{ + static assert(!__traits(compiles, { asm { int 3; } }() )); +} + +@safe +void multablecast() +{ + Object m; + const(Object) c; + immutable(Object) i; + + static assert( __traits(compiles, cast(const(Object))m)); + static assert( __traits(compiles, cast(const(Object))i)); + + static assert(!__traits(compiles, cast(immutable(Object))m)); + static assert(!__traits(compiles, cast(immutable(Object))c)); + + static assert(!__traits(compiles, cast(Object)c)); + static assert(!__traits(compiles, cast(Object)i)); + + void* mp; + const(void)* cp; + immutable(void)* ip; + + static assert( __traits(compiles, cast(const(void)*)mp)); + static assert( __traits(compiles, cast(const(void)*)ip)); + + static assert(!__traits(compiles, cast(immutable(void)*)mp)); + static assert(!__traits(compiles, cast(immutable(void)*)cp)); + + static assert(!__traits(compiles, cast(void*)cp)); + static assert(!__traits(compiles, cast(void*)ip)); +} + +@safe +void sharedcast() +{ + Object local; + shared(Object) xshared; + immutable(Object) ishared; + + static assert(!__traits(compiles, cast()xshared)); + static assert(!__traits(compiles, cast(shared)local)); + + static assert(!__traits(compiles, cast(immutable)xshared)); + static assert(!__traits(compiles, cast(shared)ishared)); +} + +int threadlocalvar; + +@safe +void takeaddr() +{ + static assert(!__traits(compiles, (int x) { auto y = &x; } )); + static assert(!__traits(compiles, { int x; auto y = &x; } )); + static assert( __traits(compiles, { static int x; auto y = &x; } )); + static assert( __traits(compiles, { auto y = &threadlocalvar; } )); +} + +__gshared int gsharedvar; + +@safe +void use__gshared() +{ + static assert(!__traits(compiles, { int x = gsharedvar; } )); +} + +@safe +void voidinitializers() +{//http://d.puremagic.com/issues/show_bug.cgi?id=4885 + static assert(!__traits(compiles, { uint* ptr = void; } )); + static assert( __traits(compiles, { uint i = void; } )); + static assert( __traits(compiles, { uint[2] a = void; } )); + + struct ValueStruct { int a; } + struct NonValueStruct { int* a; } + static assert( __traits(compiles, { ValueStruct a = void; } )); + static assert(!__traits(compiles, { NonValueStruct a = void; } )); + + static assert(!__traits(compiles, { uint[] a = void; } )); + static assert(!__traits(compiles, { int** a = void; } )); + static assert(!__traits(compiles, { int[int] a = void; } )); +} @safe void pointerindex() @@ -285,27 +297,27 @@ void pointerindex() static assert( __traits(compiles, { int* p; auto a = p[0]; })); } -@safe -void basiccast() -{//http://d.puremagic.com/issues/show_bug.cgi?id=5088 - auto a = cast(int)cast(const int)1; - auto b = cast(real)cast(const int)1; - auto c = cast(real)cast(const real)2.0; -} - -@safe -void arraycast() -{ - int[] x; - void[] y = x; - static assert( __traits(compiles, cast(void[])x)); - static assert( __traits(compiles, cast(int[])y)); - static assert(!__traits(compiles, cast(int*[])y)); - static assert(!__traits(compiles, cast(void[][])y)); - - int[3] a; - int[] b = cast(int[])a; - uint[3] c = cast(uint[3])a; +@safe +void basiccast() +{//http://d.puremagic.com/issues/show_bug.cgi?id=5088 + auto a = cast(int)cast(const int)1; + auto b = cast(real)cast(const int)1; + auto c = cast(real)cast(const real)2.0; +} + +@safe +void arraycast() +{ + int[] x; + void[] y = x; + static assert( __traits(compiles, cast(void[])x)); + static assert( __traits(compiles, cast(int[])y)); + static assert(!__traits(compiles, cast(int*[])y)); + static assert(!__traits(compiles, cast(void[][])y)); + + int[3] a; + int[] b = cast(int[])a; + uint[3] c = cast(uint[3])a; const char[] cc; static assert( __traits(compiles, cast(const(ubyte)[])cc)); @@ -316,25 +328,25 @@ void arraycast() static assert( __traits(compiles, cast(shared(ubyte)[])sc)); static assert( __traits(compiles, cast(shared(ubyte[]))sc)); static assert(!__traits(compiles, cast(const(ubyte)[])sc)); -} - -@safe -void structcast() -{ - struct A { ptrdiff_t x; } - struct B { size_t x; } - struct C { void* x; } - A a; - B b; - C c; - - static assert( __traits(compiles, a = cast(A)b)); - static assert( __traits(compiles, a = cast(A)c)); - static assert( __traits(compiles, b = cast(B)a)); - static assert( __traits(compiles, b = cast(B)c)); - static assert(!__traits(compiles, c = cast(C)a)); - static assert(!__traits(compiles, c = cast(C)b)); -} +} + +@safe +void structcast() +{ + struct A { ptrdiff_t x; } + struct B { size_t x; } + struct C { void* x; } + A a; + B b; + C c; + + static assert( __traits(compiles, a = cast(A)b)); + static assert( __traits(compiles, a = cast(A)c)); + static assert( __traits(compiles, b = cast(B)a)); + static assert( __traits(compiles, b = cast(B)c)); + static assert(!__traits(compiles, c = cast(C)a)); + static assert(!__traits(compiles, c = cast(C)b)); +} @safe void test6497() { @@ -425,5 +437,5 @@ nothrow int g7803() { return 3; } -void main() { } +void main() { }