[d] Committed merge with upstream dmd

Message ID CABOHX+dau4orSPEaW8A=D9cFZ+Qfhmo8UOb5sr1tojATtoLA_w@mail.gmail.com
State New
Headers show
Series
  • [d] Committed merge with upstream dmd
Related show

Commit Message

Iain Buclaw Jan. 21, 2019, 9:16 p.m.
Hi,

This patch merges the D front-end implementation with dmd upstream 180465274.

Main bulk of it reduces the memory footprint of the CTFE interpreter
by replacing new with emplacement new in many places.

Bootstrapped and regression tested on x86_64-linux-gnu.

Committed to trunk as r268124.

-- 
Iain
---
gcc/d/ChangeLog:

2019-01-21  Iain Buclaw  <ibuclaw@gdcproject.org>

        * d-frontend.cc (Compiler::paintAsType): Update for new signature.
---

Comments

Andreas Schwab Jan. 22, 2019, 10:08 a.m. | #1
In file included from ../../gcc/d/d-system.h:23,
                 from ../../gcc/d/dmd/root/dsystem.h:24,
                 from ../../gcc/d/dmd/mtype.c:11:
../../gcc/d/dmd/mtype.c: In member function 'Identifier* Type::getTypeInfoIdent()':
../../gcc/d/dmd/mtype.c:2329:33: error: comparison of integer expressions of different signedness: 'int' and 'size_t' {aka 'long unsigned int'} [-Werror=sign-compare]
 2329 |     assert(0 < length && length < namelen);     // don't overflow the buffer
      |                          ~~~~~~~^~~~~~~~~
../../gcc/system.h:742:14: note: in definition of macro 'gcc_assert'
  742 |    ((void)(!(EXPR) ? fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0 : 0))
      |              ^~~~
../../gcc/d/dmd/mtype.c:2329:5: note: in expansion of macro 'assert'
 2329 |     assert(0 < length && length < namelen);     // don't overflow the buffer
      |     ^~~~~~

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
Iain Buclaw Jan. 22, 2019, 9:21 p.m. | #2
On Tue, 22 Jan 2019 at 11:08, Andreas Schwab <schwab@suse.de> wrote:
>

> In file included from ../../gcc/d/d-system.h:23,

>                  from ../../gcc/d/dmd/root/dsystem.h:24,

>                  from ../../gcc/d/dmd/mtype.c:11:

> ../../gcc/d/dmd/mtype.c: In member function 'Identifier* Type::getTypeInfoIdent()':

> ../../gcc/d/dmd/mtype.c:2329:33: error: comparison of integer expressions of different signedness: 'int' and 'size_t' {aka 'long unsigned int'} [-Werror=sign-compare]

>  2329 |     assert(0 < length && length < namelen);     // don't overflow the buffer

>       |                          ~~~~~~~^~~~~~~~~

> ../../gcc/system.h:742:14: note: in definition of macro 'gcc_assert'

>   742 |    ((void)(!(EXPR) ? fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0 : 0))

>       |              ^~~~

> ../../gcc/d/dmd/mtype.c:2329:5: note: in expansion of macro 'assert'

>  2329 |     assert(0 < length && length < namelen);     // don't overflow the buffer

>       |     ^~~~~~

>


Sorry that slipped through.  Fix has gone in upstream and I'll commit it now.

-- 
Iain
---

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index e8ab8df4f7b..c1c6cc145c4 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-180465274b72a2ff218449f6793af0fbaabbcaa3
+e21c07e84bd9668e1c0fc1f45e514c5fd76988e7

 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index 09161a313ee..2a23cab74fd 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -2326,7 +2326,7 @@ Identifier *Type::getTypeInfoIdent()

     int length = sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned
long long) 9 + len, buf.data);
     //printf("%p, deco = %s, name = %s\n", this, deco, name);
-    assert(0 < length && length < namelen);     // don't overflow the buffer
+    assert(0 < length && (size_t)length < namelen);     // don't
overflow the buffer

     Identifier *id = Identifier::idPool(name, length);

Patch

diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index a1c0d53d1ca..d1d3c78ec86 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -446,7 +446,7 @@  Compiler::genCmain (Scope *sc)
    so we just lower the value to GCC and return the converted CST.  */
 
 Expression *
-Compiler::paintAsType (Expression *expr, Type *type)
+Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
 {
   /* We support up to 512-bit values.  */
   unsigned char buffer[64];
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index a3b2db74af4..e8ab8df4f7b 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-cd2034cd7b157dd8f3e94c684061bb1aa630b2b6
+180465274b72a2ff218449f6793af0fbaabbcaa3
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h
index e8ab9925c5a..a8520788f98 100644
--- a/gcc/d/dmd/compiler.h
+++ b/gcc/d/dmd/compiler.h
@@ -19,6 +19,7 @@  class Expression;
 class Module;
 class Type;
 struct Scope;
+struct UnionExp;
 
 // DMD-generated module `__entrypoint` where the C main resides
 extern Module *entrypoint;
@@ -28,7 +29,7 @@  extern Module *rootHasMain;
 struct Compiler
 {
     // CTFE support for cross-compilation.
-    static Expression *paintAsType(Expression *, Type *);
+    static Expression *paintAsType(UnionExp *, Expression *, Type *);
     // Backend
     static void loadModule(Module *);
     static void genCmain(Scope *);
diff --git a/gcc/d/dmd/constfold.c b/gcc/d/dmd/constfold.c
index 83f0f3ef14f..ddd356bb966 100644
--- a/gcc/d/dmd/constfold.c
+++ b/gcc/d/dmd/constfold.c
@@ -1457,8 +1457,7 @@  UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
             memcpy(elements->tdata(),
                    es1->elements->tdata() + ilwr,
                    (size_t)(iupr - ilwr) * sizeof((*es1->elements)[0]));
-            new(&ue) ArrayLiteralExp(e1->loc, elements);
-            ue.exp()->type = type;
+            new(&ue) ArrayLiteralExp(e1->loc, type, elements);
         }
     }
     else
@@ -1606,6 +1605,7 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
 
             new(&ue) StringExp(loc, s, len);
             StringExp *es = (StringExp *)ue.exp();
+            es->type = type;
             es->sz = sz;
             es->committed = 1;
         }
@@ -1614,9 +1614,8 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
             // Create an ArrayLiteralExp
             Expressions *elements = new Expressions();
             elements->push(e);
-            new(&ue) ArrayLiteralExp(e->loc, elements);
+            new(&ue) ArrayLiteralExp(e->loc, type, elements);
         }
-        ue.exp()->type = type;
         assert(ue.exp()->type);
         return ue;
     }
@@ -1627,8 +1626,7 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
             // Handle null ~= null
             if (t1->ty == Tarray && t2 == t1->nextOf())
             {
-                new(&ue) ArrayLiteralExp(e1->loc, e2);
-                ue.exp()->type = type;
+                new(&ue) ArrayLiteralExp(e1->loc, type, e2);
                 assert(ue.exp()->type);
                 return ue;
             }
@@ -1695,9 +1693,8 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
         {
             (*elems)[i] = ea->getElement(i);
         }
-        new(&ue) ArrayLiteralExp(e1->loc, elems);
+        new(&ue) ArrayLiteralExp(e1->loc, type, elems);
         ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
-        dest->type = type;
         sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim);
         assert(ue.exp()->type);
         return ue;
@@ -1715,9 +1712,8 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
         {
             (*elems)[es->len + i] = ea->getElement(i);
         }
-        new(&ue) ArrayLiteralExp(e1->loc, elems);
+        new(&ue) ArrayLiteralExp(e1->loc, type, elems);
         ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
-        dest->type = type;
         sliceAssignArrayLiteralFromString(dest, es, 0);
         assert(ue.exp()->type);
         return ue;
@@ -1783,7 +1779,7 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
         // Concatenate the arrays
         Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
 
-        new(&ue) ArrayLiteralExp(e1->loc, elems);
+        new(&ue) ArrayLiteralExp(e1->loc, NULL, elems);
 
         e = ue.exp();
         if (type->toBasetype()->ty == Tsarray)
@@ -1809,7 +1805,7 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
         // Concatenate the array with null
         Expressions *elems = ArrayLiteralExp::copyElements(e);
 
-        new(&ue) ArrayLiteralExp(e->loc, elems);
+        new(&ue) ArrayLiteralExp(e->loc, NULL, elems);
 
         e = ue.exp();
         if (type->toBasetype()->ty == Tsarray)
@@ -1829,7 +1825,7 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
             ? ArrayLiteralExp::copyElements(e1) : new Expressions();
         elems->push(e2);
 
-        new(&ue) ArrayLiteralExp(e1->loc, elems);
+        new(&ue) ArrayLiteralExp(e1->loc, NULL, elems);
 
         e = ue.exp();
         if (type->toBasetype()->ty == Tsarray)
@@ -1846,7 +1842,7 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
     {
         Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
 
-        new(&ue) ArrayLiteralExp(e2->loc, elems);
+        new(&ue) ArrayLiteralExp(e2->loc, NULL, elems);
 
         e = ue.exp();
         if (type->toBasetype()->ty == Tsarray)
@@ -1874,9 +1870,8 @@  UnionExp Cat(Type *type, Expression *e1, Expression *e2)
         {
             Expressions *expressions = new Expressions();
             expressions->push(e);
-            new(&ue) ArrayLiteralExp(loc, expressions);
+            new(&ue) ArrayLiteralExp(loc, t, expressions);
             e = ue.exp();
-            e->type = t;
         }
         else
         {
diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h
index 2c6a47440a8..0e49432e1b6 100644
--- a/gcc/d/dmd/ctfe.h
+++ b/gcc/d/dmd/ctfe.h
@@ -134,6 +134,7 @@  UnionExp copyLiteral(Expression *e);
 
 /// Set this literal to the given type, copying it if necessary
 Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
+Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit);
 UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
 
 /// Convert from a CTFE-internal slice, into a normal Expression
@@ -143,11 +144,11 @@  Expression *resolveSlice(Expression *e, UnionExp *pue = NULL);
 uinteger_t resolveArrayLength(Expression *e);
 
 /// Create an array literal consisting of 'elem' duplicated 'dim' times.
-ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
         Expression *elem, size_t dim);
 
 /// Create a string literal consisting of 'value' duplicated 'dim' times.
-StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
+StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
         unsigned value, size_t dim, unsigned char sz);
 
 
@@ -209,7 +210,7 @@  UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
 bool isFloatIntPaint(Type *to, Type *from);
 
 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
-Expression *paintFloatInt(Expression *fromVal, Type *to);
+Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to);
 
 /// Return true if t is an AA
 bool isAssocArray(Type *t);
@@ -264,4 +265,4 @@  UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2);
 Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
 
 /// Cast 'e' of type 'type' to type 'to'.
-Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e);
+Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e);
diff --git a/gcc/d/dmd/ctfeexpr.c b/gcc/d/dmd/ctfeexpr.c
index 713e0f9ff7d..1050e93699e 100644
--- a/gcc/d/dmd/ctfeexpr.c
+++ b/gcc/d/dmd/ctfeexpr.c
@@ -264,10 +264,9 @@  UnionExp copyLiteral(Expression *e)
         ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
         Expressions *elements = copyLiteralArray(ale->elements, ale->basis);
 
-        new(&ue) ArrayLiteralExp(e->loc, elements);
+        new(&ue) ArrayLiteralExp(e->loc, e->type, elements);
 
         ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
-        r->type = e->type;
         r->ownedByCtfe = OWNEDctfe;
         return ue;
     }
@@ -314,7 +313,10 @@  UnionExp copyLiteral(Expression *e)
                 {
                     TypeSArray *tsa = (TypeSArray *)v->type;
                     size_t len = (size_t)tsa->dim->toInteger();
-                    m = createBlockDuplicatedArrayLiteral(e->loc, v->type, m, len);
+                    UnionExp uex;
+                    m = createBlockDuplicatedArrayLiteral(&uex, e->loc, v->type, m, len);
+                    if (m == uex.exp())
+                        m = uex.copy();
                 }
             }
             (*newelems)[i] = m;
@@ -414,6 +416,14 @@  Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
     return paintTypeOntoLiteralCopy(type, lit).copy();
 }
 
+Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit)
+{
+    if (lit->type->equals(type))
+        return lit;
+    *pue = paintTypeOntoLiteralCopy(type, lit);
+    return pue->exp();
+}
+
 UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit)
 {
     UnionExp ue;
@@ -539,6 +549,7 @@  uinteger_t resolveArrayLength(Expression *e)
  * Helper for NewExp
  * Create an array literal consisting of 'elem' duplicated 'dim' times.
  * Params:
+ *      pue = where to store result
  *      loc = source location where the interpretation occurs
  *      type = target type of the result
  *      elem = the source of array element, it will be owned by the result
@@ -546,7 +557,7 @@  uinteger_t resolveArrayLength(Expression *e)
  * Returns:
  *      Constructed ArrayLiteralExp
  */
-ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
         Expression *elem, size_t dim)
 {
     if (type->ty == Tsarray && type->nextOf()->ty == Tsarray && elem->type->ty != Tsarray)
@@ -554,7 +565,10 @@  ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
         // If it is a multidimensional array literal, do it recursively
         TypeSArray *tsa = (TypeSArray *)type->nextOf();
         size_t len = (size_t)tsa->dim->toInteger();
-        elem = createBlockDuplicatedArrayLiteral(loc, type->nextOf(), elem, len);
+        UnionExp ue;
+        elem = createBlockDuplicatedArrayLiteral(&ue, loc, type->nextOf(), elem, len);
+        if (elem == ue.exp())
+            elem = ue.copy();
     }
 
     // Buzilla 15681
@@ -567,8 +581,8 @@  ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
     {
         (*elements)[i] = mustCopy ? copyLiteral(elem).copy() : elem;
     }
-    ArrayLiteralExp *ale = new ArrayLiteralExp(loc, elements);
-    ale->type = type;
+    new(pue) ArrayLiteralExp(loc, type, elements);
+    ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
     ale->ownedByCtfe = OWNEDctfe;
     return ale;
 }
@@ -577,7 +591,7 @@  ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
  * Helper for NewExp
  * Create a string literal consisting of 'value' duplicated 'dim' times.
  */
-StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
+StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
         unsigned value, size_t dim, unsigned char sz)
 {
     utf8_t *s = (utf8_t *)mem.xcalloc(dim + 1, sz);
@@ -591,7 +605,8 @@  StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
             default:    assert(0);
         }
     }
-    StringExp *se = new StringExp(loc, s, dim);
+    new(pue) StringExp(loc, s, dim);
+    StringExp *se = (StringExp *)pue->exp();
     se->type = type;
     se->sz = sz;
     se->committed = true;
@@ -984,13 +999,13 @@  bool isFloatIntPaint(Type *to, Type *from)
 }
 
 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
-Expression *paintFloatInt(Expression *fromVal, Type *to)
+Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to)
 {
     if (exceptionOrCantInterpret(fromVal))
         return fromVal;
 
     assert(to->size() == 4 || to->size() == 8);
-    return Compiler::paintAsType(fromVal, to);
+    return Compiler::paintAsType(pue, fromVal, to);
 }
 
 /******** Constant folding, with support for CTFE ***************************/
@@ -1512,10 +1527,9 @@  UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2)
         ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
         ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
 
-        new(&ue) ArrayLiteralExp(es1->loc, copyLiteralArray(es1->elements));
+        new(&ue) ArrayLiteralExp(es1->loc, type, copyLiteralArray(es1->elements));
         es1 = (ArrayLiteralExp *)ue.exp();
         es1->elements->insert(es1->elements->dim, copyLiteralArray(es2->elements));
-        es1->type = type;
         return ue;
     }
     if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
@@ -1587,29 +1601,33 @@  Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx)
     }
 }
 
-Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e)
+Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e)
 {
     if (e->op == TOKnull)
-        return paintTypeOntoLiteral(to, e);
+        return paintTypeOntoLiteral(pue, to, e);
+
     if (e->op == TOKclassreference)
     {
         // Disallow reinterpreting class casts. Do this by ensuring that
         // the original class can implicitly convert to the target class
         ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass();
         if (originalClass->type->implicitConvTo(to->mutableOf()))
-            return paintTypeOntoLiteral(to, e);
+            return paintTypeOntoLiteral(pue, to, e);
         else
-            return new NullExp(loc, to);
+        {
+            new(pue) NullExp(loc, to);
+            return pue->exp();
+        }
     }
+
     // Allow TypeInfo type painting
     if (isTypeInfo_Class(e->type) && e->type->implicitConvTo(to))
-        return paintTypeOntoLiteral(to, e);
+        return paintTypeOntoLiteral(pue, to, e);
+
     // Allow casting away const for struct literals
     if (e->op == TOKstructliteral &&
         e->type->toBasetype()->castMod(0) == to->toBasetype()->castMod(0))
-    {
-        return paintTypeOntoLiteral(to, e);
-    }
+        return paintTypeOntoLiteral(pue, to, e);
 
     Expression *r;
     if (e->type->equals(type) && type->equals(to))
@@ -1617,22 +1635,28 @@  Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e)
         // necessary not to change e's address for pointer comparisons
         r = e;
     }
-    else if (to->toBasetype()->ty == Tarray &&     type->toBasetype()->ty == Tarray &&
+    else if (to->toBasetype()->ty == Tarray &&
+             type->toBasetype()->ty == Tarray &&
              to->toBasetype()->nextOf()->size() == type->toBasetype()->nextOf()->size())
     {
         // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
-        return paintTypeOntoLiteral(to, e);
+        return paintTypeOntoLiteral(pue, to, e);
     }
     else
     {
-        r = Cast(loc, type, to, e).copy();
+        *pue = Cast(loc, type, to, e);
+        r = pue->exp();
     }
+
     if (CTFEExp::isCantExp(r))
         error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars());
+
     if (e->op == TOKarrayliteral)
         ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDctfe;
+
     if (e->op == TOKstring)
         ((StringExp *)e)->ownedByCtfe = OWNEDctfe;
+
     return r;
 }
 
@@ -1816,9 +1840,8 @@  UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
             for (size_t i = copylen; i < newlen; i++)
                 (*elements)[i] = defaultElem;
         }
-        new(&ue) ArrayLiteralExp(loc, elements);
+        new(&ue) ArrayLiteralExp(loc, arrayType, elements);
         ArrayLiteralExp *aae = (ArrayLiteralExp *)ue.exp();
-        aae->type = arrayType;
         aae->ownedByCtfe = OWNEDctfe;
     }
     return ue;
@@ -2078,9 +2101,8 @@  UnionExp voidInitLiteral(Type *t, VarDeclaration *var)
                 elem  = copyLiteral(elem).copy();
             (*elements)[i] = elem;
         }
-        new(&ue) ArrayLiteralExp(var->loc, elements);
+        new(&ue) ArrayLiteralExp(var->loc, tsa, elements);
         ArrayLiteralExp *ae = (ArrayLiteralExp *)ue.exp();
-        ae->type = tsa;
         ae->ownedByCtfe = OWNEDctfe;
     }
     else if (t->ty == Tstruct)
diff --git a/gcc/d/dmd/dinterpret.c b/gcc/d/dmd/dinterpret.c
index 7c497d8958a..140abfdd7e9 100644
--- a/gcc/d/dmd/dinterpret.c
+++ b/gcc/d/dmd/dinterpret.c
@@ -264,14 +264,18 @@  void printCtfePerformanceStats()
 #endif
 }
 
