Commits

prokhin_alexey  committed add6d77

Updated to dmdfe 2.054

  • Participants
  • Parent commits 90dbda3
  • Branches merge

Comments (0)

Files changed (54)

         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));
     {
         Expression *ec;
         Expressions *arguments;
-        bool isBit = (n->ty == Tbit);
 
         //LDC: Build arguments.
         static FuncDeclaration *adSort_fd = NULL;
             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();
     }

File dmd2/aggregate.h

                                 // 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
     static ClassDeclaration *object;
     static ClassDeclaration *classinfo;
     static ClassDeclaration *throwable;
+    static ClassDeclaration *exception;
 
     ClassDeclaration *baseClass;        // NULL only if this is Object
 #if DMDV1

File dmd2/attrib.h

 struct Initializer;
 struct Module;
 struct Condition;
-#ifdef _DH
 struct HdrGenState;
-#endif
 
 /**************************************************************/
 
 #include "utf.h"
 #include "declaration.h"
 #include "aggregate.h"
+#include "scope.h"
+
+//#define DUMP .dump(__PRETTY_FUNCTION__, this)
+#define DUMP
 
 /* ==================== implicitCast ====================== */
 
      */
     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;
     }
 
 
     switch (ty)
     {
-        case Tbit:
         case Tbool:
             value &= 1;
             ty = Tint32;
     // Only allow conversion if no change in value
     switch (toty)
     {
-        case Tbit:
         case Tbool:
             if ((value & 1) != value)
                 goto Lno;
  */
 
 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();
 
 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;
     }
     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()))
         case Tuns8:
         case Tint16:
         case Tuns16:
-        case Tbit:
         case Tbool:
         case Tchar:
         case Twchar:
 
 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))
+    // Should we ignore the possibility of div-by-0???
+    if (ir2.containsZero())
+        return Expression::getIntRange() DUMP;
+
+    // [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)
     {
-        return Expression::getIntRange();
+        irNum.imax.negative = false;
+        irNum.imax.value = 0;
     }
+    else if (irNum.imax > irDen.imax)
+        irNum.imax = irDen.imax;
 
-    if (ir2.imax == 0 || ir2.imin == 0)
-        return Expression::getIntRange();
+    return irNum.cast(type) DUMP;
+}
 
-    ir.imin = ir1.imin / ir2.imax;
-    ir.imax = ir1.imax / ir2.imin;
+// 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;
+}
 
-    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;
-}
 
 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;
+}
+

File dmd2/class.c

 ClassDeclaration *ClassDeclaration::classinfo;
 ClassDeclaration *ClassDeclaration::object;
 ClassDeclaration *ClassDeclaration::throwable;
+ClassDeclaration *ClassDeclaration::exception;
 
 ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
     : AggregateDeclaration(loc, id)
             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)
     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);
     }
 #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)

