diff --git a/dmd/mtype.c b/dmd/mtype.c
index 4f38a0fd..b8dda54b 100644
--- a/dmd/mtype.c
+++ b/dmd/mtype.c
@@ -1743,12 +1743,12 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
if (dup)
arguments->push(getTypeInfo(sc));
- // LDC repaint array type to void[]
- if (n->ty != Tvoid) {
- e = new CastExp(e->loc, e, e->type);
- e->type = Type::tvoid->arrayOf();
- }
- arguments->push(e);
+ // LDC repaint array type to void[]
+ if (n->ty != Tvoid) {
+ e = new CastExp(e->loc, e, e->type);
+ e->type = Type::tvoid->arrayOf();
+ }
+ arguments->push(e);
if (!dup)
arguments->push(new IntegerExp(0, size, Type::tsize_t));
@@ -1759,7 +1759,6 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
Expression *ec;
Expressions *arguments;
- bool isBit = (n->ty == Tbit);
//LDC: Build arguments.
static FuncDeclaration *adSort_fd = NULL;
@@ -1769,31 +1768,20 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL));
adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort");
}
- static FuncDeclaration *adSortBit_fd = NULL;
- if(!adSortBit_fd) {
- Parameters* args = new Parameters;
- args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL));
- args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL));
- adSortBit_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSortBit");
- }
- if(isBit)
- ec = new VarExp(0, adSortBit_fd);
- else
- ec = new VarExp(0, adSort_fd);
+ ec = new VarExp(0, adSort_fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
- // LDC repaint array type to void[]
- if (n->ty != Tvoid) {
- e = new CastExp(e->loc, e, e->type);
- e->type = Type::tvoid->arrayOf();
- }
- arguments->push(e);
-
- if (next->ty != Tbit)
- arguments->push(n->getTypeInfo(sc)); // LDC, we don't support the getInternalTypeInfo
- // optimization arbitrarily, not yet at least...
+ // LDC repaint array type to void[]
+ if (n->ty != Tvoid) {
+ e = new CastExp(e->loc, e, e->type);
+ e->type = Type::tvoid->arrayOf();
+ }
+ arguments->push(e);
+ // LDC, we don't support the getInternalTypeInfo
+ // optimization arbitrarily, not yet at least...
+ arguments->push(n->getTypeInfo(sc));
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h
index e1b75c30..776f8b60 100644
--- a/dmd2/aggregate.h
+++ b/dmd2/aggregate.h
@@ -67,6 +67,7 @@ struct AggregateDeclaration : ScopeDsymbol
// 0: no size
// 1: size is correct
// 2: cannot determine size; fwd referenced
+ Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
int isdeprecated; // !=0 if deprecated
#if DMDV2
@@ -234,6 +235,7 @@ struct ClassDeclaration : AggregateDeclaration
static ClassDeclaration *object;
static ClassDeclaration *classinfo;
static ClassDeclaration *throwable;
+ static ClassDeclaration *exception;
ClassDeclaration *baseClass; // NULL only if this is Object
#if DMDV1
diff --git a/dmd2/attrib.h b/dmd2/attrib.h
index 2e3bcfe6..a0b44ef1 100644
--- a/dmd2/attrib.h
+++ b/dmd2/attrib.h
@@ -23,9 +23,7 @@ struct LabelDsymbol;
struct Initializer;
struct Module;
struct Condition;
-#ifdef _DH
struct HdrGenState;
-#endif
/**************************************************************/
diff --git a/dmd2/cast.c b/dmd2/cast.c
index 0f099bc3..dfc20e66 100644
--- a/dmd2/cast.c
+++ b/dmd2/cast.c
@@ -17,6 +17,10 @@
#include "utf.h"
#include "declaration.h"
#include "aggregate.h"
+#include "scope.h"
+
+//#define DUMP .dump(__PRETTY_FUNCTION__, this)
+#define DUMP
/* ==================== implicitCast ====================== */
@@ -158,8 +162,10 @@ MATCH Expression::implicitConvTo(Type *t)
*/
if (type->isintegral() && t->isintegral() &&
type->isTypeBasic() && t->isTypeBasic())
- { IntRange ir = getIntRange();
- if (ir.imax <= t->sizemask())
+ { IntRange src = this->getIntRange() DUMP;
+ IntRange targetUnsigned = IntRange::fromType(t, /*isUnsigned*/true) DUMP;
+ IntRange targetSigned = IntRange::fromType(t, /*isUnsigned*/false) DUMP;
+ if (targetUnsigned.contains(src) || targetSigned.contains(src))
return MATCHconvert;
}
@@ -203,7 +209,6 @@ MATCH IntegerExp::implicitConvTo(Type *t)
switch (ty)
{
- case Tbit:
case Tbool:
value &= 1;
ty = Tint32;
@@ -248,7 +253,6 @@ MATCH IntegerExp::implicitConvTo(Type *t)
// Only allow conversion if no change in value
switch (toty)
{
- case Tbit:
case Tbool:
if ((value & 1) != value)
goto Lno;
@@ -1533,7 +1537,17 @@ Expression *CommaExp::castTo(Scope *sc, Type *t)
*/
Expression *BinExp::scaleFactor(Scope *sc)
-{ d_uns64 stride;
+{
+ if (sc->func && !sc->intypeof)
+ {
+ if (sc->func->setUnsafe())
+ {
+ error("pointer arithmetic not allowed in @safe functions");
+ return new ErrorExp();
+ }
+ }
+
+ d_uns64 stride;
Type *t1b = e1->type->toBasetype();
Type *t2b = e2->type->toBasetype();
@@ -1615,10 +1629,17 @@ bool isVoidArrayLiteral(Expression *e, Type *other)
int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2)
{
//printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
- //dump(0);
+ //e->dump(0);
- Expression *e1 = (*pe1)->integralPromotions(sc);
- Expression *e2 = (*pe2)->integralPromotions(sc);
+ Expression *e1 = *pe1;
+ Expression *e2 = *pe2;
+
+ if (e->op != TOKquestion ||
+ e1->type->toBasetype()->ty != e2->type->toBasetype()->ty)
+ {
+ e1 = e1->integralPromotions(sc);
+ e2 = e2->integralPromotions(sc);
+ }
Type *t1 = e1->type;
Type *t2 = e2->type;
@@ -1861,7 +1882,15 @@ Lagain:
}
else if (t1->isintegral() && t2->isintegral())
{
- assert(0);
+ assert(t1->ty == t2->ty);
+ unsigned char mod = MODmerge(t1->mod, t2->mod);
+
+ t1 = t1->castMod(mod);
+ t2 = t2->castMod(mod);
+ t = t1;
+ e1 = e1->castTo(sc, t);
+ e2 = e2->castTo(sc, t);
+ goto Lagain;
}
else if (e1->isArrayOperand() && t1->ty == Tarray &&
e2->implicitConvTo(t1->nextOf()))
@@ -1974,7 +2003,6 @@ Expression *Expression::integralPromotions(Scope *sc)
case Tuns8:
case Tint16:
case Tuns16:
- case Tbit:
case Tbool:
case Tchar:
case Twchar:
@@ -2046,233 +2074,309 @@ int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2)
uinteger_t getMask(uinteger_t v)
{
- uinteger_t u = 0;
- if (v >= 0x80)
- u = 0xFF;
- while (u < v)
- u = (u << 1) | 1;
- return u;
+ // Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v |= v >> 32;
+ return v /* | 0xff*/;
}
-
IntRange Expression::getIntRange()
{
- IntRange ir;
- ir.imin = 0;
- if (type->isintegral())
- ir.imax = type->sizemask();
- else
- ir.imax = 0xFFFFFFFFFFFFFFFFULL; // assume the worst
- return ir;
+ return IntRange::fromType(type) DUMP;
}
IntRange IntegerExp::getIntRange()
{
- IntRange ir;
- ir.imin = value & type->sizemask();
- ir.imax = ir.imin;
- return ir;
+ return IntRange(value).cast(type) DUMP;
}
IntRange CastExp::getIntRange()
{
- IntRange ir;
- ir = e1->getIntRange();
- // Do sign extension
- switch (e1->type->toBasetype()->ty)
- {
- case Tint8:
- if (ir.imax & 0x80)
- ir.imax |= 0xFFFFFFFFFFFFFF00ULL;
- break;
- case Tint16:
- if (ir.imax & 0x8000)
- ir.imax |= 0xFFFFFFFFFFFF0000ULL;
- break;
- case Tint32:
- if (ir.imax & 0x80000000)
- ir.imax |= 0xFFFFFFFF00000000ULL;
- break;
- }
- if (type->isintegral())
- {
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
- }
-//printf("CastExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
- return ir;
+ return e1->getIntRange().cast(type) DUMP;
+}
+
+IntRange AddExp::getIntRange()
+{
+ IntRange ir1 = e1->getIntRange();
+ IntRange ir2 = e2->getIntRange();
+ return IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(type) DUMP;
+}
+
+IntRange MinExp::getIntRange()
+{
+ IntRange ir1 = e1->getIntRange();
+ IntRange ir2 = e2->getIntRange();
+ return IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(type) DUMP;
}
IntRange DivExp::getIntRange()
{
- IntRange ir;
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
- if (!(e1->type->isunsigned() || ir1.imax < 0x8000000000000000ULL) &&
- !(e2->type->isunsigned() || ir2.imax < 0x8000000000000000ULL))
- {
- return Expression::getIntRange();
- }
+ // Should we ignore the possibility of div-by-0???
+ if (ir2.containsZero())
+ return Expression::getIntRange() DUMP;
- if (ir2.imax == 0 || ir2.imin == 0)
- return Expression::getIntRange();
-
- ir.imin = ir1.imin / ir2.imax;
- ir.imax = ir1.imax / ir2.imin;
-
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
-
-//printf("DivExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
+ // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+ SignExtendedNumber bdy[4] = {
+ ir1.imin / ir2.imin,
+ ir1.imin / ir2.imax,
+ ir1.imax / ir2.imin,
+ ir1.imax / ir2.imax
+ };
+ return IntRange::fromNumbers4(bdy).cast(type) DUMP;
}
+IntRange MulExp::getIntRange()
+{
+ IntRange ir1 = e1->getIntRange();
+ IntRange ir2 = e2->getIntRange();
+
+ // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
+ SignExtendedNumber bdy[4] = {
+ ir1.imin * ir2.imin,
+ ir1.imin * ir2.imax,
+ ir1.imax * ir2.imin,
+ ir1.imax * ir2.imax
+ };
+ return IntRange::fromNumbers4(bdy).cast(type) DUMP;
+}
+
+IntRange ModExp::getIntRange()
+{
+ IntRange irNum = e1->getIntRange();
+ IntRange irDen = e2->getIntRange().absNeg();
+
+ /*
+ due to the rules of D (C)'s % operator, we need to consider the cases
+ separately in different range of signs.
+
+ case 1. [500, 1700] % [7, 23] (numerator is always positive)
+ = [0, 22]
+ case 2. [-500, 1700] % [7, 23] (numerator can be negative)
+ = [-22, 22]
+ case 3. [-1700, -500] % [7, 23] (numerator is always negative)
+ = [-22, 0]
+
+ the number 22 is the maximum absolute value in the denomator's range. We
+ don't care about divide by zero.
+ */
+
+ // Modding on 0 is invalid anyway.
+ if (!irDen.imin.negative)
+ return Expression::getIntRange() DUMP;
+
+ ++ irDen.imin;
+ irDen.imax = -irDen.imin;
+
+ if (!irNum.imin.negative)
+ irNum.imin.value = 0;
+ else if (irNum.imin < irDen.imin)
+ irNum.imin = irDen.imin;
+
+ if (irNum.imax.negative)
+ {
+ irNum.imax.negative = false;
+ irNum.imax.value = 0;
+ }
+ else if (irNum.imax > irDen.imax)
+ irNum.imax = irDen.imax;
+
+ return irNum.cast(type) DUMP;
+}
+
+// The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
+// not the tightest bound. See
+// https://github.com/D-Programming-Language/dmd/pull/116
+// for detail.
+static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
+{
+ // the DiffMasks stores the mask of bits which are variable in the range.
+ uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+ uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+ // Since '&' computes the digitwise-minimum, the we could set all varying
+ // digits to 0 to get a lower bound, and set all varying digits to 1 to get
+ // an upper bound.
+ IntRange result;
+ result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
+ result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
+ // Sometimes the upper bound is overestimated. The upper bound will never
+ // exceed the input.
+ if (result.imax.value > a.imax.value)
+ result.imax.value = a.imax.value;
+ if (result.imax.value > b.imax.value)
+ result.imax.value = b.imax.value;
+ result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
+ return result;
+}
+static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
+{
+ // the DiffMasks stores the mask of bits which are variable in the range.
+ uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+ uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+ // The imax algorithm by Adam D. Ruppe.
+ // http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
+ IntRange result;
+ result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
+ result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
+ // Sometimes the lower bound is underestimated. The lower bound will never
+ // less than the input.
+ if (result.imin.value < a.imin.value)
+ result.imin.value = a.imin.value;
+ if (result.imin.value < b.imin.value)
+ result.imin.value = b.imin.value;
+ result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
+ return result;
+}
+static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
+{
+ // the DiffMasks stores the mask of bits which are variable in the range.
+ uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+ uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+ IntRange result;
+ result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
+ result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
+ result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
+ return result;
+}
+
+
IntRange AndExp::getIntRange()
{
- IntRange ir;
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
- ir.imin = ir1.imin;
- if (ir2.imin < ir.imin)
- ir.imin = ir2.imin;
+ IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+ bool has1neg, has1pos, has2neg, has2pos;
- ir.imax = ir1.imax;
- if (ir2.imax > ir.imax)
- ir.imax = ir2.imax;
+ ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+ ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
- uinteger_t u;
-
- u = getMask(ir1.imax);
- ir.imin &= u;
- ir.imax &= u;
-
- u = getMask(ir2.imax);
- ir.imin &= u;
- ir.imax &= u;
-
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
-
-//printf("AndExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
+ IntRange result;
+ bool hasResult = false;
+ if (has1pos && has2pos)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), /*ref*/hasResult);
+ if (has1pos && has2neg)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), /*ref*/hasResult);
+ if (has1neg && has2pos)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), /*ref*/hasResult);
+ if (has1neg && has2neg)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), /*ref*/hasResult);
+ assert(hasResult);
+ return result.cast(type) DUMP;
}
-/*
- * Adam D. Ruppe's algo for bitwise OR:
- * http://www.digitalmars.com/d/archives/digitalmars/D/value_range_propagation_for_logical_OR_108765.html#N108793
- */
-
IntRange OrExp::getIntRange()
{
- IntRange ir;
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
- ir.imin = ir1.imin;
- if (ir2.imin < ir.imin)
- ir.imin = ir2.imin;
+ IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+ bool has1neg, has1pos, has2neg, has2pos;
- ir.imax = ir1.imax;
- if (ir2.imax > ir.imax)
- ir.imax = ir2.imax;
+ ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+ ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
+ IntRange result;
+ bool hasResult = false;
+ if (has1pos && has2pos)
+ result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), /*ref*/hasResult);
+ if (has1pos && has2neg)
+ result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), /*ref*/hasResult);
+ if (has1neg && has2pos)
+ result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), /*ref*/hasResult);
+ if (has1neg && has2neg)
+ result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), /*ref*/hasResult);
-//printf("OrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
+ assert(hasResult);
+ return result.cast(type) DUMP;
}
IntRange XorExp::getIntRange()
{
- IntRange ir;
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
- ir.imin = ir1.imin;
- if (ir2.imin < ir.imin)
- ir.imin = ir2.imin;
+ IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+ bool has1neg, has1pos, has2neg, has2pos;
- ir.imax = ir1.imax;
- if (ir2.imax > ir.imax)
- ir.imax = ir2.imax;
+ ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+ ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
+ IntRange result;
+ bool hasResult = false;
+ if (has1pos && has2pos)
+ result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), /*ref*/hasResult);
+ if (has1pos && has2neg)
+ result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), /*ref*/hasResult);
+ if (has1neg && has2pos)
+ result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), /*ref*/hasResult);
+ if (has1neg && has2neg)
+ result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), /*ref*/hasResult);
-//printf("XorExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
+ assert(hasResult);
+ return result.cast(type) DUMP;
}
IntRange ShlExp::getIntRange()
{
- IntRange ir;
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
- ir.imin = getMask(ir1.imin) << ir2.imin;
- ir.imax = getMask(ir1.imax) << ir2.imax;
+ if (ir2.imin.negative)
+ ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
+ SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
+ SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
-//printf("ShlExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
+ return IntRange(lower, upper).cast(type) DUMP;
}
IntRange ShrExp::getIntRange()
{
- if (!e1->type->isunsigned())
- return Expression::getIntRange();
-
- IntRange ir;
IntRange ir1 = e1->getIntRange();
IntRange ir2 = e2->getIntRange();
- ir.imin = ir1.imin >> ir2.imax;
- ir.imax = ir1.imax >> ir2.imin;
+ if (ir2.imin.negative)
+ ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
+ SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
+ SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
-//printf("ShrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
+ return IntRange(lower, upper).cast(type) DUMP;
}
IntRange UshrExp::getIntRange()
{
- IntRange ir;
- IntRange ir1 = e1->getIntRange();
+ IntRange ir1 = e1->getIntRange().castUnsigned(e1->type);
IntRange ir2 = e2->getIntRange();
- ir.imin = ir1.imin >> ir2.imax;
- ir.imax = ir1.imax >> ir2.imin;
+ if (ir2.imin.negative)
+ ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
- ir.imin &= type->sizemask();
- ir.imax &= type->sizemask();
+ return IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(type) DUMP;
-//printf("UshrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
-//e1->dump(0);
-
- return ir;
}
IntRange CommaExp::getIntRange()
{
- return e2->getIntRange();
+ return e2->getIntRange() DUMP;
}
+IntRange ComExp::getIntRange()
+{
+ IntRange ir = e1->getIntRange();
+ return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative),
+ SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(type) DUMP;
+}
+
+IntRange NegExp::getIntRange()
+{
+ IntRange ir = e1->getIntRange();
+ return IntRange(-ir.imax, -ir.imin).cast(type) DUMP;
+}
diff --git a/dmd2/class.c b/dmd2/class.c
index 52ddb7ac..ad2c694b 100644
--- a/dmd2/class.c
+++ b/dmd2/class.c
@@ -32,6 +32,7 @@
ClassDeclaration *ClassDeclaration::classinfo;
ClassDeclaration *ClassDeclaration::object;
ClassDeclaration *ClassDeclaration::throwable;
+ClassDeclaration *ClassDeclaration::exception;
ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
: AggregateDeclaration(loc, id)
@@ -190,6 +191,12 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla
throwable = this;
}
+ if (id == Id::Exception)
+ { if (exception)
+ exception->error("%s", msg);
+ exception = this;
+ }
+
//if (id == Id::ClassInfo)
if (id == Id::TypeInfo_Class)
{ if (classinfo)
@@ -695,7 +702,8 @@ void ClassDeclaration::semantic(Scope *sc)
if (!ctor && baseClass && baseClass->ctor)
{
//printf("Creating default this(){} for class %s\n", toChars());
- CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0, 0);
+ Type *tf = new TypeFunction(NULL, NULL, 0, LINKd, 0);
+ CtorDeclaration *ctor = new CtorDeclaration(loc, 0, 0, tf);
ctor->fbody = new CompoundStatement(0, new Statements());
members->push(ctor);
ctor->addMember(sc, this, 1);
@@ -758,6 +766,12 @@ void ClassDeclaration::semantic(Scope *sc)
}
#endif
//printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
+
+ if (deferred)
+ {
+ deferred->semantic2(sc);
+ deferred->semantic3(sc);
+ }
}
void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
diff --git a/dmd2/clone.c b/dmd2/clone.c
index 9d568f86..cb40c76d 100644
--- a/dmd2/clone.c
+++ b/dmd2/clone.c
@@ -338,21 +338,26 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
fcp = new FuncDeclaration(loc, 0, Id::cpctor, STCundefined, ftype);
fcp->storage_class |= postblit->storage_class & STCdisable;
- // Build *this = p;
- Expression *e = new ThisExp(0);
+ if (!(fcp->storage_class & STCdisable))
+ {
+ // Build *this = p;
+ Expression *e = new ThisExp(0);
#if !STRUCTTHISREF
- e = new PtrExp(0, e);
+ e = new PtrExp(0, e);
#endif
- AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
- ea->op = TOKblit;
- Statement *s = new ExpStatement(0, ea);
+ AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
+ ea->op = TOKblit;
+ Statement *s = new ExpStatement(0, ea);
- // Build postBlit();
- e = new VarExp(0, postblit, 0);
- e = new CallExp(0, e);
+ // Build postBlit();
+ e = new VarExp(0, postblit, 0);
+ e = new CallExp(0, e);
- s = new CompoundStatement(0, s, new ExpStatement(0, e));
- fcp->fbody = s;
+ s = new CompoundStatement(0, s, new ExpStatement(0, e));
+ fcp->fbody = s;
+ }
+ else
+ fcp->fbody = new ExpStatement(0, (Expression *)NULL);
members->push(fcp);
@@ -391,7 +396,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
if (v->storage_class & STCref)
continue;
Type *tv = v->type->toBasetype();
- size_t dim = 1;
+ size_t dim = (tv->ty == Tsarray ? 1 : 0);
while (tv->ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)tv;
dim *= ((TypeSArray *)tv)->dim->toInteger();
@@ -401,15 +406,20 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
{ TypeStruct *ts = (TypeStruct *)tv;
StructDeclaration *sd = ts->sym;
if (sd->postblit)
- { Expression *ex;
-
+ {
stc |= sd->postblit->storage_class & STCdisable;
+ if (stc & STCdisable)
+ {
+ e = NULL;
+ break;
+ }
+
// this.v
- ex = new ThisExp(0);
+ Expression *ex = new ThisExp(0);
ex = new DotVarExp(0, ex, v, 0);
- if (dim == 1)
+ if (dim == 0)
{ // this.v.postblit()
ex = new DotVarExp(0, ex, sd->postblit, 0);
ex = new CallExp(0, ex);
@@ -432,7 +442,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
/* Build our own "postblit" which executes e
*/
- if (e)
+ if (e || (stc & STCdisable))
{ //printf("Building __fieldPostBlit()\n");
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__fieldPostBlit"));
dd->storage_class |= stc;
@@ -455,6 +465,11 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
for (size_t i = 0; i < postblits.dim; i++)
{ FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i];
stc |= fd->storage_class & STCdisable;
+ if (stc & STCdisable)
+ {
+ e = NULL;
+ break;
+ }
Expression *ex = new ThisExp(0);
ex = new DotVarExp(0, ex, fd, 0);
ex = new CallExp(0, ex);
@@ -493,7 +508,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
if (v->storage_class & STCref)
continue;
Type *tv = v->type->toBasetype();
- size_t dim = 1;
+ size_t dim = (tv->ty == Tsarray ? 1 : 0);
while (tv->ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)tv;
dim *= ((TypeSArray *)tv)->dim->toInteger();
@@ -509,7 +524,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
ex = new ThisExp(0);
ex = new DotVarExp(0, ex, v, 0);
- if (dim == 1)
+ if (dim == 0)
{ // this.v.dtor()
ex = new DotVarExp(0, ex, sd->dtor, 0);
ex = new CallExp(0, ex);
diff --git a/dmd2/cond.c b/dmd2/cond.c
index 831a10d6..51557961 100644
--- a/dmd2/cond.c
+++ b/dmd2/cond.c
@@ -20,10 +20,8 @@
#include "module.h"
#include "template.h"
#include "lexer.h"
-#ifdef _DH
#include "mtype.h"
#include "scope.h"
-#endif
int findCondition(Array *ids, Identifier *ident)
{
@@ -138,6 +136,7 @@ void VersionCondition::checkPredefined(Loc loc, const char *ident)
"D_NET",
#endif
"OSX", "FreeBSD",
+ "OpenBSD",
"Solaris",
"LittleEndian", "BigEndian",
"all",
diff --git a/dmd2/cond.h b/dmd2/cond.h
index 8302c23d..e3cde453 100644
--- a/dmd2/cond.h
+++ b/dmd2/cond.h
@@ -18,13 +18,9 @@ struct Module;
struct Scope;
struct ScopeDsymbol;
struct DebugCondition;
-#ifdef _DH
#include "lexer.h" // dmdhg
-#endif
enum TOK;
-#ifdef _DH
struct HdrGenState;
-#endif
int findCondition(Array *ids, Identifier *ident);
diff --git a/dmd2/constfold.c b/dmd2/constfold.c
index 7551922e..784bac21 100644
--- a/dmd2/constfold.c
+++ b/dmd2/constfold.c
@@ -27,12 +27,10 @@
#include "declaration.h"
#include "utf.h"
-#if __FreeBSD__
-#define fmodl fmod // hack for now, fix later
-#endif
-
#define LOG 0
+int RealEquals(real_t x1, real_t x2);
+
Expression *expType(Type *type, Expression *e)
{
if (type != e->type)
@@ -486,7 +484,7 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2)
{ real_t r2 = e2->toReal();
#ifdef __DMC__
- c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
+ c = Port::fmodl(e1->toReal(), r2) + Port::fmodl(e1->toImaginary(), r2) * I;
#elif defined(IN_GCC)
c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__)
@@ -494,14 +492,14 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2)
// arm also doesn't like fmodl
c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2));
#else
- c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
+ c = complex_t(Port::fmodl(e1->toReal(), r2), Port::fmodl(e1->toImaginary(), r2));
#endif
}
else if (e2->type->isimaginary())
{ real_t i2 = e2->toImaginary();
#ifdef __DMC__
- c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
+ c = Port::fmodl(e1->toReal(), i2) + Port::fmodl(e1->toImaginary(), i2) * I;
#elif defined(IN_GCC)
c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__)
@@ -509,7 +507,7 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2)
// arm also doesn't like fmodl
c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2));
#else
- c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
+ c = complex_t(Port::fmodl(e1->toReal(), i2), Port::fmodl(e1->toImaginary(), i2));
#endif
}
else
@@ -876,11 +874,27 @@ Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
cmp = (es1->var == es2->var && es1->offset == es2->offset);
}
- else if (e1->isConst() == 1 && e2->isConst() == 1)
- return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
- type, e1, e2);
else
- assert(0);
+ {
+ if (e1->type->isreal())
+ {
+ cmp = RealEquals(e1->toReal(), e2->toReal());
+ }
+ else if (e1->type->isimaginary())
+ {
+ cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
+ }
+ else if (e1->type->iscomplex())
+ {
+ complex_t v1 = e1->toComplex();
+ complex_t v2 = e2->toComplex();
+ cmp = RealEquals(creall(v1), creall(v2)) &&
+ RealEquals(cimagl(v1), cimagl(v1));
+ }
+ else
+ return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+ type, e1, e2);
+ }
if (op == TOKnotidentity)
cmp ^= 1;
return new IntegerExp(loc, cmp, type);
@@ -1089,6 +1103,13 @@ Expression *Cast(Type *type, Type *to, Expression *e1)
to->implicitConvTo(e1->type) >= MATCHconst)
return expType(to, e1);
+ // Allow covariant converions of delegates
+ // (Perhaps implicit conversion from pure to impure should be a MATCHconst,
+ // then we wouldn't need this extra check.)
+ if (e1->type->toBasetype()->ty == Tdelegate &&
+ e1->type->implicitConvTo(to) == MATCHconvert)
+ return expType(to, e1);
+
Type *tb = to->toBasetype();
Type *typeb = type->toBasetype();
@@ -1241,30 +1262,34 @@ Expression *Index(Type *type, Expression *e1, Expression *e2)
uinteger_t i = e2->toInteger();
if (i >= length)
- { e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length);
+ { e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length);
}
- else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+ else if (e1->op == TOKarrayliteral)
{ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
e = (Expression *)ale->elements->data[i];
e->type = type;
+ if (e->checkSideEffect(2))
+ e = EXP_CANT_INTERPRET;
}
}
else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
{
uinteger_t i = e2->toInteger();
- if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+ if (e1->op == TOKarrayliteral)
{ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
if (i >= ale->elements->dim)
- { e2->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+ { e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
}
else
{ e = (Expression *)ale->elements->data[i];
e->type = type;
+ if (e->checkSideEffect(2))
+ e = EXP_CANT_INTERPRET;
}
}
}
- else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
+ else if (e1->op == TOKassocarrayliteral)
{
AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
/* Search the keys backwards, in case there are duplicate keys
@@ -1279,6 +1304,8 @@ Expression *Index(Type *type, Expression *e1, Expression *e2)
if (ex->isBool(TRUE))
{ e = (Expression *)ae->values->data[i];
e->type = type;
+ if (e->checkSideEffect(2))
+ e = EXP_CANT_INTERPRET;
break;
}
}
@@ -1405,6 +1432,14 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2)
e->type = type;
return e;
}
+ else if (e1->op == TOKnull && e2->op == TOKnull)
+ {
+ if (type == e1->type)
+ return e1;
+ if (type == e2->type)
+ return e2;
+ return new NullExp(e1->loc, type);
+ }
else if (e1->op == TOKstring && e2->op == TOKstring)
{
// Concatenate the strings
diff --git a/dmd2/declaration.c b/dmd2/declaration.c
index a0a14b8d..49081815 100644
--- a/dmd2/declaration.c
+++ b/dmd2/declaration.c
@@ -273,10 +273,8 @@ TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype,
this->type = new TypeTypedef(this);
this->basetype = basetype->toBasetype();
this->init = init;
-#ifdef _DH
this->htype = NULL;
this->hbasetype = NULL;
-#endif
this->loc = loc;
#if IN_DMD
this->sinit = NULL;
@@ -294,7 +292,7 @@ Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s)
assert(!s);
TypedefDeclaration *st;
st = new TypedefDeclaration(loc, ident, basetype, init);
-#ifdef _DH
+
// Syntax copy for header file
if (!htype) // Don't overwrite original
{ if (type) // Make copy for both old and new instances
@@ -312,7 +310,7 @@ Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s)
}
else
st->hbasetype = hbasetype->syntaxCopy();
-#endif
+
return st;
}
@@ -389,10 +387,8 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type)
this->loc = loc;
this->type = type;
this->aliassym = NULL;
-#ifdef _DH
this->htype = NULL;
this->haliassym = NULL;
-#endif
this->overnext = NULL;
this->inSemantic = 0;
this->importprot = PROTundefined;
@@ -407,10 +403,8 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s)
this->loc = loc;
this->type = NULL;
this->aliassym = s;
-#ifdef _DH
this->htype = NULL;
this->haliassym = NULL;
-#endif
this->overnext = NULL;
this->inSemantic = 0;
assert(s);
@@ -425,7 +419,7 @@ Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
sa = new AliasDeclaration(loc, ident, type->syntaxCopy());
else
sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
-#ifdef _DH
+
// Syntax copy for header file
if (!htype) // Don't overwrite original
{ if (type) // Make copy for both old and new instances
@@ -443,7 +437,7 @@ Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
}
else
sa->haliassym = haliassym->syntaxCopy(s);
-#endif
+
return sa;
}
@@ -631,7 +625,7 @@ Dsymbol *AliasDeclaration::toAlias()
void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("alias ");
-#if 0 && _DH
+#if 0
if (hgs->hdrgen)
{
if (haliassym)
@@ -678,10 +672,8 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer
assert(type || init);
this->type = type;
this->init = init;
-#ifdef _DH
this->htype = NULL;
this->hinit = NULL;
-#endif
this->loc = loc;
offset = 0;
noscope = 0;
@@ -733,7 +725,7 @@ Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init);
sv->storage_class = storage_class;
}
-#ifdef _DH
+
// Syntax copy for header file
if (!htype) // Don't overwrite original
{ if (type) // Make copy for both old and new instances
@@ -751,7 +743,7 @@ Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
}
else
sv->hinit = hinit->syntaxCopy();
-#endif
+
return sv;
}
@@ -844,17 +836,33 @@ void VarDeclaration::semantic(Scope *sc)
//printf("storage_class = x%x\n", storage_class);
#if DMDV2
-#if 1
- if (storage_class & STCgshared && sc->func && sc->func->isSafe())
+ // Safety checks
+ if (sc->func && !sc->intypeof)
{
- error("__gshared not allowed in safe functions; use shared");
+ if (storage_class & STCgshared)
+ {
+ if (sc->func->setUnsafe())
+ error("__gshared not allowed in safe functions; use shared");
+ }
+ if (init && init->isVoidInitializer() && type->hasPointers())
+ {
+ 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)
+ {
+ AggregateDeclaration *ad = s->isAggregateDeclaration();
+ if (ad && ad->hasUnions)
+ {
+ if (sc->func->setUnsafe())
+ error("unions containing pointers are not allowed in @safe functions");
+ }
+ }
+ }
}
-#else
- if (storage_class & STCgshared && global.params.safe && !sc->module->safe)
- {
- error("__gshared not allowed in safe mode; use shared");
- }
-#endif
#endif
Dsymbol *parent = toParent();
@@ -1184,18 +1192,24 @@ Lagain:
ei->exp = resolveProperties(sc, ei->exp);
StructDeclaration *sd = ((TypeStruct *)t)->sym;
#if DMDV2
+ Expression** pinit = &ei->exp;
+ while ((*pinit)->op == TOKcomma)
+ {
+ pinit = &((CommaExp *)*pinit)->e2;
+ }
+
/* Look to see if initializer is a call to the constructor
*/
if (sd->ctor && // there are constructors
- ei->exp->type->ty == Tstruct && // rvalue is the same struct
- ((TypeStruct *)ei->exp->type)->sym == sd &&
- ei->exp->op == TOKcall)
+ (*pinit)->type->ty == Tstruct && // rvalue is the same struct
+ ((TypeStruct *)(*pinit)->type)->sym == sd &&
+ (*pinit)->op == TOKcall)
{
/* Look for form of constructor call which is:
* *__ctmp.ctor(arguments...)
*/
if (1)
- { CallExp *ce = (CallExp *)ei->exp;
+ { CallExp *ce = (CallExp *)(*pinit);
if (ce->e1->op == TOKdotvar)
{ DotVarExp *dve = (DotVarExp *)ce->e1;
if (dve->var->isCtorDeclaration())
@@ -1216,12 +1230,12 @@ Lagain:
e->op = TOKblit;
}
e->type = t;
- ei->exp = new CommaExp(loc, e, ei->exp);
+ (*pinit) = new CommaExp(loc, e, (*pinit));
/* Replace __ctmp being constructed with e1
*/
dve->e1 = e1;
- ei->exp = ei->exp->semantic(sc);
+ (*pinit) = (*pinit)->semantic(sc);
goto Ldtor;
}
}
@@ -1650,6 +1664,7 @@ int VarDeclaration::canTakeAddressOf()
return 1;
}
+
/*******************************
* Does symbol go into data segment?
* Includes extern variables.
diff --git a/dmd2/declaration.h b/dmd2/declaration.h
index 6714f7b9..d1d53a33 100644
--- a/dmd2/declaration.h
+++ b/dmd2/declaration.h
@@ -214,10 +214,8 @@ struct TypedefDeclaration : Declaration
const char *kind();
Type *getType();
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-#ifdef _DH
Type *htype;
Type *hbasetype;
-#endif
void toDocBuffer(OutBuffer *buf);
@@ -258,10 +256,8 @@ struct AliasDeclaration : Declaration
Type *getType();
Dsymbol *toAlias();
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-#ifdef _DH
Type *htype;
Dsymbol *haliassym;
-#endif
void toDocBuffer(OutBuffer *buf);
@@ -311,10 +307,8 @@ struct VarDeclaration : Declaration
void semantic2(Scope *sc);
const char *kind();
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-#ifdef _DH
Type *htype;
Initializer *hinit;
-#endif
AggregateDeclaration *isThis();
int needThis();
int isImportedSymbol();
@@ -722,7 +716,6 @@ struct FuncDeclaration : Declaration
Loc endloc; // location of closing curly bracket
int vtblIndex; // for member functions, index into vtbl[]
int naked; // !=0 if naked
- int inlineAsm; // !=0 if has inline assembler
ILS inlineStatus;
int inlineNest; // !=0 if nested inline
int cantInterpret; // !=0 if cannot interpret function
@@ -759,6 +752,11 @@ struct FuncDeclaration : Declaration
Dsymbols closureVars; // local variables in this function
// which are referenced by nested
// functions
+
+ unsigned flags;
+ #define FUNCFLAGpurityInprocess 1 // working on determining purity
+ #define FUNCFLAGsafetyInprocess 2 // working on determining safety
+ #define FUNCFLAGnothrowInprocess 4 // working on determining nothrow
#else
int nestedFrameRef; // !=0 if nested variables referenced
#endif
@@ -798,8 +796,10 @@ struct FuncDeclaration : Declaration
int isCodeseg();
int isOverloadable();
enum PURE isPure();
+ bool setImpure();
int isSafe();
int isTrusted();
+ bool setUnsafe();
virtual int isNested();
int needThis();
virtual int isVirtual();
@@ -857,6 +857,9 @@ struct FuncDeclaration : Declaration
// true if overridden with the pragma(allow_inline); stmt
bool allowInlining;
+
+ // true if has inline assembler
+ bool inlineAsm;
#endif
};
@@ -898,10 +901,8 @@ struct FuncLiteralDeclaration : FuncDeclaration
};
struct CtorDeclaration : FuncDeclaration
-{ Parameters *arguments;
- int varargs;
-
- CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs, StorageClass stc);
+{
+ CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
Dsymbol *syntaxCopy(Dsymbol *);
void semantic(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -1068,9 +1069,7 @@ struct DeleteDeclaration : FuncDeclaration
int isVirtual();
int addPreInvariant();
int addPostInvariant();
-#ifdef _DH
DeleteDeclaration *isDeleteDeclaration() { return this; }
-#endif
};
#endif /* DMD_DECLARATION_H */
diff --git a/dmd2/doc.c b/dmd2/doc.c
index 5dd94dbf..9debd549 100644
--- a/dmd2/doc.c
+++ b/dmd2/doc.c
@@ -1,6 +1,6 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2010 by Digital Mars
+// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -133,6 +133,7 @@ LINK = $0\n\
LINK2 = $+\n\
LPAREN= (\n\
RPAREN= )\n\
+DOLLAR= $\n\
\n\
RED = $0\n\
BLUE = $0\n\
@@ -374,6 +375,12 @@ void escapeDdocString(OutBuffer *buf, unsigned start)
unsigned char c = buf->data[u];
switch(c)
{
+ case '$':
+ buf->remove(u, 1);
+ buf->insert(u, "$(DOLLAR)", 9);
+ u += 8;
+ break;
+
case '(':
buf->remove(u, 1); //remove the (
buf->insert(u, "$(LPAREN)", 9); //insert this instead
@@ -792,29 +799,35 @@ void prefix(OutBuffer *buf, Dsymbol *s)
}
}
-void Declaration::toDocBuffer(OutBuffer *buf)
+void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td)
{
- //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType);
- if (ident)
+ //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--");
+ if (decl->ident)
{
- prefix(buf, this);
+ prefix(buf, decl);
- if (type)
+ if (decl->type)
{ HdrGenState hgs;
hgs.ddoc = 1;
- if (originalType)
- { //originalType->print();
- originalType->toCBuffer(buf, ident, &hgs);
+ Type *origType = decl->originalType ? decl->originalType : decl->type;
+ if (origType->ty == Tfunction)
+ {
+ TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type);
+ ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td);
}
else
- type->toCBuffer(buf, ident, &hgs);
+ origType->toCBuffer(buf, decl->ident, &hgs);
}
else
- buf->writestring(ident->toChars());
+ buf->writestring(decl->ident->toChars());
buf->writestring(";\n");
}
}
+void Declaration::toDocBuffer(OutBuffer *buf)
+{
+ declarationToDocBuffer(this, buf, NULL);
+}
void AliasDeclaration::toDocBuffer(OutBuffer *buf)
{
@@ -859,31 +872,9 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf)
td->onemember == this)
{ /* It's a function template
*/
- HdrGenState hgs;
unsigned o = buf->offset;
- TypeFunction *tf = (TypeFunction *)type;
- hgs.ddoc = 1;
- prefix(buf, td);
- if (tf)
- { if (tf->nextOf())
- tf->nextOf()->toCBuffer(buf, NULL, &hgs);
- else
- buf->writestring("auto");
- }
- buf->writeByte(' ');
- buf->writestring(ident->toChars());
- buf->writeByte('(');
- for (int i = 0; i < td->origParameters->dim; i++)
- {
- TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i];
- if (i)
- buf->writestring(", ");
- tp->toCBuffer(buf, &hgs);
- }
- buf->writeByte(')');
- Parameter::argsToCBuffer(buf, &hgs, tf ? tf->parameters : NULL, tf ? tf->varargs : 0);
- buf->writestring(";\n");
+ declarationToDocBuffer(this, buf, td);
highlightCode(NULL, this, buf, o);
}
@@ -894,6 +885,17 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf)
}
}
+#if DMDV1
+void CtorDeclaration::toDocBuffer(OutBuffer *buf)
+{
+ HdrGenState hgs;
+
+ buf->writestring("this");
+ Parameter::argsToCBuffer(buf, &hgs, arguments, varargs);
+ buf->writestring(";\n");
+}
+#endif
+
void AggregateDeclaration::toDocBuffer(OutBuffer *buf)
{
if (ident)
diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c
index b617e2e1..3ba307be 100644
--- a/dmd2/dsymbol.c
+++ b/dmd2/dsymbol.c
@@ -218,10 +218,13 @@ char *Dsymbol::locToChars()
OutBuffer buf;
char *p;
- Module *m = getModule();
+ if (!loc.filename) // avoid bug 5861.
+ {
+ Module *m = getModule();
- if (m && m->srcfile)
- loc.filename = m->srcfile->toChars();
+ if (m && m->srcfile)
+ loc.filename = m->srcfile->toChars();
+ }
return loc.toChars();
}
diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h
index f6319935..7bd458ad 100644
--- a/dmd2/dsymbol.h
+++ b/dmd2/dsymbol.h
@@ -178,10 +178,8 @@ struct Dsymbol : Object
Dsymbol *search_correct(Identifier *id);
Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id);
virtual int overloadInsert(Dsymbol *s);
-#ifdef _DH
char *toHChars();
virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs);
-#endif
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
virtual void toDocBuffer(OutBuffer *buf);
virtual void toJsonBuffer(OutBuffer *buf);
@@ -262,9 +260,7 @@ struct Dsymbol : Object
virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
virtual Import *isImport() { return NULL; }
virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
-#ifdef _DH
virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
-#endif
virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; }
virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
virtual OverloadSet *isOverloadSet() { return NULL; }
diff --git a/dmd2/enum.h b/dmd2/enum.h
index 70e69536..a07d80d7 100644
--- a/dmd2/enum.h
+++ b/dmd2/enum.h
@@ -21,9 +21,7 @@
struct Identifier;
struct Type;
struct Expression;
-#ifdef _DH
struct HdrGenState;
-#endif
struct EnumDeclaration : ScopeDsymbol
diff --git a/dmd2/expression.c b/dmd2/expression.c
index f397c4c0..002fb280 100644
--- a/dmd2/expression.c
+++ b/dmd2/expression.c
@@ -58,6 +58,7 @@ int isnan(double);
#include "attrib.h"
#include "hdrgen.h"
#include "parse.h"
+#include "doc.h"
#if IN_DMD
Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim);
@@ -199,7 +200,7 @@ FuncDeclaration *hasThis(Scope *sc)
break;
}
- fd = fd->parent->isFuncDeclaration();
+ fd = parent->isFuncDeclaration();
}
if (!fd->isThis())
@@ -228,9 +229,12 @@ Expression *resolveProperties(Scope *sc, Expression *e)
if (t->ty == Tfunction || e->op == TOKoverloadset)
{
-#if 0
- if (t->ty == Tfunction && !((TypeFunction *)t)->isproperty)
+#if 1
+ if (t->ty == Tfunction && !((TypeFunction *)t)->isproperty &&
+ global.params.enforcePropertySyntax)
+ {
error(e->loc, "not a property %s\n", e->toChars());
+ }
#endif
e = new CallExp(e->loc, e);
e = e->semantic(sc);
@@ -410,6 +414,7 @@ Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt
condexp.type = NULL;
condexp.e1 = e0;
condexp.e2 = e;
+ condexp.loc = e->loc;
condexp.semantic(sc);
exps->data[j0] = (void *)condexp.e1;
e = condexp.e2;
@@ -483,6 +488,41 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps)
}
}
+/************************************************
+ * If we want the value of this expression, but do not want to call
+ * the destructor on it.
+ */
+
+void valueNoDtor(Expression *e)
+{
+ if (e->op == TOKcall)
+ {
+ /* The struct value returned from the function is transferred
+ * so do not call the destructor on it.
+ * Recognize:
+ * ((S _ctmp = S.init), _ctmp).this(...)
+ * and make sure the destructor is not called on _ctmp
+ * BUG: if e is a CommaExp, we should go down the right side.
+ */
+ CallExp *ce = (CallExp *)e;
+ if (ce->e1->op == TOKdotvar)
+ { DotVarExp *dve = (DotVarExp *)ce->e1;
+ if (dve->var->isCtorDeclaration())
+ { // It's a constructor call
+ if (dve->e1->op == TOKcomma)
+ { CommaExp *comma = (CommaExp *)dve->e1;
+ if (comma->e2->op == TOKvar)
+ { VarExp *ve = (VarExp *)comma->e2;
+ VarDeclaration *ctmp = ve->var->isVarDeclaration();
+ if (ctmp)
+ ctmp->noscope = 1;
+ }
+ }
+ }
+ }
+ }
+}
+
/*********************************************
* Call copy constructor for struct value argument.
*/
@@ -603,7 +643,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
Identifier *id = Lexer::uniqueId("__arrayArg");
Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i));
t = t->semantic(loc, sc);
- VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc));
+ VarDeclaration *v = new VarDeclaration(loc, t, id, fd->isSafe() ? NULL : new VoidInitializer(loc));
v->storage_class |= STCctfe;
v->semantic(sc);
v->parent = sc->parent;
@@ -712,24 +752,8 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
/* The struct value returned from the function is transferred
* to the function, so the callee should not call the destructor
* on it.
- * ((S _ctmp = S.init), _ctmp).this(...)
*/
- CallExp *ce = (CallExp *)arg;
- if (ce->e1->op == TOKdotvar)
- { DotVarExp *dve = (DotVarExp *)ce->e1;
- if (dve->var->isCtorDeclaration())
- { // It's a constructor call
- if (dve->e1->op == TOKcomma)
- { CommaExp *comma = (CommaExp *)dve->e1;
- if (comma->e2->op == TOKvar)
- { VarExp *ve = (VarExp *)comma->e2;
- VarDeclaration *ctmp = ve->var->isVarDeclaration();
- if (ctmp)
- ctmp->noscope = 1;
- }
- }
- }
- }
+ valueNoDtor(arg);
}
else
{ /* Not transferring it, so call the copy constructor
@@ -1252,6 +1276,11 @@ void Expression::checkDeprecated(Scope *sc, Dsymbol *s)
}
#if DMDV2
+/*********************************************
+ * Calling function f.
+ * Check the purity, i.e. if we're in a pure function
+ * we can only call other pure functions.
+ */
void Expression::checkPurity(Scope *sc, FuncDeclaration *f)
{
#if 1
@@ -1287,12 +1316,14 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f)
}
// If the caller has a pure parent, then either the called func must be pure,
// OR, they must have the same pure parent.
- if (outerfunc->isPure() && !sc->intypeof &&
+ if (/*outerfunc->isPure() &&*/ // comment out because we deduce purity now
+ !sc->intypeof &&
!(sc->flags & SCOPEdebug) &&
!(f->isPure() || (calledparent == outerfunc)))
{
- error("pure function '%s' cannot call impure function '%s'",
- outerfunc->toChars(), f->toChars());
+ if (outerfunc->setImpure())
+ error("pure function '%s' cannot call impure function '%s'",
+ outerfunc->toChars(), f->toChars());
}
}
#else
@@ -1302,12 +1333,136 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f)
#endif
}
+/*******************************************
+ * Accessing variable v.
+ * Check for purity and safety violations.
+ * If ethis is not NULL, then ethis is the 'this' pointer as in ethis.v
+ */
+
+void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis)
+{
+ /* Look for purity and safety violations when accessing variable v
+ * from current function.
+ */
+ if (sc->func &&
+ !sc->intypeof && // allow violations inside typeof(expression)
+ !(sc->flags & SCOPEdebug) && // allow violations inside debug conditionals
+ v->ident != Id::ctfe && // magic variable never violates pure and safe
+ !v->isImmutable() && // always safe and pure to access immutables...
+ !(v->isConst() && v->isDataseg() && !v->type->hasPointers()) && // const global value types are immutable
+ !(v->storage_class & STCmanifest) // ...or manifest constants
+ )
+ {
+ if (v->isDataseg())
+ {
+ /* Accessing global mutable state.
+ * Therefore, this function and all its immediately enclosing
+ * functions must be pure.
+ */
+ bool msg = FALSE;
+ for (Dsymbol *s = sc->func; s; s = s->toParent2())
+ {
+ FuncDeclaration *ff = s->isFuncDeclaration();
+ if (!ff)
+ break;
+ if (ff->setImpure() && !msg)
+ { error("pure function '%s' cannot access mutable static data '%s'",
+ sc->func->toChars(), v->toChars());
+ msg = TRUE; // only need the innermost message
+ }
+ }
+ }
+ else
+ {
+ if (ethis)
+ {
+ Type *t1 = ethis->type->toBasetype();
+
+ if (t1->isImmutable() ||
+ (t1->ty == Tpointer && t1->nextOf()->isImmutable()))
+ {
+ goto L1;
+ }
+ if (ethis->op == TOKvar)
+ { VarExp *ve = (VarExp *)ethis;
+
+ v = ve->var->isVarDeclaration();
+ if (v)
+ checkPurity(sc, v, NULL);
+ return;
+ }
+ if (ethis->op == TOKdotvar)
+ { DotVarExp *ve = (DotVarExp *)ethis;
+
+ v = ve->var->isVarDeclaration();
+ if (v)
+ checkPurity(sc, v, ve->e1);
+ return;
+ }
+ }
+
+ /* Given:
+ * void f()
+ * { int fx;
+ * pure void g()
+ * { int gx;
+ * void h()
+ * { int hx;
+ * void i() { }
+ * }
+ * }
+ * }
+ * i() can modify hx and gx but not fx
+ */
+
+ /* Back up until we find the parent function of v,
+ * requiring each function in between to be impure.
+ */
+ Dsymbol *vparent = v->toParent2();
+ Dsymbol *s = sc->func, *snext = s->toParent2();
+ // Make sure we're really finding parent *functions*, not parent
+ // class.
+ if (vparent->isFuncDeclaration() || snext != vparent)
+ {
+ for (; s; s = s->toParent2())
+ {
+ if (s == vparent)
+ break;
+ FuncDeclaration *ff = s->isFuncDeclaration();
+ if (!ff)
+ break;
+ if (ff->setImpure())
+ { error("pure nested function '%s' cannot access mutable data '%s'",
+ ff->toChars(), v->toChars());
+ break;
+ }
+ }
+ }
+ }
+
+
+ /* Do not allow safe functions to access __gshared data
+ */
+ if (v->storage_class & STCgshared)
+ {
+ if (sc->func->setUnsafe())
+ error("safe function '%s' cannot access __gshared data '%s'",
+ sc->func->toChars(), v->toChars());
+ }
+
+ L1: ;
+ }
+}
+
void Expression::checkSafety(Scope *sc, FuncDeclaration *f)
{
- if (sc->func && sc->func->isSafe() && !sc->intypeof &&
+ if (sc->func && !sc->intypeof &&
!f->isSafe() && !f->isTrusted())
- error("safe function '%s' cannot call system function '%s'",
- sc->func->toChars(), f->toChars());
+ {
+ if (sc->func->setUnsafe())
+ error("safe function '%s' cannot call system function '%s'",
+ sc->func->toChars(), f->toChars());
+ }
}
#endif
@@ -1606,7 +1761,6 @@ dinteger_t IntegerExp::toInteger()
{
switch (t->ty)
{
- case Tbit:
case Tbool: value = (value != 0); break;
case Tint8: value = (d_int8) value; break;
case Tchar:
@@ -1750,13 +1904,18 @@ void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
break;
}
case Tchar:
+ {
+ unsigned o = buf->offset;
if (v == '\'')
buf->writestring("'\\''");
else if (isprint(v) && v != '\\')
buf->printf("'%c'", (int)v);
else
buf->printf("'\\x%02x'", (int)v);
+ if (hgs->ddoc)
+ escapeDdocString(buf, o);
break;
+ }
case Tint8:
buf->writestring("cast(byte)");
@@ -1793,7 +1952,6 @@ void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
buf->printf("%juLU", v);
break;
- case Tbit:
case Tbool:
buf->writestring((char *)(v ? "true" : "false"));
break;
@@ -1940,9 +2098,7 @@ complex_t RealExp::toComplex()
int RealEquals(real_t x1, real_t x2)
{
-//#if 1
// return (Port::isNan(x1) && Port::isNan(x2)) ||
-//#elif __APPLE__
#if __APPLE__
return (__inline_isnan(x1) && __inline_isnan(x2)) ||
#else
@@ -2064,9 +2220,7 @@ void realToMangleBuffer(OutBuffer *buf, real_t value)
* 0X1.9P+2 => 19P2
*/
-//#if 1
// if (Port::isNan(value))
-//#elif __APPLE__
#if __APPLE__
if (__inline_isnan(value))
#else
@@ -3156,6 +3310,7 @@ unsigned StringExp::charAt(size_t i)
void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writeByte('"');
+ unsigned o = buf->offset;
for (size_t i = 0; i < len; i++)
{ unsigned c = charAt(i);
@@ -3180,6 +3335,8 @@ void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
break;
}
}
+ if (hgs->ddoc)
+ escapeDdocString(buf, o);
buf->writeByte('"');
if (postfix)
buf->writeByte(postfix);
@@ -3279,6 +3436,12 @@ Expression *ArrayLiteralExp::semantic(Scope *sc)
type = t0->arrayOf();
//type = new TypeSArray(t0, new IntegerExp(elements->dim));
type = type->semantic(loc, sc);
+
+ /* Disallow array literals of type void being used.
+ */
+ if (elements->dim > 0 && t0->ty == Tvoid)
+ error("%s of type %s has no value", toChars(), type->toChars());
+
return this;
}
@@ -3304,7 +3467,10 @@ int ArrayLiteralExp::isBool(int result)
#if DMDV2
int ArrayLiteralExp::canThrow(bool mustNotThrow)
{
- return 1; // because it can fail allocating memory
+ /* Memory allocation failures throw non-recoverable exceptions, which
+ * we don't need to count as 'throwing'.
+ */
+ return arrayExpressionCanThrow(elements, mustNotThrow);
}
#endif
@@ -3399,7 +3565,11 @@ int AssocArrayLiteralExp::isBool(int result)
#if DMDV2
int AssocArrayLiteralExp::canThrow(bool mustNotThrow)
{
- return 1;
+ /* Memory allocation failures throw non-recoverable exceptions, which
+ * we don't need to count as 'throwing'.
+ */
+ return (arrayExpressionCanThrow(keys, mustNotThrow) ||
+ arrayExpressionCanThrow(values, mustNotThrow));
}
#endif
@@ -4210,7 +4380,22 @@ int NewExp::checkSideEffect(int flag)
#if DMDV2
int NewExp::canThrow(bool mustNotThrow)
{
- return 0; // regard storage allocation failures as not recoverable
+ if (arrayExpressionCanThrow(newargs, mustNotThrow) ||
+ arrayExpressionCanThrow(arguments, mustNotThrow))
+ return 1;
+ if (member)
+ {
+ // See if constructor call can throw
+ Type *t = member->type->toBasetype();
+ if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+ {
+ if (mustNotThrow)
+ error("constructor %s is not nothrow", member->toChars());
+ return 1;
+ }
+ }
+ // regard storage allocation failures as not recoverable
+ return 0;
}
#endif
@@ -4284,6 +4469,7 @@ int NewAnonClassExp::checkSideEffect(int flag)
#if DMDV2
int NewAnonClassExp::canThrow(bool mustNotThrow)
{
+ assert(0); // should have been lowered by semantic()
return 1;
}
#endif
@@ -4438,94 +4624,9 @@ Expression *VarExp::semantic(Scope *sc)
VarDeclaration *v = var->isVarDeclaration();
if (v)
{
-#if 0
- if ((v->isConst() || v->isImmutable()) &&
- type->toBasetype()->ty != Tsarray && v->init)
- {
- ExpInitializer *ei = v->init->isExpInitializer();
- if (ei)
- {
- //ei->exp->implicitCastTo(sc, type)->print();
- return ei->exp->implicitCastTo(sc, type);
- }
- }
-#endif
v->checkNestedReference(sc, loc);
#if DMDV2
-#if 1
- if (sc->func && !sc->intypeof && !(sc->flags & SCOPEdebug))
- {
- /* Given:
- * void f()
- * { int fx;
- * pure void g()
- * { int gx;
- * void h()
- * { int hx;
- * void i() { }
- * }
- * }
- * }
- * i() can modify hx and gx but not fx
- */
-
- /* Determine if sc->func is pure or if any function that
- * encloses it is also pure.
- */
- bool hasPureParent = false;
- for (FuncDeclaration *outerfunc = sc->func; outerfunc;)
- {
- if (outerfunc->isPure())
- {
- hasPureParent = true;
- break;
- }
- Dsymbol *parent = outerfunc->toParent2();
- if (!parent)
- break;
- outerfunc = parent->isFuncDeclaration();
- }
-
- /* Magic variable __ctfe never violates pure or safe
- */
- if (v->ident != Id::ctfe)
- {
- /* If ANY of its enclosing functions are pure,
- * it cannot do anything impure.
- * If it is pure, it cannot access any mutable variables other
- * than those inside itself
- */
- if (hasPureParent && v->isDataseg() &&
- !v->isImmutable())
- {
- error("pure function '%s' cannot access mutable static data '%s'",
- sc->func->toChars(), v->toChars());
- }
- else if (sc->func->isPure() &&
- sc->parent->pastMixin() != v->parent->pastMixin() &&
- !v->isImmutable() &&
- !(v->storage_class & STCmanifest))
- {
- error("pure nested function '%s' cannot access mutable data '%s'",
- sc->func->toChars(), v->toChars());
- if (v->isEnumDeclaration())
- error("enum");
- }
- }
-
- /* Do not allow safe functions to access __gshared data
- */
- if (sc->func->isSafe() && v->storage_class & STCgshared)
- error("safe function '%s' cannot access __gshared data '%s'",
- sc->func->toChars(), v->toChars());
- }
-#else
- if (sc->func && sc->func->isPure() && !sc->intypeof)
- {
- if (v->isDataseg() && !v->isImmutable())
- error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars());
- }
-#endif
+ checkPurity(sc, v, NULL);
#endif
}
#if 0
@@ -4955,15 +5056,88 @@ int DeclarationExp::checkSideEffect(int flag)
}
#if DMDV2
-int DeclarationExp::canThrow(bool mustNotThrow)
+/**************************************
+ * Does symbol, when initialized, throw?
+ * Mirrors logic in Dsymbol_toElem().
+ */
+
+int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow)
{
- VarDeclaration *v = declaration->isVarDeclaration();
- if (v && v->init)
- { ExpInitializer *ie = v->init->isExpInitializer();
- return ie && ie->exp->canThrow(mustNotThrow);
+ AttribDeclaration *ad;
+ VarDeclaration *vd;
+ TemplateMixin *tm;
+ TupleDeclaration *td;
+
+ //printf("Dsymbol_toElem() %s\n", s->toChars());
+ ad = s->isAttribDeclaration();
+ if (ad)
+ {
+ Array *decl = ad->include(NULL, NULL);
+ if (decl && decl->dim)
+ {
+ for (size_t i = 0; i < decl->dim; i++)
+ {
+ s = (Dsymbol *)decl->data[i];
+ if (Dsymbol_canThrow(s, mustNotThrow))
+ return 1;
+ }
+ }
+ }
+ else if ((vd = s->isVarDeclaration()) != NULL)
+ {
+ s = s->toAlias();
+ if (s != vd)
+ return Dsymbol_canThrow(s, mustNotThrow);
+ if (vd->storage_class & STCmanifest)
+ ;
+ else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
+ ;
+ else
+ {
+ if (vd->init)
+ { ExpInitializer *ie = vd->init->isExpInitializer();
+ if (ie && ie->exp->canThrow(mustNotThrow))
+ return 1;
+ }
+ if (vd->edtor && !vd->noscope)
+ return vd->edtor->canThrow(mustNotThrow);
+ }
+ }
+ else if ((tm = s->isTemplateMixin()) != NULL)
+ {
+ //printf("%s\n", tm->toChars());
+ if (tm->members)
+ {
+ for (size_t i = 0; i < tm->members->dim; i++)
+ {
+ Dsymbol *sm = (Dsymbol *)tm->members->data[i];
+ if (Dsymbol_canThrow(sm, mustNotThrow))
+ return 1;
+ }
+ }
+ }
+ else if ((td = s->isTupleDeclaration()) != NULL)
+ {
+ for (size_t i = 0; i < td->objects->dim; i++)
+ { Object *o = (Object *)td->objects->data[i];
+ if (o->dyncast() == DYNCAST_EXPRESSION)
+ { Expression *eo = (Expression *)o;
+ if (eo->op == TOKdsymbol)
+ { DsymbolExp *se = (DsymbolExp *)eo;
+ if (Dsymbol_canThrow(se->s, mustNotThrow))
+ return 1;
+ }
+ }
+ }
}
return 0;
}
+
+
+int DeclarationExp::canThrow(bool mustNotThrow)
+{
+ return Dsymbol_canThrow(declaration, mustNotThrow);
+}
#endif
void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
@@ -6069,7 +6243,8 @@ Expression *DotIdExp::semantic(Scope *sc, int flag)
}
else
{
- e1 = resolveProperties(sc, e1);
+ if (e1->op != TOKtype)
+ e1 = resolveProperties(sc, e1);
eleft = NULL;
eright = e1;
}
@@ -6386,9 +6561,9 @@ Expression *DotVarExp::semantic(Scope *sc)
}
assert(type);
+ Type *t1 = e1->type;
if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution
{
- Type *t1 = e1->type;
if (t1->ty == Tpointer)
t1 = t1->nextOf();
@@ -6401,11 +6576,27 @@ Expression *DotVarExp::semantic(Scope *sc)
accessCheck(loc, sc, e1, var);
VarDeclaration *v = var->isVarDeclaration();
+ if (v)
+ checkPurity(sc, v, e1);
Expression *e = expandVar(WANTvalue, v);
if (e)
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());
return this;
@@ -6976,7 +7167,8 @@ Lagain:
}
if (e1->op == TOKcomma)
- {
+ { /* Rewrite (a,b)(args) as (a,(b(args)))
+ */
CommaExp *ce = (CommaExp *)e1;
e1 = ce->e2;
@@ -7334,13 +7526,15 @@ Lagain:
{ TypeDelegate *td = (TypeDelegate *)t1;
assert(td->next->ty == Tfunction);
tf = (TypeFunction *)(td->next);
- if (sc->func && sc->func->isPure() && !tf->purity && !(sc->flags & SCOPEdebug))
+ if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug))
{
- error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars());
+ if (sc->func->setImpure())
+ error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars());
}
- if (sc->func && sc->func->isSafe() && tf->trust <= TRUSTsystem)
+ if (sc->func && tf->trust <= TRUSTsystem)
{
- error("safe function '%s' cannot call system delegate '%s'", sc->func->toChars(), e1->toChars());
+ if (sc->func->setUnsafe())
+ error("safe function '%s' cannot call system delegate '%s'", sc->func->toChars(), e1->toChars());
}
goto Lcheckargs;
}
@@ -7348,13 +7542,15 @@ Lagain:
{
Expression *e = new PtrExp(loc, e1);
t1 = ((TypePointer *)t1)->next;
- if (sc->func && sc->func->isPure() && !((TypeFunction *)t1)->purity && !(sc->flags & SCOPEdebug))
+ if (sc->func && !((TypeFunction *)t1)->purity && !(sc->flags & SCOPEdebug))
{
- error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars());
+ if (sc->func->setImpure())
+ error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars());
}
- if (sc->func && sc->func->isSafe() && !((TypeFunction *)t1)->trust <= TRUSTsystem)
+ if (sc->func && !((TypeFunction *)t1)->trust <= TRUSTsystem)
{
- error("safe function '%s' cannot call system function pointer '%s'", sc->func->toChars(), e1->toChars());
+ if (sc->func->setUnsafe())
+ error("safe function '%s' cannot call system function pointer '%s'", sc->func->toChars(), e1->toChars());
}
e->type = t1;
e1 = e;
@@ -7452,31 +7648,43 @@ Lcheckargs:
int CallExp::checkSideEffect(int flag)
{
#if DMDV2
- if (flag != 2)
- return 1;
+ int result = 1;
- if (e1->checkSideEffect(2))
- return 1;
+ /* Calling a function or delegate that is pure nothrow
+ * has no side effects.
+ */
+ if (e1->type)
+ {
+ Type *t = e1->type->toBasetype();
+ if ((t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak &&
+ ((TypeFunction *)t)->isnothrow)
+ ||
+ (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak &&
+ ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
+ )
+ {
+ result = 0;
+ //if (flag == 0)
+ //warning("pure nothrow function %s has no effect", e1->toChars());
+ }
+ else
+ result = 1;
+ }
+
+ result |= e1->checkSideEffect(1);
/* If any of the arguments have side effects, this expression does
*/
for (size_t i = 0; i < arguments->dim; i++)
{ Expression *e = (Expression *)arguments->data[i];
- if (e->checkSideEffect(2))
- return 1;
+ result |= e->checkSideEffect(1);
}
- /* If calling a function or delegate that is typed as pure,
- * then this expression has no side effects.
- */
- Type *t = e1->type->toBasetype();
- if (t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak)
- return 0;
- if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak)
- return 0;
-#endif
+ return result;
+#else
return 1;
+#endif
}
#if DMDV2
@@ -7488,12 +7696,8 @@ int CallExp::canThrow(bool mustNotThrow)
/* If any of the arguments can throw, then this expression can throw
*/
- for (size_t i = 0; i < arguments->dim; i++)
- { Expression *e = (Expression *)arguments->data[i];
-
- if (e && e->canThrow(mustNotThrow))
- return 1;
- }
+ if (arrayExpressionCanThrow(arguments, mustNotThrow))
+ return 1;
if (global.errors && !e1->type)
return 0; // error recovery
@@ -7615,7 +7819,11 @@ Expression *AddrExp::semantic(Scope *sc)
m = sc->module;
#endif
UnaExp::semantic(sc);
+ if (e1->type == Type::terror)
+ return new ErrorExp();
e1 = e1->toLvalue(sc, NULL);
+ if (e1->op == TOKerror)
+ return e1;
if (!e1->type)
{
error("cannot take address of %s", e1->toChars());
@@ -7656,9 +7864,23 @@ Expression *AddrExp::semantic(Scope *sc)
VarExp *ve = (VarExp *)e1;
VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && !v->canTakeAddressOf())
- { error("cannot take address of %s", e1->toChars());
- return new ErrorExp();
+ if (v)
+ {
+ if (!v->canTakeAddressOf())
+ { error("cannot take address of %s", e1->toChars());
+ return new ErrorExp();
+ }
+
+ if (sc->func && !sc->intypeof && !v->isDataseg())
+ {
+ if (sc->func->setUnsafe())
+ {
+ error("cannot take address of %s %s in @safe function %s",
+ v->isParameter() ? "parameter" : "local",
+ v->toChars(),
+ sc->func->toChars());
+ }
+ }
}
FuncDeclaration *f = ve->var->isFuncDeclaration();
@@ -8133,8 +8355,7 @@ Expression *CastExp::semantic(Scope *sc)
Type *t1b = e1->type->toBasetype();
Type *tob = to->toBasetype();
if (tob->ty == Tstruct &&
- !tob->equals(t1b) &&
- ((TypeStruct *)tob)->sym->search(0, Id::call, 0)
+ !tob->equals(t1b)
)
{
/* Look to replace:
@@ -8145,10 +8366,10 @@ Expression *CastExp::semantic(Scope *sc)
// Rewrite as to.call(e1)
e = new TypeExp(loc, to);
- e = new DotIdExp(loc, e, Id::call);
e = new CallExp(loc, e, e1);
- e = e->semantic(sc);
- return e;
+ e = e->trySemantic(sc);
+ if (e)
+ return e;
}
// Struct casts are possible only when the sizes match
@@ -8173,52 +8394,52 @@ Expression *CastExp::semantic(Scope *sc)
return new ErrorExp();
}
-#if 1
- if (sc->func && sc->func->isSafe() && !sc->intypeof)
-#else
- if (global.params.safe && !sc->module->safe && !sc->intypeof)
-#endif
+ // Check for unsafe casts
+ if (sc->func && !sc->intypeof)
{ // Disallow unsafe casts
Type *tob = to->toBasetype();
Type *t1b = e1->type->toBasetype();
+
+ // Implicit conversions are always safe
+ if (t1b->implicitConvTo(tob))
+ goto Lsafe;
+
if (!t1b->isMutable() && tob->isMutable())
- { // Cast not mutable to mutable
- Lunsafe:
- error("cast from %s to %s not allowed in safe code", e1->type->toChars(), to->toChars());
- return new ErrorExp();
- }
- else if (t1b->isShared() && !tob->isShared())
+ goto Lunsafe;
+
+ if (t1b->isShared() && !tob->isShared())
// Cast away shared
goto Lunsafe;
- else if (tob->ty == Tpointer)
- { if (t1b->ty != Tpointer)
- goto Lunsafe;
- Type *tobn = tob->nextOf()->toBasetype();
- Type *t1bn = t1b->nextOf()->toBasetype();
- if (!t1bn->isMutable() && tobn->isMutable())
- // Cast away pointer to not mutable
- goto Lunsafe;
+ if (!tob->hasPointers())
+ goto Lsafe;
- if (t1bn->isShared() && !tobn->isShared())
- // Cast away pointer to shared
- goto Lunsafe;
-
- if (t1bn->isWild() && !tobn->isConst() && !tobn->isWild())
- // Cast wild to anything but const | wild
- goto Lunsafe;
-
- if (tobn->isTypeBasic() && tobn->size() < t1bn->size())
- // Allow things like casting a long* to an int*
- ;
- else if (tobn->ty != Tvoid)
- // Cast to a pointer other than void*
- goto Lunsafe;
+ if (tob->ty == Tarray && t1b->ty == Tarray)
+ {
+ Type* tobn = tob->nextOf()->toBasetype();
+ Type* t1bn = t1b->nextOf()->toBasetype();
+ if (!tobn->hasPointers() && MODimplicitConv(t1bn->mod, tobn->mod))
+ goto Lsafe;
+ }
+ if (tob->ty == Tpointer && t1b->ty == Tpointer)
+ {
+ Type* tobn = tob->nextOf()->toBasetype();
+ Type* t1bn = t1b->nextOf()->toBasetype();
+ if (!tobn->hasPointers() &&
+ tobn->ty != Tfunction && t1bn->ty != Tfunction &&
+ tobn->size() <= t1bn->size() &&
+ MODimplicitConv(t1bn->mod, tobn->mod))
+ goto Lsafe;
}
- // BUG: Check for casting array types, such as void[] to int*[]
+ Lunsafe:
+ if (sc->func->setUnsafe())
+ { error("cast from %s to %s not allowed in safe code", e1->type->toChars(), to->toChars());
+ return new ErrorExp();
+ }
}
+Lsafe:
e = e1->castTo(sc, to);
return e;
}
@@ -8530,6 +8751,13 @@ void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
buf->writeByte(']');
}
+int SliceExp::canThrow(bool mustNotThrow)
+{
+ return UnaExp::canThrow(mustNotThrow)
+ || (lwr != NULL && lwr->canThrow(mustNotThrow))
+ || (upr != NULL && upr->canThrow(mustNotThrow));
+}
+
/********************** ArrayLength **************************************/
ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
@@ -8996,7 +9224,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->isMutable() || !type->isAssignable()))
error("%s isn't mutable", e->toChars());
Type *t1 = e1->type->toBasetype();
if (t1->ty == Taarray)
@@ -9192,6 +9420,7 @@ Expression *AssignExp::semantic(Scope *sc)
e = e->semantic(sc);
return e;
}
+#if 0 // Turned off to allow rewriting (a[i]=value) to (a.opIndex(i)=value)
else
{
// Rewrite (a[i] = value) to (a.opIndex(i, value))
@@ -9208,6 +9437,7 @@ Expression *AssignExp::semantic(Scope *sc)
return e;
}
}
+#endif
}
}
/* Look for operator overloading of a[i..j]=value.
@@ -9304,10 +9534,25 @@ Expression *AssignExp::semantic(Scope *sc)
Type *t1 = e1->type->toBasetype();
if (t1->ty == Tfunction)
- { // Rewrite f=value to f(value)
- Expression *e = new CallExp(loc, e1, e2);
- e = e->semantic(sc);
- return e;
+ { /* We have f=value.
+ * Could mean:
+ * f() = value
+ * or:
+ * f(value)
+ */
+ TypeFunction *tf = (TypeFunction *)t1;
+ if (tf->isref)
+ {
+ // Rewrite e1 = e2 to e1() = e2
+ e1 = resolveProperties(sc, e1);
+ }
+ else
+ {
+ // Rewrite f=value to f(value)
+ Expression *e = new CallExp(loc, e1, e2);
+ e = e->semantic(sc);
+ return e;
+ }
}
/* If it is an assignment from a 'foreign' type,
@@ -9330,6 +9575,8 @@ Expression *AssignExp::semantic(Scope *sc)
VarDeclaration *v = new VarDeclaration(loc, aaValueType,
id, new VoidInitializer(NULL));
v->storage_class |= STCctfe;
+ v->semantic(sc);
+ v->parent = sc->parent;
Expression *de = new DeclarationExp(loc, v);
VarExp *ve = new VarExp(loc, v);
@@ -9391,24 +9638,8 @@ Expression *AssignExp::semantic(Scope *sc)
{
/* The struct value returned from the function is transferred
* so should not call the destructor on it.
- * ((S _ctmp = S.init), _ctmp).this(...)
*/
- CallExp *ce = (CallExp *)e2;
- if (ce->e1->op == TOKdotvar)
- { DotVarExp *dve = (DotVarExp *)ce->e1;
- if (dve->var->isCtorDeclaration())
- { // It's a constructor call
- if (dve->e1->op == TOKcomma)
- { CommaExp *comma = (CommaExp *)dve->e1;
- if (comma->e2->op == TOKvar)
- { VarExp *ve = (VarExp *)comma->e2;
- VarDeclaration *ctmp = ve->var->isVarDeclaration();
- if (ctmp)
- ctmp->noscope = 1;
- }
- }
- }
- }
+ valueNoDtor(e2);
}
}
}
@@ -9455,7 +9686,7 @@ Expression *AssignExp::semantic(Scope *sc)
else if (e1->op == TOKslice)
{
Type *tn = e1->type->nextOf();
- if (tn && !tn->isMutable() && op != TOKconstruct)
+ if (op == TOKassign && tn && (!tn->isMutable() || !tn->isAssignable()))
{ error("slice %s is not mutable", e1->toChars());
return new ErrorExp();
}
@@ -9491,7 +9722,8 @@ Expression *AssignExp::semantic(Scope *sc)
}
//error("cannot assign to static array %s", e1->toChars());
}
- else if (e1->op == TOKslice)
+ else if (e1->op == TOKslice && t2->toBasetype()->ty == Tarray &&
+ t2->toBasetype()->nextOf()->implicitConvTo(t1->nextOf()))
{
e2 = e2->implicitCastTo(sc, e1->type->constOf());
}
@@ -9591,7 +9823,7 @@ Expression *AddAssignExp::semantic(Scope *sc)
e1->checkNoBool();
if (tb1->ty == Tpointer && tb2->isintegral())
e = scaleFactor(sc);
- else if (tb1->ty == Tbit || tb1->ty == Tbool)
+ else if (tb1->ty == Tbool)
{
#if 0
// Need to rethink this
diff --git a/dmd2/expression.h b/dmd2/expression.h
index 58098bf8..53ae8de3 100644
--- a/dmd2/expression.h
+++ b/dmd2/expression.h
@@ -15,6 +15,7 @@
#include "identifier.h"
#include "lexer.h"
#include "arraytypes.h"
+#include "intrange.h"
struct Type;
struct Scope;
@@ -79,7 +80,7 @@ void initPrecedence();
Expression *resolveProperties(Scope *sc, Expression *e);
void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d);
-Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id, Objects *targsi = NULL);
+Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d);
Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid);
void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module *from);
void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs);
@@ -88,6 +89,7 @@ void expandTuples(Expressions *exps);
FuncDeclaration *hasThis(Scope *sc);
Expression *fromConstInitializer(int result, Expression *e);
int arrayExpressionCanThrow(Expressions *exps, bool mustNotThrow);
+void valueNoDtor(Expression *e);
/* Interpreter: what form of return value expression is required?
*/
@@ -95,14 +97,10 @@ enum CtfeGoal
{ ctfeNeedRvalue, // Must return an Rvalue
ctfeNeedLvalue, // Must return an Lvalue
ctfeNeedAnyValue, // Can return either an Rvalue or an Lvalue
+ ctfeNeedLvalueRef,// Must return a reference to an Lvalue (for ref types)
ctfeNeedNothing // The return value is not required
};
-struct IntRange
-{ uinteger_t imin;
- uinteger_t imax;
-};
-
struct Expression : Object
{
Loc loc; // file location
@@ -152,6 +150,7 @@ struct Expression : Object
Expression *checkArithmetic();
void checkDeprecated(Scope *sc, Dsymbol *s);
void checkPurity(Scope *sc, FuncDeclaration *f);
+ void checkPurity(Scope *sc, VarDeclaration *v, Expression *e1);
void checkSafety(Scope *sc, FuncDeclaration *f);
virtual Expression *checkToBoolean(Scope *sc);
virtual Expression *addDtorHook(Scope *sc);
@@ -301,9 +300,7 @@ struct ComplexExp : Expression
int isBool(int result);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
void toMangleBuffer(OutBuffer *buf);
-#ifdef _DH
OutBuffer hexp;
-#endif
#if IN_DMD
elem *toElem(IRState *irs);
dt_t **toDt(dt_t **pdt);
@@ -1161,11 +1158,10 @@ struct AddrExp : UnaExp
MATCH implicitConvTo(Type *t);
Expression *castTo(Scope *sc, Type *t);
Expression *optimize(int result);
-
+ Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
#if IN_LLVM
DValue* toElem(IRState* irs);
llvm::Constant *toConstElem(IRState *irs);
- Expression *interpret(InterState *istate, CtfeGoal goal);
#endif
};
@@ -1202,6 +1198,7 @@ struct NegExp : UnaExp
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ IntRange getIntRange();
// For operator overloading
Identifier *opId();
@@ -1232,6 +1229,7 @@ struct ComExp : UnaExp
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ IntRange getIntRange();
// For operator overloading
Identifier *opId();
@@ -1352,6 +1350,7 @@ struct SliceExp : UnaExp
void scanForNestedRef(Scope *sc);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ int canThrow(bool mustNotThrow);
int inlineCost(InlineCostState *ics);
Expression *doInline(InlineDoState *ids);
@@ -1579,6 +1578,7 @@ struct AddExp : BinExp
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ IntRange getIntRange();
// For operator overloading
int isCommutative();
@@ -1603,6 +1603,7 @@ struct MinExp : BinExp
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ IntRange getIntRange();
// For operator overloading
Identifier *opId();
@@ -1646,6 +1647,7 @@ struct MulExp : BinExp
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ IntRange getIntRange();
// For operator overloading
int isCommutative();
@@ -1692,6 +1694,7 @@ struct ModExp : BinExp
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);
+ IntRange getIntRange();
// For operator overloading
Identifier *opId();
@@ -1917,6 +1920,7 @@ struct InExp : BinExp
{
InExp(Loc loc, Expression *e1, Expression *e2);
Expression *semantic(Scope *sc);
+ Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
int isBit();
// For operator overloading
diff --git a/dmd2/func.c b/dmd2/func.c
index 71b046c7..557d504b 100644
--- a/dmd2/func.c
+++ b/dmd2/func.c
@@ -64,7 +64,6 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla
naked = 0;
inlineStatus = ILSuninitialized;
inlineNest = 0;
- inlineAsm = 0;
cantInterpret = 0;
isArrayOp = 0;
semanticRun = PASSinit;
@@ -87,13 +86,14 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla
#if DMDV2
builtin = BUILTINunknown;
tookAddressOf = 0;
+ flags = 0;
#endif
#if IN_LLVM
// LDC
isArrayOp = false;
allowInlining = false;
-
availableExternally = true; // assume this unless proven otherwise
+ inlineAsm = true;
// function types in ldc don't merge if the context parameter differs
// so we actually don't care about the function declaration, but only
@@ -201,7 +201,7 @@ void FuncDeclaration::semantic(Scope *sc)
{
sc = sc->push();
sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCdisable
- | STCsafe | STCtrusted | STCsystem); // forward to function type
+ | STCsafe | STCtrusted | STCsystem | STCproperty); // forward to function type
if (isCtorDeclaration())
sc->flags |= SCOPEctor;
@@ -282,16 +282,31 @@ void FuncDeclaration::semantic(Scope *sc)
linkage = sc->linkage;
protection = sc->protection;
+ /* Purity and safety can be inferred for some functions by examining
+ * the function body.
+ */
+ if (fbody &&
+ (isFuncLiteralDeclaration() || parent->isTemplateInstance()))
+ {
+ if (f->purity == PUREimpure && // purity not specified
+ !f->hasLazyParameters()
+ )
+ {
+ flags |= FUNCFLAGpurityInprocess;
+ }
+ if (f->trust == TRUSTdefault)
+ flags |= FUNCFLAGsafetyInprocess;
+
+ if (!f->isnothrow)
+ flags |= FUNCFLAGnothrowInprocess;
+ }
+
if (storage_class & STCscope)
error("functions cannot be scope");
if (isAbstract() && !isVirtual())
error("non-virtual functions cannot be abstract");
- // https://github.com/donc/dmd/commit/9f7b2f8cfe5d7482f2de7f9678c176d54abe237f#commitcomment-321724
- //if (isOverride() && !isVirtual())
- //error("cannot override a non-virtual function");
-
if ((f->isConst() || f->isImmutable()) && !isThis())
error("without 'this' cannot be const/immutable");
@@ -862,6 +877,20 @@ void FuncDeclaration::semantic3(Scope *sc)
}
#endif
+ if (frequire)
+ {
+ for (int i = 0; i < foverrides.dim; i++)
+ {
+ FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i];
+
+ if (fdv->fbody && !fdv->frequire)
+ {
+ error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars());
+ break;
+ }
+ }
+ }
+
frequire = mergeFrequire(frequire);
fensure = mergeFensure(fensure);
@@ -1393,7 +1422,11 @@ void FuncDeclaration::semantic3(Scope *sc)
}
else if (!hasReturnExp && type->nextOf()->ty != Tvoid)
error("has no return statement, but is expected to return a value of type %s", type->nextOf()->toChars());
- else if (!inlineAsm)
+ else if (hasReturnExp & 8) // if inline asm
+ {
+ flags &= ~FUNCFLAGnothrowInprocess;
+ }
+ else
{
#if DMDV2
// Check for errors related to 'nothrow'.
@@ -1401,6 +1434,12 @@ void FuncDeclaration::semantic3(Scope *sc)
int blockexit = fbody ? fbody->blockExit(f->isnothrow) : BEfallthru;
if (f->isnothrow && (global.errors != nothrowErrors) )
error("'%s' is nothrow yet may throw", toChars());
+ if (flags & FUNCFLAGnothrowInprocess)
+ {
+ flags &= ~FUNCFLAGnothrowInprocess;
+ if (!(blockexit & BEthrow))
+ f->isnothrow = TRUE;
+ }
int offend = blockexit & BEfallthru;
#endif
@@ -1545,15 +1584,10 @@ void FuncDeclaration::semantic3(Scope *sc)
// Merge contracts together with body into one compound statement
-#ifdef _DH
if (frequire && global.params.useIn)
{ frequire->incontract = 1;
a->push(frequire);
}
-#else
- if (frequire && global.params.useIn)
- a->push(frequire);
-#endif
// Precondition invariant
if (addPreInvariant())
@@ -1775,6 +1809,20 @@ void FuncDeclaration::semantic3(Scope *sc)
sc2->pop();
}
+ /* If function survived being marked as impure, then it is pure
+ */
+ if (flags & FUNCFLAGpurityInprocess)
+ {
+ flags &= ~FUNCFLAGpurityInprocess;
+ f->purity = PUREfwdref;
+ }
+
+ if (flags & FUNCFLAGsafetyInprocess)
+ {
+ flags &= ~FUNCFLAGsafetyInprocess;
+ f->trust = TRUSTsafe;
+ }
+
if (global.gag && global.errors != nerrors)
semanticRun = PASSsemanticdone; // Ensure errors get reported again
else
@@ -1893,7 +1941,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf)
}
sf = fdv->mergeFrequire(sf);
- if (fdv->fdrequire)
+ if (sf && fdv->fdrequire)
{
//printf("fdv->frequire: %s\n", fdv->frequire->toChars());
/* Make the call:
@@ -1904,15 +1952,13 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf)
Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), eresult);
Statement *s2 = new ExpStatement(loc, e);
- if (sf)
- { Catch *c = new Catch(loc, NULL, NULL, sf);
- Array *catches = new Array();
- catches->push(c);
- sf = new TryCatchStatement(loc, s2, catches);
- }
- else
- sf = s2;
+ Catch *c = new Catch(loc, NULL, NULL, sf);
+ Array *catches = new Array();
+ catches->push(c);
+ sf = new TryCatchStatement(loc, s2, catches);
}
+ else
+ return NULL;
}
return sf;
}
@@ -2786,9 +2832,11 @@ enum PURE FuncDeclaration::isPure()
//printf("FuncDeclaration::isPure() '%s'\n", toChars());
assert(type->ty == Tfunction);
TypeFunction *tf = (TypeFunction *)type;
- enum PURE purity = tf->purity;
- if (purity == PUREfwdref)
+ if (flags & FUNCFLAGpurityInprocess)
+ setImpure();
+ if (tf->purity == PUREfwdref)
tf->purityLevel();
+ enum PURE purity = tf->purity;
if (purity > PUREweak && needThis())
{ // The attribute of the 'this' reference affects purity strength
if (type->mod & (MODimmutable | MODwild))
@@ -2798,21 +2846,61 @@ enum PURE FuncDeclaration::isPure()
else
purity = PUREweak;
}
+ tf->purity = purity;
+ // ^ This rely on the current situation that every FuncDeclaration has a
+ // unique TypeFunction.
return purity;
}
+/**************************************
+ * The function is doing something impure,
+ * so mark it as impure.
+ * If there's a purity error, return TRUE.
+ */
+bool FuncDeclaration::setImpure()
+{
+ if (flags & FUNCFLAGpurityInprocess)
+ {
+ flags &= ~FUNCFLAGpurityInprocess;
+ }
+ else if (isPure())
+ return TRUE;
+ return FALSE;
+}
+
int FuncDeclaration::isSafe()
{
assert(type->ty == Tfunction);
+ if (flags & FUNCFLAGsafetyInprocess)
+ setUnsafe();
return ((TypeFunction *)type)->trust == TRUSTsafe;
}
int FuncDeclaration::isTrusted()
{
assert(type->ty == Tfunction);
+ if (flags & FUNCFLAGsafetyInprocess)
+ setUnsafe();
return ((TypeFunction *)type)->trust == TRUSTtrusted;
}
+/**************************************
+ * The function is doing something unsave,
+ * so mark it as unsafe.
+ * If there's a safe error, return TRUE.
+ */
+bool FuncDeclaration::setUnsafe()
+{
+ if (flags & FUNCFLAGsafetyInprocess)
+ {
+ flags &= ~FUNCFLAGsafetyInprocess;
+ ((TypeFunction *)type)->trust = TRUSTsystem;
+ }
+ else if (isSafe())
+ return TRUE;
+ return FALSE;
+}
+
// Determine if function needs
// a static frame pointer to its lexically enclosing function
@@ -2924,6 +3012,8 @@ int FuncDeclaration::needsClosure()
* 1) is a virtual function
* 2) has its address taken
* 3) has a parent that escapes
+ * -or-
+ * 4) this function returns a local struct/class
*
* Note that since a non-virtual function can be called by
* a virtual one, if that non-virtual function accesses a closure
@@ -2954,6 +3044,25 @@ int FuncDeclaration::needsClosure()
}
}
}
+
+ /* Look for case (4)
+ */
+ if (closureVars.dim)
+ {
+ assert(type->ty == Tfunction);
+ Type *tret = ((TypeFunction *)type)->next;
+ assert(tret);
+ tret = tret->toBasetype();
+ if (tret->ty == Tclass || tret->ty == Tstruct)
+ { Dsymbol *st = tret->toDsymbol(NULL);
+ for (Dsymbol *s = st->parent; s; s = s->parent)
+ {
+ if (s == this)
+ goto Lyes;
+ }
+ }
+ }
+
return 0;
Lyes:
@@ -2978,12 +3087,6 @@ Parameters *FuncDeclaration::getParameters(int *pvarargs)
fparameters = fdtype->parameters;
fvarargs = fdtype->varargs;
}
- else // Constructors don't have type's
- { CtorDeclaration *fctor = isCtorDeclaration();
- assert(fctor);
- fparameters = fctor->arguments;
- fvarargs = fctor->varargs;
- }
if (pvarargs)
*pvarargs = fvarargs;
return fparameters;
@@ -3074,17 +3177,15 @@ void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
/********************************* CtorDeclaration ****************************/
-CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs, StorageClass stc)
- : FuncDeclaration(loc, endloc, Id::ctor, stc, NULL)
+CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type)
+ : FuncDeclaration(loc, endloc, Id::ctor, stc, type)
{
- this->arguments = arguments;
- this->varargs = varargs;
//printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
}
Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
{
- CtorDeclaration *f = new CtorDeclaration(loc, endloc, NULL, varargs, storage_class);
+ CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy());
f->outId = outId;
f->frequire = frequire ? frequire->syntaxCopy() : NULL;
@@ -3092,7 +3193,6 @@ Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
f->fbody = fbody ? fbody->syntaxCopy() : NULL;
assert(!fthrows); // deprecated
- f->arguments = Parameter::arraySyntaxCopy(arguments);
return f;
}
@@ -3100,6 +3200,10 @@ Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
void CtorDeclaration::semantic(Scope *sc)
{
//printf("CtorDeclaration::semantic() %s\n", toChars());
+ TypeFunction *tf = (TypeFunction *)type;
+ assert(tf && tf->ty == Tfunction);
+ Expressions *fargs = ((TypeFunction *)type)->fargs; // for auto ref
+
sc = sc->push();
sc->stc &= ~STCstatic; // not a static constructor
@@ -3118,15 +3222,16 @@ void CtorDeclaration::semantic(Scope *sc)
assert(tret);
tret = tret->addStorageClass(storage_class | sc->stc);
}
- if (!type)
- type = new TypeFunction(arguments, tret, varargs, LINKd, storage_class | sc->stc);
+ tf = new TypeFunction(tf->parameters, tret, tf->varargs, LINKd, storage_class | sc->stc);
+ tf->fargs = fargs;
+ type = tf;
#if STRUCTTHISREF
if (ad && ad->isStructDeclaration())
{ ((TypeFunction *)type)->isref = 1;
if (!originalType)
// Leave off the "ref"
- originalType = new TypeFunction(arguments, tret, varargs, LINKd, storage_class | sc->stc);
+ originalType = new TypeFunction(tf->parameters, tret, tf->varargs, LINKd, storage_class | sc->stc);
}
#endif
if (!originalType)
@@ -3149,7 +3254,7 @@ void CtorDeclaration::semantic(Scope *sc)
sc->pop();
// See if it's the default constructor
- if (ad && varargs == 0 && Parameter::dim(arguments) == 0)
+ if (ad && tf->varargs == 0 && Parameter::dim(tf->parameters) == 0)
{ if (ad->isStructDeclaration())
error("default constructor not allowed for structs");
else
@@ -3185,10 +3290,13 @@ int CtorDeclaration::addPostInvariant()
void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
+ TypeFunction *tf = (TypeFunction *)type;
+ assert(tf && tf->ty == Tfunction);
+
if (originalType && originalType->ty == Tfunction)
((TypeFunction *)originalType)->attributesToCBuffer(buf, 0);
buf->writestring("this");
- Parameter::argsToCBuffer(buf, hgs, arguments, varargs);
+ Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs);
bodyToCBuffer(buf, hgs);
}
diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c
index 63d70667..e11c212f 100644
--- a/dmd2/hdrgen.c
+++ b/dmd2/hdrgen.c
@@ -10,8 +10,6 @@
// Routines to emit header files
-#ifdef _DH
-
#define PRETTY_PRINT
#define TEST_EMIT_ALL 0 // For Testing
@@ -100,5 +98,3 @@ void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs)
/*************************************/
-
-#endif // #ifdef _DH
diff --git a/dmd2/identifier.h b/dmd2/identifier.h
index 1ba817a2..d8796000 100644
--- a/dmd2/identifier.h
+++ b/dmd2/identifier.h
@@ -36,9 +36,7 @@ struct Identifier : Object
int compare(Object *o);
void print();
char *toChars();
-#ifdef _DH
char *toHChars();
-#endif
const char *toHChars2();
int dyncast();
diff --git a/dmd2/impcnvgen.c b/dmd2/impcnvgen.c
index c4d9ac9f..8f182364 100644
--- a/dmd2/impcnvgen.c
+++ b/dmd2/impcnvgen.c
@@ -23,7 +23,6 @@ int integral_promotion(int t)
{
case Tchar:
case Twchar:
- //case Tbit:
case Tbool:
case Tint8:
case Tuns8:
@@ -51,29 +50,6 @@ void init()
impcnvType1[t1][t2] = nt1; \
impcnvType2[t1][t2] = nt2;
- /* ======================= */
-
-#if 0
- X(Tbit,Tbit, Tint32,Tint32, Tint32)
- X(Tbit,Tint8, Tint32,Tint32, Tint32)
- X(Tbit,Tuns8, Tint32,Tint32, Tint32)
- X(Tbit,Tint16, Tint32,Tint32, Tint32)
- X(Tbit,Tuns16, Tint32,Tint32, Tint32)
- X(Tbit,Tint32, Tint32,Tint32, Tint32)
- X(Tbit,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tbit,Tint64, Tint64,Tint64, Tint64)
- X(Tbit,Tuns64, Tuns64,Tuns64, Tuns64)
-
- X(Tbit,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tbit,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tbit,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tbit,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tbit,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tbit,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tbit,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tbit,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tbit,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-#endif
/* ======================= */
@@ -322,17 +298,6 @@ void init()
#define Y(t1,t2) impcnvWarn[t1][t2] = 1;
-#if 0
- Y(Tint8, Tbit)
- Y(Tuns8, Tbit)
- Y(Tint16, Tbit)
- Y(Tuns16, Tbit)
- Y(Tint32, Tbit)
- Y(Tuns32, Tbit)
- Y(Tint64, Tbit)
- Y(Tuns64, Tbit)
-#endif
-
Y(Tuns8, Tint8)
Y(Tint16, Tint8)
Y(Tuns16, Tint8)
diff --git a/dmd2/import.c b/dmd2/import.c
index 8a970d15..18b2850c 100644
--- a/dmd2/import.c
+++ b/dmd2/import.c
@@ -35,9 +35,6 @@ Import::Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId,
this->id = id;
this->aliasId = aliasId;
this->isstatic = isstatic;
-#if IN_LLVM
- protection = PROTundefined;
-#endif
pkg = NULL;
mod = NULL;
@@ -65,12 +62,6 @@ const char *Import::kind()
return isstatic ? (char *)"static import" : (char *)"import";
}
-#if IN_LLVM
-enum PROT Import::prot()
-{
- return protection;
-}
-#endif
Dsymbol *Import::syntaxCopy(Dsymbol *s)
{
@@ -207,14 +198,13 @@ void Import::semantic(Scope *sc)
sc = sc->push(mod);
for (size_t i = 0; i < aliasdecls.dim; i++)
- { AliasDeclaration *ad = (AliasDeclaration *)aliasdecls.data[i];
+ { Dsymbol *s = (Dsymbol *)aliasdecls.data[i];
//printf("\tImport alias semantic('%s')\n", s->toChars());
if (!mod->search(loc, (Identifier *)names.data[i], 0))
error("%s not found", ((Identifier *)names.data[i])->toChars());
- ad->importprot = protection;
- ad->semantic(sc);
+ s->semantic(sc);
}
sc = sc->pop();
}
@@ -288,7 +278,7 @@ void Import::semantic(Scope *sc)
ob->writenl();
}
- //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
+ //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
}
void Import::semantic2(Scope *sc)
diff --git a/dmd2/import.h b/dmd2/import.h
index 2ca47e37..4f442de5 100644
--- a/dmd2/import.h
+++ b/dmd2/import.h
@@ -24,9 +24,7 @@ struct OutBuffer;
struct Module;
struct Package;
struct AliasDeclaration;
-#ifdef _DH
struct HdrGenState;
-#endif
struct Import : Dsymbol
{
@@ -34,9 +32,6 @@ struct Import : Dsymbol
Identifier *id; // module Identifier
Identifier *aliasId;
int isstatic; // !=0 if static import
-#if IN_LLVM
- enum PROT protection;
-#endif
// Pairs of alias=name to bind into current namespace
Array names;
@@ -52,9 +47,6 @@ struct Import : Dsymbol
void addAlias(Identifier *name, Identifier *alias);
const char *kind();
-#if IN_LLVM
- enum PROT prot();
-#endif
Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
void load(Scope *sc);
void importAll(Scope *sc);
diff --git a/dmd2/inifile.c b/dmd2/inifile.c
index 2d74918d..ede7a76c 100644
--- a/dmd2/inifile.c
+++ b/dmd2/inifile.c
@@ -1,6 +1,6 @@
/*
* Some portions copyright (c) 1994-1995 by Symantec
- * Copyright (c) 1999-2009 by Digital Mars
+ * Copyright (c) 1999-2011 by Digital Mars
* All Rights Reserved
* http://www.digitalmars.com
* Written by Walter Bright
@@ -22,7 +22,7 @@
#if __APPLE__
#include
#endif
-#if __FreeBSD__ || __sun&&__SVR4
+#if __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
// for PATH_MAX
#include
#endif
@@ -110,12 +110,12 @@ const char *inifile(const char *argv0x, const char *inifilex)
filename = (char *)FileName::replaceName(argv0, inifile);
if (!FileName::exists(filename))
{
-#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
-#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne
+#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
+#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne
/* argv0 might be a symbolic link,
* so try again looking past it to the real path
*/
-#if __APPLE__ || __FreeBSD__ || __sun&&__SVR4
+#if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
char resolved_name[PATH_MAX + 1];
char* real_argv0 = realpath(argv0, resolved_name);
#else
diff --git a/dmd2/init.c b/dmd2/init.c
index 3b81f27b..72e2bb18 100644
--- a/dmd2/init.c
+++ b/dmd2/init.c
@@ -726,6 +726,61 @@ Initializer *ExpInitializer::syntaxCopy()
return new ExpInitializer(loc, exp->syntaxCopy());
}
+bool arrayHasNonConstPointers(Expressions *elems);
+
+bool hasNonConstPointers(Expression *e)
+{
+ if (e->op == TOKnull)
+ return false;
+ if (e->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ return arrayHasNonConstPointers(se->elements);
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ if (!e->type->nextOf()->hasPointers())
+ return false;
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
+ return arrayHasNonConstPointers(ae->elements);
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+ if (ae->type->nextOf()->hasPointers() &&
+ arrayHasNonConstPointers(ae->values))
+ return true;
+ if (((TypeAArray *)ae->type)->index->hasPointers())
+ return arrayHasNonConstPointers(ae->keys);
+ return false;
+ }
+ if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
+ {
+ if (e->op == TOKsymoff) // address of a global is OK
+ return false;
+ if (e->op == TOKint64) // cast(void *)int is OK
+ return false;
+ if (e->op == TOKstring) // "abc".ptr is OK
+ return false;
+ return true;
+ }
+ return false;
+}
+
+bool arrayHasNonConstPointers(Expressions *elems)
+{
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ if (!(Expression *)elems->data[i])
+ continue;
+ if (hasNonConstPointers((Expression *)elems->data[i]))
+ return true;
+ }
+ return false;
+}
+
+
+
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret)
{
//printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
@@ -737,6 +792,14 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret)
exp = exp->optimize(wantOptimize);
if (!global.gag && olderrors != global.errors)
return this; // Failed, suppress duplicate error messages
+
+ // Make sure all pointers are constants
+ if (needInterpret && hasNonConstPointers(exp))
+ {
+ exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars());
+ return this;
+ }
+
Type *tb = t->toBasetype();
/* Look for case of initializing a static array with a too-short
diff --git a/dmd2/init.h b/dmd2/init.h
index 10f8d640..252dfa95 100644
--- a/dmd2/init.h
+++ b/dmd2/init.h
@@ -1,6 +1,6 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2011 by Digital Mars
+// Copyright (c) 1999-2007 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -26,9 +26,8 @@ struct VoidInitializer;
struct StructInitializer;
struct ArrayInitializer;
struct ExpInitializer;
-#ifdef _DH
struct HdrGenState;
-#endif
+
struct Initializer : Object
{
diff --git a/dmd2/inline.c b/dmd2/inline.c
index 75fcac9e..824e9ee3 100644
--- a/dmd2/inline.c
+++ b/dmd2/inline.c
@@ -134,6 +134,11 @@ int ReturnStatement::inlineCost(InlineCostState *ics)
return exp ? exp->inlineCost(ics) : 0;
}
+int ImportStatement::inlineCost(InlineCostState *ics)
+{
+ return 0;
+}
+
/* -------------------------- */
int arrayInlineCost(InlineCostState *ics, Array *arguments)
@@ -464,6 +469,11 @@ Expression *ReturnStatement::doInline(InlineDoState *ids)
return exp ? exp->doInline(ids) : 0;
}
+Expression *ImportStatement::doInline(InlineDoState *ids)
+{
+ return NULL;
+}
+
/* --------------------------------------------------------------- */
/******************************
@@ -1345,12 +1355,6 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan)
}
#if !IN_LLVM
// LDC: Only extern(C) varargs count, and ctors use extern(D).
- else
- { CtorDeclaration *ctor = isCtorDeclaration();
-
- if (ctor && ctor->varargs == 1)
- goto Lno;
- }
#endif
if (
diff --git a/dmd2/interpret.c b/dmd2/interpret.c
index 2522073b..48209bba 100644
--- a/dmd2/interpret.c
+++ b/dmd2/interpret.c
@@ -25,6 +25,7 @@
#include "id.h"
#define LOG 0
+#define LOGASSIGN 0
struct InterState
{
@@ -32,7 +33,10 @@ struct InterState
FuncDeclaration *fd; // function being interpreted
Dsymbols vars; // variables used in this function
Statement *start; // if !=NULL, start execution at this statement
- Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result
+ Statement *gotoTarget; /* target of EXP_GOTO_INTERPRET result; also
+ * target of labelled EXP_BREAK_INTERPRET or
+ * EXP_CONTINUE_INTERPRET. (NULL if no label).
+ */
Expression *localThis; // value of 'this', or NULL if none
bool awaitingLvalueReturn; // Support for ref return values:
// Any return to this function should return an lvalue.
@@ -55,6 +59,68 @@ Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclarati
Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference = NULL);
Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal);
VarDeclaration *findParentVar(Expression *e, Expression *thisval);
+void addVarToInterstate(InterState *istate, VarDeclaration *v);
+bool needToCopyLiteral(Expression *expr);
+Expression *copyLiteral(Expression *e);
+Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
+
+
+// Used for debugging only
+void showCtfeExpr(Expression *e)
+{
+ Expressions *elements = NULL;
+ // We need the struct definition to detect block assignment
+ StructDeclaration *sd = NULL;
+ if (e->op == TOKstructliteral) {
+ elements = ((StructLiteralExp *)e)->elements;
+ sd = ((StructLiteralExp *)e)->sd;
+ printf("STRUCT type = %s %p :\n", e->type->toChars(), e);
+ }
+ else if (e->op == TOKarrayliteral)
+ {
+ elements = ((ArrayLiteralExp *)e)->elements;
+ printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(), e);
+ }
+ else if (e->op == TOKassocarrayliteral)
+ {
+ printf("AA LITERAL type=%s %p:\n", e->type->toChars(), e);
+ }
+ else if (e->op == TOKstring)
+ {
+ printf(" STRING %s %p\n", e->toChars(), ((StringExp *)e)->string);
+ }
+ else if (e->op == TOKslice)
+ {
+ printf(" SLICE %p: %s\n", e, e->toChars());
+ showCtfeExpr(((SliceExp *)e)->e1);
+ }
+ else printf(" VALUE %p: %s\n", e, e->toChars());
+
+ if (elements)
+ {
+ for (size_t i = 0; i < elements->dim; i++)
+ { Expression *z = (Expression *)elements->data[i];
+ if (sd)
+ {
+ Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+ VarDeclaration *v = s->isVarDeclaration();
+ assert(v);
+ // If it is a void assignment, use the default initializer
+ if (!z) {
+ printf(" field:void\n");
+ continue;
+ }
+ if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray)
+ {
+ printf(" field: block initalized static array\n");
+ continue;
+ }
+ }
+ showCtfeExpr(z);
+ }
+ }
+}
+
/*************************************
* Attempt to interpret a function given the arguments.
@@ -126,8 +192,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
Expressions vsave; // place to save previous parameter values
size_t dim = 0;
if (needThis() && !thisarg)
- { cantInterpret = 1;
- // error, no this. Prevent segfault.
+ { // error, no this. Prevent segfault.
error("need 'this' to access member %s", toChars());
return NULL;
}
@@ -154,11 +219,15 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
if (arg->storageClass & (STCout | STCref))
{
- if (!istate)
- {
- earg->error("%s cannot be passed by reference at compile time", earg->toChars());
+ if (!istate && (arg->storageClass & STCout))
+ { // initializing an out parameter involves writing to it.
+ earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars());
return NULL;
}
+ // Convert all reference arguments into lvalue references
+ earg = earg->interpret(istate, ctfeNeedLvalueRef);
+ if (earg == EXP_CANT_INTERPRET)
+ return NULL;
}
else if (arg->storageClass & STClazy)
{
@@ -174,11 +243,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
*/
earg = ((AddrExp *)earg)->e1;
}
- earg = earg->interpret(istate); // ? istate : &istatex);
+ earg = earg->interpret(istate);
if (earg == EXP_CANT_INTERPRET)
- { cantInterpret = 1;
return NULL;
- }
}
eargs.data[i] = earg;
}
@@ -196,14 +263,14 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
VarExp *ve = (VarExp *)earg;
VarDeclaration *v2 = ve->var->isVarDeclaration();
if (!v2)
- { cantInterpret = 1;
+ {
+ error("cannot interpret %s as a ref parameter", ve->toChars());
return NULL;
}
v->setValueWithoutChecking(earg);
/* Don't restore the value of v2 upon function return
*/
- assert(istate);
- for (size_t i = 0; i < istate->vars.dim; i++)
+ for (size_t i = 0; i < (istate ? istate->vars.dim : 0); i++)
{ VarDeclaration *vx = (VarDeclaration *)istate->vars.data[i];
if (vx == v2)
{ istate->vars.data[i] = NULL;
@@ -215,8 +282,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
{ // Value parameters and non-trivial references
v->setValueWithoutChecking(earg);
}
-#if LOG
+#if LOG || LOGASSIGN
printf("interpreted arg[%d] = %s\n", i, earg->toChars());
+ showCtfeExpr(earg);
#endif
}
}
@@ -238,15 +306,15 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
/* Save the values of the local variables used
*/
Expressions valueSaves;
- if (istate && !isNested())
+ if (istate)
{
//printf("saving local variables...\n");
valueSaves.setDim(istate->vars.dim);
for (size_t i = 0; i < istate->vars.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
- if (v)
+ if (v && v->parent == this)
{
- //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
+ //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->getValue() ? v->getValue()->toChars() : "");
valueSaves.data[i] = v->getValue();
v->setValueNull();
}
@@ -279,6 +347,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
else
break;
}
+ assert(e != EXP_CONTINUE_INTERPRET && e != EXP_BREAK_INTERPRET);
/* Restore the parameter values
*/
@@ -287,15 +356,19 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
VarDeclaration *v = (VarDeclaration *)parameters->data[i];
v->setValueWithoutChecking((Expression *)vsave.data[i]);
}
+ /* Clear __result. (Bug 6049).
+ */
+ if (vresult)
+ vresult->setValueNull();
- if (istate && !isNested())
+ if (istate)
{
/* Restore the variable values
*/
//printf("restoring local variables...\n");
for (size_t i = 0; i < istate->vars.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
- if (v)
+ if (v && v->parent == this)
{ v->setValueWithoutChecking((Expression *)valueSaves.data[i]);
//printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->getValue() ? v->getValue()->toChars() : "");
}
@@ -393,11 +466,20 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_CONTINUE_INTERPRET)
- { e = NULL;
+ {
+ if (istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at higher level
+ istate->gotoTarget = NULL;
+ e = NULL;
continue;
}
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
if (e)
@@ -452,112 +534,87 @@ Expression *ScopeStatement::interpret(InterState *istate)
return statement ? statement->interpret(istate) : NULL;
}
-// Helper for ReturnStatement::interpret() for returning references.
-// Given an original expression, which is known to be a reference to a reference,
-// turn it into a reference.
-Expression * replaceReturnReference(Expression *original, InterState *istate)
+Expression *resolveSlice(Expression *e)
{
- Expression *e = original;
- if (e->op == TOKcall)
- { // If it's a function call, interpret it now.
- // It also needs to return an lvalue.
- istate->awaitingLvalueReturn = true;
- e = e->interpret(istate);
- if (e == EXP_CANT_INTERPRET)
- return e;
- }
- // If it is a reference to a reference, convert it to a reference
- if (e->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e;
- VarDeclaration *v = ve->var->isVarDeclaration();
- assert (v && v->getValue());
- return v->getValue();
- }
-
- if (e->op == TOKthis)
- {
- return istate->localThis;
- }
-
- Expression *r = e->copy();
- e = r;
- Expression *next;
- for (;;)
- {
- if (e->op == TOKindex)
- next = ((IndexExp*)e)->e1;
- else if (e->op == TOKdotvar)
- next = ((DotVarExp *)e)->e1;
- else if (e->op == TOKdotti)
- next = ((DotTemplateInstanceExp *)e)->e1;
- else if (e->op == TOKslice)
- next = ((SliceExp*)e)->e1;
- else
- return EXP_CANT_INTERPRET;
-
- Expression *old = next;
-
- if (next->op == TOKcall)
- {
- bool oldWaiting = istate->awaitingLvalueReturn;
- istate->awaitingLvalueReturn = true;
- next = next->interpret(istate);
- istate->awaitingLvalueReturn = oldWaiting;
- if (next == EXP_CANT_INTERPRET)
- return next;
- }
- if (next->op == TOKvar)
- {
- VarDeclaration * v = ((VarExp*)next)->var->isVarDeclaration();
- if (v)
- next = v->getValue();
- }
- else if (next->op == TOKthis)
- next = istate->localThis;
-
- if (old == next)
- { // Haven't found the reference yet. Need to keep copying.
- next = next->copy();
- old = next;
- }
- if (e->op == TOKindex)
- { // The index needs to be evaluated now (it isn't part of the ref)
- ((IndexExp*)e)->e1 = next;
- ((IndexExp*)e)->e2 = ((IndexExp*)e)->e2->interpret(istate);
- if (((IndexExp*)e)->e2 == EXP_CANT_INTERPRET)
- return EXP_CANT_INTERPRET;
- }
- else if (e->op == TOKdotvar)
- ((DotVarExp *)e)->e1 = next;
- else if (e->op == TOKdotti)
- ((DotTemplateInstanceExp *)e)->e1 = next;
- else if (e->op == TOKslice)
- { /* Interpret the slice bounds immediately (they are
- * not part of the reference).
- */
- ((SliceExp*)e)->e1 = next;
- Expression *x = ((SliceExp*)e)->upr;
- if (x)
- x = x->interpret(istate);
- if (x == EXP_CANT_INTERPRET)
- return EXP_CANT_INTERPRET;
- ((SliceExp*)e)->upr = x;
- x = ((SliceExp*)e)->lwr;
- if (x)
- x = x->interpret(istate);
- if (x == EXP_CANT_INTERPRET)
- return EXP_CANT_INTERPRET;
- ((SliceExp*)e)->lwr = x;
- }
- if (old != next)
- break;
- e = next;
- }
-
- return r;
+ if ( ((SliceExp *)e)->e1->op == TOKnull)
+ return ((SliceExp *)e)->e1;
+ return Slice(e->type, ((SliceExp *)e)->e1,
+ ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr);
}
+/* Determine the array length, without interpreting it.
+ * e must be an array literal, or a slice
+ * It's very wasteful to resolve the slice when we only
+ * need the length.
+ */
+uinteger_t resolveArrayLength(Expression *e)
+{
+ if (e->op == TOKnull)
+ return 0;
+ if (e->op == TOKslice)
+ { uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger();
+ uinteger_t iup = ((SliceExp *)e)->upr->toInteger();
+ return iup - ilo;
+ }
+ if (e->op == TOKstring)
+ { return ((StringExp *)e)->len;
+ }
+ if (e->op == TOKarrayliteral)
+ { ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+ return ale->elements ? ale->elements->dim : 0;
+ }
+ if (e->op == TOKassocarrayliteral)
+ { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e;
+ return ale->keys->dim;
+ }
+ assert(0);
+ return 0;
+}
+
+void scrubArray(Expressions *elems);
+
+/* All results destined for use outside of CTFE need to have their CTFE-specific
+ * features removed.
+ * In particular, all slices must be resolved.
+ */
+Expression *scrubReturnValue(Expression *e)
+{
+ if (e->op == TOKslice)
+ {
+ e = resolveSlice(e);
+ }
+ if (e->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ scrubArray(se->elements);
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ scrubArray(((ArrayLiteralExp *)e)->elements);
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+ scrubArray(aae->keys);
+ scrubArray(aae->values);
+ }
+ return e;
+}
+
+// Scrub all members of an array
+void scrubArray(Expressions *elems)
+{
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *m = (Expression *)elems->data[i];
+ if (!m)
+ continue;
+ m = scrubReturnValue(m);
+ elems->data[i] = m;
+ }
+}
+
+
Expression *ReturnStatement::interpret(InterState *istate)
{
#if LOG
@@ -575,8 +632,8 @@ Expression *ReturnStatement::interpret(InterState *istate)
{
TypeFunction *tf = (TypeFunction *)istate->fd->type;
if (tf->isref && istate->caller && istate->caller->awaitingLvalueReturn)
- { // We need to return an lvalue. Can't do a normal interpret.
- Expression *e = replaceReturnReference(exp, istate);
+ { // We need to return an lvalue
+ Expression *e = exp->interpret(istate, ctfeNeedLvalue);
if (e == EXP_CANT_INTERPRET)
error("ref return %s is not yet supported in CTFE", exp->toChars());
return e;
@@ -590,13 +647,27 @@ Expression *ReturnStatement::interpret(InterState *istate)
}
}
#endif
-
- Expression *e = exp->interpret(istate);
+ // We need to treat pointers specially, because TOKsymoff can be used to
+ // return a value OR a pointer
+ Expression *e;
+ if ((exp->type->ty == Tpointer && exp->type->nextOf()->ty != Tfunction))
+ e = exp->interpret(istate, ctfeNeedLvalue);
+ else
+ e = exp->interpret(istate);
if (e == EXP_CANT_INTERPRET)
return e;
- // Convert lvalues into rvalues (See Bugzilla 4825 for rationale)
- if (e->op == TOKvar)
- e = e->interpret(istate);
+ if (!istate->caller)
+ {
+ e = scrubReturnValue(e);
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ }
+ else if (needToCopyLiteral(exp))
+ e = copyLiteral(e);
+#if LOGASSIGN
+ printf("RETURN %s\n", loc.toChars());
+ showCtfeExpr(e);
+#endif
return e;
}
@@ -607,9 +678,21 @@ Expression *BreakStatement::interpret(InterState *istate)
#endif
START()
if (ident)
- return EXP_CANT_INTERPRET;
- else
+ { LabelDsymbol *label = istate->fd->searchLabel(ident);
+ assert(label && label->statement);
+ Statement *s = label->statement;
+ if (s->isLabelStatement())
+ s = s->isLabelStatement()->statement;
+ if (s->isScopeStatement())
+ s = s->isScopeStatement()->statement;
+ istate->gotoTarget = s;
return EXP_BREAK_INTERPRET;
+ }
+ else
+ {
+ istate->gotoTarget = NULL;
+ return EXP_BREAK_INTERPRET;
+ }
}
Expression *ContinueStatement::interpret(InterState *istate)
@@ -619,7 +702,16 @@ Expression *ContinueStatement::interpret(InterState *istate)
#endif
START()
if (ident)
- return EXP_CANT_INTERPRET;
+ { LabelDsymbol *label = istate->fd->searchLabel(ident);
+ assert(label && label->statement);
+ Statement *s = label->statement;
+ if (s->isLabelStatement())
+ s = s->isLabelStatement()->statement;
+ if (s->isScopeStatement())
+ s = s->isScopeStatement()->statement;
+ istate->gotoTarget = s;
+ return EXP_CONTINUE_INTERPRET;
+ }
else
return EXP_CONTINUE_INTERPRET;
}
@@ -650,9 +742,21 @@ Expression *DoStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
return e;
if (e == EXP_BREAK_INTERPRET)
- return NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
+ return e;
+ }
if (e == EXP_CONTINUE_INTERPRET)
- goto Lcontinue;
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ goto Lcontinue;
+ }
+ else // else continue at a higher level
+ return e;
if (e)
return e;
}
@@ -663,13 +767,21 @@ Expression *DoStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
if (e && e != EXP_CONTINUE_INTERPRET)
break;
+ if (istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at a higher level
Lcontinue:
+ istate->gotoTarget = NULL;
e = condition->interpret(istate);
if (e == EXP_CANT_INTERPRET)
break;
@@ -715,9 +827,21 @@ Expression *ForStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
return e;
if (e == EXP_BREAK_INTERPRET)
- return NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ return NULL;
+ } // else break at a higher level
+ }
if (e == EXP_CONTINUE_INTERPRET)
- goto Lcontinue;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ goto Lcontinue;
+ } // else continue at a higher level
+ }
if (e)
return e;
}
@@ -740,12 +864,20 @@ Expression *ForStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
if (e && e != EXP_CONTINUE_INTERPRET)
break;
+ if (istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at a higher level
Lcontinue:
+ istate->gotoTarget = NULL;
if (increment)
{
e = increment->interpret(istate);
@@ -813,11 +945,21 @@ Expression *ForeachStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
if (e == EXP_CONTINUE_INTERPRET)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at higher level
+ istate->gotoTarget = NULL;
e = NULL;
+ }
else if (e)
break;
}
@@ -838,11 +980,21 @@ Expression *ForeachStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
if (e == EXP_CONTINUE_INTERPRET)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at higher level
+ istate->gotoTarget = NULL;
e = NULL;
+ }
else if (e)
break;
}
@@ -898,11 +1050,20 @@ Expression *ForeachRangeStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
+ if (e == EXP_CONTINUE_INTERPRET
+ && istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at higher level
if (e == NULL || e == EXP_CONTINUE_INTERPRET)
{ e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
+ istate->gotoTarget = NULL;
if (e == EXP_CANT_INTERPRET)
break;
key->value = e;
@@ -934,9 +1095,20 @@ Expression *ForeachRangeStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
break;
if (e == EXP_BREAK_INTERPRET)
- { e = NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
break;
}
+ if (e == EXP_CONTINUE_INTERPRET)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != this)
+ break; // continue at higher level
+ istate->gotoTarget = NULL;
+ }
} while (e == NULL || e == EXP_CONTINUE_INTERPRET);
}
key->value = keysave;
@@ -962,7 +1134,13 @@ Expression *SwitchStatement::interpret(InterState *istate)
if (e == EXP_CANT_INTERPRET)
return e;
if (e == EXP_BREAK_INTERPRET)
- return NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ return NULL;
+ } // else break at a higher level
+ }
return e;
}
@@ -970,6 +1148,8 @@ Expression *SwitchStatement::interpret(InterState *istate)
Expression *econdition = condition->interpret(istate);
if (econdition == EXP_CANT_INTERPRET)
return EXP_CANT_INTERPRET;
+ if (econdition->op == TOKslice)
+ econdition = resolveSlice(econdition);
Statement *s = NULL;
if (cases)
@@ -1001,7 +1181,13 @@ Expression *SwitchStatement::interpret(InterState *istate)
e = body ? body->interpret(istate) : NULL;
assert(!istate->start);
if (e == EXP_BREAK_INTERPRET)
- return NULL;
+ {
+ if (!istate->gotoTarget || istate->gotoTarget == this)
+ {
+ istate->gotoTarget = NULL;
+ e = NULL;
+ } // else break at a higher level
+ }
return e;
}
@@ -1136,6 +1322,17 @@ Expression *AsmStatement::interpret(InterState *istate)
return EXP_CANT_INTERPRET;
}
+#if DMDV2
+Expression *ImportStatement::interpret(InterState *istate)
+{
+#if LOG
+ printf("ImportStatement::interpret()\n");
+#endif
+ START();
+ return NULL;
+}
+#endif
+
/******************************** Expression ***************************/
Expression *Expression::interpret(InterState *istate, CtfeGoal goal)
@@ -1151,8 +1348,10 @@ Expression *Expression::interpret(InterState *istate, CtfeGoal goal)
Expression *ThisExp::interpret(InterState *istate, CtfeGoal goal)
{
+ if (istate && istate->localThis && istate->localThis->op == TOKstructliteral)
+ return istate->localThis;
if (istate && istate->localThis)
- return istate->localThis->interpret(istate);
+ return istate->localThis->interpret(istate, goal);
error("value of 'this' is not known at compile time");
return EXP_CANT_INTERPRET;
}
@@ -1187,6 +1386,27 @@ Expression *StringExp::interpret(InterState *istate, CtfeGoal goal)
{
#if LOG
printf("StringExp::interpret() %s\n", toChars());
+#endif
+ /* Since we are using StringExps as reference types for char[] arrays,
+ * we need to dup them if there's any chance they'll be modified.
+ * For efficiency, we try to only dup when necessary.
+ */
+ // Fixed-length char arrays always get duped later anyway.
+ if (type->ty == Tsarray)
+ return this;
+ /* String literals are normally immutable, so we don't need to dup them
+ * In D2, we can detect attempts to write to read-only literals.
+ * For D1, we could be pessimistic, and always dup.
+ * But since it fails only when there has been an explicit cast, and any
+ * such function would give different results at runtime anyway (eg, it
+ * may crash), it hardly seems worth the massive performance hit.
+ */
+#if DMDV2
+ if (!((TypeNext *)type)->next->mod & (MODconst | MODimmutable))
+ { // It seems this happens only when there has been an explicit cast
+ error("cannot cast a read-only string literal to mutable in CTFE");
+ return EXP_CANT_INTERPRET;
+ }
#endif
return this;
}
@@ -1208,10 +1428,77 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal)
{
return this;
}
+ if (type->ty != Tpointer)
+ { // Probably impossible
+ error("Cannot interpret %s at compile time", toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ Type *pointee = ((TypePointer *)type)->next;
+ Expression *val = getVarExp(loc, istate, var, goal);
+ if (val->type->ty == Tarray || val->type->ty == Tsarray)
+ {
+ TypeArray *tar = (TypeArray *)val->type;
+ dinteger_t sz = pointee->size();
+ dinteger_t indx = offset/sz;
+ assert(sz * indx == offset);
+ Expression *aggregate = NULL;
+ if (val->op == TOKarrayliteral || val->op == TOKstring)
+ aggregate = val;
+ else if (val->op == TOKslice)
+ {
+ aggregate = ((SliceExp *)val)->e1;
+ Expression *lwr = ((SliceExp *)val)->lwr->interpret(istate);
+ indx += lwr->toInteger();
+ }
+ if (aggregate)
+ {
+ IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
+ IndexExp *ie = new IndexExp(loc, aggregate, ofs);
+ ie->type = type;
+ return ie;
+ }
+ }
+ else if (offset == 0 && pointee == var->type)
+ {
+ if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef)
+ {
+ VarExp *ve = new VarExp(loc, var);
+ ve->type = type;
+ return ve;
+ }
+ Expression *e = getVarExp(loc, istate, var, goal);
+ e = new AddrExp(loc, e);
+ e->type = type;
+ return e;
+ }
+
error("Cannot interpret %s at compile time", toChars());
return EXP_CANT_INTERPRET;
}
+Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal)
+{
+#if LOG
+ printf("AddrExp::interpret() %s\n", toChars());
+#endif
+#if 0 || IN_LLVM
+ if (e1->op == TOKvar)
+ { VarExp *ve = (VarExp *)e1;
+ if (ve->var->isFuncDeclaration())
+ return this;
+
+ }
+#endif
+
+ Expression *e = e1->interpret(istate, ctfeNeedLvalue);
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ // Return a simplified address expression
+ e = new AddrExp(loc, e);
+ e->type = type;
+ return e;
+}
+
Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal)
{
#if LOG
@@ -1220,26 +1507,6 @@ Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal)
return this;
}
-#if IN_LLVM
-
-Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal)
-{
-#if LOG
- printf("AddrExp::interpret() %s\n", toChars());
-#endif
- if (e1->op == TOKvar)
- { VarExp *ve = (VarExp *)e1;
- if (ve->var->isFuncDeclaration())
- return this;
-
- }
- error("Cannot interpret %s at compile time", toChars());
- return EXP_CANT_INTERPRET;
-}
-
-#endif
-
-
// -------------------------------------------------------------
// Remove out, ref, and this
// -------------------------------------------------------------
@@ -1263,6 +1530,8 @@ Expression * resolveReferences(Expression *e, Expression *thisval, bool *isRefer
// Chase down rebinding of out and ref.
VarExp *ve = (VarExp *)e;
VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v->type->ty == Tpointer)
+ break;
if (v && v->getValue() && v->getValue()->op == TOKvar) // it's probably a reference
{
// Make sure it's a real reference.
@@ -1339,7 +1608,7 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
if (e && e != EXP_CANT_INTERPRET)
v->setValueWithoutChecking(e);
}
- else if ((v->isCTFE() || (!v->isDataseg() && istate)) && !v->getValue())
+ else if (v->isCTFE() && !v->getValue())
{
if (v->init && v->type->size() != 0)
{
@@ -1354,8 +1623,8 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
else
e = v->type->defaultInitLiteral(loc);
}
- else if (!v->isDataseg() && !istate) {
- error(loc, "variable %s cannot be read at compile time", v->toChars());
+ else if (!v->isDataseg() && !v->isCTFE() && !istate)
+ { error(loc, "variable %s cannot be read at compile time", v->toChars());
return EXP_CANT_INTERPRET;
}
else
@@ -1368,9 +1637,9 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
error(loc, "variable %s is used before initialization", v->toChars());
else if (e == EXP_CANT_INTERPRET)
return e;
- else if (goal == ctfeNeedLvalue && (e->op == TOKstring || e->op == TOKslice ||
- e->op == TOKstructliteral || e->op == TOKarrayliteral ||
- e->op == TOKassocarrayliteral))
+ else if ((goal == ctfeNeedLvalue) || e->op == TOKaddress
+ || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral
+ || e->op == TOKassocarrayliteral || e->op == TOKslice)
return e; // it's already an Lvalue
else
e = e->interpret(istate, goal);
@@ -1406,14 +1675,26 @@ Expression *VarExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("VarExp::interpret() %s\n", toChars());
#endif
+ if (goal == ctfeNeedLvalueRef)
+ {
+ // If it is a reference, return the thing it's pointing to.
+ VarDeclaration *v = var->isVarDeclaration();
+ if (v && v->getValue() && (v->storage_class & (STCref | STCout)))
+ return v->getValue();
+ if (v && !v->isDataseg() && !v->isCTFE() && !istate)
+ { error("variable %s cannot be referenced at compile time", v->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ else if (v && !v->getValue() && !v->isCTFE() && v->isDataseg())
+ { error("static variable %s cannot be referenced at compile time", v->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ return this;
+ }
Expression *e = getVarExp(loc, istate, var, goal);
// A VarExp may include an implicit cast. It must be done explicitly.
- if (e != EXP_CANT_INTERPRET && e->type != type
- && e->implicitConvTo(type) == MATCHexact)
- {
- e = e->implicitCastTo(0, type);
- e = e->interpret(istate, goal);
- }
+ if (e != EXP_CANT_INTERPRET)
+ e = paintTypeOntoLiteral(type, e);
return e;
}
@@ -1426,6 +1707,11 @@ Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal)
VarDeclaration *v = declaration->isVarDeclaration();
if (v)
{
+ if (v->getValue())
+ {
+ addVarToInterstate(istate, v);
+ v->setValueNull();
+ }
Dsymbol *s = v->toAlias();
if (s == v && !v->isStatic() && v->init)
{
@@ -1497,6 +1783,15 @@ Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal)
return ex;
}
+ // A tuple of assignments can contain void (Bug 5676).
+ if (goal == ctfeNeedNothing)
+ continue;
+ if (ex == EXP_VOID_INTERPRET)
+ {
+ error("ICE: void element %s in tuple", e->toChars());
+ assert(0);
+ }
+
/* If any changes, do Copy On Write
*/
if (ex != e)
@@ -1562,7 +1857,13 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal)
ae->type = type;
return ae;
}
- return this;
+#if DMDV2
+ if (((TypeNext *)type)->next->mod & (MODconst | MODimmutable))
+ { // If it's immutable, we don't need to dup it
+ return this;
+ }
+#endif
+ return copyLiteral(this);
Lerror:
if (expsx)
@@ -1711,7 +2012,7 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal)
se->type = type;
return se;
}
- return this;
+ return copyLiteral(this);
}
/******************************
@@ -1768,6 +2069,28 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal)
((TypeArray *)newtype)->next->defaultInitLiteral(),
lenExpr->toInteger());
}
+ if (newtype->toBasetype()->ty == Tstruct)
+ {
+ Expression *se = newtype->defaultInitLiteral();
+#if DMDV2
+ if (member)
+ {
+ int olderrors = global.errors;
+ member->interpret(istate, arguments, se);
+ if (olderrors != global.errors)
+ {
+ error("cannot evaluate %s at compile time", toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ }
+#else // The above code would fail on D1 because it doesn't use STRUCTTHISREF,
+ // but that's OK because D1 doesn't have struct constructors anyway.
+ assert(!member);
+#endif
+ Expression *e = new AddrExp(loc, se);
+ e->type = type;
+ return e;
+ }
if (newtype->ty == Tclass)
{
error("classes are not yet supported in CTFE");
@@ -1787,9 +2110,6 @@ Expression *UnaExp::interpretCommon(InterState *istate, CtfeGoal goal, Expressi
e1 = this->e1->interpret(istate);
if (e1 == EXP_CANT_INTERPRET)
goto Lcant;
- if (e1->isConst() != 1)
- goto Lcant;
-
e = (*fp)(type, e1);
return e;
@@ -1808,6 +2128,104 @@ UNA_INTERPRET(Com)
UNA_INTERPRET(Not)
UNA_INTERPRET(Bool)
+Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs)
+{
+ *ofs = 0;
+ if (e->op == TOKaddress)
+ e = ((AddrExp *)e)->e1;
+ if (e->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)e;
+ // Note that each AA element is part of its own memory block
+ if ((ie->e1->type->ty == Tarray || ie->e1->type->ty == Tsarray
+ || ie->e1->op == TOKstring || ie->e1->op==TOKarrayliteral) &&
+ ie->e2->op == TOKint64)
+ {
+ *ofs = ie->e2->toInteger();
+ return ie->e1;
+ }
+ }
+ return e;
+}
+
+// return e1 - e2 as an integer, or error if not possible
+Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+ if (agg1 == agg2)
+ {
+ Type *pointee = ((TypePointer *)agg1->type)->next;
+ dinteger_t sz = pointee->size();
+ return new IntegerExp(loc, (ofs1-ofs2)*sz, type);
+ }
+ else if (agg1->op == TOKstring && agg2->op == TOKstring)
+ {
+ if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string)
+ {
+ Type *pointee = ((TypePointer *)agg1->type)->next;
+ dinteger_t sz = pointee->size();
+ return new IntegerExp(loc, (ofs1-ofs2)*sz, type);
+ }
+ }
+#if LOGASSIGN
+ printf("FAILED POINTER DIFF\n");
+ showCtfeExpr(agg1);
+ showCtfeExpr(agg2);
+#endif
+ error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract "
+ "pointers to two different memory blocks",
+ e1->toChars(), e2->toChars());
+ return EXP_CANT_INTERPRET;
+}
+
+// Return eptr op e2, where eptr is a pointer, e2 is an integer,
+// and op is TOKadd or TOKmin
+Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type,
+ Expression *eptr, Expression *e2)
+{
+ dinteger_t ofs1, ofs2;
+ if (eptr->op == TOKaddress)
+ eptr = ((AddrExp *)eptr)->e1;
+ Expression *agg1 = getAggregateFromPointer(eptr, &ofs1);
+ if (agg1->op != TOKstring && agg1->op != TOKarrayliteral)
+ {
+ error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
+ return EXP_CANT_INTERPRET;
+ }
+ ofs2 = e2->toInteger();
+ Type *pointee = ((TypePointer *)agg1->type)->next;
+ dinteger_t sz = pointee->size();
+ Expression *dollar = ArrayLength(Type::tsize_t, agg1);
+ assert(dollar != EXP_CANT_INTERPRET);
+ dinteger_t len = dollar->toInteger();
+
+ Expression *val = agg1;
+ TypeArray *tar = (TypeArray *)val->type;
+ dinteger_t indx = ofs1;
+ if (op == TOKadd || op == TOKaddass)
+ indx = indx + ofs2/sz;
+ else if (op == TOKmin || op == TOKminass)
+ indx -= ofs2/sz;
+ else
+ error(loc, "CTFE Internal compiler error: bad pointer operation");
+ if (val->op != TOKarrayliteral && val->op != TOKstring)
+ {
+ error(loc, "CTFE Internal compiler error: pointer arithmetic %s", val->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ if (indx < 0 || indx > len)
+ {
+ error(loc, "cannot assign pointer to index %jd inside memory block [0..%jd]", indx, len);
+ return EXP_CANT_INTERPRET;
+ }
+
+ IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
+ IndexExp *ie = new IndexExp(loc, val, ofs);
+ ie->type = type;
+ return ie;
+}
typedef Expression *(*fp_t)(Type *, Expression *, Expression *);
@@ -1819,6 +2237,31 @@ Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp)
#if LOG
printf("BinExp::interpretCommon() %s\n", toChars());
#endif
+ if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer && op == TOKmin)
+ {
+ e1 = this->e1->interpret(istate, ctfeNeedLvalue);
+ e2 = this->e2->interpret(istate, ctfeNeedLvalue);
+ return pointerDifference(loc, type, e1, e2);
+ }
+ if (this->e1->type->ty == Tpointer && this->e2->type->isintegral())
+ {
+ e1 = this->e1->interpret(istate, ctfeNeedLvalue);
+ e2 = this->e2->interpret(istate);
+ if (e1 == EXP_CANT_INTERPRET || e2 == EXP_CANT_INTERPRET)
+ return EXP_CANT_INTERPRET;
+ return pointerArithmetic(loc, op, type, e1, e2);
+ }
+ if (this->e2->type->ty == Tpointer && this->e1->type->ty == TOKint64 && op==TOKadd)
+ {
+ e2 = this->e2->interpret(istate, ctfeNeedLvalue);
+ e1 = this->e1->interpret(istate);
+ return pointerArithmetic(loc, op, type, e2, e1);
+ }
+ if (this->e1->type->ty == Tpointer || this->e2->type->ty == Tpointer)
+ {
+ error("pointer expression %s cannot be interpreted at compile time", toChars());
+ return EXP_CANT_INTERPRET;
+ }
e1 = this->e1->interpret(istate);
if (e1 == EXP_CANT_INTERPRET)
goto Lcant;
@@ -1832,6 +2275,8 @@ Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp)
goto Lcant;
e = (*fp)(type, e1, e2);
+ if (e == EXP_CANT_INTERPRET)
+ error("%s cannot be interpreted at compile time", toChars());
return e;
Lcant:
@@ -1859,6 +2304,63 @@ BIN_INTERPRET(Xor)
typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *);
+// Return EXP_CANT_INTERPRET if they point to independent memory blocks
+Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2)
+{
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+ if (agg1 == agg2 ||
+ (agg1->op == TOKstring && agg2->op == TOKstring &&
+ ((StringExp *)agg1)->string == ((StringExp *)agg2)->string))
+
+ {
+ dinteger_t cm = ofs1 - ofs2;
+ dinteger_t n;
+ dinteger_t zero = 0;
+ switch(op)
+ {
+ case TOKlt: n = (ofs1 < ofs2); break;
+ case TOKle: n = (ofs1 <= ofs2); break;
+ case TOKgt: n = (ofs1 > ofs2); break;
+ case TOKge: n = (ofs1 >= ofs2); break;
+ case TOKidentity:
+ case TOKequal: n = (ofs1 == ofs2); break;
+ case TOKnotidentity:
+ case TOKnotequal: n = (ofs1 != ofs2); break;
+ default:
+ assert(0);
+ }
+ return new IntegerExp(loc, n, type);
+ }
+ int cmp;
+ if (e1->op == TOKnull)
+ {
+ cmp = (e2->op == TOKnull);
+ }
+ else if (e2->op == TOKnull)
+ {
+ cmp = 0;
+ }
+ else
+ {
+ switch(op)
+ {
+ case TOKidentity:
+ case TOKequal:
+ case TOKnotidentity: // 'cmp' gets inverted below
+ case TOKnotequal:
+ cmp = 0;
+ break;
+ default:
+ return EXP_CANT_INTERPRET;
+ }
+ }
+ if (op == TOKnotidentity || op == TOKnotequal)
+ cmp ^= -1;
+ return new IntegerExp(loc, cmp, type);
+}
+
Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp)
{ Expression *e;
Expression *e1;
@@ -1867,9 +2369,25 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp
#if LOG
printf("BinExp::interpretCommon2() %s\n", toChars());
#endif
+ if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer)
+ {
+ e1 = this->e1->interpret(istate, ctfeNeedLvalue);
+ e2 = this->e2->interpret(istate, ctfeNeedLvalue);
+ e = comparePointers(loc, op, type, e1, e2);
+ if (e == EXP_CANT_INTERPRET)
+ {
+ error("%s and %s point to independent memory blocks and "
+ "cannot be compared at compile time", this->e1->toChars(),
+ this->e2->toChars());
+ }
+ return e;
+ }
e1 = this->e1->interpret(istate);
if (e1 == EXP_CANT_INTERPRET)
goto Lcant;
+ if (e1->op == TOKslice)
+ e1 = resolveSlice(e1);
+
if (e1->isConst() != 1 &&
e1->op != TOKnull &&
e1->op != TOKstring &&
@@ -1883,6 +2401,8 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp
e2 = this->e2->interpret(istate);
if (e2 == EXP_CANT_INTERPRET)
goto Lcant;
+ if (e2->op == TOKslice)
+ e2 = resolveSlice(e2);
if (e2->isConst() != 1 &&
e2->op != TOKnull &&
e2->op != TOKstring &&
@@ -1892,8 +2412,9 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp
error("cannot compare %s at compile time", e2->toChars());
goto Lcant;
}
-
e = (*fp)(op, type, e1, e2);
+ if (e == EXP_CANT_INTERPRET)
+ error("%s cannot be interpreted at compile time", toChars());
return e;
Lcant:
@@ -2013,68 +2534,7 @@ UnaExp *isUnaExp(Expression *e)
default:
break;
}
- return NULL;
-}
-
-// To resolve an assignment expression, we need to walk to the end of the
-// expression to find the ultimate variable which is modified. But, in building
-// up the expression, we need to walk the tree *backwards*. There isn't a
-// standard way to do this, but if we know we're at depth d, iterating from
-// the root up to depth d-1 will give us the parent node. Inefficient, but
-// depth is almost always < 3.
-struct ExpressionReverseIterator
-{
- Expression *totalExpr; // The root expression
- Expression *thisval; // The value to be used for TOKthis
- int totalDepth;
-
- ExpressionReverseIterator(Expression *root, Expression *thisexpr)
- {
- totalExpr = root;
- thisval = thisexpr;
- totalDepth = findExpressionDepth(totalExpr);
- }
-
- int findExpressionDepth(Expression *e);
- Expression *getExpressionAtDepth(int depth);
-};
-
-// Determines the depth in unary expressions.
-int ExpressionReverseIterator::findExpressionDepth(Expression *e)
-{
- int depth = 0;
- for (;;)
- {
- e = resolveReferences(e, thisval);
- if (e->op == TOKvar)
- return depth;
- if (e->op == TOKcall)
- return depth;
- ++depth;
- UnaExp *u = isUnaExp(e);
- if (u)
- e = u->e1;
- else
- return depth;
- }
-}
-
-Expression *ExpressionReverseIterator::getExpressionAtDepth(int depth)
-{
- Expression *e = totalExpr;
- int d = 0;
- for (;;)
- {
- e = resolveReferences(e, thisval);
- if (d == depth) return e;
- ++d;
- assert(e->op != TOKvar);
- UnaExp *u = isUnaExp(e);
- if (u)
- e = u->e1;
- else
- return e;
- }
+ return NULL;
}
// Returns the variable which is eventually modified, or NULL if an rvalue.
@@ -2102,40 +2562,6 @@ VarDeclaration * findParentVar(Expression *e, Expression *thisval)
return v;
}
-// Returns the value to be assigned to the last dotVar, given the existing value at this depth.
-Expression *assignDotVar(ExpressionReverseIterator rvs, int depth, Expression *existing, Expression *newval)
-{
- if (depth == 0)
- return newval;
- assert(existing && existing != EXP_CANT_INTERPRET);
- Expression *e = rvs.getExpressionAtDepth(depth - 1);
- if (e->op == TOKdotvar)
- {
- VarDeclaration *member = ((DotVarExp *)e)->var->isVarDeclaration();
- assert(member);
- assert(existing);
- assert(existing != EXP_CANT_INTERPRET);
- assert(existing->op == TOKstructliteral);
- if (existing->op != TOKstructliteral)
- return EXP_CANT_INTERPRET;
-
- StructLiteralExp *se = (StructLiteralExp *)existing;
- int fieldi = se->getFieldIndex(member->type, member->offset);
- if (fieldi == -1)
- return EXP_CANT_INTERPRET;
- assert(fieldi>=0 && fieldi < se->elements->dim);
- Expression *ex = (Expression *)(se->elements->data[fieldi]);
-
- newval = assignDotVar(rvs, depth - 1, ex, newval);
- Expressions *expsx = changeOneElement(se->elements, fieldi, newval);
- Expression * ee = new StructLiteralExp(se->loc, se->sd, expsx);
- ee->type = se->type;
- return ee;
- }
- assert(0);
- return NULL;
-}
-
// Given expr, which evaluates to an array/AA/string literal,
// return true if it needs to be copied
bool needToCopyLiteral(Expression *expr)
@@ -2146,9 +2572,9 @@ bool needToCopyLiteral(Expression *expr)
{
case TOKarrayliteral:
case TOKassocarrayliteral:
- case TOKstring:
case TOKstructliteral:
return true;
+ case TOKstring:
case TOKthis:
case TOKvar:
return false;
@@ -2161,23 +2587,29 @@ bool needToCopyLiteral(Expression *expr)
expr = ((UnaExp *)expr)->e1;
continue;
case TOKcat:
+ return needToCopyLiteral(((BinExp *)expr)->e1) ||
+ needToCopyLiteral(((BinExp *)expr)->e2);
case TOKcatass:
- return false;
- case TOKcall:
- // TODO: Return statement should
- // guarantee we never return a naked literal, but
- // currently it doesn't.
- return true;
-
- // There are probably other cases which don't need
- // a copy. But for now, we conservatively copy all
- // other cases.
+ expr = ((BinExp *)expr)->e2;
+ continue;
default:
- return true;
+ return false;
}
}
}
+Expressions *copyLiteralArray(Expressions *oldelems)
+{
+ if (!oldelems)
+ return oldelems;
+ Expressions *newelems = new Expressions();
+ newelems->setDim(oldelems->dim);
+ for (size_t i = 0; i < oldelems->dim; i++)
+ newelems->data[i] = copyLiteral((Expression *)(oldelems->data[i]));
+ return newelems;
+}
+
+
// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
// This value will be used for in-place modification.
@@ -2199,12 +2631,16 @@ Expression *copyLiteral(Expression *e)
else if (e->op == TOKarrayliteral)
{
ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
- Expressions *oldelems = ae->elements;
- Expressions *newelems = new Expressions();
- newelems->setDim(oldelems->dim);
- for (size_t i = 0; i < oldelems->dim; i++)
- newelems->data[i] = copyLiteral((Expression *)(oldelems->data[i]));
- ArrayLiteralExp *r = new ArrayLiteralExp(ae->loc, newelems);
+ ArrayLiteralExp *r = new ArrayLiteralExp(e->loc,
+ copyLiteralArray(ae->elements));
+ r->type = e->type;
+ return r;
+ }
+ else if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+ AssocArrayLiteralExp *r = new AssocArrayLiteralExp(e->loc,
+ copyLiteralArray(aae->keys), copyLiteralArray(aae->values));
r->type = e->type;
return r;
}
@@ -2226,14 +2662,20 @@ Expression *copyLiteral(Expression *e)
Dsymbol *s = (Dsymbol *)sd->fields.data[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v);
+ // If it is a void assignment, use the default initializer
+ if (!m)
+ m = v->type->defaultInitLiteral(e->loc);
+ if (m->op == TOKslice)
+ m = resolveSlice(m);
if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray)
{
// Block assignment from inside struct literals
TypeSArray *tsa = (TypeSArray *)v->type;
uinteger_t length = tsa->dim->toInteger();
-
m = createBlockDuplicatedArrayLiteral(v->type, m, length);
- } else m = copyLiteral(m);
+ }
+ else if (v->type->ty != Tarray) // NOTE: do not copy array references
+ m = copyLiteral(m);
newelems->data[i] = m;
}
#if DMDV2
@@ -2250,7 +2692,171 @@ Expression *copyLiteral(Expression *e)
return r;
}
-void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val)
+/* Deal with type painting.
+ * Type painting is a major nuisance: we can't just set
+ * e->type = type, because that would change the original literal.
+ * But, we can't simply copy the literal either, because that would change
+ * the values of any pointers.
+ */
+Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
+{
+ if (lit->type == type)
+ return lit;
+ Expression *e;
+ if (lit->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)lit;
+ e = new SliceExp(lit->loc, se->e1, se->lwr, se->upr);
+ }
+ else if (lit->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)lit;
+ e = new IndexExp(lit->loc, ie->e1, ie->e2);
+ }
+ else if (lit->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)lit;
+ e = new ArrayLiteralExp(lit->loc, ae->elements);
+ }
+ else if (lit->op == TOKstring)
+ {
+ // For strings, we need to introduce another level of indirection
+ e = new SliceExp(lit->loc, lit,
+ new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit));
+ }
+ else if (lit->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit;
+ e = new AssocArrayLiteralExp(lit->loc, aae->keys, aae->values);
+ }
+ else
+ e = copyLiteral(lit);
+ e->type = type;
+ return e;
+}
+
+/* Set a slice of char array literal 'existingAE' from a string 'newval'.
+ * existingAE[firstIndex..firstIndex+newval.length] = newval.
+ */
+void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex)
+{
+ size_t newlen = newval->len;
+ size_t sz = newval->sz;
+ unsigned char *s = (unsigned char *)newval->string;
+ Type *elemType = existingAE->type->nextOf();
+ for (size_t j = 0; j < newlen; j++)
+ {
+ dinteger_t val;
+ switch (sz)
+ {
+ case 1: val = s[j]; break;
+ case 2: val = ((unsigned short *)s)[j]; break;
+ case 4: val = ((unsigned *)s)[j]; break;
+ default:
+ assert(0);
+ break;
+ }
+ existingAE->elements->data[j+firstIndex]
+ = new IntegerExp(newval->loc, val, elemType);
+ }
+}
+
+/* Set a slice of string 'existingSE' from a char array literal 'newae'.
+ * existingSE[firstIndex..firstIndex+newae.length] = newae.
+ */
+void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex)
+{
+ unsigned char *s = (unsigned char *)existingSE->string;
+ for (size_t j = 0; j < newae->elements->dim; j++)
+ {
+ unsigned value = ((Expression *)(newae->elements->data[j]))->toInteger();
+ switch (existingSE->sz)
+ {
+ case 1: s[j+firstIndex] = value; break;
+ case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
+ case 4: ((unsigned *)s)[j+firstIndex] = value; break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+/* Set a slice of string 'existingSE' from a string 'newstr'.
+ * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
+ */
+void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex)
+{
+ unsigned char *s = (unsigned char *)existingSE->string;
+ size_t sz = existingSE->sz;
+ assert(sz == newstr->sz);
+ memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
+}
+
+
+/* Set dest = src, where both dest and src are container value literals
+ * (ie, struct literals, or static arrays (can be an array literal or a string)
+ * Assignment is recursively in-place.
+ * Purpose: any reference to a member of 'dest' will remain valid after the
+ * assignment.
+ */
+void assignInPlace(Expression *dest, Expression *src)
+{
+ assert(dest->op == TOKstructliteral || dest->op == TOKarrayliteral ||
+ dest->op == TOKstring);
+ Expressions *oldelems;
+ Expressions *newelems;
+ if (dest->op == TOKstructliteral)
+ {
+ assert(dest->op == src->op);
+ oldelems = ((StructLiteralExp *)dest)->elements;
+ newelems = ((StructLiteralExp *)src)->elements;
+ }
+ else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral)
+ {
+ oldelems = ((ArrayLiteralExp *)dest)->elements;
+ newelems = ((ArrayLiteralExp *)src)->elements;
+ }
+ else if (dest->op == TOKstring && src->op == TOKstring)
+ {
+ sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0);
+ return;
+ }
+ else if (dest->op == TOKarrayliteral && src->op == TOKstring)
+ {
+ sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0);
+ return;
+ }
+ else if (src->op == TOKarrayliteral && dest->op == TOKstring)
+ {
+ sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0);
+ return;
+ }
+ else assert(0);
+
+ assert(oldelems->dim == newelems->dim);
+
+ for (size_t i= 0; i < oldelems->dim; ++i)
+ {
+ Expression *e = (Expression *)newelems->data[i];
+ Expression *o = (Expression *)oldelems->data[i];
+ if (e->op == TOKstructliteral)
+ {
+ assert(o->op == e->op);
+ assignInPlace(o, e);
+ }
+ else if (e->type->ty == Tsarray && o->type->ty == Tsarray)
+ {
+ assignInPlace(o, e);
+ }
+ else
+ {
+ oldelems->data[i] = newelems->data[i];
+ }
+ }
+}
+
+void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef)
{
assert( ae->type->ty == Tsarray || ae->type->ty == Tarray);
#if DMDV2
@@ -2260,13 +2866,23 @@ void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val)
Type *desttype = ((TypeArray *)ae->type)->next;
bool directblk = (val->type->toBasetype()) == desttype;
#endif
+
+ bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral
+ || val->op == TOKstring);
+
for (size_t k = 0; k < ae->elements->dim; k++)
{
if (!directblk && ((Expression *)(ae->elements->data[k]))->op == TOKarrayliteral)
{
- recursiveBlockAssign((ArrayLiteralExp *)(ae->elements->data[k]), val);
+ recursiveBlockAssign((ArrayLiteralExp *)(ae->elements->data[k]), val, wantRef);
+ }
+ else
+ {
+ if (wantRef || cow)
+ ae->elements->data[k] = val;
+ else
+ assignInPlace((Expression *)ae->elements->data[k], val);
}
- else ae->elements->data[k] = val;
}
}
@@ -2276,12 +2892,12 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
#if LOG
printf("BinExp::interpretAssignCommon() %s\n", toChars());
#endif
- Expression *e = EXP_CANT_INTERPRET;
+ Expression *returnValue = EXP_CANT_INTERPRET;
Expression *e1 = this->e1;
if (!istate)
{
error("value of %s is not known at compile time", e1->toChars());
- return e;
+ return returnValue;
}
/* Before we begin, we need to know if this is a reference assignment
* (dynamic array, AA, or class) or a value assignment.
@@ -2335,6 +2951,9 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
VarDeclaration * targetVar = findParentVar(e2, istate->localThis);
if (!(targetVar && targetVar->isConst()))
wantRef = true;
+ // slice assignment of static arrays is not reference assignment
+ if ((e1->op==TOKslice) && ((SliceExp *)e1)->e1->type->ty == Tsarray)
+ wantRef = false;
#endif
}
if (isBlockAssignment && (e2->type->toBasetype()->ty == Tarray || e2->type->toBasetype()->ty == Tsarray))
@@ -2347,6 +2966,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
* construction of a struct with an invariant().
*/
if (op==TOKconstruct && this->e1->op==TOKvar && this->e2->op != TOKthis
+ && this->e2->op != TOKcomma
&& ((VarExp*)this->e1)->var->storage_class & STCref)
wantRef = true;
@@ -2373,6 +2993,21 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
istate->awaitingLvalueReturn = oldWaiting;
if (e1 == EXP_CANT_INTERPRET)
return e1;
+ if (e1->op == TOKarrayliteral || e1->op == TOKstring)
+ {
+ // f() = e2, when f returns an array, is always a slice assignment.
+ // Convert into arr[0..arr.length] = e2
+ e1 = new SliceExp(loc, e1,
+ new IntegerExp(0, 0, Type::tsize_t),
+ ArrayLength(Type::tsize_t, e1));
+ e1->type = type;
+ }
+ }
+ if (e1->op == TOKstar)
+ {
+ e1 = e1->interpret(istate, ctfeNeedLvalue);
+ if (e1 == EXP_CANT_INTERPRET)
+ return EXP_CANT_INTERPRET;
}
if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar
@@ -2384,10 +3019,17 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
Expression * newval = NULL;
if (!wantRef)
- newval = this->e2->interpret(istate);
+ { // We need to treat pointers specially, because TOKsymoff can be used to
+ // return a value OR a pointer
+ assert(e1);
+ assert(e1->type);
+ if ((e1->type->ty == Tpointer && e1->type->nextOf()->ty != Tfunction) && (e2->op == TOKsymoff || e2->op==TOKaddress || e2->op==TOKvar)) // && (e1->op==TOKaddress)) //TOKsymoff || e1->op==TOKdotvar))
+ newval = this->e2->interpret(istate, ctfeNeedLvalue);
+ else
+ newval = this->e2->interpret(istate);
+ }
if (newval == EXP_CANT_INTERPRET)
return newval;
-
// ----------------------------------------------------
// Deal with read-modify-write assignments.
// Set 'newval' to the final assignment value
@@ -2411,26 +3053,52 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
if (fp)
{
- newval = (*fp)(type, oldval, newval);
+ // ~= can create new values (see bug 6052)
+ if (op == TOKcatass)
+ {
+ if (needToCopyLiteral(this->e2))
+ newval = copyLiteral(newval);
+ if (newval->op == TOKslice)
+ newval = resolveSlice(newval);
+ }
+ if (oldval->op == TOKslice)
+ oldval = resolveSlice(oldval);
+ if (this->e1->type->ty == Tpointer && this->e2->type->isintegral()
+ && (op==TOKaddass || op == TOKminass))
+ {
+ oldval = this->e1->interpret(istate, ctfeNeedLvalue);
+ newval = this->e2->interpret(istate);
+ if (oldval == EXP_CANT_INTERPRET || newval == EXP_CANT_INTERPRET)
+ return EXP_CANT_INTERPRET;
+ newval = pointerArithmetic(loc, op, type, oldval, newval);
+ }
+ else if (this->e1->type->ty == Tpointer)
+ {
+ error("pointer expression %s cannot be interpreted at compile time", toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ else
+ {
+ newval = (*fp)(type, oldval, newval);
+ }
if (newval == EXP_CANT_INTERPRET)
{
error("Cannot interpret %s at compile time", toChars());
return EXP_CANT_INTERPRET;
}
// Determine the return value
- e = Cast(type, type, post ? oldval : newval);
- if (e == EXP_CANT_INTERPRET)
- return e;
+ returnValue = Cast(type, type, post ? oldval : newval);
+ if (returnValue == EXP_CANT_INTERPRET)
+ return returnValue;
}
else
- e = newval;
-
+ returnValue = newval;
if (e1->op == TOKarraylength)
{
size_t oldlen = oldval->toInteger();
size_t newlen = newval->toInteger();
if (oldlen == newlen) // no change required -- we're done!
- return e;
+ return returnValue;
// Now change the assignment from arr.length = n into arr = newval
e1 = ((ArrayLengthExp *)e1)->e1;
if (oldlen != 0)
@@ -2441,6 +3109,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
oldval = oldval->interpret(istate);
}
}
+ if (oldval->op == TOKslice)
+ oldval = resolveSlice(oldval);
Type *t = e1->type->toBasetype();
if (t->ty == Tarray)
{
@@ -2452,15 +3122,29 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
Expressions *elements = new Expressions();
elements->setDim(newlen);
size_t copylen = oldlen < newlen ? oldlen : newlen;
+ if (oldlen !=0)
+ assert(oldval->op == TOKarrayliteral);
ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
for (size_t i = 0; i < copylen; i++)
- elements->data[i] = ae->elements->data[i];
-
- for (size_t i = copylen; i < newlen; i++)
- elements->data[i] = defaultElem;
+ elements->data[i] = ae->elements->data[i];
+ if (elemType->ty == Tstruct || elemType->ty == Tsarray)
+ { /* If it is an aggregate literal representing a value type,
+ * we need to create a unique copy for each element
+ */
+ for (size_t i = copylen; i < newlen; i++)
+ elements->data[i] = copyLiteral(defaultElem);
+ }
+ else
+ {
+ for (size_t i = copylen; i < newlen; i++)
+ elements->data[i] = defaultElem;
+ }
ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements);
aae->type = t;
newval = aae;
+ // We have changed it into a reference assignment
+ // Note that returnValue is still the new length.
+ wantRef = true;
}
else
{
@@ -2478,7 +3162,12 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
newval = type->defaultInitLiteral(loc);
}
newval = Cast(type, type, newval);
- e = newval;
+ if (newval == EXP_CANT_INTERPRET)
+ {
+ error("CTFE error: cannot cast %s to type %s", this->e2->toChars(), type->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ returnValue = newval;
}
if (newval == EXP_CANT_INTERPRET)
return newval;
@@ -2497,14 +3186,18 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
// This happens inside compiler-generated foreach statements.
if (op==TOKconstruct && this->e1->op==TOKvar && this->e2->op != TOKthis
+ && this->e2->op != TOKcomma
&& ((VarExp*)this->e1)->var->storage_class & STCref)
{
- //error("assignment to ref variable %s is not yet supported in CTFE", this->toChars());
VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
v->setValueNull();
v->createStackValue(e2);
+#if (LOGASSIGN)
+ printf("FOREACH ASSIGN %s=%s\n", v->toChars(), e2->toChars());
+#endif
return e2;
}
+
bool destinationIsReference = false;
e1 = resolveReferences(e1, istate->localThis, &destinationIsReference);
@@ -2514,247 +3207,60 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
if (e1->op != TOKvar && ultimateVar && !ultimateVar->getValue())
ultimateVar->createRefValue(copyLiteral(ultimateVar->type->defaultInitLiteral()));
- // ----------------------------------------------------------
- // Deal with dotvar expressions - non-reference types
- // ----------------------------------------------------------
- // Because structs are not reference types, dotvar expressions can be
- // collapsed into a single assignment.
- bool startedWithCall = false;
- if (e1->op == TOKcall)
- startedWithCall = true;
- while (!wantRef && (e1->op == TOKdotvar || e1->op == TOKcall))
- {
- ExpressionReverseIterator rvs(e1, istate->localThis);
- Expression *lastNonDotVar = e1;
- // Strip of all of the leading dotvars.
- if (e1->op == TOKdotvar)
- {
- int numDotVars = 0;
- while(lastNonDotVar->op == TOKdotvar)
- {
- ++numDotVars;
- if (lastNonDotVar->op == TOKdotvar)
- lastNonDotVar = ((DotVarExp *)lastNonDotVar)->e1;
- lastNonDotVar = resolveReferences(lastNonDotVar, istate->localThis);
- assert(lastNonDotVar);
- }
- // We need the value of this first nonvar, since only part of it will be
- // modified.
- Expression * existing = lastNonDotVar->interpret(istate);
- if (existing == EXP_CANT_INTERPRET)
- return existing;
- assert(newval !=EXP_CANT_INTERPRET);
- newval = assignDotVar(rvs, numDotVars, existing, newval);
- e1 = lastNonDotVar;
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- v->setRefValue(newval);
- return e;
- }
- assert(newval !=EXP_CANT_INTERPRET);
-
- } // end tokdotvar
- else
- {
- Expression * existing = lastNonDotVar->interpret(istate);
- if (existing == EXP_CANT_INTERPRET)
- return existing;
- // It might be a reference. Turn it into an rvalue, by interpreting again.
- existing = existing->interpret(istate);
- if (existing == EXP_CANT_INTERPRET)
- return existing;
- assert(newval !=EXP_CANT_INTERPRET);
- newval = assignDotVar(rvs, 0, existing, newval);
- assert(newval !=EXP_CANT_INTERPRET);
- }
- if (e1->op == TOKcall)
- {
- bool oldWaiting = istate->awaitingLvalueReturn;
- istate->awaitingLvalueReturn = true;
- e1 = e1->interpret(istate);
- istate->awaitingLvalueReturn = oldWaiting;
-
- if (e1 == EXP_CANT_INTERPRET)
- return e1;
- assert(newval);
- assert(newval != EXP_CANT_INTERPRET);
- }
- }
// ---------------------------------------
// Deal with reference assignment
+ // (We already have 'newval' for arraylength operations)
// ---------------------------------------
- if (wantRef)
+ if (wantRef && this->e1->op != TOKarraylength)
{
- if (this->e2->op == TOKvar)
- newval = this->e2;
- else if (this->e2->op==TOKslice)
- {
- SliceExp * sexp = (SliceExp *)this->e2;
-
- /* Set the $ variable
- */
- Expression *e1val = sexp->e1->interpret(istate);
- Expression *dollar;
- if (e1val->op == TOKnull)
- dollar = new IntegerExp(0, 0, Type::tsize_t);
- else
- dollar = ArrayLength(Type::tsize_t, e1val);
-
- if (dollar != EXP_CANT_INTERPRET && sexp->lengthVar)
- {
- sexp->lengthVar->createStackValue(dollar);
- }
- Expression *upper = NULL;
- Expression *lower = NULL;
- if (sexp->upr)
- upper = sexp->upr->interpret(istate);
- else upper = dollar;
- if (sexp->lwr)
- lower = sexp->lwr->interpret(istate);
- else
- lower = new IntegerExp(loc, 0, Type::tsize_t);
- if (sexp->lengthVar)
- sexp->lengthVar->setValueNull(); // $ is defined only in [L..U]
- if (upper == EXP_CANT_INTERPRET || lower == EXP_CANT_INTERPRET)
- return EXP_CANT_INTERPRET;
- // We need the interpreted aggregate, except in the case where it
- // was a variable.
- if (sexp->e1->op == TOKvar)
- e1val = sexp->e1;
- newval = new SliceExp(sexp->loc, e1val, lower, upper);
- newval->type = sexp->type;
- }
- else
- newval = this->e2->interpret(istate, ctfeNeedLvalue);
+ newval = this->e2->interpret(istate, ctfeNeedLvalue);
if (newval == EXP_CANT_INTERPRET)
return newval;
+ // If it is an assignment from a array function parameter passed by
+ // reference, resolve the reference. (This should NOT happen for
+ // non-reference types).
+ if (newval->op == TOKvar && (newval->type->ty == Tarray ||
+ newval->type->ty == Tclass))
+ {
+ newval = newval->interpret(istate);
+ }
- if (newval->op == TOKarrayliteral || (newval->op == TOKassocarrayliteral)
- || newval->op == TOKstring)
+ if (newval->op == TOKassocarrayliteral || newval->op == TOKstring ||
+ newval->op==TOKarrayliteral)
{
if (needToCopyLiteral(this->e2))
newval = copyLiteral(newval);
}
- else if (newval->op == TOKnull)
- { // do nothing
- }
- else if (newval->op == TOKvar)
- {
- VarExp *vv = (VarExp *)newval;
-
- VarDeclaration *v2 = vv->var->isVarDeclaration();
- assert(v2 && v2->getValue());
- newval = v2->getValue();
- }
- else if ((e1->op == TOKdotvar || e1->op == TOKvar) && newval->op == TOKslice)
- {
- // This one is interesting because it could be a slice of itself
- SliceExp * sexp = (SliceExp *)newval;
- Expression *agg = sexp->e1;
- dinteger_t newlo = sexp->lwr->toInteger();
- dinteger_t newup = sexp->upr->toInteger();
- if (agg->op == TOKvar)
- {
- VarExp *vv = (VarExp *)agg;
- VarDeclaration *v2 = vv->var->isVarDeclaration();
- assert(v2 && v2->getValue());
- if (v2->getValue()->op == TOKarrayliteral
- || v2->getValue()->op == TOKstring)
- {
- Expression *dollar = ArrayLength(Type::tsize_t, v2->getValue());
- if ((newup < newlo) || (newup > dollar->toInteger()))
- {
- error("slice [%jd..%jd] exceeds array bounds [0..%jd]",
- newlo, newup, dollar->toInteger());
- return EXP_CANT_INTERPRET;
- }
- sexp->e1 = v2->getValue();
- newval = sexp;
- }
- else if (v2->getValue()->op == TOKslice)
- {
- SliceExp *sexpold = (SliceExp *)v2->getValue();
- sexp->e1 = sexpold->e1;
- dinteger_t hi = newup + sexpold->lwr->toInteger();
- dinteger_t lo = newlo + sexpold->lwr->toInteger();
- if ((newup < newlo) || (hi > sexpold->upr->toInteger()))
- {
- error("slice [%jd..%jd] exceeds array bounds [0..%jd]",
- newlo, newup, sexpold->upr->toInteger()-sexpold->lwr->toInteger());
- return EXP_CANT_INTERPRET;
- }
- sexp->lwr = new IntegerExp(loc, lo, Type::tsize_t);
- sexp->upr = new IntegerExp(loc, hi, Type::tsize_t);
- newval = sexp;
- }
- else
- {
- newval = newval->interpret(istate);
- if (newval == EXP_CANT_INTERPRET)
- return newval;
- }
- }
- else
- {
- newval = newval->interpret(istate);
- if (newval == EXP_CANT_INTERPRET)
- return newval;
- }
- }
- if (e1->op == TOKvar || e1->op == TOKdotvar)
- {
-
- assert((newval->op == TOKarrayliteral ||
- newval->op == TOKassocarrayliteral ||
- newval->op == TOKstring ||
- newval->op == TOKslice ||
- newval->op == TOKnull) );
- if (newval->op == TOKslice)
- {
- Expression *sss = ((SliceExp *)newval)->e1;
- assert(sss->op == TOKarrayliteral || sss->op == TOKstring);
- }
- }
-
- if (e1->op == TOKdotvar)
- {
- Expression *exx = ((DotVarExp *)e1)->e1->interpret(istate);
- if (exx == EXP_CANT_INTERPRET)
- return exx;
- if (exx->op != TOKstructliteral)
- {
- error("CTFE internal error: Dotvar assignment");
- return EXP_CANT_INTERPRET;
- }
- StructLiteralExp *se3 = (StructLiteralExp *)exx;
- VarDeclaration *vv = ((DotVarExp *)e1)->var->isVarDeclaration();
- if (!vv)
- {
- error("CTFE internal error: Dotvar assignment");
- return EXP_CANT_INTERPRET;
- }
- int se_indx = se3->getFieldIndex(e1->type, vv->offset);
- se3->elements->data[se_indx] = newval;
- // Mark the parent variable as modified
- if (!destinationIsReference)
- addVarToInterstate(istate, ultimateVar);
- return newval;
- }
- else if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (!destinationIsReference)
- addVarToInterstate(istate, v);
- v->setValueNull();
- v->createRefValue(newval);
- return newval;
- }
- e = newval;
+ returnValue = newval;
}
+ // ---------------------------------------
+ // Deal with dotvar expressions
+ // ---------------------------------------
+ // Because structs are not reference types, dotvar expressions can be
+ // collapsed into a single assignment.
+ if (!wantRef && e1->op == TOKdotvar)
+ {
+ // Strip of all of the leading dotvars, unless we started with a call
+ // (in which case, we already have the lvalue).
+ if (this->e1->op != TOKcall)
+ e1 = e1->interpret(istate, ctfeNeedLvalue);
+ if (e1 == EXP_CANT_INTERPRET)
+ return e1;
+ if (e1->op == TOKstructliteral && newval->op == TOKstructliteral)
+ {
+ assignInPlace(e1, newval);
+ return returnValue;
+ }
+ }
+#if LOGASSIGN
+ if (wantRef)
+ printf("REF ASSIGN: %s=%s\n", e1->toChars(), newval->toChars());
+ else
+ printf("ASSIGN: %s=%s\n", e1->toChars(), newval->toChars());
+ showCtfeExpr(newval);
+#endif
+
/* Assignment to variable of the form:
* v = newval
*/
@@ -2764,23 +3270,32 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
VarDeclaration *v = ve->var->isVarDeclaration();
if (!destinationIsReference)
addVarToInterstate(istate, v);
- if (e1->type->toBasetype()->ty == Tstruct)
+ if (wantRef)
{
- // This should be an in-place modification
- if (newval->op == TOKstructliteral)
+ v->setValueNull();
+ v->createRefValue(newval);
+ }
+ else if (e1->type->toBasetype()->ty == Tstruct)
+ {
+ // In-place modification
+ if (newval->op != TOKstructliteral)
{
- v->setValueNull();
- v->createRefValue(copyLiteral(newval));
+ error("CTFE internal error assigning struct");
+ return EXP_CANT_INTERPRET;
}
- else v->setRefValue(newval);
+ newval = copyLiteral(newval);
+ if (v->getValue())
+ assignInPlace(v->getValue(), newval);
+ else
+ v->createRefValue(newval);
}
else
{
if (e1->type->toBasetype()->ty == Tarray || e1->type->toBasetype()->ty == Taarray)
{ // arr op= arr
if (!v->getValue())
- v->createRefValue(newval->interpret(istate));
- else v->setRefValue(newval->interpret(istate));
+ v->createRefValue(newval);
+ else v->setRefValue(newval);
}
else
{
@@ -2791,13 +3306,49 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
}
}
}
+ else if (e1->op == TOKdotvar)
+ {
+ /* Assignment to member variable of the form:
+ * e.v = newval
+ */
+ Expression *exx = ((DotVarExp *)e1)->e1;
+ if (wantRef && exx->op != TOKstructliteral)
+ {
+ exx = exx->interpret(istate);
+ if (exx == EXP_CANT_INTERPRET)
+ return exx;
+ }
+ if (exx->op != TOKstructliteral)
+ {
+ error("CTFE internal error: Dotvar assignment");
+ return EXP_CANT_INTERPRET;
+ }
+ StructLiteralExp *se = (StructLiteralExp *)exx;
+ VarDeclaration *member = ((DotVarExp *)e1)->var->isVarDeclaration();
+ if (!member)
+ {
+ error("CTFE internal error: Dotvar assignment");
+ return EXP_CANT_INTERPRET;
+ }
+ int fieldi = se->getFieldIndex(member->type, member->offset);
+ if (fieldi == -1)
+ return EXP_CANT_INTERPRET;
+ assert(fieldi>=0 && fieldi < se->elements->dim);
+ if (newval->op == TOKstructliteral)
+ assignInPlace((Expression *)(se->elements->data[fieldi]), newval);
+ else
+ se->elements->data[fieldi] = newval;
+ if (ultimateVar && !destinationIsReference)
+ addVarToInterstate(istate, ultimateVar);
+ return returnValue;
+ }
else if (e1->op == TOKindex)
{
/* Assignment to array element of the form:
* aggregate[i] = newval
*/
IndexExp *ie = (IndexExp *)e1;
- int destarraylen = 0; // not for AAs
+ uinteger_t destarraylen = 0; // not for AAs
// Set the $ variable, and find the array literal to modify
if (ie->e1->type->toBasetype()->ty != Taarray)
@@ -2808,12 +3359,19 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
error("cannot index null array %s", ie->e1->toChars());
return EXP_CANT_INTERPRET;
}
- Expression *dollar = ArrayLength(Type::tsize_t, oldval);
- if (dollar == EXP_CANT_INTERPRET)
+ if (oldval->op != TOKarrayliteral && oldval->op != TOKstring
+ && oldval->op != TOKslice)
+ {
+ error("cannot determine length of %s at compile time",
+ ie->e1->toChars());
return EXP_CANT_INTERPRET;
- destarraylen = dollar->toInteger();
+ }
+ destarraylen = resolveArrayLength(oldval);
if (ie->lengthVar)
- ie->lengthVar->createStackValue(dollar);
+ {
+ IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t);
+ ie->lengthVar->createStackValue(dollarExp);
+ }
}
Expression *index = ie->e2->interpret(istate);
if (ie->lengthVar)
@@ -2830,7 +3388,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
if (ie->e1->type->toBasetype()->ty != Taarray)
{
indexToModify = index->toInteger();
- if (indexToModify > destarraylen)
+ if (indexToModify >= destarraylen)
{
error("array index %d is out of bounds [0..%d]", indexToModify,
destarraylen);
@@ -2843,9 +3401,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
/* The only possible indexable LValue aggregates are array literals,
* slices of array literals, and AA literals.
*/
-
if (aggregate->op == TOKindex || aggregate->op == TOKdotvar ||
- aggregate->op == TOKslice)
+ aggregate->op == TOKslice || aggregate->op == TOKcall)
{
aggregate = aggregate->interpret(istate, ctfeNeedLvalue);
if (aggregate == EXP_CANT_INTERPRET)
@@ -2856,7 +3413,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
VarExp *ve = (VarExp *)aggregate;
VarDeclaration *v = ve->var->isVarDeclaration();
aggregate = v->getValue();
- if (v->getValue()->op == TOKnull)
+ if (aggregate->op == TOKnull)
{
if (v->type->ty == Taarray)
{ // Assign to empty associative array
@@ -2871,7 +3428,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
aae2->type = v->type;
newval = aae2;
v->setRefValue(newval);
- return e;
+ return returnValue;
}
// This would be a runtime segfault
error("cannot index null array %s", v->toChars());
@@ -2896,10 +3453,23 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
error("CTFE internal compiler error %s", aggregate->toChars());
return EXP_CANT_INTERPRET;
}
+ if (!wantRef && newval->op == TOKslice)
+ {
+ newval = resolveSlice(newval);
+ if (newval == EXP_CANT_INTERPRET)
+ {
+ error("Compiler error: CTFE index assign %s", toChars());
+ assert(0);
+ }
+ }
+
if (existingAE)
{
- existingAE->elements->data[indexToModify] = newval;
- return e;
+ if (newval->op == TOKstructliteral)
+ assignInPlace((Expression *)(existingAE->elements->data[indexToModify]), newval);
+ else
+ existingAE->elements->data[indexToModify] = newval;
+ return returnValue;
}
if (existingSE)
{
@@ -2914,20 +3484,20 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
assert(0);
break;
}
- return e;
+ return returnValue;
}
else if (existingAA)
{
if (assignAssocArrayElement(loc, existingAA, index, newval) == EXP_CANT_INTERPRET)
return EXP_CANT_INTERPRET;
- return e;
+ return returnValue;
}
else
{
error("Index assignment %s is not yet supported in CTFE ", toChars());
return EXP_CANT_INTERPRET;
}
- return e;
+ return returnValue;
}
else if (e1->op == TOKslice)
{
@@ -2937,19 +3507,30 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
// ------------------------------
SliceExp * sexp = (SliceExp *)e1;
// Set the $ variable
- Expression *oldval = sexp->e1->interpret(istate);
- if (oldval->op == TOKnull)
+ Expression *oldval = sexp->e1;
+ bool assignmentToSlicedPointer = false;
+ if (oldval->type->toBasetype()->ty == Tpointer && oldval->type->toBasetype()->nextOf()->ty != Tfunction)
+ { // Slicing a pointer
+ oldval = oldval->interpret(istate, ctfeNeedLvalue);
+ dinteger_t ofs;
+ oldval = getAggregateFromPointer(oldval, &ofs);
+ assignmentToSlicedPointer = true;
+ } else
+ oldval = oldval->interpret(istate);
+
+ if (oldval->op != TOKarrayliteral && oldval->op != TOKstring
+ && oldval->op != TOKslice && oldval->op != TOKnull)
{
- error("cannot slice null array %s", sexp->e1->toChars());
+ error("CTFE ICE: cannot resolve array length");
return EXP_CANT_INTERPRET;
}
- Expression *arraylen = ArrayLength(Type::tsize_t, oldval);
- if (arraylen == EXP_CANT_INTERPRET)
- return EXP_CANT_INTERPRET;
+ uinteger_t dollar = resolveArrayLength(oldval);
if (sexp->lengthVar)
{
+ Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t);
sexp->lengthVar->createStackValue(arraylen);
}
+
Expression *upper = NULL;
Expression *lower = NULL;
if (sexp->upr)
@@ -2960,16 +3541,19 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
sexp->lengthVar->setValueNull(); // $ is defined only in [L..U]
if (upper == EXP_CANT_INTERPRET || lower == EXP_CANT_INTERPRET)
return EXP_CANT_INTERPRET;
- int dim = arraylen->toInteger();
+
+ int dim = dollar;
int upperbound = upper ? upper->toInteger() : dim;
int lowerbound = lower ? lower->toInteger() : 0;
- if (((int)lowerbound < 0) || (upperbound > dim))
+ if (!assignmentToSlicedPointer && (((int)lowerbound < 0) || (upperbound > dim)))
{
error("Array bounds [0..%d] exceeded in slice [%d..%d]",
dim, lowerbound, upperbound);
return EXP_CANT_INTERPRET;
}
+ if (upperbound == lowerbound)
+ return newval;
Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis);
int firstIndex = lowerbound;
@@ -2982,7 +3566,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
*/
if (aggregate->op == TOKindex || aggregate->op == TOKdotvar ||
- aggregate->op == TOKslice)
+ aggregate->op == TOKslice || aggregate->op == TOKcall)
{
aggregate = aggregate->interpret(istate, ctfeNeedLvalue);
if (aggregate == EXP_CANT_INTERPRET)
@@ -3008,11 +3592,35 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
}
aggregate = sexpold->e1;
}
+ if (aggregate->type->toBasetype()->ty == Tpointer && aggregate->type->toBasetype()->nextOf()->ty != Tfunction)
+ { // Slicing a pointer --> change the bounds
+ aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue);
+ dinteger_t ofs;
+ aggregate = getAggregateFromPointer(aggregate, &ofs);
+ dinteger_t hi = upperbound + ofs;
+ firstIndex = lowerbound + ofs;
+ if (firstIndex < 0 || hi > dim)
+ {
+ error("slice [%d..%jd] exceeds memory block bounds [0..%jd]",
+ firstIndex, hi, dim);
+ return EXP_CANT_INTERPRET;
+ }
+ }
if (aggregate->op==TOKarrayliteral)
existingAE = (ArrayLiteralExp *)aggregate;
else if (aggregate->op==TOKstring)
existingSE = (StringExp *)aggregate;
+ if (!wantRef && newval->op == TOKslice)
+ {
+ newval = resolveSlice(newval);
+ if (newval == EXP_CANT_INTERPRET)
+ {
+ error("Compiler error: CTFE slice %s", toChars());
+ assert(0);
+ }
+ }
+
// For slice assignment, we check that the lengths match.
size_t srclen = 0;
if (newval->op == TOKarrayliteral)
@@ -3037,57 +3645,21 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
}
else if (newval->op == TOKstring && existingSE)
{
- StringExp * newstr = (StringExp *)newval;
- unsigned char *s = (unsigned char *)existingSE->string;
- size_t sz = existingSE->sz;
- assert(sz == ((StringExp *)newval)->sz);
- memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
+ sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, firstIndex);
return newval;
}
else if (newval->op == TOKstring && existingAE)
{ /* Mixed slice: it was initialized as an array literal of chars.
* Now a slice of it is being set with a string.
*/
- size_t newlen = ((StringExp *)newval)->len;
- size_t sz = ((StringExp *)newval)->sz;
- unsigned char *s = (unsigned char *)((StringExp *)newval)->string;
- Type *elemType = existingAE->type->nextOf();
- for (size_t j = 0; j < newlen; j++)
- {
- dinteger_t val;
- switch (sz)
- {
- case 1: val = s[j]; break;
- case 2: val = ((unsigned short *)s)[j]; break;
- case 4: val = ((unsigned *)s)[j]; break;
- default:
- assert(0);
- break;
- }
- existingAE->elements->data[j+firstIndex]
- = new IntegerExp(newval->loc, val, elemType);
- }
+ sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, firstIndex);
return newval;
}
else if (newval->op == TOKarrayliteral && existingSE)
{ /* Mixed slice: it was initialized as a string literal.
* Now a slice of it is being set with an array literal.
*/
- unsigned char *s = (unsigned char *)existingSE->string;
- ArrayLiteralExp *newae = (ArrayLiteralExp *)newval;
- for (size_t j = 0; j < newae->elements->dim; j++)
- {
- unsigned value = ((Expression *)(newae->elements->data[j]))->toInteger();
- switch (existingSE->sz)
- {
- case 1: s[j+firstIndex] = value; break;
- case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
- case 4: ((unsigned *)s)[j+firstIndex] = value; break;
- default:
- assert(0);
- break;
- }
- }
+ sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, firstIndex);
return newval;
}
else if (existingSE)
@@ -3131,13 +3703,20 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
Type *desttype = ((TypeArray *)existingAE->type)->next;
bool directblk = (e2->type->toBasetype()) == desttype;
#endif
+ bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral
+ || newval->op == TOKstring);
for (size_t j = 0; j < upperbound-lowerbound; j++)
{
if (!directblk)
// Multidimensional array block assign
- recursiveBlockAssign((ArrayLiteralExp *)w->data[j+firstIndex], newval);
+ recursiveBlockAssign((ArrayLiteralExp *)w->data[j+firstIndex], newval, wantRef);
else
- existingAE->elements->data[j+firstIndex] = newval;
+ {
+ if (wantRef || cow)
+ existingAE->elements->data[j+firstIndex] = newval;
+ else
+ assignInPlace((Expression *)existingAE->elements->data[j+firstIndex], newval);
+ }
}
if (goal == ctfeNeedNothing)
return NULL; // avoid creating an unused literal
@@ -3150,40 +3729,6 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
else
error("Slice operation %s cannot be evaluated at compile time", toChars());
}
- else if (e1->op == TOKstar)
- {
- /* Assignment to struct member of the form:
- * *(symoffexp) = newval
- */
- if (((PtrExp *)e1)->e1->op == TOKsymoff)
- { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1;
- VarDeclaration *v = soe->var->isVarDeclaration();
- if (v->isDataseg() && !v->isCTFE())
- {
- error("%s cannot be modified at compile time", v->toChars());
- return EXP_CANT_INTERPRET;
- }
- if (fp && !v->getValue())
- { error("variable %s is used before initialization", v->toChars());
- return e;
- }
- Expression *vie = v->getValue();
- if (vie->op == TOKvar)
- {
- Declaration *d = ((VarExp *)vie)->var;
- vie = getVarExp(e1->loc, istate, d, ctfeNeedRvalue);
- }
- if (vie->op != TOKstructliteral)
- return EXP_CANT_INTERPRET;
-
- StructLiteralExp *se = (StructLiteralExp *)vie;
-
- newval = modifyStructField(type, se, soe->offset, newval);
-
- addVarToInterstate(istate, v);
- v->setRefValue(newval);
- }
- }
else
{
error("%s cannot be evaluated at compile time", toChars());
@@ -3191,7 +3736,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
dump(0);
#endif
}
- return e;
+ return returnValue;
}
Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal)
@@ -3394,6 +3939,14 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
pthis = istate ? istate->localThis : NULL;
else if (pthis->op == TOKcomma)
pthis = pthis->interpret(istate);
+ if (pthis == EXP_CANT_INTERPRET)
+ return NULL;
+ // Evaluate 'this'
+ if (pthis->op != TOKvar)
+ pthis = pthis->interpret(istate, ctfeNeedLvalue);
+ if (pthis == EXP_CANT_INTERPRET)
+ return NULL;
+
if (!fd->fbody)
{
error("%s cannot be interpreted at compile time,"
@@ -3447,7 +4000,10 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
e = e->interpret(istate);
if (e != EXP_CANT_INTERPRET)
{
+ if (e->op == TOKslice)
+ e= resolveSlice(e);
e = expType(type, e);
+ e = copyLiteral(e);
}
}
else
@@ -3494,7 +4050,8 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal)
// If the comma returns a temporary variable, it needs to be an lvalue
// (this is particularly important for struct constructors)
if (e1->op == TOKdeclaration && e2->op == TOKvar
- && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var)
+ && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var
+ && ((VarExp*)e2)->var->storage_class & STCctfe) // same as Expression::isTemp
{
VarExp* ve = (VarExp *)e2;
VarDeclaration *v = ve->var->isVarDeclaration();
@@ -3515,11 +4072,13 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal)
v->setValueWithoutChecking(copyLiteral(newval));
}
}
- return e2;
+ if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef)
+ return e2;
+ return e2->interpret(istate, goal);
}
- Expression *e = e1->interpret(istate);
+ Expression *e = e1->interpret(istate, ctfeNeedNothing);
if (e != EXP_CANT_INTERPRET)
- e = e2->interpret(istate);
+ e = e2->interpret(istate, goal);
return e;
}
@@ -3528,15 +4087,29 @@ Expression *CondExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("CondExp::interpret() %s\n", toChars());
#endif
- Expression *e = econd->interpret(istate);
+ Expression *e;
+ if (econd->type->ty == Tpointer && econd->type->nextOf()->ty != Tfunction)
+ {
+ e = econd->interpret(istate, ctfeNeedLvalue);
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ if (e->op != TOKnull)
+ e = new IntegerExp(loc, 1, Type::tbool);
+ }
+ else
+ e = econd->interpret(istate);
if (e != EXP_CANT_INTERPRET)
{
if (e->isBool(TRUE))
- e = e1->interpret(istate);
+ e = e1->interpret(istate, goal);
else if (e->isBool(FALSE))
- e = e2->interpret(istate);
+ e = e2->interpret(istate, goal);
else
+ {
+ error("%s does not evaluate to boolean result at compile time",
+ econd->toChars());
e = EXP_CANT_INTERPRET;
+ }
}
return e;
}
@@ -3551,59 +4124,81 @@ Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal)
e1 = this->e1->interpret(istate);
assert(e1);
if (e1 == EXP_CANT_INTERPRET)
- goto Lcant;
- if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
+ return EXP_CANT_INTERPRET;
+ if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice
+ || e1->op == TOKassocarrayliteral || e1->op == TOKnull)
{
- e = ArrayLength(type, e1);
- }
- else if (e1->op == TOKnull)
- {
- e = new IntegerExp(loc, 0, type);
+ e = new IntegerExp(loc, resolveArrayLength(e1), type);
}
else
- goto Lcant;
+ {
+ error("%s cannot be evaluated at compile time", toChars());
+ return EXP_CANT_INTERPRET;
+ }
return e;
+}
-Lcant:
- return EXP_CANT_INTERPRET;
+/* Given an AA literal 'ae', and a key 'e2':
+ * Return ae[e2] if present, or NULL if not found.
+ * Return EXP_CANT_INTERPRET on error.
+ */
+Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2)
+{
+ /* Search the keys backwards, in case there are duplicate keys
+ */
+ for (size_t i = ae->keys->dim; i;)
+ {
+ i--;
+ Expression *ekey = (Expression *)ae->keys->data[i];
+ Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
+ if (ex == EXP_CANT_INTERPRET)
+ {
+ error("cannot evaluate %s==%s at compile time",
+ ekey->toChars(), e2->toChars());
+ return ex;
+ }
+ if (ex->isBool(TRUE))
+ {
+ return (Expression *)ae->values->data[i];
+ }
+ }
+ return NULL;
}
Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal)
-{ Expression *e;
- Expression *e1;
+{
+ Expression *e1 = NULL;
Expression *e2;
#if LOG
printf("IndexExp::interpret() %s\n", toChars());
#endif
- e1 = this->e1->interpret(istate, goal);
+
+ e1 = this->e1->interpret(istate);
if (e1 == EXP_CANT_INTERPRET)
- goto Lcant;
+ return EXP_CANT_INTERPRET;
if (e1->op == TOKnull)
{
error("cannot index null array %s", this->e1->toChars());
return EXP_CANT_INTERPRET;
}
-
- if (e1->op == TOKstring || e1->op == TOKarrayliteral)
+ /* Set the $ variable.
+ * Note that foreach uses indexing but doesn't need $
+ */
+ if (lengthVar && (e1->op == TOKstring || e1->op == TOKarrayliteral
+ || e1->op == TOKslice))
{
- /* Set the $ variable
- */
- e = ArrayLength(Type::tsize_t, e1);
- if (e == EXP_CANT_INTERPRET)
- goto Lcant;
- if (lengthVar)
- {
- lengthVar->createStackValue(e);
- }
+ uinteger_t dollar = resolveArrayLength(e1);
+ Expression *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t);
+ lengthVar->createStackValue(dollarExp);
}
e2 = this->e2->interpret(istate);
if (lengthVar)
lengthVar->setValueNull(); // $ is defined only inside []
if (e2 == EXP_CANT_INTERPRET)
- goto Lcant;
+ return EXP_CANT_INTERPRET;
if (e1->op == TOKslice && e2->op == TOKint64)
{
// Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
@@ -3614,24 +4209,53 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal)
if (indx > iup - ilo)
{
error("index %ju exceeds array length %ju", indx, iup - ilo);
- goto Lcant;
+ return EXP_CANT_INTERPRET;
}
indx += ilo;
e1 = ((SliceExp *)e1)->e1;
e2 = new IntegerExp(e2->loc, indx, e2->type);
}
- e = Index(type, e1, e2);
+ Expression *e = NULL;
+ if ((goal == ctfeNeedLvalue && type->ty != Taarray && type->ty != Tarray
+ && type->ty != Tsarray && type->ty != Tstruct && type->ty != Tclass)
+ || (goal == ctfeNeedLvalueRef && type->ty != Tsarray && type->ty != Tstruct)
+ )
+ { // Pointer or reference of a scalar type
+ e = new IndexExp(loc, e1, e2);
+ e->type = type;
+ return e;
+ }
+ if (e1->op == TOKassocarrayliteral)
+ {
+ e = findKeyInAA((AssocArrayLiteralExp *)e1, e2);
+ if (!e)
+ {
+ error("key %s not found in associative array %s",
+ e2->toChars(), this->e1->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ assert(!e->checkSideEffect(2));
+ e = paintTypeOntoLiteral(type, e);
+ }
+ else
+ {
+ e = Index(type, e1, e2);
+ }
if (e == EXP_CANT_INTERPRET)
+ {
error("%s cannot be interpreted at compile time", toChars());
+ return e;
+ }
+ if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar))
+ e = e->interpret(istate);
return e;
-
-Lcant:
- return EXP_CANT_INTERPRET;
}
Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
-{ Expression *e;
+{
Expression *e1;
Expression *lwr;
Expression *upr;
@@ -3639,51 +4263,103 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("SliceExp::interpret() %s\n", toChars());
#endif
- e1 = this->e1->interpret(istate, goal);
+
+ if (this->e1->type->toBasetype()->ty == Tpointer)
+ {
+ // Slicing a pointer. Note that there is no $ in this case.
+ e1 = this->e1->interpret(istate);
+ if (e1 == EXP_CANT_INTERPRET)
+ return EXP_CANT_INTERPRET;
+
+ /* Evaluate lower and upper bounds of slice
+ */
+ lwr = this->lwr->interpret(istate);
+ if (lwr == EXP_CANT_INTERPRET)
+ return EXP_CANT_INTERPRET;
+ upr = this->upr->interpret(istate);
+ if (upr == EXP_CANT_INTERPRET)
+ return EXP_CANT_INTERPRET;
+ uinteger_t ilwr;
+ uinteger_t iupr;
+ ilwr = lwr->toInteger();
+ iupr = upr->toInteger();
+ Expression *e;
+ dinteger_t ofs;
+ Expression *agg = getAggregateFromPointer(e1, &ofs);
+ if (agg->op == TOKnull)
+ {
+ if (iupr == ilwr)
+ {
+ IntegerExp * zero = new IntegerExp(loc, 0, Type::tsize_t);
+ e = new SliceExp(loc, agg, zero, zero);
+ e->type = type;
+ return e;
+ }
+ error("cannot slice null pointer %s", this->e1->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ assert(agg->op == TOKarrayliteral || agg->op == TOKstring);
+ dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger();
+ Type *pointee = ((TypePointer *)agg->type)->next;
+ if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr)
+ {
+ error("pointer slice [%jd..%jd] exceeds allocated memory block [0..%jd]",
+ ilwr+ofs, iupr+ofs, len);
+ return EXP_CANT_INTERPRET;
+ }
+ e = new SliceExp(loc, agg, lwr, upr);
+ e->type = type;
+ return e;
+ }
+ if (goal == ctfeNeedRvalue && this->e1->op == TOKstring)
+ e1 = this->e1; // Will get duplicated anyway
+ else
+ e1 = this->e1->interpret(istate, goal);
if (e1 == EXP_CANT_INTERPRET)
- goto Lcant;
+ return EXP_CANT_INTERPRET;
+ if (e1->op == TOKvar)
+ e1 = e1->interpret(istate);
if (!this->lwr)
{
- if (goal == ctfeNeedLvalue)
+ if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef)
return e1;
- e = e1->castTo(NULL, type);
+ Expression *e = e1->castTo(NULL, type);
return e->interpret(istate);
}
/* Set the $ variable
*/
- if (e1->op == TOKnull)
- e = new IntegerExp(0, 0, Type::tsize_t);
- else if (e1->op == TOKslice)
- {
- // For lvalue slices, slice ends have already been calculated
- e = new IntegerExp(0, ((SliceExp *)e1)->upr->toInteger()
- - ((SliceExp *)e1)->lwr->toInteger(), Type::tsize_t);
- }
- else
- e = ArrayLength(Type::tsize_t, e1);
- if (e == EXP_CANT_INTERPRET)
+ if (e1->op != TOKarrayliteral && e1->op != TOKstring &&
+ e1->op != TOKnull && e1->op != TOKslice)
{
error("Cannot determine length of %s at compile time\n", e1->toChars());
- goto Lcant;
+ return EXP_CANT_INTERPRET;
}
+ uinteger_t dollar = resolveArrayLength(e1);
if (lengthVar)
- lengthVar->createStackValue(e);
+ {
+ IntegerExp *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t);
+ lengthVar->createStackValue(dollarExp);
+ }
/* Evaluate lower and upper bounds of slice
*/
lwr = this->lwr->interpret(istate);
- if (lwr == EXP_CANT_INTERPRET)
- goto Lcant;
- upr = this->upr->interpret(istate);
- if (upr == EXP_CANT_INTERPRET)
- goto Lcant;
+ if (lwr != EXP_CANT_INTERPRET)
+ upr = this->upr->interpret(istate);
if (lengthVar)
lengthVar->setValueNull(); // $ is defined only inside [L..U]
+ if (lwr == EXP_CANT_INTERPRET || upr == EXP_CANT_INTERPRET)
{
- uinteger_t ilwr = lwr->toInteger();
- uinteger_t iupr = upr->toInteger();
+ return EXP_CANT_INTERPRET;
+ }
+
+ Expression *e;
+ uinteger_t ilwr;
+ uinteger_t iupr;
+ ilwr = lwr->toInteger();
+ iupr = upr->toInteger();
if (e1->op == TOKnull)
{
if (ilwr== 0 && iupr == 0)
@@ -3691,45 +4367,70 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
e1->error("slice [%ju..%ju] is out of bounds", ilwr, iupr);
return EXP_CANT_INTERPRET;
}
- if (goal == ctfeNeedLvalue)
+ if (e1->op == TOKslice)
{
- if (e1->op == TOKslice)
+ SliceExp *se = (SliceExp *)e1;
+ // Simplify slice of slice:
+ // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
+ uinteger_t lo1 = se->lwr->toInteger();
+ uinteger_t up1 = se->upr->toInteger();
+ if (ilwr > iupr || iupr > up1 - lo1)
{
- SliceExp *se = (SliceExp *)e1;
- // Simplify slice of slice:
- // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
- uinteger_t lo1 = se->lwr->toInteger();
- uinteger_t up1 = se->upr->toInteger();
- if (ilwr > iupr || iupr > up1 - lo1)
- {
- error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]",
- ilwr, iupr, lo1, up1);
- goto Lcant;
- }
- ilwr += lo1;
- iupr += lo1;
- e = new SliceExp(loc, se->e1,
- new IntegerExp(loc, ilwr, lwr->type),
- new IntegerExp(loc, iupr, upr->type));
- e->type = type;
- return e;
+ error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]",
+ ilwr, iupr, lo1, up1);
+ return EXP_CANT_INTERPRET;
}
- e = new SliceExp(loc, e1, lwr, upr);
+ ilwr += lo1;
+ iupr += lo1;
+ e = new SliceExp(loc, se->e1,
+ new IntegerExp(loc, ilwr, lwr->type),
+ new IntegerExp(loc, iupr, upr->type));
e->type = type;
return e;
}
- e = Slice(type, e1, lwr, upr);
- if (e == EXP_CANT_INTERPRET)
- error("%s cannot be interpreted at compile time", toChars());
+ if (e1->op == TOKarrayliteral
+ || e1->op == TOKstring)
+ {
+ if (iupr < ilwr || ilwr < 0 || iupr > dollar)
+ {
+ error("slice [%jd..%jd] exceeds array bounds [0..%jd]",
+ ilwr, iupr, dollar);
+ return EXP_CANT_INTERPRET;
+ }
}
+ e = new SliceExp(loc, e1, lwr, upr);
+ e->type = type;
return e;
-
-Lcant:
- if (lengthVar)
- lengthVar->setValueNull();
- return EXP_CANT_INTERPRET;
}
+Expression *InExp::interpret(InterState *istate, CtfeGoal goal)
+{ Expression *e = EXP_CANT_INTERPRET;
+
+#if LOG
+ printf("InExp::interpret() %s\n", toChars());
+#endif
+ Expression *e1 = this->e1->interpret(istate);
+ if (e1 == EXP_CANT_INTERPRET)
+ return e1;
+ Expression *e2 = this->e2->interpret(istate);
+ if (e2 == EXP_CANT_INTERPRET)
+ return e2;
+ if (e2->op == TOKnull)
+ return new NullExp(loc, type);
+ if (e2->op != TOKassocarrayliteral)
+ {
+ error(" %s cannot be interpreted at compile time", toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ e = findKeyInAA((AssocArrayLiteralExp *)e2, e1);
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ if (!e)
+ return new NullExp(loc, type);
+ e = new IndexExp(loc, e2, e1);
+ e->type = type;
+ return e;
+}
Expression *CatExp::interpret(InterState *istate, CtfeGoal goal)
{ Expression *e;
@@ -3744,9 +4445,15 @@ Expression *CatExp::interpret(InterState *istate, CtfeGoal goal)
{
goto Lcant;
}
+ if (e1->op == TOKslice)
+ {
+ e1 = resolveSlice(e1);
+ }
e2 = this->e2->interpret(istate);
if (e2 == EXP_CANT_INTERPRET)
goto Lcant;
+ if (e2->op == TOKslice)
+ e2 = resolveSlice(e2);
e = Cat(type, e1, e2);
if (e == EXP_CANT_INTERPRET)
error("%s cannot be interpreted at compile time", toChars());
@@ -3767,9 +4474,63 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("CastExp::interpret() %s\n", toChars());
#endif
- e1 = this->e1->interpret(istate);
+ e1 = this->e1->interpret(istate, goal);
if (e1 == EXP_CANT_INTERPRET)
goto Lcant;
+ if (to->ty == Tpointer && e1->op != TOKnull)
+ { // Deal with casts from char[] to char *
+ if (e1->op == TOKslice)
+ {
+ if ( ((SliceExp *)e1)->e1->op == TOKnull)
+ {
+ return paintTypeOntoLiteral(type, ((SliceExp *)e1)->e1);
+ }
+ e = new IndexExp(loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr);
+ e->type = type;
+ return e;
+ }
+ if (e1->op == TOKarrayliteral)
+ {
+ e = new IndexExp(loc, e1, new IntegerExp(loc, 0, Type::tsize_t));
+ e->type = type;
+ return e;
+ }
+ if (e1->op == TOKstring)
+ {
+ return e1;
+ }
+ }
+ if (to->ty == Tarray && e1->op == TOKslice)
+ {
+ e1 = new SliceExp(e1->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr,
+ ((SliceExp *)e1)->upr);
+ e1->type = to;
+ return e1;
+ }
+ // Disallow array type painting, except for conversions between built-in
+ // types of identical size.
+ if ((to->ty == Tsarray || to->ty == Tarray) &&
+ (e1->type->ty == Tsarray || e1->type->ty == Tarray) &&
+#if DMDV2
+ e1->type->nextOf()->castMod(0) != to->nextOf()->castMod(0)
+#else
+ e1->type->nextOf() != to->nextOf()
+#endif
+ && !(to->nextOf()->isTypeBasic() && e1->type->nextOf()->isTypeBasic()
+ && to->nextOf()->size() == e1->type->nextOf()->size()) )
+ {
+ error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), to->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ if (to->ty == Tsarray && e1->op == TOKslice)
+ e1 = resolveSlice(e1);
+ if (to->toBasetype()->ty == Tbool && e1->type->ty==Tpointer)
+ {
+ return new IntegerExp(loc, e1->op != TOKnull, to);
+ }
+ if (e1->op == TOKnull)
+ return paintTypeOntoLiteral(to, e1);
+
e = Cast(type, to, e1);
if (e == EXP_CANT_INTERPRET)
error("%s cannot be interpreted at compile time", toChars());
@@ -3790,16 +4551,6 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("AssertExp::interpret() %s\n", toChars());
#endif
- if( this->e1->op == TOKaddress)
- { // Special case: deal with compiler-inserted assert(&this, "null this")
- AddrExp *ade = (AddrExp *)this->e1;
- if (ade->e1->op == TOKthis && istate->localThis)
- if (istate->localThis->op == TOKdotvar
- && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis)
- return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var, ctfeNeedRvalue);
- else
- return istate->localThis->interpret(istate);
- }
if (this->e1->op == TOKthis)
{
if (istate->localThis)
@@ -3811,10 +4562,20 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal)
return istate->localThis->interpret(istate);
}
}
- e1 = this->e1->interpret(istate);
+ // Deal with pointers (including compiler-inserted assert(&this, "null this"))
+ if (this->e1->type->ty == Tpointer && this->e1->type->nextOf()->ty != Tfunction)
+ {
+ e1 = this->e1->interpret(istate, ctfeNeedLvalue);
+ if (e1 == EXP_CANT_INTERPRET)
+ goto Lcant;
+ if (e1->op != TOKnull)
+ return new IntegerExp(loc, 1, Type::tbool);
+ }
+ else
+ e1 = this->e1->interpret(istate);
if (e1 == EXP_CANT_INTERPRET)
goto Lcant;
- if (e1->isBool(TRUE))
+ if ((this->e1->op == TOKaddress && e1->op != TOKnull) || e1->isBool(TRUE))
{
}
else if (e1->isBool(FALSE))
@@ -3831,7 +4592,10 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal)
goto Lcant;
}
else
+ {
+ error("%s is not a compile-time boolean expression", e1->toChars());
goto Lcant;
+ }
return e1;
Lcant:
@@ -3844,7 +4608,6 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("PtrExp::interpret() %s\n", toChars());
#endif
-
// Constant fold *(&structliteral + offset)
if (e1->op == TOKadd)
{ AddExp *ae = (AddExp *)e1;
@@ -3866,19 +4629,6 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal)
}
e = Ptr(type, e1);
}
- else if (e1->op == TOKsymoff)
- { SymOffExp *soe = (SymOffExp *)e1;
- VarDeclaration *v = soe->var->isVarDeclaration();
- if (v)
- { Expression *ev = getVarExp(loc, istate, v, ctfeNeedLvalue);
- if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral)
- { StructLiteralExp *se = (StructLiteralExp *)ev;
- e = se->getField(type, soe->offset);
- if (!e)
- e = EXP_CANT_INTERPRET;
- }
- }
- }
#if DMDV2
#else // this is required for D1, where structs return *this instead of 'this'.
else if (e1->op == TOKthis)
@@ -3888,7 +4638,53 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal)
}
#endif
else
- error("Cannot interpret %s at compile time", toChars());
+ { // It's possible we have an array bounds error. We need to make sure it
+ // errors with this line number, not the one where the pointer was set.
+ e = e1->interpret(istate, ctfeNeedLvalue);
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ if (e->op == TOKaddress)
+ e = ((AddrExp*)e)->e1;
+ if (goal != ctfeNeedLvalue)
+ {
+ if (e->op == TOKindex && e->type->ty == Tpointer)
+ {
+ IndexExp *ie = (IndexExp *)e;
+ if ((ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring)
+ && ie->e2->op == TOKint64)
+ {
+ Expression *dollar = ArrayLength(Type::tsize_t, ie->e1);
+ dinteger_t len = dollar->toInteger();
+ dinteger_t indx = ie->e2->toInteger();
+ assert(indx >=0 && indx <= len); // invalid pointer
+ if (indx == len)
+ {
+ error("dereference of pointer %s one past end of memory block limits [0..%jd]",
+ toChars(), len);
+ return EXP_CANT_INTERPRET;
+ }
+ return Index(type, ie->e1, ie->e2);
+ }
+ }
+ if (e->op == TOKstructliteral)
+ return e;
+ e = e1->interpret(istate, goal);
+ if (e->op == TOKaddress)
+ {
+ e = ((AddrExp*)e)->e1;
+ if (e->op == TOKdotvar || e->op == TOKindex)
+ e = e->interpret(istate, goal);
+ }
+ if (e == EXP_CANT_INTERPRET)
+ return e;
+ e->type = type;
+ }
+ if (e->op == TOKnull)
+ {
+ error("dereference of null pointer '%s'", e1->toChars());
+ return EXP_CANT_INTERPRET;
+ }
+ }
#if LOG
if (e == EXP_CANT_INTERPRET)
@@ -3907,12 +4703,14 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal)
Expression *ex = e1->interpret(istate);
if (ex != EXP_CANT_INTERPRET)
{
+ if (ex->op == TOKaddress)
+ ex = ((AddrExp *)ex)->e1;
if (ex->op == TOKstructliteral)
{ StructLiteralExp *se = (StructLiteralExp *)ex;
VarDeclaration *v = var->isVarDeclaration();
if (v)
{
- if (goal == ctfeNeedLvalue)
+ if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef)
{
// We can't use getField, because it makes a copy
int i = se->getFieldIndex(type, v->offset);
@@ -3923,12 +4721,24 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal)
}
e = (Expression *)se->elements->data[i];
// If it is an lvalue literal, return it...
- if (e->op == TOKstructliteral || e->op == TOKarrayliteral ||
+ if (e->op == TOKstructliteral)
+ return e;
+ if ((type->ty == Tsarray || goal == ctfeNeedLvalue) && (
+ e->op == TOKarrayliteral ||
e->op == TOKassocarrayliteral || e->op == TOKstring ||
- e->op == TOKslice)
+ e->op == TOKslice))
+ return e;
+ /* Element is an allocated pointer, which was created in
+ * CastExp.
+ */
+ if (goal == ctfeNeedLvalue && e->op == TOKindex &&
+ e->type == type &&
+ (type->ty == Tpointer && type->nextOf()->ty != Tfunction))
return e;
// ...Otherwise, just return the (simplified) dotvar expression
- return new DotVarExp(loc, ex, v);
+ e = new DotVarExp(loc, ex, v);
+ e->type = type;
+ return e;
}
e = se->getField(type, v->offset);
if (!e)
@@ -3936,7 +4746,16 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal)
error("couldn't find field %s in %s", v->toChars(), type->toChars());
e = EXP_CANT_INTERPRET;
}
- return e;
+ // If it is an rvalue literal, return it...
+ if (e->op == TOKstructliteral || e->op == TOKarrayliteral ||
+ e->op == TOKassocarrayliteral || e->op == TOKstring)
+ return e;
+ if (type->ty == Tpointer && type->nextOf()->ty != Tfunction)
+ {
+ assert(e->type == type);
+ return e;
+ }
+ return e->interpret(istate, goal);
}
}
else
@@ -3980,15 +4799,15 @@ Expression *interpret_aaKeys(InterState *istate, Expressions *arguments)
earg = earg->interpret(istate);
if (earg == EXP_CANT_INTERPRET)
return NULL;
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
if (earg->op == TOKnull)
return new NullExp(earg->loc);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
Expression *e = new ArrayLiteralExp(aae->loc, aae->keys);
Type *elemType = ((TypeAArray *)aae->type)->index;
e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0));
- return e;
+ return copyLiteral(e);
}
Expression *interpret_aaValues(InterState *istate, Expressions *arguments)
@@ -4002,16 +4821,16 @@ Expression *interpret_aaValues(InterState *istate, Expressions *arguments)
earg = earg->interpret(istate);
if (earg == EXP_CANT_INTERPRET)
return NULL;
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
if (earg->op == TOKnull)
return new NullExp(earg->loc);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
Expression *e = new ArrayLiteralExp(aae->loc, aae->values);
Type *elemType = ((TypeAArray *)aae->type)->next;
e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0));
- printf("result is %s\n", e->toChars());
- return e;
+ //printf("result is %s\n", e->toChars());
+ return copyLiteral(e);
}
#endif
@@ -4039,10 +4858,10 @@ Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration
earg = earg->interpret(istate);
if (earg == EXP_CANT_INTERPRET)
return NULL;
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
if (earg->op == TOKnull)
return new NullExp(earg->loc);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
assert(earg->op == TOKassocarrayliteral);
AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
Expression *e = new ArrayLiteralExp(aae->loc, aae->keys);
@@ -4050,7 +4869,7 @@ Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration
assert(fd->type->nextOf()->ty == Tarray);
Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf();
e->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim));
- return e;
+ return copyLiteral(e);
}
Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd)
@@ -4061,10 +4880,10 @@ Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclarati
earg = earg->interpret(istate);
if (earg == EXP_CANT_INTERPRET)
return NULL;
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
if (earg->op == TOKnull)
return new NullExp(earg->loc);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
assert(earg->op == TOKassocarrayliteral);
AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
Expression *e = new ArrayLiteralExp(aae->loc, aae->values);
@@ -4073,7 +4892,7 @@ Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclarati
Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf();
e->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim));
//printf("result is %s\n", e->toChars());
- return e;
+ return copyLiteral(e);
}
#endif
@@ -4084,14 +4903,55 @@ Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclarati
bool isStackValueValid(Expression *newval)
{
+ if (newval->type->ty == Tpointer && newval->type->nextOf()->ty != Tfunction)
+ {
+ if (newval->op == TOKaddress || newval->op == TOKnull ||
+ newval->op == TOKstring)
+ return true;
+ if (newval->op == TOKindex)
+ {
+ Expression *g = ((IndexExp *)newval)->e1;
+ if (g->op == TOKarrayliteral || g->op == TOKstring ||
+ g->op == TOKassocarrayliteral)
+ return true;
+ }
+ if (newval->op == TOKvar)
+ return true;
+ newval->error("CTFE internal error: illegal pointer value %s\n", newval->toChars());
+ return false;
+ }
if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) ||
(newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) ||
(newval->op == TOKnull) || (newval->op == TOKslice))
{ return false;
}
- if (newval->op == TOKvar) return true;
- if (newval->op == TOKdotvar) return true;
- if (newval->op == TOKindex) return true;
+ if (newval->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)newval;
+ VarDeclaration *vv = ve->var->isVarDeclaration();
+ // Must not be a reference to a reference
+ if (!(vv && vv->getValue() && vv->getValue()->op == TOKvar))
+ return true;
+ }
+ if (newval->op == TOKdotvar)
+ {
+ if (((DotVarExp *)newval)->e1->op == TOKstructliteral)
+ return true;
+ }
+ if (newval->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)newval;
+ if (ie->e2->op == TOKint64)
+ {
+ if (ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring)
+ return true;
+ }
+ if (ie->e1->op == TOKassocarrayliteral)
+ return true;
+ // BUG: Happens ONLY in ref foreach. Should tighten this.
+ if (ie->e2->op == TOKvar)
+ return true;
+ }
if (newval->op == TOKfunction) return true; // function/delegate literal
if (newval->op == TOKdelegate) return true;
if (newval->op == TOKsymoff) // function pointer
@@ -4122,11 +4982,17 @@ bool isRefValueValid(Expression *newval)
(newval->op == TOKnull))
{ return true;
}
+ // Dynamic arrays passed by ref may be null. When this happens
+ // they may originate from an index or dotvar expression.
+ if (newval->type->ty == Tarray || newval->type->ty == Taarray
+ || newval->type->ty == Tclass)
+ if (newval->op == TOKdotvar || newval->op == TOKindex)
+ return isStackValueValid(newval); // actually must be null
if (newval->op == TOKslice)
{
SliceExp *se = (SliceExp *)newval;
- assert(se->lwr && se->lwr != EXP_CANT_INTERPRET);
- assert(se->upr && se->upr != EXP_CANT_INTERPRET);
+ assert(se->lwr && se->lwr != EXP_CANT_INTERPRET && se->lwr->op == TOKint64);
+ assert(se->upr && se->upr != EXP_CANT_INTERPRET && se->upr->op == TOKint64);
assert(se->e1->op == TOKarrayliteral || se->e1->op == TOKstring);
return true;
}
diff --git a/dmd2/intrange.c b/dmd2/intrange.c
new file mode 100644
index 00000000..12128ca2
--- /dev/null
+++ b/dmd2/intrange.c
@@ -0,0 +1,1105 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2011 by Digital Mars
+// All Rights Reserved
+// written by KennyTM
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include "intrange.h"
+#include "mars.h"
+#include "mtype.h"
+#include "expression.h"
+
+#ifndef PERFORM_UNITTEST
+#define PERFORM_UNITTEST 0
+#endif
+
+// Copy the sign to the value *x*. Equivalent to `sign ? -x : x`.
+static uinteger_t copySign(uinteger_t x, bool sign)
+{
+ // return sign ? -x : x;
+ return (x - sign) ^ -sign;
+}
+
+#ifndef UINT64_MAX
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
+#endif
+
+//==================== SignExtendedNumber ======================================
+
+SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_)
+{
+ return SignExtendedNumber(value_, value_ >> 63);
+}
+
+bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const
+{
+ return value == a.value && negative == a.negative;
+}
+
+bool SignExtendedNumber::operator<(const SignExtendedNumber& a) const
+{
+ return (negative && !a.negative)
+ || (negative == a.negative && value < a.value);
+}
+
+SignExtendedNumber SignExtendedNumber::extreme(bool minimum)
+{
+ return SignExtendedNumber(minimum-1, minimum);
+}
+
+SignExtendedNumber SignExtendedNumber::max()
+{
+ return SignExtendedNumber(UINT64_MAX, false);
+}
+
+SignExtendedNumber SignExtendedNumber::operator-() const
+{
+ if (value == 0)
+ return SignExtendedNumber(-negative);
+ else
+ return SignExtendedNumber(-value, !negative);
+}
+
+SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const
+{
+ uinteger_t sum = value + a.value;
+ bool carry = sum < value && sum < a.value;
+ if (negative != a.negative)
+ return SignExtendedNumber(sum, !carry);
+ else if (negative)
+ return SignExtendedNumber(carry ? sum : 0, true);
+ else
+ return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
+}
+
+SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
+{
+ if (a.isMinimum())
+ return negative ? SignExtendedNumber(value, false) : max();
+ else
+ return *this + (-a);
+}
+
+
+SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
+{
+ // perform *saturated* multiplication, otherwise we may get bogus ranges
+ // like 0x10 * 0x10 == 0x100 == 0.
+
+ /* Special handling for zeros:
+ INT65_MIN * 0 = 0
+ INT65_MIN * + = INT65_MIN
+ INT65_MIN * - = INT65_MAX
+ 0 * anything = 0
+ */
+ if (value == 0)
+ {
+ if (!negative)
+ return *this;
+ else if (a.negative)
+ return max();
+ else
+ return a.value == 0 ? a : *this;
+ }
+ else if (a.value == 0)
+ return a * *this; // don't duplicate the symmetric case.
+
+ SignExtendedNumber rv;
+ // these are != 0 now surely.
+ uinteger_t tAbs = copySign(value, negative);
+ uinteger_t aAbs = copySign(a.value, a.negative);
+ rv.negative = negative != a.negative;
+ if (UINT64_MAX / tAbs < aAbs)
+ rv.value = rv.negative-1;
+ else
+ rv.value = copySign(tAbs * aAbs, rv.negative);
+ return rv;
+}
+
+SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const
+{
+ /* special handling for zeros:
+ INT65_MIN / INT65_MIN = 1
+ anything / INT65_MIN = 0
+ + / 0 = INT65_MAX (eh?)
+ - / 0 = INT65_MIN (eh?)
+ */
+ if (a.value == 0)
+ {
+ if (a.negative)
+ return SignExtendedNumber(value == 0 && negative);
+ else
+ return extreme(negative);
+ }
+
+ uinteger_t aAbs = copySign(a.value, a.negative);
+ uinteger_t rvVal;
+
+ if (!isMinimum())
+ rvVal = copySign(value, negative) / aAbs;
+ // Special handling for INT65_MIN
+ // if the denominator is not a power of 2, it is same as UINT64_MAX / x.
+ else if (aAbs & (aAbs-1))
+ rvVal = UINT64_MAX / aAbs;
+ // otherwise, it's the same as reversing the bits of x.
+ else
+ {
+ if (aAbs == 1)
+ return extreme(!a.negative);
+ rvVal = 1ULL << 63;
+ aAbs >>= 1;
+ if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
+ if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2;
+ if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4;
+ if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8;
+ if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
+ if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
+ }
+ bool rvNeg = negative != a.negative;
+ rvVal = copySign(rvVal, rvNeg);
+
+ return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
+}
+
+SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const
+{
+ if (a.value == 0)
+ return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this;
+
+ uinteger_t aAbs = copySign(a.value, a.negative);
+ uinteger_t rvVal;
+
+ // a % b == sgn(a) * abs(a) % abs(b).
+ if (!isMinimum())
+ rvVal = copySign(value, negative) % aAbs;
+ // Special handling for INT65_MIN
+ // if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1.
+ else if (aAbs & (aAbs - 1))
+ rvVal = UINT64_MAX % aAbs + 1;
+ // otherwise, the modulus is trivially zero.
+ else
+ rvVal = 0;
+
+ rvVal = copySign(rvVal, negative);
+ return SignExtendedNumber(rvVal, rvVal != 0 && negative);
+}
+
+SignExtendedNumber& SignExtendedNumber::operator++()
+{
+ if (value != UINT64_MAX)
+ ++ value;
+ else if (negative)
+ {
+ value = 0;
+ negative = false;
+ }
+ return *this;
+}
+
+SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) const
+{
+ // assume left-shift the shift-amount is always unsigned. Thus negative
+ // shifts will give huge result.
+ if (value == 0)
+ return *this;
+ else if (a.negative)
+ return extreme(negative);
+
+ uinteger_t v = copySign(value, negative);
+
+ // compute base-2 log of 'v' to determine the maximum allowed bits to shift.
+ // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+
+ size_t r, s;
+
+ r = (v > 0xFFFFFFFFULL) << 5; v >>= r;
+ s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s;
+ s = (v > 0xFFULL ) << 3; v >>= s; r |= s;
+ s = (v > 0xFULL ) << 2; v >>= s; r |= s;
+ s = (v > 0x3ULL ) << 1; v >>= s; r |= s;
+ r |= (v >> 1);
+
+ uinteger_t allowableShift = 63 - r;
+ if (a.value > allowableShift)
+ return extreme(negative);
+ else
+ return SignExtendedNumber(value << a.value, negative);
+}
+
+SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
+{
+ if (a.negative || a.value > 64)
+ return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
+ else if (isMinimum())
+ return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
+
+ uinteger_t x = value ^ -negative;
+ x >>= a.value;
+ return SignExtendedNumber(x ^ -negative, negative);
+}
+
+
+//==================== IntRange ================================================
+
+IntRange IntRange::widest()
+{
+ return IntRange(SignExtendedNumber::min(), SignExtendedNumber::max());
+}
+
+#if !PERFORM_UNITTEST
+IntRange IntRange::fromType(Type *type)
+{
+ return fromType(type, type->isunsigned());
+}
+
+IntRange IntRange::fromType(Type *type, bool isUnsigned)
+{
+ if (!type->isintegral())
+ return widest();
+
+ uinteger_t mask = type->sizemask();
+ SignExtendedNumber lower(0), upper(mask);
+ if (type->toBasetype()->ty == Tdchar)
+ upper.value = 0x10FFFFULL;
+ else if (!isUnsigned)
+ {
+ lower.value = ~(mask >> 1);
+ lower.negative = true;
+ upper.value = (mask >> 1);
+ }
+ return IntRange(lower, upper);
+}
+#endif
+
+IntRange IntRange::fromNumbers2(const SignExtendedNumber numbers[2])
+{
+ if (numbers[0] < numbers[1])
+ return IntRange(numbers[0], numbers[1]);
+ else
+ return IntRange(numbers[1], numbers[0]);
+}
+IntRange IntRange::fromNumbers4(const SignExtendedNumber numbers[4])
+{
+ IntRange ab = fromNumbers2(numbers);
+ IntRange cd = fromNumbers2(numbers + 2);
+ if (cd.imin < ab.imin)
+ ab.imin = cd.imin;
+ if (cd.imax > ab.imax)
+ ab.imax = cd.imax;
+ return ab;
+}
+
+bool IntRange::contains(const IntRange& a) const
+{
+ return imin <= a.imin && imax >= a.imax;
+}
+
+bool IntRange::containsZero() const
+{
+ return (imin.negative && !imax.negative)
+ || (!imin.negative && imin.value == 0);
+}
+
+IntRange& IntRange::castUnsigned(uinteger_t mask)
+{
+ // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
+ //
+ // regular unsigned type. We just need to see if ir steps across the
+ // boundary of validRange. If yes, ir will represent the whole validRange,
+ // otherwise, we just take the modulus.
+ // e.g. [0x105, 0x107] & 0xff == [5, 7]
+ // [0x105, 0x207] & 0xff == [0, 0xff]
+ uinteger_t minChunk = imin.value & ~mask;
+ uinteger_t maxChunk = imax.value & ~mask;
+ if (minChunk == maxChunk && imin.negative == imax.negative)
+ {
+ imin.value &= mask;
+ imax.value &= mask;
+ }
+ else
+ {
+ imin.value = 0;
+ imax.value = mask;
+ }
+ imin.negative = imax.negative = false;
+ return *this;
+}
+
+IntRange& IntRange::castSigned(uinteger_t mask)
+{
+ // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
+ //
+ // regular signed type. We use a technique similar to the unsigned version,
+ // but the chunk has to be offset by 1/2 of the range.
+ uinteger_t halfChunkMask = mask >> 1;
+ uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
+ uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
+ int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
+ int maxHalfChunkNegativity = imax.negative;
+ if (minHalfChunk & mask)
+ {
+ minHalfChunk += halfChunkMask+1;
+ if (minHalfChunk == 0)
+ -- minHalfChunkNegativity;
+ }
+ if (maxHalfChunk & mask)
+ {
+ maxHalfChunk += halfChunkMask+1;
+ if (maxHalfChunk == 0)
+ -- maxHalfChunkNegativity;
+ }
+ if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
+ {
+ imin.value &= mask;
+ imax.value &= mask;
+ // sign extend if necessary.
+ imin.negative = imin.value & ~halfChunkMask;
+ imax.negative = imax.value & ~halfChunkMask;
+ halfChunkMask += 1;
+ imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
+ imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
+ }
+ else
+ {
+ imin = SignExtendedNumber(~halfChunkMask, true);
+ imax = SignExtendedNumber(halfChunkMask, false);
+ }
+ return *this;
+}
+
+IntRange& IntRange::castDchar()
+{
+ // special case for dchar. Casting to dchar means "I'll ignore all
+ // invalid characters."
+ castUnsigned(0xFFFFFFFFULL);
+ if (imin.value > 0x10FFFFULL) // ??
+ imin.value = 0x10FFFFULL; // ??
+ if (imax.value > 0x10FFFFULL)
+ imax.value = 0x10FFFFULL;
+ return *this;
+}
+
+#if !PERFORM_UNITTEST
+IntRange& IntRange::cast(Type *type)
+{
+ if (!type->isintegral())
+ return *this;
+ else if (!type->isunsigned())
+ return castSigned(type->sizemask());
+ else if (type->toBasetype()->ty == Tdchar)
+ return castDchar();
+ else
+ return castUnsigned(type->sizemask());
+}
+
+IntRange& IntRange::castUnsigned(Type *type)
+{
+ if (!type->isintegral())
+ return castUnsigned(UINT64_MAX);
+ else if (type->toBasetype()->ty == Tdchar)
+ return castDchar();
+ else
+ return castUnsigned(type->sizemask());
+}
+#endif
+
+IntRange IntRange::absNeg() const
+{
+ if (imax.negative)
+ return *this;
+ else if (!imin.negative)
+ return IntRange(-imax, -imin);
+ else
+ {
+ SignExtendedNumber imaxAbsNeg = -imax;
+ return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
+ SignExtendedNumber(0));
+ }
+}
+
+IntRange IntRange::unionWith(const IntRange& other) const
+{
+ return IntRange(imin < other.imin ? imin : other.imin,
+ imax > other.imax ? imax : other.imax);
+}
+
+void IntRange::unionOrAssign(const IntRange& other, bool& union_)
+{
+ if (!union_ || imin > other.imin)
+ imin = other.imin;
+ if (!union_ || imax < other.imax)
+ imax = other.imax;
+ union_ = true;
+}
+
+void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
+ IntRange& nonNegRange, bool& hasNonNegRange) const
+{
+ hasNegRange = imin.negative;
+ if (hasNegRange)
+ {
+ negRange.imin = imin;
+ negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
+ }
+ hasNonNegRange = !imax.negative;
+ if (hasNonNegRange)
+ {
+ nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
+ nonNegRange.imax = imax;
+ }
+}
+
+
+#if !PERFORM_UNITTEST
+const IntRange& IntRange::dump(const char* funcName, Expression *e) const
+{
+ printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
+ imin.negative?'-':'+', imin.value,
+ imax.negative?'-':'+', imax.value,
+ funcName, e->toChars());
+ return *this;
+}
+#endif
+
+//------------------------------------------------------------------------------
+
+#if PERFORM_UNITTEST
+#include
+#include
+
+class AssertionError : public std::exception {
+public:
+ AssertionError() : std::exception() {}
+};
+
+void _assertPred(uinteger_t x, uinteger_t y, int line) {
+ if (x != y) {
+ printf("Line %d: %#018llx != %#018llx\n", line, x, y);
+ throw AssertionError();
+ }
+}
+void _assertPred(const SignExtendedNumber& x, const SignExtendedNumber& y, int line) {
+ if (x != y) {
+ printf("Line %d: (%c)%#018llx != (%c)%#018llx\n", line,
+ x.negative?'-':'+', x.value,
+ y.negative?'-':'+', y.value);
+ throw AssertionError();
+ }
+}
+void _assertPred(bool x, bool y, int line) {
+ if (x != y) {
+ static const char* const names[] = {"false", "true"};
+ printf("Line %d: %s != %s\n", line, names[x], names[y]);
+ throw AssertionError();
+ }
+}
+#define assertPred(x, y) _assertPred(x, y, __LINE__)
+#define RUN(testName) \
+ try { \
+ testName(); \
+ } catch (const AssertionError&) { \
+ printf("********" #testName " failed\n"); \
+ }
+
+void testAssertSanity() {
+ int saneCount = 0;
+
+ printf("Testing 'assert' sanity. You should see 3 assertion failures below\n");
+
+ assertPred(true, true);
+ try {
+ assertPred(true, false);
+ } catch (const AssertionError&) {
+ ++ saneCount;
+ }
+
+ assertPred(4ULL, 4ULL);
+ try {
+ assertPred(3ULL, -3ULL);
+ } catch (const AssertionError&) {
+ ++ saneCount;
+ }
+
+ assertPred(SignExtendedNumber(5, false), SignExtendedNumber(5, false));
+ try {
+ assertPred(SignExtendedNumber(4, false), SignExtendedNumber(4, true));
+ } catch (const AssertionError&) {
+ ++ saneCount;
+ }
+
+ printf("--------------\n");
+
+ if (saneCount != 3) throw AssertionError();
+}
+
+void testNegation() {
+ SignExtendedNumber s (4);
+ SignExtendedNumber t = -s;
+ assertPred(t.value, -4ULL);
+ assertPred(t.negative, true);
+
+ s = SignExtendedNumber::max();
+ t = -s;
+ assertPred(t.value, 1);
+ assertPred(t.negative, true);
+
+ s = SignExtendedNumber::fromInteger(-4);
+ assertPred(s.value, -4ULL);
+ assertPred(s.negative, true);
+
+ t = -s;
+ assertPred(t.value, 4);
+ assertPred(t.negative, false);
+
+ s = SignExtendedNumber::min();
+ t = -s;
+ assertPred(t.value, UINT64_MAX);
+ assertPred(t.negative, false);
+
+ s = SignExtendedNumber(0);
+ t = -s;
+ assertPred(t.value, 0);
+ assertPred(t.negative, false);
+}
+
+void testCompare() {
+ SignExtendedNumber a = SignExtendedNumber::min();
+ SignExtendedNumber b = SignExtendedNumber(-5, true);
+ SignExtendedNumber c = SignExtendedNumber(0, false);
+ SignExtendedNumber d = SignExtendedNumber(5, false);
+ SignExtendedNumber e = SignExtendedNumber::max();
+
+ assertPred(a == a, true);
+ assertPred(a != a, false);
+ assertPred(a < b, true);
+ assertPred(b < c, true);
+ assertPred(c < d, true);
+ assertPred(d < e, true);
+ assertPred(a < c, true);
+ assertPred(c < e, true);
+ assertPred(b < d, true);
+ assertPred(b < a, false);
+ assertPred(c < b, false);
+ assertPred(d < c, false);
+ assertPred(e < d, false);
+ assertPred(e < c, false);
+ assertPred(d < b, false);
+ assertPred(c < a, false);
+
+ assertPred(a, a);
+ assertPred(SignExtendedNumber::extreme(false), SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::extreme(true), SignExtendedNumber::min());
+}
+
+void testAddition() {
+ assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(8, false),
+ SignExtendedNumber(12, false));
+ assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(-9, true),
+ SignExtendedNumber(-5, true));
+ assertPred(SignExtendedNumber(-9, true) + SignExtendedNumber(4, false),
+ SignExtendedNumber(-5, true));
+ assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(9, false),
+ SignExtendedNumber(5, false));
+ assertPred(SignExtendedNumber(9, false) + SignExtendedNumber(-4, true),
+ SignExtendedNumber(5, false));
+ assertPred(SignExtendedNumber(9, true) + SignExtendedNumber(-4, false),
+ SignExtendedNumber(5, false));
+ assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(-6, true),
+ SignExtendedNumber(-10, true));
+ assertPred(SignExtendedNumber::max() + SignExtendedNumber(1, false),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(UINT64_MAX/2+1, false) + SignExtendedNumber(UINT64_MAX/2+1, false),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::max() + SignExtendedNumber::min(),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber::min() + SignExtendedNumber(-1, true),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::max() + SignExtendedNumber::max(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::min() + SignExtendedNumber::min(),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(1, true) + SignExtendedNumber(1, true),
+ SignExtendedNumber::min());
+
+ SignExtendedNumber x(0);
+ assertPred(++x, SignExtendedNumber(1));
+ x = SignExtendedNumber(-1, true);
+ assertPred(++x, SignExtendedNumber(0));
+ x = SignExtendedNumber::min();
+ assertPred(++x, SignExtendedNumber(1, true));
+ x = SignExtendedNumber::max();
+ assertPred(++x, SignExtendedNumber::max());
+}
+
+void testSubtraction() {
+ assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(8, false),
+ SignExtendedNumber(-4, true));
+ assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(-9, true),
+ SignExtendedNumber(13, false));
+ assertPred(SignExtendedNumber(-9, true) - SignExtendedNumber(4, false),
+ SignExtendedNumber(-13, true));
+ assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(9, false),
+ SignExtendedNumber(-13, true));
+ assertPred(SignExtendedNumber(9, false) - SignExtendedNumber(-4, true),
+ SignExtendedNumber(13, false));
+ assertPred(SignExtendedNumber(9, true) - SignExtendedNumber(-4, false),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(-6, true),
+ SignExtendedNumber(2, false));
+ assertPred(SignExtendedNumber::max() - SignExtendedNumber(-1, true),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::max() - SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::max() - SignExtendedNumber::min(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::min() - SignExtendedNumber(1, false),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(1, false) - SignExtendedNumber::min(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::min() - SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(1, true) - SignExtendedNumber::min(),
+ SignExtendedNumber(1, false));
+}
+
+void testMultiplication() {
+ assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(8, false),
+ SignExtendedNumber(32, false));
+ assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(-9, true),
+ SignExtendedNumber(-36, true));
+ assertPred(SignExtendedNumber(-9, true) * SignExtendedNumber(4, false),
+ SignExtendedNumber(-36, true));
+ assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(9, false),
+ SignExtendedNumber(-36, true));
+ assertPred(SignExtendedNumber(9, false) * SignExtendedNumber(-4, true),
+ SignExtendedNumber(-36, true));
+ assertPred(SignExtendedNumber(9, true) * SignExtendedNumber(-4, false),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(-6, true),
+ SignExtendedNumber(24, false));
+ assertPred(SignExtendedNumber::max() * SignExtendedNumber::max(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::max() * SignExtendedNumber(0),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::max() * SignExtendedNumber::min(),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(0) * SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) * SignExtendedNumber(0),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) * SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() * SignExtendedNumber::max(),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::min() * SignExtendedNumber(0),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() * SignExtendedNumber::min(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(2, false),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(-2, true),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::max() * SignExtendedNumber(-1, true),
+ SignExtendedNumber(1, true));
+ assertPred(SignExtendedNumber::max() * SignExtendedNumber(-2, true),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::max() * SignExtendedNumber(2, false),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::min() * SignExtendedNumber(2, false),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::min() * SignExtendedNumber(-1, true),
+ SignExtendedNumber::max());
+}
+
+void testDivision() {
+ assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(8, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(8, false) / SignExtendedNumber(4, false),
+ SignExtendedNumber(2, false));
+ assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(-9, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(-9, true) / SignExtendedNumber(4, false),
+ SignExtendedNumber(-2, true));
+ assertPred(SignExtendedNumber(-4, true) / SignExtendedNumber(9, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(9, false) / SignExtendedNumber(-4, true),
+ SignExtendedNumber(-2, true));
+ assertPred(SignExtendedNumber(4, true) / SignExtendedNumber(-9, false),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber(-6, true) / SignExtendedNumber(-4, true),
+ SignExtendedNumber(1, false));
+ assertPred(SignExtendedNumber::max() / SignExtendedNumber::max(),
+ SignExtendedNumber(1));
+ assertPred(SignExtendedNumber::max() / SignExtendedNumber(0),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::max() / SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) / SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) / SignExtendedNumber(0),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(0) / SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber::max(),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber(0),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber::min(),
+ SignExtendedNumber(1));
+ assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(2, false),
+ SignExtendedNumber((~5ULL)>>1));
+ assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(-2, true),
+ SignExtendedNumber(3 | 1ULL<<63, true));
+ assertPred(SignExtendedNumber::max() / SignExtendedNumber(-1, true),
+ SignExtendedNumber(1, true));
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1, true),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::max() / SignExtendedNumber(1, false),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber(1, false),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber(2, false),
+ SignExtendedNumber(-(1ULL << 63), true));
+ assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1024, true),
+ SignExtendedNumber(1ULL << 54));
+}
+
+void testModulus() {
+ assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(8, false),
+ SignExtendedNumber(4, false));
+ assertPred(SignExtendedNumber(8, false) % SignExtendedNumber(4, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(-9, true),
+ SignExtendedNumber(4, false));
+ assertPred(SignExtendedNumber(-9, true) % SignExtendedNumber(4, false),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber(-4, true) % SignExtendedNumber(9, false),
+ SignExtendedNumber(-4, true));
+ assertPred(SignExtendedNumber(9, false) % SignExtendedNumber(-4, true),
+ SignExtendedNumber(1, false));
+ assertPred(SignExtendedNumber(4, true) % SignExtendedNumber(-9, false),
+ SignExtendedNumber(-5, true));
+ assertPred(SignExtendedNumber(-6, true) % SignExtendedNumber(-4, true),
+ SignExtendedNumber(-2, true));
+ assertPred(SignExtendedNumber::max() % SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::max() % SignExtendedNumber(0),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::max() % SignExtendedNumber::min(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(0) % SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) % SignExtendedNumber(0),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) % SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber::max(),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber(0),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(2, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(-2, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::max() % SignExtendedNumber(-1, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber(-1, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::max() % SignExtendedNumber(1, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber(1, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber(2, false),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber::min() % SignExtendedNumber(999, false),
+ SignExtendedNumber(-160, true));
+}
+
+void testShift() {
+ assertPred(SignExtendedNumber(0) << SignExtendedNumber(4),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) << SignExtendedNumber(74),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) << SignExtendedNumber(-5, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) << SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) << SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(1) << SignExtendedNumber(4),
+ SignExtendedNumber(16));
+ assertPred(SignExtendedNumber(1) << SignExtendedNumber(74),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(1) << SignExtendedNumber(-5, true),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(1) << SignExtendedNumber::max(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(1) << SignExtendedNumber::min(),
+ SignExtendedNumber::max());
+ assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(4),
+ SignExtendedNumber(-16, true));
+ assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(74),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(-5, true),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::max(),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::min(),
+ SignExtendedNumber::min());
+ assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(12, false),
+ SignExtendedNumber(0xabcdef000ULL));
+ assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(40, false),
+ SignExtendedNumber(0xabcdef0000000000ULL));
+ assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(41, false),
+ SignExtendedNumber::max());
+
+
+ assertPred(SignExtendedNumber(0) >> SignExtendedNumber(4),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) >> SignExtendedNumber(74),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) >> SignExtendedNumber(-5, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) >> SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(0) >> SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(16) >> SignExtendedNumber(4),
+ SignExtendedNumber(1));
+ assertPred(SignExtendedNumber(16) >> SignExtendedNumber(74),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(16) >> SignExtendedNumber(-5, true),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(16) >> SignExtendedNumber::max(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(16) >> SignExtendedNumber::min(),
+ SignExtendedNumber(0));
+ assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(4),
+ SignExtendedNumber(-2, true));
+ assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(74),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(-5, true),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::max(),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::min(),
+ SignExtendedNumber(-1, true));
+ assertPred(SignExtendedNumber(0xabcdef, false) >> SignExtendedNumber(12, false),
+ SignExtendedNumber(0xabcULL));
+ assertPred(SignExtendedNumber(0xabcdef, true) >> SignExtendedNumber(12, false),
+ SignExtendedNumber(0xFFF0000000000ABCULL, true));
+ assertPred(SignExtendedNumber::min() >> SignExtendedNumber(1, false),
+ SignExtendedNumber(0x8000000000000000ULL, true));
+ assertPred(SignExtendedNumber::min() >> SignExtendedNumber(63, false),
+ SignExtendedNumber(-2, true));
+ assertPred(SignExtendedNumber::min() >> SignExtendedNumber(65, false),
+ SignExtendedNumber(-1, true));
+}
+
+void testFromNumbers() {
+ SignExtendedNumber a[] = {
+ SignExtendedNumber(12, false),
+ SignExtendedNumber(-35, true),
+ SignExtendedNumber(40, false),
+ SignExtendedNumber(-21, true),
+ SignExtendedNumber::min()
+ };
+
+ IntRange ir1 = IntRange::fromNumbers2(a);
+ assertPred(ir1.imin, SignExtendedNumber(-35, true));
+ assertPred(ir1.imax, SignExtendedNumber(12, false));
+
+ IntRange ir2 = IntRange::fromNumbers2(a+1);
+ assertPred(ir2.imin, SignExtendedNumber(-35, true));
+ assertPred(ir2.imax, SignExtendedNumber(40, false));
+
+ IntRange ir3 = IntRange::fromNumbers4(a);
+ assertPred(ir3.imin, SignExtendedNumber(-35, true));
+ assertPred(ir3.imax, SignExtendedNumber(40, false));
+
+ IntRange ir4 = IntRange::fromNumbers4(a+1);
+ assertPred(ir4.imin, SignExtendedNumber::min());
+ assertPred(ir4.imax, SignExtendedNumber(40, false));
+
+ assertPred(ir4.contains(ir3), true);
+ assertPred(ir1.contains(ir2), false);
+
+ IntRange ir5 = IntRange::widest();
+ assertPred(ir5.imin, SignExtendedNumber::min());
+ assertPred(ir5.imax, SignExtendedNumber::max());
+ assertPred(ir5.contains(ir4), true);
+}
+
+void testContainsZero() {
+ IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(4));
+ assertPred(ir1.containsZero(), true);
+
+ IntRange ir2 (SignExtendedNumber(-4, true), SignExtendedNumber(0));
+ assertPred(ir2.containsZero(), true);
+
+ IntRange ir3 (SignExtendedNumber(-5, true), SignExtendedNumber(5));
+ assertPred(ir3.containsZero(), true);
+
+ assertPred(IntRange::widest().containsZero(), true);
+
+ IntRange ir4 (SignExtendedNumber(8), SignExtendedNumber(9));
+ assertPred(ir4.containsZero(), false);
+
+ IntRange ir5 (SignExtendedNumber(-5, true), SignExtendedNumber(-2, true));
+ assertPred(ir5.containsZero(), false);
+
+ IntRange ir6 (SignExtendedNumber(0), SignExtendedNumber(0));
+ assertPred(ir6.containsZero(), true);
+}
+
+void testCast() {
+ {
+ IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF));
+ ir1.castUnsigned(0xFF);
+ assertPred(ir1.imin, SignExtendedNumber(0));
+ assertPred(ir1.imax, SignExtendedNumber(0xFF));
+
+ IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105));
+ ir2.castUnsigned(0xFF);
+ assertPred(ir2.imin, SignExtendedNumber(1));
+ assertPred(ir2.imax, SignExtendedNumber(5));
+
+ IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false));
+ ir3.castUnsigned(0xFF);
+ assertPred(ir3.imin, SignExtendedNumber(0));
+ assertPred(ir3.imax, SignExtendedNumber(0xFF));
+
+ IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999));
+ ir4.castUnsigned(0xFF);
+ assertPred(ir4.imin, SignExtendedNumber(0x7F));
+ assertPred(ir4.imax, SignExtendedNumber(0x99));
+
+ IntRange ir5 (SignExtendedNumber(-1, true), SignExtendedNumber(1, false));
+ ir5.castUnsigned(UINT64_MAX);
+ assertPred(ir5.imin, SignExtendedNumber(0));
+ assertPred(ir5.imax, SignExtendedNumber::max());
+
+ IntRange ir6 (SignExtendedNumber::min(), SignExtendedNumber(0));
+ ir6.castUnsigned(UINT64_MAX);
+ assertPred(ir6.imin, SignExtendedNumber(0));
+ assertPred(ir6.imax, SignExtendedNumber::max());
+
+ IntRange ir7 (SignExtendedNumber::min(), SignExtendedNumber(-0x80, true));
+ ir7.castUnsigned(UINT64_MAX);
+ assertPred(ir7.imin, SignExtendedNumber(0));
+ assertPred(ir7.imax, SignExtendedNumber(-0x80, false));
+
+ IntRange ir8 = IntRange::widest();
+ ir8.castUnsigned(0xFF);
+ assertPred(ir8.imin, SignExtendedNumber(0));
+ assertPred(ir8.imax, SignExtendedNumber(0xFF));
+ }
+
+ {
+ IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF));
+ ir1.castSigned(0xFF);
+ assertPred(ir1.imin, SignExtendedNumber(-0x80, true));
+ assertPred(ir1.imax, SignExtendedNumber(0x7F, false));
+
+ IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105));
+ ir2.castSigned(0xFF);
+ assertPred(ir2.imin, SignExtendedNumber(1));
+ assertPred(ir2.imax, SignExtendedNumber(5));
+
+ IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false));
+ ir3.castSigned(0xFF);
+ assertPred(ir3.imin, SignExtendedNumber(-7, true));
+ assertPred(ir3.imax, SignExtendedNumber(7, false));
+
+ IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999));
+ ir4.castSigned(0xFF);
+ assertPred(ir4.imin, SignExtendedNumber(-0x80, true));
+ assertPred(ir4.imax, SignExtendedNumber(0x7F, false));
+
+ IntRange ir5 (SignExtendedNumber(-0xFF, true), SignExtendedNumber(-0x80, true));
+ ir5.castSigned(0xFF);
+ assertPred(ir5.imin, SignExtendedNumber(-0x80, true));
+ assertPred(ir5.imax, SignExtendedNumber(0x7F, false));
+
+ IntRange ir6 (SignExtendedNumber(-0x80, true), SignExtendedNumber(-0x80, true));
+ ir6.castSigned(0xFF);
+ assertPred(ir6.imin, SignExtendedNumber(-0x80, true));
+ assertPred(ir6.imax, SignExtendedNumber(-0x80, true));
+
+ IntRange ir7 = IntRange::widest();
+ ir7.castSigned(0xFFFFFFFFULL);
+ assertPred(ir7.imin, SignExtendedNumber(-0x80000000ULL, true));
+ assertPred(ir7.imax, SignExtendedNumber( 0x7FFFFFFFULL, false));
+ }
+
+ {
+ IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0x9999));
+ ir1.castDchar();
+ assertPred(ir1.imin, SignExtendedNumber(0));
+ assertPred(ir1.imax, SignExtendedNumber(0x9999));
+
+ IntRange ir2 (SignExtendedNumber(0xFFFF), SignExtendedNumber(0x7FFFFFFF));
+ ir2.castDchar();
+ assertPred(ir2.imin, SignExtendedNumber(0xFFFF));
+ assertPred(ir2.imax, SignExtendedNumber(0x10FFFF));
+
+ IntRange ir3 = IntRange::widest();
+ ir3.castDchar();
+ assertPred(ir3.imin, SignExtendedNumber(0));
+ assertPred(ir3.imax, SignExtendedNumber(0x10FFFF));
+ }
+}
+
+void testAbsNeg() {
+ IntRange ir1 = IntRange(SignExtendedNumber(5), SignExtendedNumber(104)).absNeg();
+ assertPred(ir1.imin, SignExtendedNumber(-104, true));
+ assertPred(ir1.imax, SignExtendedNumber(-5, true));
+
+ IntRange ir2 = IntRange(SignExtendedNumber(-46, true), SignExtendedNumber(-3, true)).absNeg();
+ assertPred(ir2.imin, SignExtendedNumber(-46, true));
+ assertPred(ir2.imax, SignExtendedNumber(-3, true));
+
+ IntRange ir3 = IntRange(SignExtendedNumber(-7, true), SignExtendedNumber(9)).absNeg();
+ assertPred(ir3.imin, SignExtendedNumber(-9, true));
+ assertPred(ir3.imax, SignExtendedNumber(0));
+
+ IntRange ir4 = IntRange(SignExtendedNumber(-12, true), SignExtendedNumber(2)).absNeg();
+ assertPred(ir4.imin, SignExtendedNumber(-12, true));
+ assertPred(ir4.imax, SignExtendedNumber(0));
+
+ IntRange ir5 = IntRange::widest().absNeg();
+ assertPred(ir5.imin, SignExtendedNumber::min());
+ assertPred(ir5.imax, SignExtendedNumber(0));
+
+ IntRange ir6 = IntRange(SignExtendedNumber(0), SignExtendedNumber::max()).absNeg();
+ assertPred(ir6.imin, SignExtendedNumber(1, true));
+ assertPred(ir6.imax, SignExtendedNumber(0));
+}
+
+int main() {
+ RUN(testAssertSanity);
+ RUN(testNegation);
+ RUN(testCompare);
+ RUN(testAddition);
+ RUN(testSubtraction);
+ RUN(testMultiplication);
+ RUN(testDivision);
+ RUN(testModulus);
+ RUN(testShift);
+ RUN(testFromNumbers);
+ RUN(testContainsZero);
+ RUN(testCast);
+ RUN(testAbsNeg);
+ printf("Finished all tests.\n");
+}
+
+
+#endif
+
+
diff --git a/dmd2/intrange.h b/dmd2/intrange.h
new file mode 100644
index 00000000..2904dab9
--- /dev/null
+++ b/dmd2/intrange.h
@@ -0,0 +1,149 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2011 by Digital Mars
+// All Rights Reserved
+// written by KennyTM
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#ifndef DMD_SXNUM_H
+#define DMD_SXNUM_H
+
+#include "mars.h" // for uinteger_t
+struct Type;
+struct Expression;
+
+/**
+This class represents a "sign-extended number", i.e. a 65-bit number, which can
+represent all built-in integer types in D. This class is mainly used for
+performing value-range propagation only, therefore all arithmetic are done with
+saturation, not wrapping as usual.
+*/
+struct SignExtendedNumber
+{
+ /// The lower 64-bit of the number.
+ uinteger_t value;
+ /// The sign (i.e. the most significant bit) of the number.
+ bool negative;
+
+ /// Create an uninitialized sign-extended number.
+ SignExtendedNumber() {}
+
+ /// Create a sign-extended number from an unsigned 64-bit number.
+ SignExtendedNumber(uinteger_t value_)
+ : value(value_), negative(false) {}
+ /// Create a sign-extended number from the lower 64-bit and the sign bit.
+ SignExtendedNumber(uinteger_t value_, bool negative_)
+ : value(value_), negative(negative_) {}
+
+ /// Create a sign-extended number from a signed 64-bit number.
+ static SignExtendedNumber fromInteger(uinteger_t value_);
+
+ /// Get the minimum or maximum value of a sign-extended number.
+ static SignExtendedNumber extreme(bool minimum);
+ static SignExtendedNumber max();
+ static SignExtendedNumber min() { return SignExtendedNumber(0, true); }
+
+ /// Check if the sign-extended number is minimum or zero.
+ bool isMinimum() const { return negative && value == 0; }
+
+ /// Compare two sign-extended number.
+ bool operator==(const SignExtendedNumber&) const;
+ bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); }
+ bool operator<(const SignExtendedNumber&) const;
+ bool operator>(const SignExtendedNumber& a) const { return a < *this; }
+ bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
+ bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
+
+ /// Compute the saturated negation of a sign-extended number.
+ SignExtendedNumber operator-() const;
+
+ /// Compute the saturated sum of two sign-extended number.
+ SignExtendedNumber operator+(const SignExtendedNumber&) const;
+ /// Compute the saturated difference of two sign-extended number.
+ SignExtendedNumber operator-(const SignExtendedNumber& a) const;
+ /// Compute the saturated product of two sign-extended number.
+ SignExtendedNumber operator*(const SignExtendedNumber&) const;
+ /// Compute the saturated quotient of two sign-extended number.
+ SignExtendedNumber operator/(const SignExtendedNumber&) const;
+ /// Compute the saturated modulus of two sign-extended number.
+ SignExtendedNumber operator%(const SignExtendedNumber&) const;
+
+ /// Increase the sign-extended number by 1 (saturated).
+ SignExtendedNumber& operator++();
+
+ /// Compute the saturated shifts of two sign-extended number.
+ SignExtendedNumber operator<<(const SignExtendedNumber&) const;
+ SignExtendedNumber operator>>(const SignExtendedNumber&) const;
+};
+
+/**
+This class represents a range of integers, denoted by its lower and upper bounds
+(inclusive).
+*/
+struct IntRange
+{
+ SignExtendedNumber imin, imax;
+
+ /// Create an uninitialized range.
+ IntRange() {}
+
+ /// Create a range consisting of a single number.
+ IntRange(const SignExtendedNumber& a)
+ : imin(a), imax(a) {}
+ /// Create a range with the lower and upper bounds.
+ IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper)
+ : imin(lower), imax(upper) {}
+
+ /// Create the tightest range containing all valid integers in the specified
+ /// type.
+ static IntRange fromType(Type *type);
+ /// Create the tightest range containing all valid integers in the type with
+ /// a forced signedness.
+ static IntRange fromType(Type *type, bool isUnsigned);
+
+
+ /// Create the tightest range containing all specified numbers.
+ static IntRange fromNumbers2(const SignExtendedNumber numbers[2]);
+ static IntRange fromNumbers4(const SignExtendedNumber numbers[4]);
+
+ /// Create the widest range possible.
+ static IntRange widest();
+
+ /// Cast the integer range to a signed type with the given size mask.
+ IntRange& castSigned(uinteger_t mask);
+ /// Cast the integer range to an unsigned type with the given size mask.
+ IntRange& castUnsigned(uinteger_t mask);
+ /// Cast the integer range to the dchar type.
+ IntRange& castDchar();
+
+ /// Cast the integer range to a specific type.
+ IntRange& cast(Type *type);
+ /// Cast the integer range to a specific type, forcing it to be unsigned.
+ IntRange& castUnsigned(Type *type);
+
+ /// Check if this range contains another range.
+ bool contains(const IntRange& a) const;
+
+ /// Check if this range contains 0.
+ bool containsZero() const;
+
+ /// Compute the range of the negated absolute values of the original range.
+ IntRange absNeg() const;
+
+ /// Compute the union of two ranges.
+ IntRange unionWith(const IntRange& other) const;
+ void unionOrAssign(const IntRange& other, bool& union_);
+
+ /// Dump the content of the integer range to the console.
+ const IntRange& dump(const char* funcName, Expression *e) const;
+
+ /// Split the range into two nonnegative- and negative-only subintervals.
+ void splitBySign(IntRange& negRange, bool& hasNegRange,
+ IntRange& nonNegRange, bool& hasNonNegRange) const;
+};
+
+#endif
diff --git a/dmd2/lexer.h b/dmd2/lexer.h
index d5da99e0..abe8df6d 100644
--- a/dmd2/lexer.h
+++ b/dmd2/lexer.h
@@ -211,7 +211,6 @@ enum TOK
case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \
case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \
case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \
- case TOKbit: t = Type::tbit; goto LabelX; \
case TOKbool: t = Type::tbool; goto LabelX; \
case TOKchar: t = Type::tchar; goto LabelX; \
case TOKwchar: t = Type::twchar; goto LabelX; \
diff --git a/dmd2/mangle.c b/dmd2/mangle.c
index a6d8d34d..0c19040c 100644
--- a/dmd2/mangle.c
+++ b/dmd2/mangle.c
@@ -24,7 +24,7 @@
#include "id.h"
#include "module.h"
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
char *cpp_mangle(Dsymbol *s);
#endif
diff --git a/dmd2/mars.c b/dmd2/mars.c
index b8471310..8673fbe3 100644
--- a/dmd2/mars.c
+++ b/dmd2/mars.c
@@ -77,7 +77,7 @@ Global::Global()
#else
#if TARGET_WINDOS
obj_ext = "obj";
-#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
obj_ext = "o";
#elif TARGET_NET
#else
@@ -86,7 +86,7 @@ Global::Global()
#if TARGET_WINDOS
lib_ext = "lib";
-#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
lib_ext = "a";
#elif TARGET_NET
#else
@@ -100,7 +100,7 @@ Global::Global()
"\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates.";
#endif
;
- version = "v2.053";
+ version = "v2.054";
#if IN_LLVM
ldc_version = "LDC trunk";
llvm_version = "LLVM 2.9";
@@ -182,7 +182,7 @@ void verror(Loc loc, const char *format, va_list ap)
#endif
fprintf(stdmsg, "\n");
fflush(stdmsg);
-halt();
+//halt();
}
global.errors++;
}
@@ -238,8 +238,8 @@ void halt()
#endif
}
-
extern signed char tyalignsize[];
+
/***********************************
* Parse and append contents of environment variable envvar
* to argc and argv[].
diff --git a/dmd2/mars.h b/dmd2/mars.h
index b9329f5a..8efc2664 100644
--- a/dmd2/mars.h
+++ b/dmd2/mars.h
@@ -37,6 +37,7 @@ Macros defined by the compiler, not the code:
linux Linux
__APPLE__ Mac OSX
__FreeBSD__ FreeBSD
+ __OpenBSD__ OpenBSD
__sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary)
For the target systems, there are the target operating system and
@@ -47,6 +48,7 @@ the target object file format:
TARGET_LINUX Covers 32 and 64 bit linux
TARGET_OSX Covers 32 and 64 bit Mac OSX
TARGET_FREEBSD Covers 32 and 64 bit FreeBSD
+ TARGET_OPENBSD Covers 32 and 64 bit OpenBSD
TARGET_SOLARIS Covers 32 and 64 bit Solaris
TARGET_NET Covers .Net
@@ -55,7 +57,7 @@ the target object file format:
Target object module format:
OMFOBJ Intel Object Module Format, used on Windows
- ELFOBJ Elf Object Module Format, used on linux, FreeBSD and Solaris
+ ELFOBJ Elf Object Module Format, used on linux, FreeBSD, OpenBSD and Solaris
MACHOBJ Mach-O Object Module Format, used on Mac OSX
There are currently no macros for byte endianness order.
@@ -103,9 +105,9 @@ void unittests();
#define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class
// Set if C++ mangling is done by the front end
-#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS))
+#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS))
-/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD and
+/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD, TARGET_OPENBSD and
* TARGET_SOLARIS, which are
* set on the command line via the compiler makefile.
*/
@@ -115,7 +117,7 @@ void unittests();
#define OMFOBJ 1
#endif
-#if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS
+#if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
#ifndef ELFOBJ
#define ELFOBJ 1
#endif
@@ -192,6 +194,7 @@ struct Param
bool useInline; // inline expand functions
bool warnings; // enable warnings
ubyte Dversion; // D version number
+ char enforcePropertySyntax;
char *argv0; // program name
Array *imppath; // array of char*'s of where to look for import modules
diff --git a/dmd2/module.c b/dmd2/module.c
index 0973893f..244dfad3 100644
--- a/dmd2/module.c
+++ b/dmd2/module.c
@@ -1,6 +1,6 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2010 by Digital Mars
+// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -544,7 +544,7 @@ void Module::read(Loc loc)
inline unsigned readwordLE(unsigned short *p)
{
-#if __I86__
+#if LITTLE_ENDIAN
return *p;
#else
return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0];
@@ -558,7 +558,7 @@ inline unsigned readwordBE(unsigned short *p)
inline unsigned readlongLE(unsigned *p)
{
-#if __I86__
+#if LITTLE_ENDIAN
return *p;
#else
return ((unsigned char *)p)[0] |
diff --git a/dmd2/module.h b/dmd2/module.h
index 0183e04f..dc66a981 100644
--- a/dmd2/module.h
+++ b/dmd2/module.h
@@ -154,9 +154,7 @@ struct Module : Package
#if !IN_LLVM
void setHdrfile(); // set hdrfile member
#endif
-#ifdef _DH
void genhdrfile(); // generate D import file
-#endif
// void gensymfile();
void gendocfile();
int needModuleInfo();
diff --git a/dmd2/mtype.c b/dmd2/mtype.c
index 01bca3c5..1ad0fb57 100644
--- a/dmd2/mtype.c
+++ b/dmd2/mtype.c
@@ -52,7 +52,6 @@
#include "import.h"
#include "aggregate.h"
#include "hdrgen.h"
-#include "doc.h"
#if IN_LLVM
//#include "gen/tollvm.h"
@@ -83,7 +82,7 @@ int PTRSIZE = 4;
int REALSIZE = 16;
int REALPAD = 6;
int REALALIGNSIZE = 16;
-#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS
+#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
int REALSIZE = 12;
int REALPAD = 2;
int REALALIGNSIZE = 4;
@@ -264,7 +263,6 @@ void Type::init()
mangleChar[Tdchar] = 'w';
// '@' shouldn't appear anywhere in the deco'd names
- mangleChar[Tbit] = '@';
mangleChar[Tinstance] = '@';
mangleChar[Terror] = '@';
mangleChar[Ttypeof] = '@';
@@ -313,7 +311,7 @@ void Type::init()
#if TARGET_OSX
REALSIZE = 16;
REALPAD = 6;
-#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS
+#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
REALSIZE = 12;
REALPAD = 2;
#else
@@ -1244,6 +1242,8 @@ Type *Type::toHeadMutable()
Type *Type::pointerTo()
{
+ if (ty == Terror)
+ return this;
if (!pto)
{ Type *t;
@@ -1255,6 +1255,8 @@ Type *Type::pointerTo()
Type *Type::referenceTo()
{
+ if (ty == Terror)
+ return this;
if (!rto)
{ Type *t;
@@ -1266,6 +1268,8 @@ Type *Type::referenceTo()
Type *Type::arrayOf()
{
+ if (ty == Terror)
+ return this;
if (!arrayof)
{ Type *t;
@@ -1764,6 +1768,8 @@ Expression *Type::getProperty(Loc loc, Identifier *ident)
{
if (ty == Tvoid)
error(loc, "void does not have an initializer");
+ if (ty == Tfunction)
+ error(loc, "function does not have an initializer");
e = defaultInitLiteral(loc);
}
else if (ident == Id::mangleof)
@@ -1928,7 +1934,7 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident)
{ /* Rewrite e.ident as:
* e.opDot().ident
*/
- e = build_overload(e->loc, sc, e, NULL, fd->ident);
+ e = build_overload(e->loc, sc, e, NULL, fd);
e = new DotIdExp(e->loc, e, ident);
return e->semantic(sc);
}
@@ -2562,7 +2568,7 @@ unsigned TypeBasic::alignsize()
if (ty == Tvoid)
return 1;
return GetTypeAlignment(sir, this);
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
case Tint64:
case Tuns64:
sz = global.params.isX86_64 ? 8 : 4;
@@ -3271,7 +3277,6 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
Expression *ec;
Expressions *arguments;
- bool isBit = (n->ty == Tbit);
//LDC: Build arguments.
static FuncDeclaration *adSort_fd = NULL;
@@ -3281,18 +3286,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL));
adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort");
}
- static FuncDeclaration *adSortBit_fd = NULL;
- if(!adSortBit_fd) {
- Parameters* args = new Parameters;
- args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL));
- args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL));
- adSortBit_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSortBit");
- }
- if(isBit)
- ec = new VarExp(0, adSortBit_fd);
- else
- ec = new VarExp(0, adSort_fd);
+ ec = new VarExp(0, adSort_fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
@@ -3304,13 +3299,9 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
e = exp;
}
arguments->push(e);
-
- if (next->ty != Tbit) {
- // LDC, we don't support the getInternalTypeInfo
- // optimization arbitrarily, not yet at least...
- arguments->push(n->getTypeInfo(sc));
- }
-
+ // LDC, we don't support the getInternalTypeInfo
+ // optimization arbitrarily, not yet at least...
+ arguments->push(n->getTypeInfo(sc));
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
@@ -3517,6 +3508,9 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc)
dim = dim->optimize(WANTvalue);
dinteger_t d2 = dim->toInteger();
+ if (dim->op == TOKerror)
+ goto Lerror;
+
if (d1 != d2)
goto Loverflow;
@@ -4142,7 +4136,6 @@ printf("index->ito->ito = x%x\n", index->ito->ito);
switch (index->toBasetype()->ty)
{
- case Tbool:
case Tfunction:
case Tvoid:
case Tnone:
@@ -4920,6 +4913,11 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag, bool mangle)
}
void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+ toCBufferWithAttributes(buf, ident, hgs, this, NULL);
+}
+
+void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td)
{
//printf("TypeFunction::toCBuffer() this = %p\n", this);
const char *p = NULL;
@@ -4932,22 +4930,22 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs
/* Use 'storage class' style for attributes
*/
- if (mod)
+ if (attrs->mod)
{
- MODtoBuffer(buf, mod);
+ MODtoBuffer(buf, attrs->mod);
buf->writeByte(' ');
}
- if (purity)
+ if (attrs->purity)
buf->writestring("pure ");
- if (isnothrow)
+ if (attrs->isnothrow)
buf->writestring("nothrow ");
- if (isproperty)
+ if (attrs->isproperty)
buf->writestring("@property ");
- if (isref)
+ if (attrs->isref)
buf->writestring("ref ");
- switch (trust)
+ switch (attrs->trust)
{
case TRUSTsystem:
buf->writestring("@system ");
@@ -4964,9 +4962,11 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs
if (next && (!ident || ident->toHChars2() == ident->toChars()))
next->toCBuffer2(buf, hgs, 0);
+ else if (hgs->ddoc && !next)
+ buf->writestring("auto");
if (hgs->ddoc != 1)
{
- switch (linkage)
+ switch (attrs->linkage)
{
case LINKd: p = NULL; break;
case LINKc: p = "C "; break;
@@ -4988,6 +4988,17 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs
{ buf->writeByte(' ');
buf->writestring(ident->toHChars2());
}
+ if (td)
+ { buf->writeByte('(');
+ for (int i = 0; i < td->origParameters->dim; i++)
+ {
+ TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i];
+ if (i)
+ buf->writestring(", ");
+ tp->toCBuffer(buf, hgs);
+ }
+ buf->writeByte(')');
+ }
Parameter::argsToCBuffer(buf, hgs, parameters, varargs);
inuse--;
}
@@ -5210,8 +5221,9 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
size_t tdim = tt->arguments->dim;
for (size_t j = 0; j < tdim; j++)
{ Parameter *narg = (Parameter *)tt->arguments->data[j];
- narg->storageClass = fparam->storageClass;
+ narg->storageClass |= fparam->storageClass;
}
+ fparam->storageClass = 0;
}
/* Reset number of parameters, and back up one to do this fparam again,
@@ -5548,6 +5560,20 @@ Type *TypeFunction::reliesOnTident()
return next ? next->reliesOnTident() : NULL;
}
+/********************************************
+ * Return TRUE if there are lazy parameters.
+ */
+bool TypeFunction::hasLazyParameters()
+{
+ size_t dim = Parameter::dim(parameters);
+ for (size_t i = 0; i < dim; i++)
+ { Parameter *fparam = Parameter::getNth(parameters, i);
+ if (fparam->storageClass & STClazy)
+ return TRUE;
+ }
+ return FALSE;
+}
+
/***************************
* Examine function signature for parameter p and see if
* p can 'escape' the scope of the function.
@@ -5583,6 +5609,12 @@ bool TypeFunction::parameterEscapes(Parameter *p)
return TRUE;
}
+Expression *TypeFunction::defaultInit(Loc loc)
+{
+ error(loc, "function does not have a default initializer");
+ return new ErrorExp();
+}
+
/***************************** TypeDelegate *****************************/
TypeDelegate::TypeDelegate(Type *t)
@@ -5644,7 +5676,7 @@ MATCH TypeDelegate::implicitConvTo(Type *to)
//printf("to : %s\n", to->toChars());
if (this == to)
return MATCHexact;
-#if 0 // not allowing covariant conversions because it interferes with overriding
+#if 1 // not allowing covariant conversions because it interferes with overriding
if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1)
return MATCHconvert;
#endif
@@ -6201,9 +6233,6 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc)
if (!t)
{
-#ifdef DEBUG
- printf("2: ");
-#endif
error(loc, "%s is used as a type", toChars());
t = terror;
}
@@ -7380,15 +7409,37 @@ int TypeStruct::needsDestruction()
int TypeStruct::isAssignable()
{
+ int assignable = TRUE;
+ unsigned offset;
+
/* If any of the fields are const or invariant,
* then one cannot assign this struct.
*/
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
- if (v->isConst() || v->isImmutable())
- return FALSE;
+ //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind());
+ if (i == 0)
+ ;
+ else if (v->offset == offset)
+ {
+ /* If any fields of anonymous union are assignable,
+ * then regard union as assignable.
+ * This is to support unsafe things like Rebindable templates.
+ */
+ if (assignable)
+ continue;
+ }
+ else
+ {
+ if (!assignable)
+ return FALSE;
+ }
+ assignable = v->type->isMutable() && v->type->isAssignable();
+ offset = v->offset;
+ //printf(" -> assignable = %d\n", assignable);
}
- return TRUE;
+
+ return assignable;
}
int TypeStruct::hasPointers()
@@ -8442,12 +8493,7 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu
if (arg->defaultArg)
{
argbuf.writestring(" = ");
- unsigned o = argbuf.offset;
arg->defaultArg->toCBuffer(&argbuf, hgs);
- if (hgs->ddoc)
- {
- escapeDdocString(&argbuf, o);
- }
}
buf->write(&argbuf);
}
diff --git a/dmd2/mtype.h b/dmd2/mtype.h
index db060aff..ed0c96cc 100644
--- a/dmd2/mtype.h
+++ b/dmd2/mtype.h
@@ -96,7 +96,6 @@ enum ENUMTY
Tcomplex64,
Tcomplex80,
- Tbit,
Tbool,
Tchar,
Twchar,
@@ -175,7 +174,6 @@ struct Type : Object
#define tcomplex64 basic[Tcomplex64]
#define tcomplex80 basic[Tcomplex80]
- #define tbit basic[Tbit]
#define tbool basic[Tbool]
#define tchar basic[Tchar]
#define twchar basic[Twchar]
@@ -412,7 +410,6 @@ struct TypeBasic : Type
void toCppMangle(OutBuffer *buf, CppMangleState *cms);
#endif
int isintegral();
- int isbit();
int isfloating();
int isreal();
int isimaginary();
@@ -630,11 +627,13 @@ struct TypeFunction : TypeNext
void purityLevel();
void toDecoBuffer(OutBuffer *buf, int flag, bool mangle);
void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+ void toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td);
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
void attributesToCBuffer(OutBuffer *buf, int mod);
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
TypeInfoDeclaration *getTypeInfoDeclaration();
Type *reliesOnTident();
+ bool hasLazyParameters();
#if CPP_MANGLE
void toCppMangle(OutBuffer *buf, CppMangleState *cms);
#endif
@@ -649,7 +648,11 @@ struct TypeFunction : TypeNext
#if IN_DMD
unsigned totym();
-#elif IN_LLVM
+#endif
+
+ Expression *defaultInit(Loc loc);
+
+#if IN_LLVM
// LDC
IrFuncTy fty;
@@ -857,7 +860,6 @@ struct TypeTypedef : Type
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
Expression *getProperty(Loc loc, Identifier *ident);
- int isbit();
int isintegral();
int isfloating();
int isreal();
diff --git a/dmd2/opover.c b/dmd2/opover.c
index 68dded02..ae402ee8 100644
--- a/dmd2/opover.c
+++ b/dmd2/opover.c
@@ -327,7 +327,7 @@ Expression *UnaExp::op_overload(Scope *sc)
else
{
// Rewrite +e1 as e1.add()
- return build_overload(loc, sc, e1, NULL, fd->ident);
+ return build_overload(loc, sc, e1, NULL, fd);
}
}
}
@@ -418,7 +418,7 @@ Expression *CastExp::op_overload(Scope *sc)
#if 1 // Backwards compatibility with D1 if opCast is a function, not a template
if (fd->isFuncDeclaration())
{ // Rewrite as: e1.opCast()
- return build_overload(loc, sc, e1, NULL, fd->ident);
+ return build_overload(loc, sc, e1, NULL, fd);
}
#endif
Objects *targsi = new Objects();
@@ -475,8 +475,10 @@ Expression *BinExp::op_overload(Scope *sc)
Objects *targsi = NULL;
#if DMDV2
- if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign)
- { /* Try the new D2 scheme, opBinary and opBinaryRight
+ if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign &&
+ op != TOKplusplus && op != TOKminusminus)
+ {
+ /* Try the new D2 scheme, opBinary and opBinaryRight
*/
if (ad1)
s = search_function(ad1, Id::opBinary);
@@ -520,7 +522,7 @@ Expression *BinExp::op_overload(Scope *sc)
}
else
{ TemplateDeclaration *td = s->isTemplateDeclaration();
- templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
+ templateResolve(&m, td, sc, loc, targsi, e1, &args2);
}
}
@@ -535,7 +537,7 @@ Expression *BinExp::op_overload(Scope *sc)
}
else
{ TemplateDeclaration *td = s_r->isTemplateDeclaration();
- templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
+ templateResolve(&m, td, sc, loc, targsi, e2, &args1);
}
}
@@ -560,13 +562,13 @@ Expression *BinExp::op_overload(Scope *sc)
// as unary, but it's implemented as a binary.
// Rewrite (e1 ++ e2) as e1.postinc()
// Rewrite (e1 -- e2) as e1.postdec()
- e = build_overload(loc, sc, e1, NULL, id);
- else if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
+ e = build_overload(loc, sc, e1, NULL, m.lastf ? m.lastf : s);
+ else if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch)
// Rewrite (e1 op e2) as e1.opfunc(e2)
- e = build_overload(loc, sc, e1, e2, id, targsi);
+ e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
else
// Rewrite (e1 op e2) as e2.opfunc_r(e1)
- e = build_overload(loc, sc, e2, e1, id_r, targsi);
+ e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r);
return e;
}
@@ -613,7 +615,7 @@ L1:
}
else
{ TemplateDeclaration *td = s_r->isTemplateDeclaration();
- templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
+ templateResolve(&m, td, sc, loc, targsi, e1, &args2);
}
}
FuncDeclaration *lastf = m.lastf;
@@ -627,7 +629,7 @@ L1:
}
else
{ TemplateDeclaration *td = s->isTemplateDeclaration();
- templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
+ templateResolve(&m, td, sc, loc, targsi, e2, &args1);
}
}
@@ -645,13 +647,12 @@ L1:
}
Expression *e;
- if (lastf && m.lastf == lastf ||
- id_r && m.last == MATCHnomatch)
+ if (lastf && m.lastf == lastf || !s && m.last == MATCHnomatch)
// Rewrite (e1 op e2) as e1.opfunc_r(e2)
- e = build_overload(loc, sc, e1, e2, id_r, targsi);
+ e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s_r);
else
// Rewrite (e1 op e2) as e2.opfunc(e1)
- e = build_overload(loc, sc, e2, e1, id, targsi);
+ e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s);
// When reversing operands of comparison operators,
// need to reverse the sense of the op
@@ -825,12 +826,12 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id)
}
Expression *e;
- if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
+ if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch)
// Rewrite (e1 op e2) as e1.opfunc(e2)
- e = build_overload(loc, sc, e1, e2, id, targsi);
+ e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
else
{ // Rewrite (e1 op e2) as e2.opfunc_r(e1)
- e = build_overload(loc, sc, e2, e1, id, targsi);
+ e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r);
// When reversing operands of comparison operators,
// need to reverse the sense of the op
@@ -1011,6 +1012,7 @@ Expression *BinAssignExp::op_overload(Scope *sc)
#endif
BinExp::semantic(sc);
+ e1 = resolveProperties(sc, e1);
e2 = resolveProperties(sc, e2);
Identifier *id = opId();
@@ -1067,7 +1069,7 @@ Expression *BinAssignExp::op_overload(Scope *sc)
}
else
{ TemplateDeclaration *td = s->isTemplateDeclaration();
- templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
+ templateResolve(&m, td, sc, loc, targsi, e1, &args2);
}
}
@@ -1086,10 +1088,8 @@ Expression *BinAssignExp::op_overload(Scope *sc)
goto L1;
}
- Expression *e;
// Rewrite (e1 op e2) as e1.opOpAssign(e2)
- e = build_overload(loc, sc, e1, e2, id, targsi);
- return e;
+ return build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
}
L1:
@@ -1130,22 +1130,20 @@ L1:
*/
Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
- Identifier *id, Objects *targsi)
+ Dsymbol *d)
{
+ assert(d);
Expression *e;
//printf("build_overload(id = '%s')\n", id->toChars());
//earg->print();
//earg->type->print();
- if (targsi)
- e = new DotTemplateInstanceExp(loc, ethis, id, targsi);
+ Declaration *decl = d->isDeclaration();
+ if (decl)
+ e = new DotVarExp(loc, ethis, decl, 0);
else
- e = new DotIdExp(loc, ethis, id);
-
- if (earg)
- e = new CallExp(loc, e, earg);
- else
- e = new CallExp(loc, e);
+ e = new DotIdExp(loc, ethis, d->ident);
+ e = new CallExp(loc, e, earg);
e = e->semantic(sc);
return e;
diff --git a/dmd2/parse.c b/dmd2/parse.c
index 6c66b9bc..c1eb0fff 100644
--- a/dmd2/parse.c
+++ b/dmd2/parse.c
@@ -1,6 +1,6 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2010 by Digital Mars
+// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -427,8 +427,10 @@ Dsymbols *Parser::parseDeclDefs(int once)
if (token.value == TOKidentifier &&
(tk = peek(&token))->value == TOKlparen &&
skipParens(tk, &tk) &&
- (peek(tk)->value == TOKlparen ||
- peek(tk)->value == TOKlcurly)
+ ((tk = peek(tk)), 1) &&
+ skipAttributes(tk, &tk) &&
+ (tk->value == TOKlparen ||
+ tk->value == TOKlcurly)
)
{
a = parseDeclarations(storageClass, comment);
@@ -971,7 +973,8 @@ Dsymbol *Parser::parseCtor()
Expression *constraint = tpl ? parseConstraint() : NULL;
- CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs, stc);
+ Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
+ CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf);
parseContracts(f);
// Wrap a template around it
@@ -987,7 +990,8 @@ Dsymbol *Parser::parseCtor()
int varargs;
Parameters *parameters = parseParameters(&varargs);
StorageClass stc = parsePostfix();
- CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs, stc);
+ Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
+ CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf);
parseContracts(f);
return f;
}
@@ -2074,6 +2078,7 @@ Objects *Parser::parseTemplateArgument()
case TOKstring:
case TOKfile:
case TOKline:
+ case TOKthis:
{ // Template argument is an expression
Expression *ea = parsePrimaryExp();
tiargs->push(ea);
@@ -2473,7 +2478,7 @@ Type *Parser::parseBasicType2(Type *t)
return NULL;
}
-Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
+Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl, StorageClass storage_class)
{ Type *ts;
//printf("parseDeclarator(tpl = %p)\n", tpl);
@@ -2602,6 +2607,7 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters *
/* Parse const/immutable/shared/inout/nothrow/pure postfix
*/
StorageClass stc = parsePostfix();
+ stc |= storage_class; // merge prefix storage classes
Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
if (stc & STCconst)
@@ -2816,7 +2822,7 @@ L2:
TemplateParameters *tpl = NULL;
ident = NULL;
- t = parseDeclarator(ts, &ident, &tpl);
+ t = parseDeclarator(ts, &ident, &tpl, storage_class);
assert(t);
if (!tfirst)
tfirst = t;
@@ -2879,6 +2885,9 @@ L2:
tpl = new TemplateParameters();
}
#endif
+
+ //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
+
FuncDeclaration *f =
new FuncDeclaration(loc, 0, ident, storage_class, t);
addComment(f, comment);
@@ -3184,6 +3193,8 @@ Initializer *Parser::parseInitializer()
break;
default:
+ if (comma == 1)
+ error("comma expected separating field initializers");
value = parseInitializer();
is->addInit(NULL, value);
comma = 1;
@@ -3427,9 +3438,8 @@ Statement *Parser::parseStatement(int flags)
case TOKstatic:
{ // Look ahead to see if it's static assert() or static if()
- Token *t;
- t = peek(&token);
+ Token *t = peek(&token);
if (t->value == TOKassert)
{
nextToken();
@@ -3452,6 +3462,13 @@ Statement *Parser::parseStatement(int flags)
s = new ScopeStatement(loc, s);
break;
}
+ if (t->value == TOKimport)
+ { nextToken();
+ Dsymbols *imports = new Dsymbols();
+ parseImport(imports, 1); // static import ...
+ s = new ImportStatement(loc, imports);
+ break;
+ }
goto Ldeclaration;
}
@@ -3477,6 +3494,7 @@ Statement *Parser::parseStatement(int flags)
case TOKwild:
case TOKnothrow:
case TOKpure:
+ case TOKref:
case TOKtls:
case TOKgshared:
case TOKat:
@@ -4233,6 +4251,13 @@ Statement *Parser::parseStatement(int flags)
break;
}
+ case TOKimport:
+ { Dsymbols *imports = new Dsymbols();
+ parseImport(imports, 0);
+ s = new ImportStatement(loc, imports);
+ break;
+ }
+
default:
error("found '%s' instead of statement", token.toChars());
goto Lerror;
@@ -4892,7 +4917,6 @@ int Parser::skipParens(Token *t, Token **pt)
break;
case TOKeof:
- case TOKsemicolon:
goto Lfalse;
default:
@@ -4910,6 +4934,61 @@ int Parser::skipParens(Token *t, Token **pt)
return 0;
}
+/*******************************************
+ * Skip attributes.
+ * Input:
+ * t is on a candidate attribute
+ * Output:
+ * *pt is set to first non-attribute token on success
+ * Returns:
+ * !=0 successful
+ * 0 some parsing error
+ */
+
+int Parser::skipAttributes(Token *t, Token **pt)
+{
+ while (1)
+ {
+ switch (t->value)
+ {
+ case TOKconst:
+ case TOKinvariant:
+ case TOKimmutable:
+ case TOKshared:
+ case TOKwild:
+ case TOKfinal:
+ case TOKauto:
+ case TOKscope:
+ case TOKoverride:
+ case TOKabstract:
+ case TOKsynchronized:
+ case TOKdeprecated:
+ case TOKnothrow:
+ case TOKpure:
+ case TOKref:
+ case TOKtls:
+ case TOKgshared:
+ //case TOKmanifest:
+ break;
+ case TOKat:
+ if (parseAttribute() == STCundefined)
+ break;
+ goto Lerror;
+ default:
+ goto Ldone;
+ }
+ t = peek(t);
+ }
+
+ Ldone:
+ if (*pt)
+ *pt = t;
+ return 1;
+
+ Lerror:
+ return 0;
+}
+
/********************************* Expression Parser ***************************/
Expression *Parser::parsePrimaryExp()
diff --git a/dmd2/parse.h b/dmd2/parse.h
index bfcddd57..9319503a 100644
--- a/dmd2/parse.h
+++ b/dmd2/parse.h
@@ -107,7 +107,7 @@ struct Parser : Lexer
Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL);
Type *parseBasicType();
Type *parseBasicType2(Type *t);
- Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL);
+ Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL, StorageClass storage_class = 0);
Dsymbols *parseDeclarations(StorageClass storage_class, unsigned char *comment);
void parseContracts(FuncDeclaration *f);
Statement *parseStatement(int flags);
@@ -124,6 +124,7 @@ struct Parser : Lexer
int isExpression(Token **pt);
int isTemplateInstance(Token *t, Token **pt);
int skipParens(Token *t, Token **pt);
+ int skipAttributes(Token *t, Token **pt);
Expression *parseExpression();
Expression *parsePrimaryExp();
diff --git a/dmd2/root/dchar.c b/dmd2/root/dchar.c
index c9462197..0b11a8a4 100644
--- a/dmd2/root/dchar.c
+++ b/dmd2/root/dchar.c
@@ -327,7 +327,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len)
case 2:
hash *= 37;
-#if __I86__
+#if LITTLE_ENDIAN
hash += *(const uint16_t *)str;
#else
hash += str[0] * 256 + str[1];
@@ -336,7 +336,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len)
case 3:
hash *= 37;
-#if __I86__
+#if LITTLE_ENDIAN
hash += (*(const uint16_t *)str << 8) +
((const uint8_t *)str)[2];
#else
@@ -346,7 +346,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len)
default:
hash *= 37;
-#if __I86__
+#if LITTLE_ENDIAN
hash += *(const uint32_t *)str;
#else
hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
@@ -379,7 +379,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len)
case 2:
hash *= 37;
-#if __I86__
+#if LITTLE_ENDIAN
hash += *(const uint16_t *)str;
#else
hash += str[0] * 256 + str[1];
@@ -388,7 +388,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len)
case 3:
hash *= 37;
-#if __I86__
+#if LITTLE_ENDIAN
hash += (*(const uint16_t *)str << 8) +
((const uint8_t *)str)[2];
#else
@@ -398,7 +398,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len)
default:
hash *= 37;
-#if __I86__
+#if LITTLE_ENDIAN
hash += *(const uint32_t *)str;
#else
hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
diff --git a/dmd2/root/man.c b/dmd2/root/man.c
index ad0d3c74..3770aa96 100644
--- a/dmd2/root/man.c
+++ b/dmd2/root/man.c
@@ -26,7 +26,7 @@ void browse(const char *url)
#endif
-#if linux || __FreeBSD__ || __sun&&__SVR4
+#if linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
#include
#include
diff --git a/dmd2/root/port.c b/dmd2/root/port.c
index 2bba4ef2..b7beef5c 100644
--- a/dmd2/root/port.c
+++ b/dmd2/root/port.c
@@ -1,5 +1,5 @@
-// Copyright (c) 1999-2009 by Digital Mars
+// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -70,6 +70,11 @@ double Port::pow(double x, double y)
return ::pow(x, y);
}
+long double Port::fmodl(long double x, long double y)
+{
+ return ::fmodl(x, y);
+}
+
unsigned long long Port::strtoull(const char *p, char **pend, int base)
{
return ::strtoull(p, pend, base);
@@ -201,6 +206,11 @@ double Port::pow(double x, double y)
return ::pow(x, y);
}
+long double Port::fmodl(long double x, long double y)
+{
+ return ::fmodl(x, y);
+}
+
unsigned _int64 Port::strtoull(const char *p, char **pend, int base)
{
unsigned _int64 number = 0;
@@ -315,7 +325,7 @@ char *Port::strupr(char *s)
#endif
-#if linux || __APPLE__ || __FreeBSD__ || __HAIKU__
+#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__
#include
#if linux
@@ -332,6 +342,7 @@ char *Port::strupr(char *s)
#include
#include
#include
+#include
static double zero = 0;
double Port::nan = NAN;
@@ -369,15 +380,15 @@ PortInitializer::PortInitializer()
}
#ifndef __HAIKU__
-#undef isnan
#endif
int Port::isNan(double r)
{
#if __APPLE__
return __inline_isnan(r);
-#elif defined __HAIKU__
+#elif defined __HAIKU__ || __OpenBSD__
return isnan(r);
#else
+ #undef isnan
return ::isnan(r);
#endif
}
@@ -386,9 +397,10 @@ int Port::isNan(long double r)
{
#if __APPLE__
return __inline_isnan(r);
-#elif defined __HAIKU__
+#elif defined __HAIKU__ || __OpenBSD__
return isnan(r);
#else
+ #undef isnan
return ::isnan(r);
#endif
}
@@ -416,15 +428,15 @@ int Port::isFinite(double r)
}
#if !defined __HAIKU__
-#undef isinf
#endif
int Port::isInfinity(double r)
{
#if __APPLE__
return fpclassify(r) == FP_INFINITE;
-#elif defined __HAIKU__
+#elif defined __HAIKU__ || __OpenBSD__
return isinf(r);
#else
+ #undef isinf
return ::isinf(r);
#endif
}
@@ -447,6 +459,15 @@ double Port::pow(double x, double y)
return ::pow(x, y);
}
+long double Port::fmodl(long double x, long double y)
+{
+#if __FreeBSD__ || __OpenBSD__
+ return ::fmod(x, y); // hack for now, fix later
+#else
+ return ::fmodl(x, y);
+#endif
+}
+
unsigned long long Port::strtoull(const char *p, char **pend, int base)
{
return ::strtoull(p, pend, base);
@@ -460,7 +481,11 @@ char *Port::ull_to_string(char *buffer, ulonglong ull)
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
{
+#if __OpenBSD__
+ assert(0);
+#else
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
+#endif
return buffer;
}
diff --git a/dmd2/root/port.h b/dmd2/root/port.h
index b4e7fbb7..d915991d 100644
--- a/dmd2/root/port.h
+++ b/dmd2/root/port.h
@@ -40,7 +40,8 @@ struct Port
static double dbl_min;
static long double ldbl_max;
-#if __GNUC__ && !defined __HAIKU__
+#if !defined __HAIKU__ || __OpenBSD__
+#elif __GNUC__
// These conflict with macros in math.h, should rename them
#undef isnan
#undef isfinite
@@ -60,6 +61,8 @@ struct Port
static double floor(double);
static double pow(double x, double y);
+ static long double fmodl(long double x, long double y);
+
static ulonglong strtoull(const char *p, char **pend, int base);
static char *ull_to_string(char *buffer, ulonglong ull);
diff --git a/dmd2/root/response.c b/dmd2/root/response.c
index ff085199..56c350af 100644
--- a/dmd2/root/response.c
+++ b/dmd2/root/response.c
@@ -19,7 +19,7 @@
#include
#endif
-#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
+#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
#include
#include
#include
diff --git a/dmd2/root/root.c b/dmd2/root/root.c
index 6cd0ea64..5513e195 100644
--- a/dmd2/root/root.c
+++ b/dmd2/root/root.c
@@ -8,7 +8,7 @@
// See the included readme.txt for details.
#ifndef POSIX
-#define POSIX (linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4)
+#define POSIX (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4)
#endif
#include
diff --git a/dmd2/statement.c b/dmd2/statement.c
index 1a0c8bba..d11a8e96 100644
--- a/dmd2/statement.c
+++ b/dmd2/statement.c
@@ -53,11 +53,9 @@ extern int os_critsecsize64();
Statement::Statement(Loc loc)
: loc(loc)
{
-#ifdef _DH
// If this is an in{} contract scope statement (skip for determining
// inlineStatus of a function body for header content)
incontract = 0;
-#endif
}
Statement *Statement::syntaxCopy()
@@ -178,6 +176,11 @@ int Statement::isEmpty()
return FALSE;
}
+Statement *Statement::last()
+{
+ return this;
+}
+
/****************************************
* If this statement has code that needs to run in a finally clause
* at the end of the current scope, return that code in the form of
@@ -616,6 +619,22 @@ ReturnStatement *CompoundStatement::isReturnStatement()
return rs;
}
+Statement *CompoundStatement::last()
+{
+ Statement *s = NULL;
+
+ for (size_t i = statements->dim; i; --i)
+ { s = (Statement *) statements->data[i - 1];
+ if (s)
+ {
+ s = s->last();
+ if (s)
+ break;
+ }
+ }
+ return s;
+}
+
void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
for (int i = 0; i < statements->dim; i++)
@@ -639,12 +658,31 @@ int CompoundStatement::blockExit(bool mustNotThrow)
{
//printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
int result = BEfallthru;
+ Statement *slast = NULL;
for (size_t i = 0; i < statements->dim; i++)
{ Statement *s = (Statement *) statements->data[i];
if (s)
{
-//printf("result = x%x\n", result);
-//printf("%s\n", s->toChars());
+ //printf("result = x%x\n", result);
+ //printf("%s\n", s->toChars());
+ if (global.params.warnings && result & BEfallthru && slast)
+ {
+ slast = slast->last();
+ if (slast && (s->isCaseStatement() || s->isDefaultStatement()))
+ {
+ // Allow if last case/default was empty
+ CaseStatement *sc = slast->isCaseStatement();
+ DefaultStatement *sd = slast->isDefaultStatement();
+ if (sc && sc->statement->isEmpty())
+ ;
+ else if (sd && sd->statement->isEmpty())
+ ;
+ else
+ s->error("switch case fallthrough - use 'goto %s;' if intended",
+ s->isCaseStatement() ? "case" : "default");
+ }
+ }
+
if (!(result & BEfallthru) && !s->comeFrom())
{
if (s->blockExit(mustNotThrow) != BEhalt && !s->isEmpty())
@@ -655,6 +693,7 @@ int CompoundStatement::blockExit(bool mustNotThrow)
result &= ~BEfallthru;
result |= s->blockExit(mustNotThrow);
}
+ slast = s;
}
}
return result;
@@ -1725,7 +1764,7 @@ Lagain:
// __r.next
e = new VarExp(loc, r);
- Expression *increment = new DotIdExp(loc, e, idnext);
+ Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idnext));
/* Declaration statement for e:
* auto e = __r.idhead;
@@ -2399,9 +2438,6 @@ Statement *IfStatement::syntaxCopy()
Statement *IfStatement::semantic(Scope *sc)
{
- condition = condition->semantic(sc);
- condition = resolveProperties(sc, condition);
-
// Evaluate at runtime
unsigned cs0 = sc->callSuper;
unsigned cs1;
@@ -2415,24 +2451,29 @@ Statement *IfStatement::semantic(Scope *sc)
sym->parent = sc->scopesym;
scd = sc->push(sym);
- Type *t = arg->type ? arg->type : condition->type;
- match = new VarDeclaration(loc, t, arg->ident, NULL);
- match->noscope = 1;
- match->semantic(scd);
- if (!scd->insert(match))
- assert(0);
+ match = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, condition));
match->parent = sc->func;
- /* Generate:
- * ((arg = condition), arg)
- */
- VarExp *v = new VarExp(0, match);
- condition = new AssignExp(loc, v, condition);
- condition = new CommaExp(loc, condition, v);
+ DeclarationExp *de = new DeclarationExp(loc, match);
+ VarExp *ve = new VarExp(0, match);
+ condition = new CommaExp(loc, de, ve);
condition = condition->semantic(scd);
+
+ if (match->edtor)
+ {
+ Statement *sdtor = new ExpStatement(loc, match->edtor);
+ sdtor = new OnScopeStatement(loc, TOKon_scope_exit, sdtor);
+ ifbody = new CompoundStatement(loc, sdtor, ifbody);
+ match->noscope = 1;
+ }
}
else
+ {
+ condition = condition->semantic(sc);
+ condition = condition->addDtorHook(sc);
+ condition = resolveProperties(sc, condition);
scd = sc->push();
+ }
// Convert to boolean after declaring arg so this works:
// if (S arg = S()) {}
@@ -2913,7 +2954,8 @@ Statement *SwitchStatement::semantic(Scope *sc)
if (!sc->sw->sdefault && !isFinal)
{ hasNoDefault = 1;
- warning("switch statement has no default");
+ if (!global.params.useDeprecated)
+ error("non-final switch statement without a default is deprecated");
// Generate runtime error if the default is hit
Statements *a = new Statements();
@@ -3007,7 +3049,7 @@ int SwitchStatement::blockExit(bool mustNotThrow)
void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
- buf->writestring("switch (");
+ buf->writestring(isFinal ? "final switch (" : "switch (");
condition->toCBuffer(buf, hgs);
buf->writebyte(')');
buf->writenl();
@@ -3510,7 +3552,8 @@ Statement *ReturnStatement::semantic(Scope *sc)
exp = exp->semantic(sc);
exp = resolveProperties(sc, exp);
- exp = exp->optimize(WANTvalue);
+ if (!((TypeFunction *)fd->type)->isref)
+ exp = exp->optimize(WANTvalue);
if (fd->nrvo_can && exp->op == TOKvar)
{ VarExp *ve = (VarExp *)exp;
@@ -3592,7 +3635,8 @@ Statement *ReturnStatement::semantic(Scope *sc)
else if (tbret->ty != Tvoid)
{
exp = exp->implicitCastTo(sc, tret);
- exp = exp->optimize(WANTvalue);
+ if (!((TypeFunction *)fd->type)->isref)
+ exp = exp->optimize(WANTvalue);
}
}
else if (fd->inferRetType)
@@ -3745,6 +3789,17 @@ Statement *ReturnStatement::semantic(Scope *sc)
return new CompoundStatement(loc, s, this);
}
+ if (exp)
+ { if (exp->op == TOKcall)
+ valueNoDtor(exp);
+ else
+ {
+ Expression *e = exp->isTemp();
+ if (e)
+ exp = e; // don't need temporary
+ }
+ }
+
return this;
}
@@ -4331,8 +4386,7 @@ int TryCatchStatement::blockExit(bool mustNotThrow)
/* If we're catching Object, then there is no throwing
*/
Identifier *id = c->type->toBasetype()->isClassHandle()->ident;
- if (i == 0 &&
- (id == Id::Object || id == Id::Throwable || id == Id::Exception))
+ if (id == Id::Object || id == Id::Throwable || id == Id::Exception)
{
result &= ~BEthrow;
}
@@ -4412,6 +4466,15 @@ void Catch::semantic(Scope *sc)
type = Type::terror;
}
}
+ else if (sc->func &&
+ !sc->intypeof &&
+ cd != ClassDeclaration::exception &&
+ !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
+ sc->func->setUnsafe())
+ {
+ error(loc, "can only catch class objects derived from Exception in @safe code, not '%s'", type->toChars());
+ type = Type::terror;
+ }
else if (ident)
{
var = new VarDeclaration(loc, type, ident, NULL);
@@ -5014,3 +5077,50 @@ void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
}
#endif
+
+/************************ ImportStatement ***************************************/
+
+ImportStatement::ImportStatement(Loc loc, Dsymbols *imports)
+ : Statement(loc)
+{
+ this->imports = imports;
+}
+
+Statement *ImportStatement::syntaxCopy()
+{
+ Dsymbols *m = new Dsymbols();
+ m->setDim(imports->dim);
+ for (int i = 0; i < imports->dim; i++)
+ { Dsymbol *s = (Dsymbol *)imports->data[i];
+ m->data[i] = (void *)s->syntaxCopy(NULL);
+ }
+ return new ImportStatement(loc, m);
+}
+
+Statement *ImportStatement::semantic(Scope *sc)
+{
+ for (int i = 0; i < imports->dim; i++)
+ { Dsymbol *s = (Dsymbol *)imports->data[i];
+ s->semantic(sc);
+ sc->insert(s);
+ }
+ return this;
+}
+
+int ImportStatement::blockExit(bool mustNotThrow)
+{
+ return BEfallthru;
+}
+
+int ImportStatement::isEmpty()
+{
+ return TRUE;
+}
+
+void ImportStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+ for (int i = 0; i < imports->dim; i++)
+ { Dsymbol *s = (Dsymbol *)imports->data[i];
+ s->toCBuffer(buf, hgs);
+ }
+}
diff --git a/dmd2/statement.h b/dmd2/statement.h
index d96c3f67..a6f43ac7 100644
--- a/dmd2/statement.h
+++ b/dmd2/statement.h
@@ -1,6 +1,6 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2010 by Digital Mars
+// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -48,6 +48,9 @@ struct GotoStatement;
struct ScopeStatement;
struct TryCatchStatement;
struct TryFinallyStatement;
+struct CaseStatement;
+struct DefaultStatement;
+struct LabelStatement;
struct HdrGenState;
struct InterState;
#if IN_LLVM
@@ -114,12 +117,7 @@ struct Statement : Object
void warning(const char *format, ...) IS_PRINTF(2);
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; }
-#if IN_LLVM
- virtual LabelStatement *isLabelStatement() { return NULL; }
-#endif
-#ifdef _DH
int incontract;
-#endif
virtual ScopeStatement *isScopeStatement() { return NULL; }
virtual Statement *semantic(Scope *sc);
Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue);
@@ -133,6 +131,7 @@ struct Statement : Object
virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
virtual Statements *flatten(Scope *sc);
virtual Expression *interpret(InterState *istate);
+ virtual Statement *last();
virtual int inlineCost(InlineCostState *ics);
virtual Expression *doInline(InlineDoState *ids);
@@ -146,7 +145,9 @@ struct Statement : Object
virtual CompoundStatement *isCompoundStatement() { return NULL; }
virtual ReturnStatement *isReturnStatement() { return NULL; }
virtual IfStatement *isIfStatement() { return NULL; }
- virtual CaseStatement* isCaseStatement() { return NULL; }
+ virtual CaseStatement *isCaseStatement() { return NULL; }
+ virtual DefaultStatement *isDefaultStatement() { return NULL; }
+ virtual LabelStatement *isLabelStatement() { return NULL; }
#if IN_LLVM
virtual void toNakedIR(IRState *irs);
@@ -216,6 +217,7 @@ struct CompoundStatement : Statement
virtual Statements *flatten(Scope *sc);
ReturnStatement *isReturnStatement();
Expression *interpret(InterState *istate);
+ Statement *last();
int inlineCost(InlineCostState *ics);
Expression *doInline(InlineDoState *ids);
@@ -534,13 +536,12 @@ struct CaseStatement : Statement
int comeFrom();
Expression *interpret(InterState *istate);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+ CaseStatement *isCaseStatement() { return this; }
Statement *inlineScan(InlineScanState *iss);
void toIR(IRState *irs);
- CaseStatement* isCaseStatement() { return this; }
-
#if IN_LLVM
llvm::BasicBlock* bodyBB;
llvm::Value* llvmIdx;
@@ -582,6 +583,7 @@ struct DefaultStatement : Statement
int comeFrom();
Expression *interpret(InterState *istate);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+ DefaultStatement *isDefaultStatement() { return this; }
Statement *inlineScan(InlineScanState *iss);
@@ -885,13 +887,13 @@ struct LabelStatement : Statement
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
Statement *inlineScan(InlineScanState *iss);
+ LabelStatement *isLabelStatement() { return this; }
void toIR(IRState *irs);
#if IN_LLVM
bool asmLabel; // for labels inside inline assembler
void toNakedIR(IRState *irs);
- virtual LabelStatement *isLabelStatement() { return this; }
#endif
};
@@ -925,8 +927,8 @@ struct AsmStatement : Statement
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
void toIR(IRState *irs);
-
-#if IN_LLVM
+
+ #if IN_LLVM
// non-zero if this is a branch, contains the target labels identifier
Identifier* isBranchToLabel;
@@ -934,6 +936,25 @@ struct AsmStatement : Statement
#endif
};
+struct ImportStatement : Statement
+{
+ Dsymbols *imports; // Array of Import's
+
+ ImportStatement(Loc loc, Dsymbols *imports);
+ Statement *syntaxCopy();
+ Statement *semantic(Scope *sc);
+ int blockExit(bool mustNotThrow);
+ int isEmpty();
+ Expression *interpret(InterState *istate);
+
+ void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+ int inlineCost(InlineCostState *ics);
+ Expression *doInline(InlineDoState *ids);
+
+ //void toIR(IRState *irs);
+};
+
struct AsmBlockStatement : CompoundStatement
{
TryFinallyStatement* enclosingFinally;
diff --git a/dmd2/staticassert.h b/dmd2/staticassert.h
index 632c1e90..2f7e0906 100644
--- a/dmd2/staticassert.h
+++ b/dmd2/staticassert.h
@@ -18,9 +18,7 @@
#include "dsymbol.h"
struct Expression;
-#ifdef _DH
struct HdrGenState;
-#endif
struct StaticAssert : Dsymbol
{
diff --git a/dmd2/struct.c b/dmd2/struct.c
index c045b279..92c8c418 100644
--- a/dmd2/struct.c
+++ b/dmd2/struct.c
@@ -1,6 +1,6 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2010 by Digital Mars
+// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -38,6 +38,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
structalign = 0; // struct member alignment in effect
hasUnions = 0;
sizeok = 0; // size not determined yet
+ deferred = NULL;
isdeprecated = 0;
inv = NULL;
aggNew = NULL;
@@ -348,7 +349,7 @@ void StructDeclaration::semantic(Scope *sc)
{
Scope *sc2;
- //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toChars(), sizeok);
+ //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
//static int count; if (++count == 20) halt();
@@ -675,6 +676,11 @@ void StructDeclaration::semantic(Scope *sc)
semantic2(sc);
semantic3(sc);
}
+ if (deferred)
+ {
+ deferred->semantic2(sc);
+ deferred->semantic3(sc);
+ }
}
Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags)
@@ -730,6 +736,7 @@ const char *StructDeclaration::kind()
UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
: StructDeclaration(loc, id)
{
+ hasUnions = 1;
}
Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
diff --git a/dmd2/template.c b/dmd2/template.c
index 8a9b01c2..d48d432c 100644
--- a/dmd2/template.c
+++ b/dmd2/template.c
@@ -376,6 +376,20 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
this->literal = 0;
this->ismixin = ismixin;
this->previous = NULL;
+
+ // Compute in advance for Ddoc's use
+ if (members)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(members, &s))
+ {
+ if (s && s->ident && s->ident->equals(ident))
+ {
+ onemember = s;
+ s->parent = this;
+ }
+ }
+ }
}
Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
@@ -500,6 +514,8 @@ void TemplateDeclaration::semantic(Scope *sc)
paramscope->pop();
+ // Compute again
+ onemember = NULL;
if (members)
{
Dsymbol *s;
@@ -1650,11 +1666,14 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc,
void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
-#if 0 // Should handle template functions
+#if 0 // Should handle template functions for doc generation
if (onemember && onemember->isFuncDeclaration())
buf->writestring("foo ");
#endif
- buf->writestring(kind());
+ if (hgs->ddoc)
+ buf->writestring(kind());
+ else
+ buf->writestring("template");
buf->writeByte(' ');
buf->writestring(ident->toChars());
buf->writeByte('(');
@@ -4126,7 +4145,13 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
{ Dsymbol *sd = (Dsymbol *)Module::deferred.data[i];
if (sd->parent == this)
+ {
+ //printf("deferred %s %s\n", sd->parent->toChars(), sd->toChars());
+ AggregateDeclaration *ad = sd->isAggregateDeclaration();
+ if (ad)
+ ad->deferred = this;
goto Laftersemantic;
+ }
}
/* The problem is when to parse the initializer for a variable.
@@ -4730,6 +4755,12 @@ Identifier *TemplateInstance::genIdent(Objects *args)
ea = NULL;
goto Lsa;
}
+ if (ea->op == TOKthis)
+ {
+ sa = ((ThisExp *)ea)->var;
+ ea = NULL;
+ goto Lsa;
+ }
if (ea->op == TOKfunction)
{
sa = ((FuncExp *)ea)->fd;
diff --git a/dmd2/traits.c b/dmd2/traits.c
index 0753ad23..b085b0ed 100644
--- a/dmd2/traits.c
+++ b/dmd2/traits.c
@@ -163,7 +163,7 @@ Expression *TraitsExp::semantic(Scope *sc)
#if DMDV2
else if (ident == Id::isStaticFunction)
{
- ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && !f->needThis())
+ ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && !f->needThis() && !f->isNested())
}
else if (ident == Id::isRef)
{
diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp
index 9c5a78ad..0dc9716e 100644
--- a/gen/asmstmt.cpp
+++ b/gen/asmstmt.cpp
@@ -162,7 +162,7 @@ Statement *AsmStatement::semantic(Scope *sc)
//puts(toChars());
- sc->func->inlineAsm = 1;
+ sc->func->inlineAsm = true;
sc->func->inlineStatus = ILSno; // %% not sure
// %% need to set DECL_UNINLINABLE too?
sc->func->hasReturnExp = 1; // %% DMD does this, apparently...