-VarDeclaration *findParentVar(Expression *e);
-Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
+static Expression *evaluateIfBuiltin(UnionExp *pue, InterState *istate, Loc loc,
     FuncDeclaration *fd, Expressions *arguments, Expression *pthis);
-Expression *evaluatePostblit(InterState *istate, Expression *e);
-Expression *evaluateDtor(InterState *istate, Expression *e);
-Expression *scrubReturnValue(Loc loc, Expression *e);
+static Expression *evaluatePostblit(InterState *istate, Expression *e);
+static Expression *evaluateDtor(InterState *istate, Expression *e);
 
-Expression *scrubCacheValue(Loc loc, Expression *e);
+static bool isEntirelyVoid(Expressions* elems);
+static Expression *scrubArray(Loc loc, Expressions *elems, bool structlit = false);
+static Expression *scrubStructLiteral(Loc loc, StructLiteralExp *sle);
+static Expression *scrubReturnValue(Loc loc, Expression *e);
+static Expression *scrubArrayCache(Expressions *elems);
+static Expression *scrubStructLiteralCache(StructLiteralExp *sle);
+static Expression *scrubCacheValue(Expression *e);
 
 
 /*************************************
@@ -635,8 +639,24 @@  void ctfeCompile(FuncDeclaration *fd)
  */
 Expression *ctfeInterpret(Expression *e)
 {
-    if (e->op == TOKerror)
+    switch (e->op)
+    {
+    case TOKint64:
+    case TOKfloat64:
+    case TOKcomplex80:
+    case TOKnull:
+    case TOKstring:
+        if (e->type->ty == Terror)
+            return new ErrorExp();
+        /* fall through */
+
+    case TOKerror:
         return e;
+
+    default:
+        break;
+    }
+
     assert(e->type);                    // Bugzilla 14642
     //assert(e->type->ty != Terror);    // FIXME
     if (e->type->ty == Terror)
@@ -710,6 +730,8 @@  Expression *ctfeInterpretForPragmaMsg(Expression *e)
 /*************************************
  * Attempt to interpret a function given the arguments.
  * Input:
+ *      pue        storage for result
+ *      fd         function being called
  *      istate     state for calling function (NULL if none)
  *      arguments  function arguments
  *      thisarg    'this', if a needThis() function, NULL if not.
@@ -718,8 +740,9 @@  Expression *ctfeInterpretForPragmaMsg(Expression *e)
  * or CTFEExp if function returned void.
  */
 
-static Expression *interpretFunction(FuncDeclaration *fd, InterState *istate, Expressions *arguments, Expression *thisarg)
+static Expression *interpretFunction(UnionExp *pue, FuncDeclaration *fd, InterState *istate, Expressions *arguments, Expression *thisarg)
 {
+    assert(pue);
     if (fd->semanticRun == PASSsemantic3)
     {
         fd->error("circular dependency. Functions cannot be interpreted while being compiled");
@@ -898,7 +921,7 @@  static Expression *interpretFunction(FuncDeclaration *fd, InterState *istate, Ex
             e = CTFEExp::cantexp;
             break;
         }
-        e = interpret(fd->fbody, &istatex);
+        e = interpret(pue, fd->fbody, &istatex);
 
         if (istatex.start)
         {
@@ -938,6 +961,8 @@  static Expression *interpretFunction(FuncDeclaration *fd, InterState *istate, Ex
     // If it generated an uncaught exception, report error.
     if (!istate && e->op == TOKthrownexception)
     {
+        if (e == pue->exp())
+            e = pue->copy();
         ((ThrownExceptionExp *)e)->generateUncaughtError();
         e = CTFEExp::cantexp;
     }
@@ -2004,7 +2029,8 @@  public:
         {
             // Normally this is already done by optimize()
             // Do it here in case optimize(WANTvalue) wasn't run before CTFE
-            result = new SymOffExp(e->loc, ((VarExp *)e->e1)->var, 0);
+            new(pue) SymOffExp(e->loc, ((VarExp *)e->e1)->var, 0);
+            result = pue->exp();
             result->type = e->type;
             return;
         }
@@ -2032,7 +2058,7 @@  public:
             return;
         }
 
-        Expression *er = interpret(e->e1, istate);
+        Expression *er = interpret(pue, e->e1, istate);
         if (exceptionOrCant(er))
             return;
         if (er == e->e1)
@@ -2042,6 +2068,7 @@  public:
         }
         else
         {
+            er = (er == pue->exp()) ? pue->copy() : er;
             new(pue) DelegateExp(e->loc, er, e->func, false);
             result = pue->exp();
             result->type = e->type;
@@ -2100,7 +2127,7 @@  public:
                     /* Bugzilla 14304: e is a value that is not yet owned by CTFE.
                      * Mark as "cached", and use it directly during interpretation.
                      */
-                    e = scrubCacheValue(v->loc, e);
+                    e = scrubCacheValue(e);
                     ctfeStack.saveGlobalConstant(v, e);
                 }
                 else
@@ -2236,7 +2263,7 @@  public:
              *  foo(s); // VarExp('s') will have const(S)
              */
             // A VarExp may include an implicit cast. It must be done explicitly.
-            result = paintTypeOntoLiteral(e->type, result);
+            result = paintTypeOntoLiteral(pue, e->type, result);
         }
     }
 
@@ -2363,7 +2390,7 @@  public:
         }
         if (Expression *ex = isExpression(e->obj))
         {
-            result = interpret(ex, istate);
+            result = interpret(pue, ex, istate);
             if (exceptionOrCant(ex))
                 return;
 
@@ -2493,9 +2520,8 @@  public:
                 result = CTFEExp::cantexp;
                 return;
             }
-            new(pue) ArrayLiteralExp(e->loc, basis, expsx);
+            new(pue) ArrayLiteralExp(e->loc, e->type, basis, expsx);
             ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
-            ale->type = e->type;
             ale->ownedByCtfe = OWNEDctfe;
             result = ale;
         }
@@ -2505,7 +2531,10 @@  public:
             result = e;
         }
         else
-            result = copyLiteral(e).copy();
+        {
+            *pue = copyLiteral(e);
+            result = pue->exp();
+        }
     }
 
     void visit(AssocArrayLiteralExp *e)
@@ -2585,7 +2614,10 @@  public:
             result = ae;
         }
         else
-            result = copyLiteral(e).copy();
+        {
+            *pue = copyLiteral(e);
+            result = pue->exp();
+        }
     }
 
     void visit(StructLiteralExp *e)
@@ -2635,7 +2667,10 @@  public:
                     // Block assignment from inside struct literals
                     TypeSArray *tsa = (TypeSArray *)v->type;
                     size_t len = (size_t)tsa->dim->toInteger();
-                    ex = createBlockDuplicatedArrayLiteral(ex->loc, v->type, ex, len);
+                    UnionExp ue;
+                    ex = createBlockDuplicatedArrayLiteral(&ue, ex->loc, v->type, ex, len);
+                    if (ex == ue.exp())
+                        ex = ue.copy();
                 }
             }
 
@@ -2665,22 +2700,25 @@  public:
             result = sle;
         }
         else
-            result = copyLiteral(e).copy();
+        {
+            *pue = copyLiteral(e);
+            result = pue->exp();
+        }
     }
 
     // Create an array literal of type 'newtype' with dimensions given by
     // 'arguments'[argnum..$]
-    static Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate,
+    static Expression *recursivelyCreateArrayLiteral(UnionExp *pue, Loc loc, Type *newtype, InterState *istate,
         Expressions *arguments, int argnum)
     {
-        Expression *lenExpr = interpret((*arguments)[argnum], istate);
+        Expression *lenExpr = interpret(pue, (*arguments)[argnum], istate);
         if (exceptionOrCantInterpret(lenExpr))
             return lenExpr;
         size_t len = (size_t)(lenExpr->toInteger());
         Type *elemType = ((TypeArray *)newtype)->next;
         if (elemType->ty == Tarray && argnum < (int)arguments->dim - 1)
         {
-            Expression *elem = recursivelyCreateArrayLiteral(loc, elemType, istate,
+            Expression *elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate,
                 arguments, argnum + 1);
             if (exceptionOrCantInterpret(elem))
                 return elem;
@@ -2689,8 +2727,8 @@  public:
             elements->setDim(len);
             for (size_t i = 0; i < len; i++)
                  (*elements)[i] = copyLiteral(elem).copy();
-            ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements);
-            ae->type = newtype;
+            new(pue) ArrayLiteralExp(loc, newtype, elements);
+            ArrayLiteralExp *ae = (ArrayLiteralExp *)pue->exp();
             ae->ownedByCtfe = OWNEDctfe;
             return ae;
         }
@@ -2699,12 +2737,12 @@  public:
         {
             const unsigned ch = (unsigned)elemType->defaultInitLiteral(loc)->toInteger();
             const unsigned char sz = (unsigned char)elemType->size();
-            return createBlockDuplicatedStringLiteral(loc, newtype, ch, len, sz);
+            return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
         }
         else
         {
             Expression *el = interpret(elemType->defaultInitLiteral(loc), istate);
-            return createBlockDuplicatedArrayLiteral(loc, newtype, el, len);
+            return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
         }
     }
 
@@ -2717,13 +2755,13 @@  public:
             return;
         }
 
-        result = interpret(e->argprefix, istate, ctfeNeedNothing);
-        if (exceptionOrCant(result))
+        Expression *epre = interpret(pue, e->argprefix, istate, ctfeNeedNothing);
+        if (exceptionOrCant(epre))
             return;
 
         if (e->newtype->ty == Tarray && e->arguments)
         {
-            result = recursivelyCreateArrayLiteral(e->loc, e->newtype, istate, e->arguments, 0);
+            result = recursivelyCreateArrayLiteral(pue, e->loc, e->newtype, istate, e->arguments, 0);
             return;
         }
         if (e->newtype->toBasetype()->ty == Tstruct)
