diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index d7f714760f7..00169a743a1 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -162,6 +162,7 @@ D_FRONTEND_OBJS = \
 	d/root-filename.o \
 	d/root-hash.o \
 	d/root-longdouble.o \
+	d/root-optional.o \
 	d/root-port.o \
 	d/root-region.o \
 	d/root-rmem.o \
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 04b9791ab1b..5c9f569d1c4 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -337,10 +337,10 @@ build_attributes (Expressions *eattrs)
 	continue;
 
       /* Get the result of the attribute if it hasn't already been folded.  */
-      if (attr->op == TOKcall)
+      if (attr->op == EXP::call)
 	attr = attr->ctfeInterpret ();
 
-      if (attr->op != TOKstructliteral)
+      if (attr->op != EXP::structLiteral)
 	{
 	  warning_at (make_location_t (attr->loc), OPT_Wattributes,
 		      "%qE attribute has no effect",
@@ -353,7 +353,7 @@ build_attributes (Expressions *eattrs)
       Expressions *elems = attr->isStructLiteralExp ()->elements;
       Expression *e0 = (*elems)[0];
 
-      if (e0->op != TOKstring)
+      if (e0->op != EXP::string_)
 	{
 	  warning_at (make_location_t (attr->loc), OPT_Wattributes,
 		      "unknown attribute %qs", e0->toChars());
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index c082ac5ab80..39c3c6ce987 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -2154,9 +2154,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
 	{
 	Lagain:
 	  Expression *arg = (*arguments)[i];
-	  gcc_assert (arg->op != TOKtuple);
+	  gcc_assert (arg->op != EXP::tuple);
 
-	  if (arg->op == TOKcomma)
+	  if (arg->op == EXP::comma)
 	    {
 	      CommaExp *ce = arg->isCommaExp ();
 	      tree tce = build_expr (ce->e1);
@@ -2200,7 +2200,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
 	      /* Nested structs also have ADDRESSABLE set, but if the type has
 		 neither a copy constructor nor a destructor available, then we
 		 need to take care of copying its value before passing it.  */
-	      if (arg->op == TOKstructliteral || (!sd->postblit && !sd->dtor))
+	      if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor))
 		targ = force_target_expr (targ);
 
 	      targ = convert (build_reference_type (TREE_TYPE (targ)),
diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc
index 3df40073ac5..c1e78c0a5de 100644
--- a/gcc/d/d-compiler.cc
+++ b/gcc/d/d-compiler.cc
@@ -50,7 +50,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
     cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
   else if (expr->type->isfloating ())
     cst = build_float_cst (expr->toReal (), expr->type);
-  else if (expr->op == TOKarrayliteral)
+  else if (expr->op == EXP::arrayLiteral)
     {
       /* Build array as VECTOR_CST, assumes EXPR is constant.  */
       Expressions *elements = expr->isArrayLiteralExp ()->elements;
@@ -99,7 +99,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
       cst = native_interpret_expr (vectype, buffer, len);
 
       Expression *e = d_eval_constant_expression (expr->loc, cst);
-      gcc_assert (e != NULL && e->op == TOKvector);
+      gcc_assert (e != NULL && e->op == EXP::vector);
 
       return e->isVectorExp ()->e1;
     }
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 576eefcc01f..2c5d206a95f 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -620,10 +620,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.inclusiveInContracts = value;
       break;
 
-    case OPT_fpreview_intpromote:
-      global.params.fix16997 = value;
-      break;
-
     case OPT_fpreview_nosharedaccess:
       global.params.noSharedAccess = value;
       break;
@@ -642,8 +638,9 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 
     case OPT_frevert_all:
       global.params.useDIP25 = FeatureState::disabled;
-      global.params.markdown = !value;
       global.params.dtorFields = FeatureState::disabled;
+      global.params.fix16997 = !value;
+      global.params.markdown = !value;
       break;
 
     case OPT_frevert_dip25:
@@ -654,6 +651,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.dtorFields = FeatureState::disabled;
       break;
 
+    case OPT_frevert_intpromote:
+      global.params.fix16997 = !value;
+      break;
+
     case OPT_frevert_markdown:
       global.params.markdown = !value;
       break;
diff --git a/gcc/d/d-port.cc b/gcc/d/d-port.cc
index 58b3fe138b2..4e867a7db4a 100644
--- a/gcc/d/d-port.cc
+++ b/gcc/d/d-port.cc
@@ -145,6 +145,8 @@ Port::readlongBE (const void *buffer)
 void
 Port::valcpy (void *buffer, uint64_t value, size_t sz)
 {
+  gcc_assert (((size_t) buffer) % sz == 0);
+
   switch (sz)
     {
     case 1:
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index 21417dddf78..dd244f12119 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -287,7 +287,7 @@ Target::isVectorTypeSupported (int sz, Type *type)
    Returns true if the operation is supported or type is not a vector.  */
 
 bool
-Target::isVectorOpSupported (Type *type, unsigned op, Type *)
+Target::isVectorOpSupported (Type *type, EXP op, Type *)
 {
   if (type->ty != TY::Tvector)
     return true;
@@ -299,31 +299,31 @@ Target::isVectorOpSupported (Type *type, unsigned op, Type *)
   /* Don't support if expression cannot be represented.  */
   switch (op)
     {
-    case TOKpow:
-    case TOKpowass:
+    case EXP::pow:
+    case EXP::powAssign:
       /* pow() is lowered as a function call.  */
       return false;
 
-    case TOKmod:
-    case TOKmodass:
+    case EXP::mod:
+    case EXP::modAssign:
       /* fmod() is lowered as a function call.  */
       if (type->isfloating ())
 	return false;
       break;
 
-    case TOKandand:
-    case TOKoror:
+    case EXP::andAnd:
+    case EXP::orOr:
       /* Logical operators must have a result type of bool.  */
       return false;
 
-    case TOKle:
-    case TOKlt:
-    case TOKge:
-    case TOKgt:
-    case TOKequal:
-    case TOKnotequal:
-    case TOKidentity:
-    case TOKnotidentity:
+    case EXP::lessOrEqual:
+    case EXP::lessThan:
+    case EXP::greaterOrEqual:
+    case EXP::greaterThan:
+    case EXP::equal:
+    case EXP::notEqual:
+    case EXP::identity:
+    case EXP::notIdentity:
       /* Comparison operators must have a result type of bool.  */
       return false;
 
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index c69f5664e8c..bbde4a669e4 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -2239,7 +2239,7 @@ layout_class_initializer (ClassDeclaration *cd)
   ne->type = cd->type;
 
   Expression *e = ne->ctfeInterpret ();
-  gcc_assert (e->op == TOKclassreference);
+  gcc_assert (e->op == EXP::classReference);
 
   return build_class_instance (e->isClassReferenceExp ());
 }
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 8e1d43e2b8f..f1c014dbc16 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -88,7 +88,7 @@ lvalue_p (Expression *e)
   if (ce != NULL && ce->e1->isLvalue ())
     return true;
 
-  return (e->op != TOKslice && e->isLvalue ());
+  return (e->op != EXP::slice && e->isLvalue ());
 }
 
 /* Build an expression of code CODE, data type TYPE, and operands ARG0 and
@@ -162,7 +162,7 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2)
 {
   /* Skip casts for lhs assignment.  */
   Expression *e1b = e1;
-  while (e1b->op == TOKcast)
+  while (e1b->op == EXP::cast_)
     {
       CastExp *ce = e1b->isCastExp ();
       gcc_assert (same_type_p (ce->type, ce->to));
@@ -264,7 +264,7 @@ public:
 
   void visit (IdentityExp *e)
   {
-    tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR;
+    tree_code code = (e->op == EXP::identity) ? EQ_EXPR : NE_EXPR;
     Type *tb1 = e->e1->type->toBasetype ();
     Type *tb2 = e->e2->type->toBasetype ();
 
@@ -331,7 +331,7 @@ public:
   {
     Type *tb1 = e->e1->type->toBasetype ();
     Type *tb2 = e->e2->type->toBasetype ();
-    tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
+    tree_code code = (e->op == EXP::equal) ? EQ_EXPR : NE_EXPR;
 
     if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray)
 	&& (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray))
@@ -391,7 +391,7 @@ public:
 	       Otherwise for inequality:
 		    (e1.length != 0 && memcmp);  */
 	    tree tsizecmp = build_boolop (code, t1len, size_zero_node);
-	    if (e->op == TOKequal)
+	    if (e->op == EXP::equal)
 	      result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result);
 	    else
 	      result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result);
@@ -404,7 +404,7 @@ public:
 	    else
 	      {
 		tree tlencmp = build_boolop (code, t1len, t2len);
-		if (e->op == TOKequal)
+		if (e->op == EXP::equal)
 		  result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result);
 		else
 		  result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result);
@@ -428,7 +428,7 @@ public:
 					 d_array_convert (e->e2),
 					 build_typeinfo (e->loc, t1array));
 
-	    if (e->op == TOKnotequal)
+	    if (e->op == EXP::notEqual)
 	      result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
 
 	    this->result_ = result;
@@ -453,7 +453,7 @@ public:
 				     build_expr (e->e1),
 				     build_expr (e->e2));
 
-	if (e->op == TOKnotequal)
+	if (e->op == EXP::notEqual)
 	  result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
 
 	this->result_ = result;
@@ -499,19 +499,19 @@ public:
 
     switch (e->op)
       {
-      case TOKle:
+      case EXP::lessOrEqual:
 	code = LE_EXPR;
 	break;
 
-      case TOKlt:
+      case EXP::lessThan:
 	code = LT_EXPR;
 	break;
 
-      case TOKge:
+      case EXP::greaterOrEqual:
 	code = GE_EXPR;
 	break;
 
-      case TOKgt:
+      case EXP::greaterThan:
 	code = GT_EXPR;
 	break;
 
@@ -540,7 +540,7 @@ public:
 
   void visit (LogicalExp *e)
   {
-    tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+    tree_code code = (e->op == EXP::andAnd) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
 
     if (e->e2->type->toBasetype ()->ty != TY::Tvoid)
       {
@@ -559,7 +559,7 @@ public:
 	tree t2 = build_expr_dtor (e->e2);
 
 	/* Invert condition for logical or if expression.  */
-	if (e->op == TOKoror)
+	if (e->op == EXP::orOr)
 	  t1 = build1 (TRUTH_NOT_EXPR, d_bool_type, t1);
 
 	this->result_ = build_condition (build_ctype (e->type),
@@ -576,8 +576,8 @@ public:
 
     switch (e->op)
       {
-      case TOKadd:
-      case TOKmin:
+      case EXP::add:
+      case EXP::min:
 	if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
 	    || (e->e1->type->isimaginary () && e->e2->type->isreal ()))
 	  {
@@ -586,7 +586,7 @@ public:
 	    tree t1 = build_expr (e->e1);
 	    tree t2 = build_expr (e->e2);
 
-	    if (e->op == TOKmin)
+	    if (e->op == EXP::min)
 	      t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
 
 	    if (e->e1->type->isreal ())
@@ -597,22 +597,22 @@ public:
 	    return;
 	  }
 	else
-	  code = (e->op == TOKadd)
+	  code = (e->op == EXP::add)
 	    ? PLUS_EXPR : MINUS_EXPR;
 	break;
 
-      case TOKmul:
+      case EXP::mul:
 	code = MULT_EXPR;
 	break;
 
-      case TOKdiv:
+      case EXP::div:
 	/* Determine if the div expression is a lowered pointer diff operation.
 	   The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'.  */
 	if (MinExp *me = e->e1->isMinExp ())
 	  {
 	    if (me->e1->type->ty == TY::Tpointer
 		&& me->e2->type->ty == TY::Tpointer
-		&& e->e2->op == TOKint64)
+		&& e->e2->op == EXP::int64)
 	      {
 		code = EXACT_DIV_EXPR;
 		break;
@@ -623,32 +623,32 @@ public:
 	  ? TRUNC_DIV_EXPR : RDIV_EXPR;
 	break;
 
-      case TOKmod:
+      case EXP::mod:
 	code = e->e1->type->isfloating ()
 	  ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
 	break;
 
-      case TOKand:
+      case EXP::and_:
 	code = BIT_AND_EXPR;
 	break;
 
-      case TOKor:
+      case EXP::or_:
 	code = BIT_IOR_EXPR;
 	break;
 
-      case TOKxor:
+      case EXP::xor_:
 	code = BIT_XOR_EXPR;
 	break;
 
-      case TOKshl:
+      case EXP::leftShift:
 	code = LSHIFT_EXPR;
 	  break;
 
-      case TOKshr:
+      case EXP::rightShift:
 	code = RSHIFT_EXPR;
 	break;
 
-      case TOKushr:
+      case EXP::unsignedRightShift:
 	code = UNSIGNED_RSHIFT_EXPR;
 	break;
 
@@ -678,15 +678,15 @@ public:
 
     tree result;
 
-    if (e->e1->op == TOKcat)
+    if (e->e1->op == EXP::concatenate)
       {
 	/* Flatten multiple concatenations to an array.
 	   So the expression ((a ~ b) ~ c) becomes [a, b, c]  */
 	int ndims = 2;
 
-	for (Expression *ex = e->e1; ex->op == TOKcat;)
+	for (Expression *ex = e->e1; ex->op == EXP::concatenate;)
 	  {
-	    if (ex->op == TOKcat)
+	    if (ex->op == EXP::concatenate)
 	      {
 		ex = ex->isCatExp ()->e1;
 		ndims++;
@@ -703,7 +703,7 @@ public:
 	int dim = ndims - 1;
 
 	for (Expression *oe = ce->e2; oe != NULL;
-	     (ce->e1->op != TOKcat
+	     (ce->e1->op != EXP::concatenate
 	      ? (oe = ce->e1)
 	      : (ce = ce->e1->isCatExp (), oe = ce->e2)))
 	  {
@@ -751,59 +751,59 @@ public:
 
     switch (e->op)
       {
-      case TOKaddass:
+      case EXP::addAssign:
 	code = PLUS_EXPR;
 	break;
 
-      case TOKminass:
+      case EXP::minAssign:
 	code = MINUS_EXPR;
 	break;
 
-      case TOKmulass:
+      case EXP::mulAssign:
 	code = MULT_EXPR;
 	break;
 
-      case TOKdivass:
+      case EXP::divAssign:
 	code = e->e1->type->isintegral ()
 	  ? TRUNC_DIV_EXPR : RDIV_EXPR;
 	break;
 
-      case TOKmodass:
+      case EXP::modAssign:
 	code = e->e1->type->isfloating ()
 	  ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
 	break;
 
-      case TOKandass:
+      case EXP::andAssign:
 	code = BIT_AND_EXPR;
 	break;
 
-      case TOKorass:
+      case EXP::orAssign:
 	code = BIT_IOR_EXPR;
 	break;
 
-      case TOKxorass:
+      case EXP::xorAssign:
 	code = BIT_XOR_EXPR;
 	break;
 
-      case TOKpowass:
+      case EXP::powAssign:
 	gcc_unreachable ();
 
-      case TOKshlass:
+      case EXP::leftShiftAssign:
 	code = LSHIFT_EXPR;
 	break;
 
-      case TOKshrass:
-      case TOKushrass:
+      case EXP::rightShiftAssign:
+      case EXP::unsignedRightShiftAssign:
 	/* Use the original lhs type before it was promoted.  The left operand
 	   of `>>>=' does not undergo integral promotions before shifting.
 	   Strip off casts just incase anyway.  */
-	while (e1b->op == TOKcast)
+	while (e1b->op == EXP::cast_)
 	  {
 	    CastExp *ce = e1b->isCastExp ();
 	    gcc_assert (same_type_p (ce->type, ce->to));
 	    e1b = ce->e1;
 	  }
-	code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
+	code = (e->op == EXP::rightShiftAssign) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
 	break;
 
       default:
@@ -908,7 +908,7 @@ public:
     /* First, handle special assignment semantics.  */
 
     /* Look for array.length = n;  */
-    if (e->e1->op == TOKarraylength)
+    if (e->e1->op == EXP::arrayLength)
       {
 	/* This case should have been rewritten to `_d_arraysetlengthT` in the
 	   semantic phase.  */
@@ -916,7 +916,7 @@ public:
       }
 
     /* Look for array[] = n;  */
-    if (e->e1->op == TOKslice)
+    if (e->e1->op == EXP::slice)
       {
 	SliceExp *se = e->e1->isSliceExp ();
 	Type *stype = se->e1->type->toBasetype ();
@@ -937,15 +937,18 @@ public:
 	    tree init = stabilize_expr (&t1);
 	    t1 = d_save_expr (t1);
 
-	    if ((postblit || destructor) && e->op != TOKblit)
+	    if ((postblit || destructor) && e->op != EXP::blit)
 	      {
-		libcall_fn libcall = (e->op == TOKconstruct)
-		  ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
+		/* Need to call postblit/destructor as part of assignment.
+		   Construction has already been handled by the front-end.  */
+		gcc_assert (e->op != EXP::construct);
+
 		/* So we can call postblits on const/immutable objects.  */
 		Type *tm = etype->unSharedOf ()->mutableOf ();
 		tree ti = build_typeinfo (e->loc, tm);
 
-		result = build_libcall (libcall, Type::tvoid, 4,
+		/* Generate: _d_arraysetassign (t1.ptr, &t2, t1.length, ti);  */
+		result = build_libcall (LIBCALL_ARRAYSETASSIGN, Type::tvoid, 4,
 					d_array_ptr (t1),
 					build_address (t2),
 					d_array_length (t1), ti);
@@ -1011,14 +1014,11 @@ public:
 
 		this->result_ = compound_expr (result, t1);
 	      }
-	    else if ((postblit || destructor) && e->op != TOKblit)
+	    else if ((postblit || destructor)
+		     && e->op != EXP::blit && e->op != EXP::construct)
 	      {
-		/* Generate: _d_arrayassign(ti, from, to)
-			 or: _d_arrayctor(ti, from, to)  */
-		libcall_fn libcall = (e->op == TOKconstruct)
-		  ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
-
-		this->result_ = build_libcall (libcall, e->type, 3,
+		/* Generate: _d_arrayassign(ti, from, to);  */
+		this->result_ = build_libcall (LIBCALL_ARRAYASSIGN, e->type, 3,
 					       build_typeinfo (e->loc, etype),
 					       d_array_convert (e->e2),
 					       d_array_convert (e->e1));
@@ -1039,8 +1039,8 @@ public:
     /* Look for reference initializations.  */
     if (e->memset == MemorySet::referenceInit)
       {
-	gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
-	gcc_assert (e->e1->op == TOKvar);
+	gcc_assert (e->op == EXP::construct || e->op == EXP::blit);
+	gcc_assert (e->e1->op == EXP::variable);
 
 	Declaration *decl = e->e1->isVarExp ()->var;
 	if (decl->storage_class & (STCout | STCref))
@@ -1060,7 +1060,7 @@ public:
 
     /* Other types of assignments that may require post construction.  */
     Type *tb1 = e->e1->type->toBasetype ();
-    tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
+    tree_code modifycode = (e->op == EXP::construct) ? INIT_EXPR : MODIFY_EXPR;
 
     /* Look for struct assignment.  */
     if (tb1->ty == TY::Tstruct)
@@ -1071,10 +1071,10 @@ public:
 	StructDeclaration *sd = tb1->isTypeStruct ()->sym;
 
 	/* Look for struct = 0.  */
-	if (e->e2->op == TOKint64)
+	if (e->e2->op == EXP::int64)
 	  {
 	    /* Use memset to fill struct.  */
-	    gcc_assert (e->op == TOKblit);
+	    gcc_assert (e->op == EXP::blit);
 	    tree result = build_memset_call (t1);
 
 	    /* Maybe set-up hidden pointer to outer scope context.  */
@@ -1095,8 +1095,8 @@ public:
 	    tree init = NULL_TREE;
 
 	    /* Fill any alignment holes in the struct using memset.  */
-	    if ((e->op == TOKconstruct
-		 || (e->e2->op == TOKstructliteral && e->op == TOKblit))
+	    if ((e->op == EXP::construct
+		 || (e->e2->op == EXP::structLiteral && e->op == EXP::blit))
 		&& (sd->isUnionDeclaration () || !identity_compare_p (sd)))
 	      {
 		t1 = stabilize_reference (t1);
@@ -1120,10 +1120,10 @@ public:
     if (tb1->ty == TY::Tsarray)
       {
 	/* Look for array = 0.  */
-	if (e->e2->op == TOKint64)
+	if (e->e2->op == EXP::int64)
 	  {
 	    /* Use memset to fill the array.  */
-	    gcc_assert (e->op == TOKblit);
+	    gcc_assert (e->op == EXP::blit);
 	    this->result_ = build_memset_call (build_expr (e->e1));
 	    return;
 	  }
@@ -1132,17 +1132,17 @@ public:
 	gcc_assert (e->e2->type->toBasetype ()->ty == TY::Tsarray);
 
 	/* Determine if we need to run postblit.  */
-	bool postblit = needs_postblit (etype);
-	bool destructor = needs_dtor (etype);
-	bool lvalue = lvalue_p (e->e2);
+	const bool postblit = needs_postblit (etype);
+	const bool destructor = needs_dtor (etype);
+	const bool lvalue = lvalue_p (e->e2);
 
 	/* Optimize static array assignment with array literal.  Even if the
 	   elements in rhs are all rvalues and don't have to call postblits,
 	   this assignment should call dtors on old assigned elements.  */
 	if ((!postblit && !destructor)
-	    || (e->op == TOKconstruct && e->e2->op == TOKarrayliteral)
-	    || (e->op == TOKconstruct && !lvalue && postblit)
-	    || (e->op == TOKblit || e->e1->type->size () == 0))
+	    || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral)
+	    || (e->op == EXP::construct && !lvalue && postblit)
+	    || (e->op == EXP::blit || e->e1->type->size () == 0))
 	  {
 	    tree t1 = build_expr (e->e1);
 	    tree t2 = convert_for_assignment (build_expr (e->e2),
@@ -1152,32 +1152,22 @@ public:
 	    return;
 	  }
 
+	/* All other kinds of lvalue or rvalue static array assignment.
+	   Array construction has already been handled by the front-end.  */
+	gcc_assert (e->op != EXP::construct);
+
+	/* Generate: _d_arrayassign_l()
+		 or: _d_arrayassign_r()  */
+	libcall_fn libcall = (lvalue)
+	  ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
+	tree elembuf = build_local_temp (build_ctype (etype));
 	Type *arrtype = (e->type->ty == TY::Tsarray)
 	  ? etype->arrayOf () : e->type;
-	tree result;
-
-	if (e->op == TOKconstruct)
-	  {
-	    /* Generate: _d_arrayctor(ti, from, to)  */
-	    result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
-				    build_typeinfo (e->loc, etype),
-				    d_array_convert (e->e2),
-				    d_array_convert (e->e1));
-	  }
-	else
-	  {
-	    /* Generate: _d_arrayassign_l()
-		     or: _d_arrayassign_r()  */
-	    libcall_fn libcall = (lvalue)
-	      ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
-	    tree elembuf = build_local_temp (build_ctype (etype));
-
-	    result = build_libcall (libcall, arrtype, 4,
-				    build_typeinfo (e->loc, etype),
-				    d_array_convert (e->e2),
-				    d_array_convert (e->e1),
-				    build_address (elembuf));
-	  }
+	tree result = build_libcall (libcall, arrtype, 4,
+				     build_typeinfo (e->loc, etype),
+				     d_array_convert (e->e2),
+				     d_array_convert (e->e1),
+				     build_address (elembuf));
 
 	/* Cast the libcall result back to a static array.  */
 	if (e->type->ty == TY::Tsarray)
@@ -1202,12 +1192,12 @@ public:
   {
     tree result;
 
-    if (e->op == TOKplusplus)
+    if (e->op == EXP::plusPlus)
       {
 	result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type),
 			 build_expr (e->e1), build_expr (e->e2));
       }
-    else if (e->op == TOKminusminus)
+    else if (e->op == EXP::minusMinus)
       {
 	result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type),
 			 build_expr (e->e1), build_expr (e->e2));
@@ -1441,7 +1431,7 @@ public:
 	   the destructor is called for the object instance.  */
 	libcall_fn libcall;
 
-	if (e->e1->op == TOKvar)
+	if (e->e1->op == EXP::variable)
 	  {
 	    VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration ();
 	    if (v && v->onstack)
@@ -1586,10 +1576,10 @@ public:
     size_t offset;
     tree result;
 
-    if (e->e1->op == TOKadd)
+    if (e->e1->op == EXP::add)
       {
 	AddExp *ae = e->e1->isAddExp ();
-	if (ae->e1->op == TOKaddress
+	if (ae->e1->op == EXP::address
 	    && ae->e2->isConst () && ae->e2->type->isintegral ())
 	  {
 	    Expression *ex = ae->e1->isAddrExp ()->e1;
@@ -1598,7 +1588,7 @@ public:
 	    offset = ae->e2->toUInteger ();
 	  }
       }
-    else if (e->e1->op == TOKsymoff)
+    else if (e->e1->op == EXP::symbolOffset)
       {
 	SymOffExp *se = e->e1->isSymOffExp ();
 	if (!declaration_reference_p (se->var))
@@ -1650,7 +1640,7 @@ public:
 
     /* The frontend optimizer can convert const symbol into a struct literal.
        Taking the address of a struct literal is otherwise illegal.  */
-    if (e->e1->op == TOKstructliteral)
+    if (e->e1->op == EXP::structLiteral)
       {
 	StructLiteralExp *sle = e->e1->isStructLiteralExp ()->origin;
 	gcc_assert (sle != NULL);
@@ -1689,21 +1679,21 @@ public:
     TypeFunction *tf = NULL;
 
     /* Calls to delegates can sometimes look like this.  */
-    if (e1b->op == TOKcomma)
+    if (e1b->op == EXP::comma)
       {
 	e1b = e1b->isCommaExp ()->e2;
-	gcc_assert (e1b->op == TOKvar);
+	gcc_assert (e1b->op == EXP::variable);
 
 	Declaration *var = e1b->isVarExp ()->var;
 	gcc_assert (var->isFuncDeclaration () && !var->needThis ());
       }
 
-    if (e1b->op == TOKdotvar && tb->ty != TY::Tdelegate)
+    if (e1b->op == EXP::dotVariable && tb->ty != TY::Tdelegate)
       {
 	DotVarExp *dve = e1b->isDotVarExp ();
 
 	/* Don't modify the static initializer for struct literals.  */
-	if (dve->e1->op == TOKstructliteral)
+	if (dve->e1->op == EXP::structLiteral)
 	  {
 	    StructLiteralExp *sle = dve->e1->isStructLiteralExp ();
 	    sle->useStaticInit = false;
@@ -1775,7 +1765,7 @@ public:
       {
 	/* This could be a delegate expression (TY == Tdelegate), but not
 	   actually a delegate variable.  */
-	if (e1b->op == TOKdotvar)
+	if (e1b->op == EXP::dotVariable)
 	  {
 	    /* This gets the true function type, getting the function type
 	       from e1->type can sometimes be incorrect, such as when calling
@@ -1795,7 +1785,7 @@ public:
 	object = delegate_object (callee);
 	callee = delegate_method (callee);
       }
-    else if (e1b->op == TOKvar)
+    else if (e1b->op == EXP::variable)
       {
 	FuncDeclaration *fd = e1b->isVarExp ()->var->isFuncDeclaration ();
 	gcc_assert (fd != NULL);
@@ -1877,7 +1867,7 @@ public:
 
     if (e->func->isNested () && !e->func->isThis ())
       {
-	if (e->e1->op == TOKnull)
+	if (e->e1->op == EXP::null_)
 	  object = build_expr (e->e1);
 	else
 	  object = get_frame_for_symbol (e->func);
@@ -1908,7 +1898,7 @@ public:
 
 	/* Get pointer to function out of the virtual table.  */
 	if (e->func->isVirtual () && !e->func->isFinalFunc ()
-	    && e->e1->op != TOKsuper && e->e1->op != TOKdottype)
+	    && e->e1->op != EXP::super_ && e->e1->op != EXP::dotType)
 	  {
 	    tree fntype = build_pointer_type (TREE_TYPE (fndecl));
 	    object = d_save_expr (object);
@@ -2105,9 +2095,9 @@ public:
     Type *ftype = e->type->toBasetype ();
 
     /* This check is for lambda's, remove `vthis' as function isn't nested.  */
-    if (e->fd->tok == TOKreserved && ftype->ty == TY::Tpointer)
+    if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer)
       {
-	e->fd->tok = TOKfunction;
+	e->fd->tok = TOK::function_;
 	e->fd->vthis = NULL;
       }
 
@@ -2196,9 +2186,9 @@ public:
     FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
     if (fld != NULL)
       {
-	if (fld->tok == TOKreserved)
+	if (fld->tok == TOK::reserved)
 	  {
-	    fld->tok = TOKfunction;
+	    fld->tok = TOK::function_;
 	    fld->vthis = NULL;
 	  }
 
@@ -2210,7 +2200,7 @@ public:
       {
 	/* Want the initializer, not the expression.  */
 	VarDeclaration *var = e->var->isVarDeclaration ();
-	SymbolDeclaration *sd = e->var->isSymbolDeclaration ();
+	SymbolDeclaration *sdecl = e->var->isSymbolDeclaration ();
 	tree init = NULL_TREE;
 
 	if (var && (var->isConst () || var->isImmutable ())
@@ -2226,8 +2216,15 @@ public:
 		var->inuse--;
 	      }
 	  }
-	else if (sd && sd->dsym)
-	  init = layout_struct_initializer (sd->dsym);
+	else if (sdecl && sdecl->dsym)
+	  {
+	    if (StructDeclaration *sd = sdecl->dsym->isStructDeclaration ())
+	      init = layout_struct_initializer (sd);
+	    else if (ClassDeclaration *cd = sdecl->dsym->isClassDeclaration ())
+	      init = layout_class_initializer (cd);
+	    else
+	      gcc_unreachable ();
+	  }
 	else
 	  error_at (make_location_t (e->loc), "non-constant expression %qs",
 		    e->toChars ());
@@ -2242,6 +2239,26 @@ public:
 	tree result = get_decl_tree (e->var);
 	TREE_USED (result) = 1;
 
+	/* The variable expression generated for `__traits(initSymbol)'.  */
+	if (SymbolDeclaration *sd = e->var->isSymbolDeclaration ())
+	  {
+	    if (e->type->isTypeDArray ())
+	      {
+		/* Generate a slice for non-zero initialized aggregates,
+		   otherwise create an empty array.  */
+		gcc_assert (e->type == Type::tvoid->arrayOf ()->constOf ());
+
+		tree type = build_ctype (e->type);
+		tree length = size_int (sd->dsym->structsize);
+		tree ptr = (sd->dsym->isStructDeclaration ()
+			    && sd->dsym->type->isZeroInit (e->loc))
+		  ? null_pointer_node : build_address (result);
+
+		this->result_ = d_array_value (type, length, ptr);
+		return;
+	      }
+	  }
+
 	/* For variables that are references - currently only out/inout
 	   arguments; objects don't count - evaluating the variable means
 	   we want what it refers to.  */
@@ -2954,7 +2971,7 @@ public:
     tree type = build_ctype (e->type);
 
     /* First handle array literal expressions.  */
-    if (e->e1->op == TOKarrayliteral)
+    if (e->e1->op == EXP::arrayLiteral)
       {
 	ArrayLiteralExp *ale = e->e1->isArrayLiteralExp ();
 	vec <constructor_elt, va_gc> *elms = NULL;
diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
index b14b0ca5111..dec2bd47265 100644
--- a/gcc/d/intrinsics.cc
+++ b/gcc/d/intrinsics.cc
@@ -431,7 +431,7 @@ expand_intrinsic_rotate (intrinsic_code intrinsic, tree callexp)
       gcc_assert (ti && ti->tiargs && ti->tiargs->length == 2);
 
       Expression *e = isExpression ((*ti->tiargs)[0]);
-      gcc_assert (e && e->op == TOKint64);
+      gcc_assert (e && e->op == EXP::int64);
       count = build_expr (e, true);
     }
 
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index d0a5e2f6859..893bc238631 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -380,10 +380,6 @@ fpreview=inclusiveincontracts
 D RejectNegative
 Implement 'in' contracts of overridden methods to be a superset of parent contract.
 
-fpreview=intpromote
-D RejectNegative
-Use C-style integral promotion for unary '+', '-' and '~'.
-
 fpreview=nosharedaccess
 D RejectNegative
 Disable access to shared memory objects.
@@ -412,6 +408,10 @@ frevert=dtorfields
 D RejectNegative
 Don't destruct fields of partially constructed objects.
 
+frevert=intpromote
+D RejectNegative
+Use C-style integral promotion for unary '+', '-' and '~'.
+
 frevert=markdown
 D RejectNegative
 Disable Markdown replacements in Ddoc.
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index fdff6db0626..3961a1d9bed 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -140,13 +140,6 @@ DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID),
 DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR),
 	       P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
 
-/* Used for constructing a new array from an existing array.  The `set' variant
-   is for when the constructor value is a single element.  */
-DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID),
-	       P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
-DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR),
-	       P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
-
 /* Used for concatenating two or more arrays together.  Then `n' variant is
    for when there is more than two arrays to handle.  */
 DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE),
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
index 55d63f89cb7..17b63ba8a7d 100644
--- a/gcc/d/toir.cc
+++ b/gcc/d/toir.cc
@@ -969,8 +969,7 @@ public:
 	StructLiteralExp *sle = NULL;
 	bool using_rvo_p = false;
 
-	if (DotVarExp *dve = (s->exp->op == TOKcall
-			      && s->exp->isCallExp ()->e1->op == TOKdotvar
+	if (DotVarExp *dve = (s->exp->isCallExp ()
 			      ? s->exp->isCallExp ()->e1->isDotVarExp ()
 			      : NULL))
 	  {
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index b39b92eb822..1d551e5249b 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -338,7 +338,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
 		  RootObject *ro = (*td->objects)[j];
 		  gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION);
 		  Expression *e = (Expression *) ro;
-		  gcc_assert (e->op == TOKdsymbol);
+		  gcc_assert (e->op == EXP::dSymbol);
 		  DsymbolExp *se = e->isDsymbolExp ();
 
 		  tmembers.push (se->s);