File dmd2/clone.c

         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);
 
         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();
         {   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);
 
     /* 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;
             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);
         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();
                 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);
 #include "module.h"
 #include "template.h"
 #include "lexer.h"
-#ifdef _DH
 #include "mtype.h"
 #include "scope.h"
-#endif
 
 int findCondition(Array *ids, Identifier *ident)
 {
         "D_NET",
 #endif
         "OSX", "FreeBSD",
+        "OpenBSD",
         "Solaris",
         "LittleEndian", "BigEndian",
         "all",
 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);
 

File dmd2/constfold.c

 #include "declaration.h"
 #include "utf.h"
 
-#if __FreeBSD__
-#define fmodl fmod      // hack for now, fix later
-#endif
+#define LOG 0
 
-#define LOG 0
+int RealEquals(real_t x1, real_t x2);
 
 Expression *expType(Type *type, Expression *e)
 {
         {   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__)
 	// 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__)
 	// 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
 
         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);
         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();
 
         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
             if (ex->isBool(TRUE))
             {   e = (Expression *)ae->values->data[i];
                 e->type = type;
+                if (e->checkSideEffect(2))
+                    e = EXP_CANT_INTERPRET;
                 break;
             }
         }
         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

File dmd2/declaration.c

     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;
     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
     }
     else
         st->hbasetype = hbasetype->syntaxCopy();
-#endif
+
     return st;
 }
 
     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;
     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);
         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
     }
     else
         sa->haliassym = haliassym->syntaxCopy(s);
-#endif
+
     return sa;
 }
 
 void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("alias ");
-#if 0 && _DH
+#if 0
     if (hgs->hdrgen)
     {
         if (haliassym)
     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;
         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
     }
     else
         sv->hinit = hinit->syntaxCopy();
-#endif
+
     return sv;
 }
 
     //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();
                     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())
                                         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;
                                 }
                             }
     return 1;
 }
 
+
 /*******************************
  * Does symbol go into data segment?
  * Includes extern variables.

File dmd2/declaration.h

     const char *kind();
     Type *getType();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-#ifdef _DH
     Type *htype;
     Type *hbasetype;
-#endif
 
     void toDocBuffer(OutBuffer *buf);
 
     Type *getType();
     Dsymbol *toAlias();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-#ifdef _DH
     Type *htype;
     Dsymbol *haliassym;
-#endif
 
     void toDocBuffer(OutBuffer *buf);
 
     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();
     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
     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
     int isCodeseg();
     int isOverloadable();
     enum PURE isPure();
+    bool setImpure();
     int isSafe();
     int isTrusted();
+    bool setUnsafe();
     virtual int isNested();
     int needThis();
     virtual int isVirtual();
 
     // true if overridden with the pragma(allow_inline); stmt
     bool allowInlining;
+    
+    // true if has inline assembler
+    bool inlineAsm;
 #endif
 };
 
 };
 
 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);
     int isVirtual();
     int addPreInvariant();
     int addPostInvariant();
-#ifdef _DH
     DeleteDeclaration *isDeleteDeclaration() { return this; }
-#endif
 };
 
 #endif /* DMD_DECLARATION_H */
 
 // 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
 LINK2 = <a href=\"$1\">$+</a>\n\
 LPAREN= (\n\
 RPAREN= )\n\
+DOLLAR= $\n\
 \n\
 RED =   <font color=red>$0</font>\n\
 BLUE =  <font color=blue>$0</font>\n\
         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
     }
 }
 
-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)
 {
             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);
         }
     }
 }
 
+#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)

File dmd2/dsymbol.c

     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();
 }
 

File dmd2/dsymbol.h

     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);
     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; }
 struct Identifier;
 struct Type;
 struct Expression;
-#ifdef _DH
 struct HdrGenState;
-#endif
 
 
 struct EnumDeclaration : ScopeDsymbol

File dmd2/expression.c

 #include "attrib.h"
 #include "hdrgen.h"
 #include "parse.h"
+#include "doc.h"
 
 #if IN_DMD
 Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim);
                 break;
         }
 
-        fd = fd->parent->isFuncDeclaration();
+        fd = parent->isFuncDeclaration();
     }
 
     if (!fd->isThis())
 
         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);
                 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;
     }
 }
 
+/************************************************
+ * 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.
  */
                         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;
                     /* 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
 }
 
 #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
         }
         // 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
 #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
 
     {
         switch (t->ty)
         {
-            case Tbit:
             case Tbool:         value = (value != 0);           break;
             case Tint8:         value = (d_int8)  value;        break;
             case Tchar:
                      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)");
                 buf->printf("%juLU", v);
                 break;
 
-            case Tbit:
             case Tbool:
                 buf->writestring((char *)(v ? "true" : "false"));
                 break;
 
 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
      * 0X1.9P+2                 => 19P2
      */
 
-//#if 1
 //    if (Port::isNan(value))
-//#elif __APPLE__
 #if __APPLE__
     if (__inline_isnan(value))
 #else
 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);
 
                 break;
         }
     }
+    if (hgs->ddoc)
+        escapeDdocString(buf, o);
     buf->writeByte('"');
     if (postfix)
         buf->writeByte(postfix);
     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;
 }
 
 #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
 
 #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
 
 #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
 
 #if DMDV2
 int NewAnonClassExp::canThrow(bool mustNotThrow)
 {
+    assert(0);          // should have been lowered by semantic()
     return 1;
 }
 #endif
     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
 }
 
 #if DMDV2
+/**************************************
+ * Does symbol, when initialized, throw?
+ * Mirrors logic in Dsymbol_toElem().
+ */
+
+int Dsymbol_canThrow(Dsymbol *s, bool 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;
+                }