@@ -2734,7 +2772,7 @@  public:
                 se = interpret(se, istate);
                 if (exceptionOrCant(se))
                     return;
-                result = interpretFunction(e->member, istate, e->arguments, se);
+                result = interpretFunction(pue, e->member, istate, e->arguments, se);
 
                 // Repaint as same as CallExp::interpret() does.
                 result->loc = e->loc;
@@ -2761,11 +2799,12 @@  public:
                 StructLiteralExp *se = new StructLiteralExp(e->loc, sd, exps, e->newtype);
                 se->type = e->newtype;
                 se->ownedByCtfe = OWNEDctfe;
-                result = interpret(se, istate);
+                result = interpret(pue, se, istate);
             }
             if (exceptionOrCant(result))
                 return;
-            new(pue) AddrExp(e->loc, result, e->type);
+            Expression *ev = (result == pue->exp()) ? pue->copy() : result;
+            new(pue) AddrExp(e->loc, ev, e->type);
             result = pue->exp();
             return;
         }
@@ -2809,13 +2848,14 @@  public:
             // We probably won't get away with this.
             StructLiteralExp *se = new StructLiteralExp(e->loc, (StructDeclaration *)cd, elems, e->newtype);
             se->ownedByCtfe = OWNEDctfe;
-            Expression *eref = new ClassReferenceExp(e->loc, se, e->type);
+            new(pue) ClassReferenceExp(e->loc, se, e->type);
+            Expression *eref = pue->exp();
             if (e->member)
             {
                 // Call constructor
                 if (!e->member->fbody)
                 {
-                    Expression *ctorfail = evaluateIfBuiltin(istate, e->loc, e->member, e->arguments, eref);
+                    Expression *ctorfail = evaluateIfBuiltin(pue, istate, e->loc, e->member, e->arguments, eref);
                     if (ctorfail)
                     {
                         if (exceptionOrCant(ctorfail))
@@ -2827,7 +2867,8 @@  public:
                     result = CTFEExp::cantexp;
                     return;
                 }
-                Expression *ctorfail = interpretFunction(e->member, istate, e->arguments, eref);
+                UnionExp ue;
+                Expression *ctorfail = interpretFunction(&ue, e->member, istate, e->arguments, eref);
                 if (exceptionOrCant(ctorfail))
                     return;
 
@@ -2855,8 +2896,7 @@  public:
             Expressions *elements = new Expressions();
             elements->setDim(1);
             (*elements)[0] = newval;
-            ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, elements);
-            ae->type = e->newtype->arrayOf();
+            ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, e->newtype->arrayOf(), elements);
             ae->ownedByCtfe = OWNEDctfe;
 
             IndexExp *ei = new IndexExp(e->loc, ae, new IntegerExp(Loc(), 0, Type::tsize_t));
@@ -3462,7 +3502,7 @@  public:
             assignAssocArrayElement(e->loc, existingAA, lastIndex, newval);
 
             // Determine the return value
-            result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+            result = ctfeCast(pue, e->loc, e->type, e->type, fp && post ? oldval : newval);
             return;
         }
         if (e1->op == TOKarraylength)
@@ -3474,10 +3514,13 @@  public:
              */
 
             // Determine the return value
-            result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+            result = ctfeCast(pue, e->loc, e->type, e->type, fp && post ? oldval : newval);
             if (exceptionOrCant(result))
                 return;
 
+            if (result == pue->exp())
+                result = pue->copy();
+
             size_t oldlen = (size_t)oldval->toInteger();
             size_t newlen = (size_t)newval->toInteger();
             if (oldlen == newlen) // no change required -- we're done!
@@ -3511,15 +3554,21 @@  public:
 
         if (!isBlockAssignment)
         {
-            newval = ctfeCast(e->loc, e->type, e->type, newval);
+            newval = ctfeCast(pue, e->loc, e->type, e->type, newval);
             if (exceptionOrCant(newval))
                 return;
+            if (newval == pue->exp())
+                newval = pue->copy();
 
             // Determine the return value
             if (goal == ctfeNeedLvalue)     // Bugzilla 14371
                 result = e1;
             else
-                result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+            {
+                result = ctfeCast(pue, e->loc, e->type, e->type, fp && post ? oldval : newval);
+                if (result == pue->exp())
+                    result = pue->copy();
+            }
             if (exceptionOrCant(result))
                 return;
         }
@@ -3536,7 +3585,7 @@  public:
         {
             // Note that slice assignments don't support things like ++, so
             // we don't need to remember 'returnValue'.
-            result = interpretAssignToSlice(e, e1, newval, isBlockAssignment);
+            result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
             if (exceptionOrCant(result))
                 return;
             if (e->e1->op == TOKslice)
@@ -3781,7 +3830,7 @@  public:
      * it returns aggregate[low..upp], except that as an optimisation,
      * if goal == ctfeNeedNothing, it will return NULL
      */
-    Expression *interpretAssignToSlice(BinExp *e,
+    Expression *interpretAssignToSlice(UnionExp *pue, BinExp *e,
         Expression *e1, Expression *newval, bool isBlockAssignment)
     {
         dinteger_t lowerbound;
@@ -3962,7 +4011,7 @@  public:
                 new IntegerExp(e->loc, firstIndex, Type::tsize_t),
                 new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
             retslice->type = e->type;
-            return interpret(retslice, istate);
+            return interpret(pue, retslice, istate);
         }
         if (aggregate->op == TOKarrayliteral)
         {
@@ -4178,7 +4227,7 @@  public:
                 new IntegerExp(e->loc, firstIndex, Type::tsize_t),
                 new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
             retslice->type = e->type;
-            return interpret(retslice, istate);
+            return interpret(pue, retslice, istate);
         }
 
         e->error("slice operation %s = %s cannot be evaluated at compile time",
@@ -4285,7 +4334,7 @@  public:
      *  relational sub-expressions can be negated, eg
      *  (!(q1 < p1) && p2 <= q2) is valid.
      */
-    void interpretFourPointerRelation(BinExp *e)
+    void interpretFourPointerRelation(UnionExp *pue, BinExp *e)
     {
         assert(e->op == TOKandand || e->op == TOKoror);
 
@@ -4311,12 +4360,16 @@  public:
         }
 
         //printf("FourPointerRelation %s\n", toChars());
+        UnionExp ue1;
+        UnionExp ue2;
+        UnionExp ue3;
+        UnionExp ue4;
 
         // Evaluate the first two pointers
-        p1 = interpret(p1, istate);
+        p1 = interpret(&ue1, p1, istate);
         if (exceptionOrCant(p1))
             return;
-        p2 = interpret(p2, istate);
+        p2 = interpret(&ue2, p2, istate);
         if (exceptionOrCant(p2))
             return;
         dinteger_t ofs1, ofs2;
@@ -4329,7 +4382,7 @@  public:
         {
             // Here it is either CANT_INTERPRET,
             // or an IsInside comparison returning false.
-            p3 = interpret(p3, istate);
+            p3 = interpret(&ue3, p3, istate);
             if (CTFEExp::isCantExp(p3))
                 return;
             // Note that it is NOT legal for it to throw an exception!
@@ -4338,7 +4391,7 @@  public:
                 except = p3;
             else
             {
-                p4 = interpret(p4, istate);
+                p4 = interpret(&ue4, p4, istate);
                 if (CTFEExp::isCantExp(p4))
                 {
                     result = p4;
@@ -4367,7 +4420,8 @@  public:
                 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
             {
                 // it's a legal two-sided comparison
-                result = new IntegerExp(e->loc, (e->op == TOKandand) ?  0 : 1, e->type);
+                new(pue) IntegerExp(e->loc, (e->op == TOKandand) ?  0 : 1, e->type);
+                result = pue->exp();
                 return;
             }
             // It's an invalid four-pointer comparison. Either the second
@@ -4393,25 +4447,24 @@  public:
             nott = !nott;
             ex = ((NotExp *)ex)->e1;
         }
-        TOK cmpop = ex->op;
-        if (nott)
-            cmpop = reverseRelation(cmpop);
-        int cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
+        const TOK cmpop = nott ? reverseRelation(ex->op) : ex->op;
+        const int cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
         // We already know this is a valid comparison.
         assert(cmp >= 0);
         if ((e->op == TOKandand && cmp == 1) ||
             (e->op == TOKoror   && cmp == 0))
         {
-            result = interpret(e->e2, istate);
+            result = interpret(pue, e->e2, istate);
             return;
         }
-        result = new IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
+        new(pue) IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
+        result = pue->exp();
     }
 
     void visit(AndAndExp *e)
     {
         // Check for an insidePointer expression, evaluate it if so
-        interpretFourPointerRelation(e);
+        interpretFourPointerRelation(pue, e);
         if (result)
             return;
 
@@ -4461,7 +4514,7 @@  public:
     void visit(OrOrExp *e)
     {
         // Check for an insidePointer expression, evaluate it if so
-        interpretFourPointerRelation(e);
+        interpretFourPointerRelation(pue, e);
         if (result)
             return;
 
@@ -4695,7 +4748,7 @@  public:
         }
 
         // Check for built-in functions
-        result = evaluateIfBuiltin(istate, e->loc, fd, e->arguments, pthis);
+        result = evaluateIfBuiltin(pue, istate, e->loc, fd, e->arguments, pthis);
         if (result)
             return;
 
@@ -4707,13 +4760,17 @@  public:
             return;
         }
 
-        result = interpretFunction(fd, istate, e->arguments, pthis);
+        result = interpretFunction(pue, fd, istate, e->arguments, pthis);
         if (result->op == TOKvoidexp)
             return;
         if (!exceptionOrCantInterpret(result))
         {
-            if (goal != ctfeNeedLvalue) // Peel off CTFE reference if it's unnesessary
-                result = interpret(result, istate);
+            if (goal != ctfeNeedLvalue) // Peel off CTFE reference if it's unnecessary
+            {
+                if (result == pue->exp())
+                    result = pue->copy();
+                result = interpret(pue, result, istate);
+            }
         }
         if (!exceptionOrCantInterpret(result))
         {
@@ -5306,17 +5363,37 @@  public:
 
     void visit(CatExp *e)
     {
-        Expression *e1 = interpret(e->e1, istate);
+        UnionExp ue1;
+        Expression *e1 = interpret(&ue1, e->e1, istate);
         if (exceptionOrCant(e1))
             return;
-        Expression *e2 = interpret(e->e2, istate);
+
+        UnionExp ue2;
+        Expression *e2 = interpret(&ue2, e->e2, istate);
         if (exceptionOrCant(e2))
             return;
+
         UnionExp e1tmp;
         e1 = resolveSlice(e1, &e1tmp);
+
         UnionExp e2tmp;
         e2 = resolveSlice(e2, &e2tmp);
-        result = ctfeCat(e->loc, e->type, e1, e2).copy();
+
+        /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
+         * result in [x,y] and then x or y is on the stack.
+         * But if they are both strings, we can, because it isn't the x~[y] case.
+         */
+        if (!(e1->op == TOKstring && e2->op == TOKstring))
+        {
+            if (e1 == ue1.exp())
+                e1 = ue1.copy();
+            if (e2 == ue2.exp())
+                e2 = ue2.copy();
+        }
+
+        *pue = ctfeCat(e->loc, e->type, e1, e2);
+        result = pue->exp();
+
         if (CTFEExp::isCantExp(result))
         {
             e->error("%s cannot be interpreted at compile time", e->toChars());
@@ -5375,7 +5452,7 @@  public:
 
             if (cd->dtor)
             {
-                result = interpretFunction(cd->dtor, istate, NULL, cre);
+                result = interpretFunction(pue, cd->dtor, istate, NULL, cre);
                 if (exceptionOrCant(result))
                     return;
             }
@@ -5406,7 +5483,7 @@  public:
 
                 if (sd->dtor)
                 {
-                    result = interpretFunction(sd->dtor, istate, NULL, sle);
+                    result = interpretFunction(pue, sd->dtor, istate, NULL, sle);
                     if (exceptionOrCant(result))
                         return;
                 }
@@ -5440,7 +5517,7 @@  public:
                     for (size_t i = 0; i < ale->elements->dim; i++)
                     {
                         Expression *el = (*ale->elements)[i];
-                        result = interpretFunction(sd->dtor, istate, NULL, el);
+                        result = interpretFunction(pue, sd->dtor, istate, NULL, el);
                         if (exceptionOrCant(result))
                             return;
                     }
@@ -5473,7 +5550,7 @@  public:
             if (e1->op == TOKint64)
             {
                 // Happens with Windows HANDLEs, for example.
-                result = paintTypeOntoLiteral(e->to, e1);
+                result = paintTypeOntoLiteral(pue, e->to, e1);
                 return;
             }
             bool castToSarrayPointer = false;
@@ -5516,13 +5593,14 @@  public:
 
             if (e1->op == TOKslice)
             {
-                if (((SliceExp *)e1)->e1->op == TOKnull)
+                SliceExp *se = (SliceExp *)e1;
+                if (se->e1->op == TOKnull)
                 {
-                    result = paintTypeOntoLiteral(e->type, ((SliceExp *)e1)->e1);
+                    result = paintTypeOntoLiteral(pue, e->type, se->e1);
                     return;
                 }
                 // Create a CTFE pointer &aggregate[1..2]
-                IndexExp *ei = new IndexExp(e->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr);
+                IndexExp *ei = new IndexExp(e->loc, se->e1, se->lwr);
                 ei->type = e->type->nextOf();
                 new(pue) AddrExp(e->loc, ei, e->type);
                 result = pue->exp();
@@ -5541,7 +5619,6 @@  public:
             {
                 // type painting operation
                 IndexExp *ie = (IndexExp *)e1;
-                result = new IndexExp(e1->loc, ie->e1, ie->e2);
                 if (castBackFromVoid)
                 {
                     // get the original type. For strings, it's just the type...
@@ -5550,7 +5627,7 @@  public:
                     if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64)
                     {
                         ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1;
-                        size_t indx = (size_t)ie->e2->toInteger();
+                        const size_t indx = (size_t)ie->e2->toInteger();
                         if (indx < ale->elements->dim)
                         {
                             Expression *xx = (*ale->elements)[indx];
@@ -5572,23 +5649,26 @@  public:
                         return;
                     }
                 }
+                new(pue) IndexExp(e1->loc, ie->e1, ie->e2);
+                result = pue->exp();
                 result->type = e->type;
                 return;
             }
             if (e1->op == TOKaddress)
             {
-                Type *origType = ((AddrExp *)e1)->e1->type;
+                AddrExp *ae = (AddrExp *)e1;
+                Type *origType = ae->e1->type;
                 if (isSafePointerCast(origType, pointee))
                 {
-                    new(pue) AddrExp(e->loc, ((AddrExp *)e1)->e1, e->type);
+                    new(pue) AddrExp(e->loc, ae->e1, e->type);
                     result = pue->exp();
                     return;
                 }
-                if (castToSarrayPointer && pointee->toBasetype()->ty == Tsarray && ((AddrExp *)e1)->e1->op == TOKindex)
+                if (castToSarrayPointer && pointee->toBasetype()->ty == Tsarray && ae->e1->op == TOKindex)
                 {
                     // &val[idx]
                     dinteger_t dim = ((TypeSArray *)pointee->toBasetype())->dim->toInteger();
-                    IndexExp *ie = (IndexExp *)((AddrExp *)e1)->e1;
+                    IndexExp *ie = (IndexExp *)ae->e1;
                     Expression *lwr = ie->e2;
                     Expression *upr = new IntegerExp(ie->e2->loc, ie->e2->toInteger() + dim, Type::tsize_t);
 
@@ -5669,7 +5749,7 @@  public:
             result = pue->exp();
             return;
         }
-        result = ctfeCast(e->loc, e->type, e->to, e1);
+        result = ctfeCast(pue, e->loc, e->type, e->to, e1);
     }
 
     void visit(AssertExp *e)
@@ -5708,20 +5788,30 @@  public:
     void visit(PtrExp *e)
     {
         // Check for int<->float and long<->double casts.
-        if (e->e1->op == TOKsymoff && ((SymOffExp *)e->e1)->offset == 0 && ((SymOffExp *)e->e1)->var->isVarDeclaration() && isFloatIntPaint(e->type, ((SymOffExp *)e->e1)->var->type))
+        if (e->e1->op == TOKsymoff)
         {
-            // *(cast(int*)&v), where v is a float variable
-            result = paintFloatInt(getVarExp(e->loc, istate, ((SymOffExp *)e->e1)->var, ctfeNeedRvalue), e->type);
-            return;
+            SymOffExp *soe = (SymOffExp *)e->e1;
+            if (soe->offset == 0 && soe->var->isVarDeclaration() && isFloatIntPaint(e->type, soe->var->type))
+            {
+                // *(cast(int*)&v), where v is a float variable
+                result = paintFloatInt(pue, getVarExp(e->loc, istate, soe->var, ctfeNeedRvalue), e->type);
+                return;
+            }
         }
-        if (e->e1->op == TOKcast && ((CastExp *)e->e1)->e1->op == TOKaddress)
+
+        if (e->e1->op == TOKcast)
         {
-            // *(cast(int*)&x), where x is a float expression
-            Expression *x = ((AddrExp *)(((CastExp *)e->e1)->e1))->e1;
-            if (isFloatIntPaint(e->type, x->type))
+            CastExp *ce1 = (CastExp *)e->e1;
+            if (ce1->e1->op == TOKaddress)
             {
-                result = paintFloatInt(interpret(x, istate), e->type);
-                return;
+                AddrExp *ae11 = (AddrExp *)ce1->e1;
+                // *(cast(int*)&x), where x is a float expression
+                Expression *x = ae11->e1;
+                if (isFloatIntPaint(e->type, x->type))
+                {
+                    result = paintFloatInt(pue, interpret(x, istate), e->type);
+                    return;
+                }
             }
         }
 
@@ -5785,7 +5875,7 @@  public:
              */
             return;
         }
-        result = interpret(result, istate, goal);
+        result = interpret(pue, result, istate, goal);
         if (exceptionOrCant(result))
             return;
     }
@@ -5898,7 +5988,10 @@  public:
             // Block assignment from inside struct literals
             TypeSArray *tsa = (TypeSArray *)v->type;
             size_t len = (size_t)tsa->dim->toInteger();
-            result = createBlockDuplicatedArrayLiteral(ex->loc, v->type, ex, len);
+            UnionExp ue;
+            result = createBlockDuplicatedArrayLiteral(&ue, ex->loc, v->type, ex, len);
+            if (result == ue.exp())
+                result = ue.copy();
             (*se->elements)[i] = result;
         }
     }
@@ -6022,57 +6115,47 @@  Expression *interpret(Statement *s, InterState *istate)
     return result;
 }
 
-Expression *scrubArray(Loc loc, Expressions *elems, bool structlit = false);
-
-/* All results destined for use outside of CTFE need to have their CTFE-specific
+/**
+ * All results destined for use outside of CTFE need to have their CTFE-specific
  * features removed.
- * In particular, all slices must be resolved.
+ * In particular,
+ * 1. all slices must be resolved.
+ * 2. all .ownedByCtfe set to OWNEDcode
  */
 Expression *scrubReturnValue(Loc loc, Expression *e)
 {
     if (e->op == TOKclassreference)
     {
-        StructLiteralExp *se = ((ClassReferenceExp*)e)->value;
-        se->ownedByCtfe = OWNEDcode;
-        if (!(se->stageflags & stageScrub))
-        {
-            int old = se->stageflags;
-            se->stageflags |= stageScrub;
-            if (Expression *ex = scrubArray(loc, se->elements, true))
-                return ex;
-            se->stageflags = old;
-        }
+        StructLiteralExp *sle = ((ClassReferenceExp*)e)->value;
+        if (Expression *ex = scrubStructLiteral(loc, sle))
+            return ex;
     }
-    if (e->op == TOKvoid)
+    else if (e->op == TOKvoid)
     {
         error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
         return new ErrorExp();
     }
+
     e = resolveSlice(e);
+
     if (e->op == TOKstructliteral)
     {
-        StructLiteralExp *se = (StructLiteralExp *)e;
-        se->ownedByCtfe = OWNEDcode;
-        if (!(se->stageflags & stageScrub))
-        {
-            int old = se->stageflags;
-            se->stageflags |= stageScrub;
-            if (Expression *ex = scrubArray(loc, se->elements, true))
-                return ex;
-            se->stageflags = old;
-        }
+        StructLiteralExp *sle = (StructLiteralExp *)e;
+        if (Expression *ex = scrubStructLiteral(loc, sle))
+            return ex;
     }
-    if (e->op == TOKstring)
+    else if (e->op == TOKstring)
     {
         ((StringExp *)e)->ownedByCtfe = OWNEDcode;
     }
-    if (e->op == TOKarrayliteral)
+    else if (e->op == TOKarrayliteral)
     {
-        ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDcode;
-        if (Expression *ex = scrubArray(loc, ((ArrayLiteralExp *)e)->elements))
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+        ale->ownedByCtfe = OWNEDcode;
+        if (Expression *ex = scrubArray(loc, ale->elements))
             return ex;
     }
-    if (e->op == TOKassocarrayliteral)
+    else if (e->op == TOKassocarrayliteral)
     {
         AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
         aae->ownedByCtfe = OWNEDcode;
@@ -6085,24 +6168,34 @@  Expression *scrubReturnValue(Loc loc, Expression *e)
     return e;
 }
 
+/* Returns: true if e is void,
+ * or is an array literal or struct literal of void elements.
+ */
+static bool isVoid(Expression *e)
+{
+    if (e->op == TOKvoid)
+        return true;
+
+    if (e->op == TOKarrayliteral)
+        return isEntirelyVoid(((ArrayLiteralExp *)e)->elements);
+
+    if (e->op == TOKstructliteral)
+        return isEntirelyVoid(((StructLiteralExp *)e)->elements);
+
+    return false;
+}
+
 // Return true if every element is either void,
 // or is an array literal or struct literal of void elements.
 bool isEntirelyVoid(Expressions *elems)
 {
     for (size_t i = 0; i < elems->dim; i++)
     {
-        Expression *m = (*elems)[i];
+        Expression *e = (*elems)[i];
         // It can be NULL for performance reasons,
         // see StructLiteralExp::interpret().
-        if (!m)
-            continue;
-
-        if (!(m->op == TOKvoid) &&
-            !(m->op == TOKarrayliteral && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) &&
-            !(m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements)))
-        {
+        if (e && !isVoid(e))
             return false;
-        }
     }
     return true;
 }
@@ -6112,102 +6205,116 @@  Expression *scrubArray(Loc loc, Expressions *elems, bool structlit)
 {
     for (size_t i = 0; i < elems->dim; i++)
     {
-        Expression *m = (*elems)[i];
+        Expression *e = (*elems)[i];
         // It can be NULL for performance reasons,
         // see StructLiteralExp::interpret().
-        if (!m)
+        if (!e)
             continue;
 
         // A struct .init may contain void members.
         // Static array members are a weird special case (bug 10994).
-        if (structlit &&
-            ((m->op == TOKvoid) ||
-             (m->op == TOKarrayliteral && m->type->ty == Tsarray && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) ||
-             (m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements))))
+        if (structlit && isVoid(e))
         {
-                m = NULL;
+            e = NULL;
         }
         else
         {
-            m = scrubReturnValue(loc, m);
-            if (CTFEExp::isCantExp(m) || m->op == TOKerror)
-                return m;
+            e = scrubReturnValue(loc, e);
+            if (CTFEExp::isCantExp(e) || e->op == TOKerror)
+                return e;
         }
-        (*elems)[i] = m;
+        (*elems)[i] = e;
     }
     return NULL;
 }
 
-Expression *scrubArrayCache(Loc loc, Expressions *elems);
+Expression *scrubStructLiteral(Loc loc, StructLiteralExp *sle)
+{
+    sle->ownedByCtfe = OWNEDcode;
+    if (!(sle->stageflags & stageScrub))
+    {
+        const int old = sle->stageflags;
+        sle->stageflags |= stageScrub;       // prevent infinite recursion
+        if (Expression *ex = scrubArray(loc, sle->elements, true))
+            return ex;
+        sle->stageflags = old;
+    }
+    return NULL;
+}
 
-Expression *scrubCacheValue(Loc loc, Expression *e)
+/**************************************
+ * Transitively set all .ownedByCtfe to OWNEDcache
+ */
+Expression *scrubCacheValue(Expression *e)
 {
+    if (!e)
+        return e;
+
     if (e->op == TOKclassreference)
     {
         StructLiteralExp *sle = ((ClassReferenceExp*)e)->value;
-        sle->ownedByCtfe = OWNEDcache;
-        if (!(sle->stageflags & stageScrub))
-        {
-            int old = sle->stageflags;
-            sle->stageflags |= stageScrub;
-            if (Expression *ex = scrubArrayCache(loc, sle->elements))
-                return ex;
-            sle->stageflags = old;
-        }
+        if (Expression *ex = scrubStructLiteralCache(sle))
+            return ex;
     }
-    if (e->op == TOKstructliteral)
+    else if (e->op == TOKstructliteral)
     {
         StructLiteralExp *sle = (StructLiteralExp *)e;
-        sle->ownedByCtfe = OWNEDcache;
-        if (!(sle->stageflags & stageScrub))
-        {
-            int old = sle->stageflags;
-            sle->stageflags |= stageScrub;
-            if (Expression *ex = scrubArrayCache(loc, sle->elements))
-                return ex;
-            sle->stageflags = old;
-        }
+        if (Expression *ex = scrubStructLiteralCache(sle))
+            return ex;
     }
-    if (e->op == TOKstring)
+    else if (e->op == TOKstring)
     {
         ((StringExp *)e)->ownedByCtfe = OWNEDcache;
     }
-    if (e->op == TOKarrayliteral)
+    else if (e->op == TOKarrayliteral)
     {
-        ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDcache;
-        if (Expression *ex = scrubArrayCache(loc, ((ArrayLiteralExp *)e)->elements))
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+        ale->ownedByCtfe = OWNEDcache;
+        if (Expression *ex = scrubArrayCache(ale->elements))
             return ex;
     }
-    if (e->op == TOKassocarrayliteral)
+    else if (e->op == TOKassocarrayliteral)
     {
         AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
         aae->ownedByCtfe = OWNEDcache;
-        if (Expression *ex = scrubArrayCache(loc, aae->keys))
+        if (Expression *ex = scrubArrayCache(aae->keys))
             return ex;
-        if (Expression *ex = scrubArrayCache(loc, aae->values))
+        if (Expression *ex = scrubArrayCache(aae->values))
             return ex;
     }
     return e;
 }
 
-Expression *scrubArrayCache(Loc loc, Expressions *elems)
+Expression *scrubArrayCache(Expressions *elems)
 {
     for (size_t i = 0; i < elems->dim; i++)
     {
-        Expression *m = (*elems)[i];
-        if (!m)
-            continue;
-        (*elems)[i] = scrubCacheValue(loc, m);
+        Expression *e = (*elems)[i];
+        (*elems)[i] = scrubCacheValue(e);
+    }
+    return NULL;
+}
+
+Expression *scrubStructLiteralCache(StructLiteralExp *sle)
+{
+    sle->ownedByCtfe = OWNEDcache;
+    if (!(sle->stageflags & stageScrub))
+    {
+        const int old = sle->stageflags;
+        sle->stageflags |= stageScrub;       // prevent infinite recursion
+        if (Expression *ex = scrubArrayCache(sle->elements))
+            return ex;
+        sle->stageflags = old;
     }
     return NULL;
 }
 
 /******************************* Special Functions ***************************/
 
-Expression *interpret_length(InterState *istate, Expression *earg)
+static Expression *interpret_length(UnionExp *pue, InterState *istate, Expression *earg)
 {
     //printf("interpret_length()\n");
-    earg = interpret(earg, istate);
+    earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
     dinteger_t len = 0;
@@ -6215,52 +6322,61 @@  Expression *interpret_length(InterState *istate, Expression *earg)
         len = ((AssocArrayLiteralExp *)earg)->keys->dim;
     else
         assert(earg->op == TOKnull);
-    Expression *e = new IntegerExp(earg->loc, len, Type::tsize_t);
-    return e;
+    new(pue) IntegerExp(earg->loc, len, Type::tsize_t);
+    return pue->exp();
 }
 
-Expression *interpret_keys(InterState *istate, Expression *earg, Type *returnType)
+static Expression *interpret_keys(UnionExp *pue, InterState *istate, Expression *earg, Type *returnType)
 {
-    earg = interpret(earg, istate);
+    earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
     if (earg->op == TOKnull)
-        return new NullExp(earg->loc, returnType);
+    {
+        new(pue) NullExp(earg->loc, earg->type);
+        return pue->exp();
+    }
     if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
         return NULL;
     assert(earg->op == TOKassocarrayliteral);
     AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
-    ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->keys);
+    ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, returnType, aae->keys);
     ae->ownedByCtfe = aae->ownedByCtfe;
-    ae->type = returnType;
-    return copyLiteral(ae).copy();
+    *pue = copyLiteral(ae);
+    return pue->exp();
 }
 
-Expression *interpret_values(InterState *istate, Expression *earg, Type *returnType)
+static Expression *interpret_values(UnionExp *pue, InterState *istate, Expression *earg, Type *returnType)
 {
-    earg = interpret(earg, istate);
+    earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
     if (earg->op == TOKnull)
-        return new NullExp(earg->loc, returnType);
+    {
+        new(pue) NullExp(earg->loc, earg->type);
+        return pue->exp();
+    }
     if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
         return NULL;
     assert(earg->op == TOKassocarrayliteral);
     AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
-    ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->values);
+    ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, returnType, aae->values);
     ae->ownedByCtfe = aae->ownedByCtfe;
-    ae->type = returnType;
     //printf("result is %s\n", e->toChars());
-    return copyLiteral(ae).copy();
+    *pue = copyLiteral(ae);
+    return pue->exp();
 }
 
-Expression *interpret_dup(InterState *istate, Expression *earg)
+Expression *interpret_dup(UnionExp *pue, InterState *istate, Expression *earg)
 {
-    earg = interpret(earg, istate);
+    earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
     if (earg->op == TOKnull)
-        return new NullExp(earg->loc, earg->type);
+    {
+        new(pue) NullExp(earg->loc, earg->type);
+        return pue->exp();
+    }
     if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
         return NULL;
     assert(earg->op == TOKassocarrayliteral);
@@ -6278,13 +6394,16 @@  Expression *interpret_dup(InterState *istate, Expression *earg)
 }
 
 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
-Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg)
+Expression *interpret_aaApply(UnionExp *pue, InterState *istate, Expression *aa, Expression *deleg)
 {
     aa = interpret(aa, istate);
     if (exceptionOrCantInterpret(aa))
         return aa;
     if (aa->op != TOKassocarrayliteral)
-        return new IntegerExp(deleg->loc, 0, Type::tsize_t);
+    {
+        new(pue) IntegerExp(deleg->loc, 0, Type::tsize_t);
+        return pue->exp();
+    }
 
     FuncDeclaration *fd = NULL;
     Expression *pthis = NULL;
@@ -6323,9 +6442,13 @@  Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de
             evalue->type = t;
         }
         args[numParams - 1] = evalue;
-        if (numParams == 2) args[0] = ekey;
+        if (numParams == 2)
+            args[0] = ekey;
 
-        eresult = interpretFunction(fd, istate, &args, pthis);
+        UnionExp ue;
+        eresult = interpretFunction(&ue, fd, istate, &args, pthis);
+        if (eresult == ue.exp())
+            eresult = ue.copy();
         if (exceptionOrCantInterpret(eresult))
             return eresult;
 
@@ -6336,19 +6459,10 @@  Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de
     return eresult;
 }
 
-// Helper function: given a function of type A[] f(...),
-// return A[].
-Type *returnedArrayType(FuncDeclaration *fd)
-{
-    assert(fd->type->ty == Tfunction);
-    assert(fd->type->nextOf()->ty == Tarray);
-    return ((TypeFunction *)fd->type)->nextOf();
-}
-
 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
  * the twelve _aApplyXXn functions in aApply.d in the runtime.
  */
-Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *deleg, bool rvs)
+static Expression *foreachApplyUtf(UnionExp *pue, InterState *istate, Expression *str, Expression *deleg, bool rvs)
 {
     FuncDeclaration *fd = NULL;
     Expression *pthis = NULL;
@@ -6369,7 +6483,10 @@  Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del
                                      : Type::tsize_t;
     size_t len = (size_t)resolveArrayLength(str);
     if (len == 0)
-        return new IntegerExp(deleg->loc, 0, indexType);
+    {
+        new(pue) IntegerExp(deleg->loc, 0, indexType);
+        return pue->exp();
+    }
 
     str = resolveSlice(str);
 
@@ -6584,7 +6701,10 @@  Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del
 
             args[numParams - 1] = val;
 
-            eresult = interpretFunction(fd, istate, &args, pthis);
+            UnionExp ue;
+            eresult = interpretFunction(&ue, fd, istate, &args, pthis);
+            if (eresult == ue.exp())
+                eresult = ue.copy();
             if (exceptionOrCantInterpret(eresult))
                 return eresult;
             assert(eresult->op == TOKint64);
@@ -6598,7 +6718,7 @@  Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del
 /* If this is a built-in function, return the interpreted result,
  * Otherwise, return NULL.
  */
-Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
+Expression *evaluateIfBuiltin(UnionExp *pue, InterState *istate, Loc loc,
     FuncDeclaration *fd, Expressions *arguments, Expression *pthis)
 {
     Expression *e = NULL;
@@ -6631,21 +6751,31 @@  Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
         if (firstarg && firstarg->type->toBasetype()->ty == Taarray)
         {
             TypeAArray *firstAAtype = (TypeAArray *)firstarg->type;
-            const char *id = fd->ident->toChars();
-            if (nargs == 1 && fd->ident == Id::aaLen)
-                return interpret_length(istate, firstarg);
-            if (nargs == 3 && !strcmp(id, "_aaApply"))
-                return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2]));
-            if (nargs == 3 && !strcmp(id, "_aaApply2"))
-                return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2]));
-            if (nargs == 1 && !strcmp(id, "keys") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
-                return interpret_keys(istate, firstarg, firstAAtype->index->arrayOf());
-            if (nargs == 1 && !strcmp(id, "values") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
-                return interpret_values(istate, firstarg, firstAAtype->nextOf()->arrayOf());
-            if (nargs == 1 && !strcmp(id, "rehash") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
-                return interpret(firstarg, istate);
-            if (nargs == 1 && !strcmp(id, "dup") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
-                return interpret_dup(istate, firstarg);
+            const Identifier *id = fd->ident;
+            if (nargs == 1)
+            {
+                if (fd->ident == Id::aaLen)
+                    return interpret_length(pue, istate, firstarg);
+
+                if (fd->toParent2()->ident == Id::object)
+                {
+                    if (id == Id::keys)
+                        return interpret_keys(pue, istate, firstarg, firstAAtype->index->arrayOf());
+                    if (id == Id::values)
+                        return interpret_values(pue, istate, firstarg, firstAAtype->nextOf()->arrayOf());
+                    if (id == Id::rehash)
+                        return interpret(pue, firstarg, istate);
+                    if (id == Id::dup)
+                        return interpret_dup(pue, istate, firstarg);
+                }
+            }
+            else // (nargs == 3)
+            {
+                if (id == Id::_aaApply)
+                    return interpret_aaApply(pue, istate, firstarg, (Expression *)(arguments->data[2]));
+                if (id == Id::_aaApply2)
+                    return interpret_aaApply(pue, istate, firstarg, (Expression *)(arguments->data[2]));
+            }
         }
     }
     if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object)
@@ -6693,7 +6823,7 @@  Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
                 str = interpret(str, istate);
                 if (exceptionOrCantInterpret(str))
                     return str;
-                return foreachApplyUtf(istate, str, (*arguments)[1], rvs);
+                return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
             }
         }
     }
@@ -6723,7 +6853,10 @@  Expression *evaluatePostblit(InterState *istate, Expression *e)
     if (e->op == TOKstructliteral)
     {
         // e.__postblit()
-        e = interpretFunction(sd->postblit, istate, NULL, e);
+        UnionExp ue;
+        e = interpretFunction(&ue, sd->postblit, istate, NULL, e);
+        if (e == ue.exp())
+            e = ue.copy();
         if (exceptionOrCantInterpret(e))
             return e;
         return NULL;
@@ -6741,6 +6874,7 @@  Expression *evaluateDtor(InterState *istate, Expression *e)
     if (!sd->dtor)
         return NULL;
 
+    UnionExp ue;
     if (e->op == TOKarrayliteral)
     {
         ArrayLiteralExp *alex = (ArrayLiteralExp *)e;
@@ -6750,12 +6884,16 @@  Expression *evaluateDtor(InterState *istate, Expression *e)
     else if (e->op == TOKstructliteral)
     {
         // e.__dtor()
-        e = interpretFunction(sd->dtor, istate, NULL, e);
+        e = interpretFunction(&ue, sd->dtor, istate, NULL, e);
     }
     else
         assert(0);
     if (exceptionOrCantInterpret(e))
+    {
+        if (e == ue.exp())
+            e = ue.copy();
         return e;
+    }
     return NULL;
 }
 
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
index b7fcf43f6c1..4d82d7217e1 100644
--- a/gcc/d/dmd/dsymbol.c
+++ b/gcc/d/dmd/dsymbol.c
@@ -1189,23 +1189,26 @@  void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
     }
 }
 
+#define BITS_PER_INDEX (sizeof(size_t) * CHAR_BIT)
+
 static void bitArraySet(BitArray *array, size_t idx)
 {
-    array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1ULL << (idx & (sizeof(size_t) * CHAR_BIT - 1));
+    array->ptr[idx / BITS_PER_INDEX] |= 1ULL << (idx % BITS_PER_INDEX);
 }
 
 static bool bitArrayGet(BitArray *array, size_t idx)
 {
-    return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1ULL << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
+    const size_t boffset = idx % BITS_PER_INDEX;
+    return (array->ptr[idx / BITS_PER_INDEX] & (1ULL << boffset)) >> boffset;
 }
 
 static void bitArrayLength(BitArray *array, size_t len)
 {
-    size_t obytes = (array->len + CHAR_BIT - 1) / CHAR_BIT;
-    size_t nbytes = (len + CHAR_BIT - 1) / CHAR_BIT;
-
-    if (obytes < nbytes)
+    if (array->len < len)
     {
+        const size_t obytes = (array->len + BITS_PER_INDEX - 1) / BITS_PER_INDEX;
+        const size_t nbytes = (len + BITS_PER_INDEX - 1) / BITS_PER_INDEX;
+
         if (!array->ptr)
             array->ptr = (size_t *)mem.xmalloc(nbytes * sizeof(size_t));
         else
@@ -1213,8 +1216,9 @@  static void bitArrayLength(BitArray *array, size_t len)
 
         for (size_t i = obytes; i < nbytes; i++)
             array->ptr[i] = 0;
+
+        array->len = nbytes * BITS_PER_INDEX;
     }
-    array->len = len;
 }
 
 void ScopeDsymbol::addAccessiblePackage(Package *p, Prot protection)
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
index a1186c9fb53..cbc38195cca 100644
--- a/gcc/d/dmd/expression.c
+++ b/gcc/d/dmd/expression.c
@@ -1493,7 +1493,6 @@  bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
                          * is now optimized. See Bugzilla 2356.
                          */
                         Type *tbn = ((TypeArray *)tb)->next;
-                        Type *tsa = tbn->sarrayOf(nargs - i);
 
                         Expressions *elements = new Expressions();
                         elements->setDim(nargs - i);
@@ -1511,8 +1510,7 @@  bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
                             (*elements)[u] = a;
                         }
                         // Bugzilla 14395: Convert to a static array literal, or its slice.
-                        arg = new ArrayLiteralExp(loc, elements);
-                        arg->type = tsa;
+                        arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
                         if (tb->ty == Tarray)
                         {
                             arg = new SliceExp(loc, arg, NULL, NULL);
@@ -3741,34 +3739,37 @@  unsigned StringExp::charAt(uinteger_t i) const
 
 // [ e1, e2, e3, ... ]
 
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements)
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expressions *elements)
     : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
 {
     this->basis = NULL;
+    this->type = type;
     this->elements = elements;
     this->ownedByCtfe = OWNEDcode;
 }
 
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e)
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expression *e)
     : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
 {
     this->basis = NULL;
+    this->type = type;
     elements = new Expressions;
     elements->push(e);
     this->ownedByCtfe = OWNEDcode;
 }
 
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *basis, Expressions *elements)
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expression *basis, Expressions *elements)
     : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
 {
     this->basis = basis;
+    this->type = type;
     this->elements = elements;
     this->ownedByCtfe = OWNEDcode;
 }
 
 ArrayLiteralExp *ArrayLiteralExp::create(Loc loc, Expressions *elements)
 {
-    return new ArrayLiteralExp(loc, elements);
+    return new ArrayLiteralExp(loc, NULL, elements);
 }
 
 bool ArrayLiteralExp::equals(RootObject *o)
@@ -3806,6 +3807,7 @@  bool ArrayLiteralExp::equals(RootObject *o)
 Expression *ArrayLiteralExp::syntaxCopy()
 {
     return new ArrayLiteralExp(loc,
+        NULL,
         basis ? basis->syntaxCopy() : NULL,
         arraySyntaxCopy(elements));
 }
@@ -4082,8 +4084,7 @@  Expression *StructLiteralExp::getField(Type *type, unsigned offset)
                 z->setDim(length);
                 for (size_t q = 0; q < length; ++q)
                     (*z)[q] = e->copy();
-                e = new ArrayLiteralExp(loc, z);
-                e->type = type;
+                e = new ArrayLiteralExp(loc, type, z);
             }
             else
             {
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 51490828b1c..2dd0b249458 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -410,9 +410,9 @@  public:
     Expressions *elements;
     OwnedBy ownedByCtfe;
 
-    ArrayLiteralExp(Loc loc, Expressions *elements);
-    ArrayLiteralExp(Loc loc, Expression *e);
-    ArrayLiteralExp(Loc loc, Expression *basis, Expressions *elements);
+    ArrayLiteralExp(Loc loc, Type *type, Expressions *elements);
+    ArrayLiteralExp(Loc loc, Type *type, Expression *e);
+    ArrayLiteralExp(Loc loc, Type *type, Expression *basis, Expressions *elements);
     static ArrayLiteralExp *create(Loc loc, Expressions *elements);
     Expression *syntaxCopy();
     bool equals(RootObject *o);
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index b3274e4cfe4..d5319e55a6e 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -6632,8 +6632,7 @@  public:
                 if (tb2->ty == Tarray || tb2->ty == Tsarray)
                 {
                     // Make e2 into [e2]
-                    exp->e2 = new ArrayLiteralExp(exp->e2->loc, exp->e2);
-                    exp->e2->type = exp->type;
+                    exp->e2 = new ArrayLiteralExp(exp->e2->loc, exp->type, exp->e2);
                 }
                 result = exp->optimize(WANTvalue);
                 return;
@@ -6669,8 +6668,7 @@  public:
                 if (tb1->ty == Tarray || tb1->ty == Tsarray)
                 {
                     // Make e1 into [e1]
-                    exp->e1 = new ArrayLiteralExp(exp->e1->loc, exp->e1);
-                    exp->e1->type = exp->type;
+                    exp->e1 = new ArrayLiteralExp(exp->e1->loc, exp->type, exp->e1);
                 }
                 result = exp->optimize(WANTvalue);
                 return;
diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c
index d413ded33b4..ec26b2c7008 100644
--- a/gcc/d/dmd/idgen.c
+++ b/gcc/d/dmd/idgen.c
@@ -267,6 +267,9 @@  Msgtable msgtable[] =
     { "_ArrayEq", NULL },
     { "_ArrayPostblit", NULL },
     { "_ArrayDtor", NULL },
+    { "dup", NULL },
+    { "_aaApply", NULL },
+    { "_aaApply2", NULL },
 
     // For pragma's
     { "Pinline", "inline" },
diff --git a/gcc/d/dmd/initsem.c b/gcc/d/dmd/initsem.c
index 74929389177..52e26bccd85 100644
--- a/gcc/d/dmd/initsem.c
+++ b/gcc/d/dmd/initsem.c
@@ -612,7 +612,7 @@  public:
                 assert((*elements)[i]->op != TOKerror);
             }
 
-            Expression *e = new ArrayLiteralExp(init->loc, elements);
+            Expression *e = new ArrayLiteralExp(init->loc, NULL, elements);
             ExpInitializer *ei = new ExpInitializer(init->loc, e);
             result = inferType(ei, sc);
             return;
@@ -857,8 +857,7 @@  public:
                             elements2->setDim(dim);
                             for (size_t j = 0; j < dim; j++)
                                 (*elements2)[j] = e;
-                            e = new ArrayLiteralExp(e->loc, elements2);
-                            e->type = tn;
+                            e = new ArrayLiteralExp(e->loc, tn, elements2);
                             (*elements)[i] = e;
                         }
                     }
@@ -877,8 +876,7 @@  public:
                 }
             }
 
-            Expression *e = new ArrayLiteralExp(init->loc, elements);
-            e->type = init->type;
+            Expression *e = new ArrayLiteralExp(init->loc, init->type, elements);
             result = e;
             return;
         }
@@ -902,8 +900,7 @@  public:
                 elements->setDim(d);
                 for (size_t i = 0; i < d; i++)
                     (*elements)[i] = e;
-                ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, elements);
-                ae->type = itype;
+                ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, itype, elements);
                 result = ae;
                 return;
             }
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index 50a33e5c4c5..09161a313ee 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -2324,16 +2324,11 @@  Identifier *Type::getTypeInfoIdent()
     size_t namelen = 19 + sizeof(len) * 3 + len + 1;
     char *name = namelen <= sizeof(namebuf) ? namebuf : (char *)mem.xmalloc(namelen);
 
-    sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.data);
+    int length = sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.data);
     //printf("%p, deco = %s, name = %s\n", this, deco, name);
-    assert(strlen(name) < namelen);     // don't overflow the buffer
+    assert(0 < length && length < namelen);     // don't overflow the buffer
 
-    size_t off = 0;
-#ifndef IN_GCC
-    if (global.params.isOSX || (global.params.isWindows && !global.params.is64bit))
-        ++off;                 // C mangling will add '_' back in
-#endif
-    Identifier *id = Identifier::idPool(name + off);
+    Identifier *id = Identifier::idPool(name, length);
 
     if (name != namebuf)
         free(name);
@@ -4340,8 +4335,7 @@  Expression *TypeSArray::defaultInitLiteral(Loc loc)
     elements->setDim(d);
     for (size_t i = 0; i < d; i++)
         (*elements)[i] = NULL;
-    ArrayLiteralExp *ae = new ArrayLiteralExp(Loc(), elementinit, elements);
-    ae->type = this;
+    ArrayLiteralExp *ae = new ArrayLiteralExp(Loc(), this, elementinit, elements);
     return ae;
 }
 
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
index c081e806785..171ed14f132 100644
--- a/gcc/d/dmd/parse.c
+++ b/gcc/d/dmd/parse.c
@@ -7020,7 +7020,7 @@  Expression *Parser::parsePrimaryExp()
             if (keys)
                 e = new AssocArrayLiteralExp(loc, keys, values);
             else
-                e = new ArrayLiteralExp(loc, values);
+                e = new ArrayLiteralExp(loc, NULL, values);
             break;
         }
 
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
index a2d5c9b7a9c..1d5f3fc1064 100644
--- a/gcc/d/dmd/traits.c
+++ b/gcc/d/dmd/traits.c
@@ -479,8 +479,7 @@  Expression *pointerBitmap(TraitsExp *e)
     for (d_uns64 i = 0; i < cntdata; i++)
         exps->push(new IntegerExp(e->loc, data[(size_t)i], Type::tsize_t));
 
-    ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, exps);
-    ale->type = Type::tsize_t->sarrayOf(cntdata + 1);
+    ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, Type::tsize_t->sarrayOf(cntdata + 1), exps);
     return ale;
 }