]> git.ipfire.org Git - people/ms/gcc.git/commitdiff
d: Merge upstream dmd 3982604c5, druntime bc58b1e9, phobos 12329adb6.
authorIain Buclaw <ibuclaw@gdcproject.org>
Fri, 10 Dec 2021 02:14:20 +0000 (03:14 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Fri, 10 Dec 2021 04:25:41 +0000 (05:25 +0100)
D front-end changes:

    - Import dmd mainline development.
    - Split off enum EXP from enum TOK.
    - Integer promotions now follow C integral promotions by default.
    - Implements __traits(initSymbol).
    - Lowering of array construction has been moved to the dmd
      front-end.
    - Fix segfault in dmd.lexer from unaligned read (PR103529).

Druntime changes:

    - Import druntime mainline development.
    - Define SIG_BLOCK for Solaris (PR103528).

Phobos changes:

    - Import phobos mainline development.

gcc/d/ChangeLog:

PR d/103529
* dmd/MERGE: Merge upstream dmd 3982604c5.
* Make-lang.in (D_FRONTEND_OBJS): Add d/root-optional.o.
* d-attribs.cc (build_attributes): Update for new front-end interface.
* d-codegen.cc (d_build_call): Likewise.
* d-compiler.cc (Compiler::paintAsType): Likewise.
* d-lang.cc (d_handle_option): Remove OPT_fpreview_intpromote, add
handling of OPT_frevert_intpromote.
* d-port.cc (Port::valcpy): Assert buffer is aligned.
* d-target.cc (Target::isVectorOpSupported): Update for new front-end
interface.
* decl.cc (layout_class_initializer): Likewise.
* expr.cc (lvalue_p): Likewise.
(binop_assignment): Likewise.
(ExprVisitor::visit): Likewise.
(ExprVisitor::visit (AssignExp *)): Remove generation of _d_arrayctor
and _d_arraysetctor library helpers.
(ExprVisitor::visit (VarExp *)): Support __traits(initSymbol).
* intrinsics.cc (expand_intrinsic_rotate): Update for new front-end
interface.
* lang.opt (fpreview=intpromote): Remove.
(frevert=intpromote): New.
* runtime.def (ARRAYCTOR): Remove.
(ARRAYSETCTOR): Remove.
* toir.cc (IRVisitor::visit): Update for new front-end interface.
* types.cc (layout_aggregate_members): Likewise.
* dmd/root/optional.d: New file.
* dmd/root/optional.h: New file.

libphobos/ChangeLog:

PR d/103528
* libdruntime/MERGE: Merge upstream druntime bc58b1e9.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES_LINUX): Remove
core/sys/linux/syscalls.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 12329adb6.
* testsuite/libphobos.config/config.exp: Add test22523.
* libdruntime/core/sys/linux/syscalls.d: Removed.
* testsuite/libphobos.config/test22523.d: New test.

175 files changed:
gcc/d/Make-lang.in
gcc/d/d-attribs.cc
gcc/d/d-codegen.cc
gcc/d/d-compiler.cc
gcc/d/d-lang.cc
gcc/d/d-port.cc
gcc/d/d-target.cc
gcc/d/decl.cc
gcc/d/dmd/MERGE
gcc/d/dmd/access.d
gcc/d/dmd/aggregate.d
gcc/d/dmd/aliasthis.d
gcc/d/dmd/arrayop.d
gcc/d/dmd/astenums.d
gcc/d/dmd/attrib.d
gcc/d/dmd/blockexit.d
gcc/d/dmd/builtin.d
gcc/d/dmd/canthrow.d
gcc/d/dmd/clone.d
gcc/d/dmd/common/outbuffer.h
gcc/d/dmd/cond.d
gcc/d/dmd/constfold.d
gcc/d/dmd/cparse.d
gcc/d/dmd/cppmangle.d
gcc/d/dmd/ctfeexpr.d
gcc/d/dmd/dcast.d
gcc/d/dmd/declaration.d
gcc/d/dmd/declaration.h
gcc/d/dmd/dinterpret.d
gcc/d/dmd/dmangle.d
gcc/d/dmd/dstruct.d
gcc/d/dmd/dsymbol.d
gcc/d/dmd/dsymbolsem.d
gcc/d/dmd/dtemplate.d
gcc/d/dmd/dtoh.d
gcc/d/dmd/escape.d
gcc/d/dmd/expression.d
gcc/d/dmd/expression.h
gcc/d/dmd/expressionsem.d
gcc/d/dmd/foreachvar.d
gcc/d/dmd/func.d
gcc/d/dmd/globals.d
gcc/d/dmd/hdrgen.d
gcc/d/dmd/iasmgcc.d
gcc/d/dmd/id.d
gcc/d/dmd/initsem.d
gcc/d/dmd/lambdacomp.d
gcc/d/dmd/lexer.d
gcc/d/dmd/mtype.d
gcc/d/dmd/nogc.d
gcc/d/dmd/ob.d
gcc/d/dmd/objc.d
gcc/d/dmd/opover.d
gcc/d/dmd/optimize.d
gcc/d/dmd/parse.d
gcc/d/dmd/printast.d
gcc/d/dmd/root/dcompat.h
gcc/d/dmd/root/file.d
gcc/d/dmd/root/optional.d [new file with mode: 0644]
gcc/d/dmd/root/optional.h [new file with mode: 0644]
gcc/d/dmd/safe.d
gcc/d/dmd/semantic2.d
gcc/d/dmd/semantic3.d
gcc/d/dmd/sideeffect.d
gcc/d/dmd/statementsem.d
gcc/d/dmd/staticcond.d
gcc/d/dmd/target.d
gcc/d/dmd/target.h
gcc/d/dmd/templateparamsem.d
gcc/d/dmd/tokens.d
gcc/d/dmd/tokens.h
gcc/d/dmd/traits.d
gcc/d/dmd/typesem.d
gcc/d/expr.cc
gcc/d/intrinsics.cc
gcc/d/lang.opt
gcc/d/runtime.def
gcc/d/toir.cc
gcc/d/types.cc
gcc/testsuite/gdc.test/compilable/covariant_override.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/emptygenmain.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/noreturn1.d
gcc/testsuite/gdc.test/compilable/test17870.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test19873.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test21719.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22254.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22510.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/covariant_override.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail10964.d
gcc/testsuite/gdc.test/fail_compilation/fail10968.d
gcc/testsuite/gdc.test/fail_compilation/fail16997.d
gcc/testsuite/gdc.test/fail_compilation/fail809.d [deleted file]
gcc/testsuite/gdc.test/fail_compilation/fob2.d
gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/retscope.d
gcc/testsuite/gdc.test/fail_compilation/test15191.d
gcc/testsuite/gdc.test/fail_compilation/test17977.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test20023.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/b19294.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/mars1.d
gcc/testsuite/gdc.test/runnable/test15862.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test21367.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test22227.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/testOpApply.d
gcc/testsuite/gdc.test/runnable/testcgelem.d
gcc/testsuite/gdc.test/runnable/testconst.d
gcc/testsuite/gdc.test/runnable/traits_initSymbol.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/xtest46.d
gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable_cxx/test7925.d [new file with mode: 0644]
libphobos/libdruntime/MERGE
libphobos/libdruntime/Makefile.am
libphobos/libdruntime/Makefile.in
libphobos/libdruntime/core/demangle.d
libphobos/libdruntime/core/internal/array/construction.d
libphobos/libdruntime/core/internal/convert.d
libphobos/libdruntime/core/internal/lifetime.d
libphobos/libdruntime/core/internal/string.d
libphobos/libdruntime/core/internal/utf.d
libphobos/libdruntime/core/lifetime.d
libphobos/libdruntime/core/memory.d
libphobos/libdruntime/core/stdc/stdlib.d
libphobos/libdruntime/core/stdc/string.d
libphobos/libdruntime/core/stdc/wchar_.d
libphobos/libdruntime/core/stdcpp/exception.d
libphobos/libdruntime/core/sync/mutex.d
libphobos/libdruntime/core/sys/bionic/string.d
libphobos/libdruntime/core/sys/darwin/mach/nlist.d
libphobos/libdruntime/core/sys/darwin/string.d
libphobos/libdruntime/core/sys/dragonflybsd/string.d
libphobos/libdruntime/core/sys/freebsd/string.d
libphobos/libdruntime/core/sys/linux/string.d
libphobos/libdruntime/core/sys/linux/syscalls.d [deleted file]
libphobos/libdruntime/core/sys/linux/unistd.d
libphobos/libdruntime/core/sys/netbsd/string.d
libphobos/libdruntime/core/sys/openbsd/string.d
libphobos/libdruntime/core/sys/posix/signal.d
libphobos/libdruntime/core/sys/posix/string.d
libphobos/libdruntime/core/sys/posix/sys/socket.d
libphobos/libdruntime/core/sys/solaris/sys/elf.d
libphobos/libdruntime/core/sys/solaris/sys/elf_386.d
libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d
libphobos/libdruntime/core/sys/windows/dbghelp.d
libphobos/libdruntime/core/thread/osthread.d
libphobos/libdruntime/core/thread/threadbase.d
libphobos/libdruntime/object.d
libphobos/libdruntime/rt/aaA.d
libphobos/libdruntime/rt/cast_.d
libphobos/libdruntime/rt/config.d
libphobos/libdruntime/rt/lifetime.d
libphobos/libdruntime/rt/monitor_.d
libphobos/src/MERGE
libphobos/src/std/algorithm/iteration.d
libphobos/src/std/algorithm/mutation.d
libphobos/src/std/algorithm/sorting.d
libphobos/src/std/concurrency.d
libphobos/src/std/container/dlist.d
libphobos/src/std/container/rbtree.d
libphobos/src/std/datetime/interval.d
libphobos/src/std/datetime/systime.d
libphobos/src/std/datetime/timezone.d
libphobos/src/std/file.d
libphobos/src/std/internal/cstring.d
libphobos/src/std/internal/math/biguintcore.d
libphobos/src/std/json.d
libphobos/src/std/net/isemail.d
libphobos/src/std/process.d
libphobos/src/std/random.d
libphobos/src/std/stdio.d
libphobos/src/std/typecons.d
libphobos/src/std/uni/package.d
libphobos/src/std/utf.d
libphobos/testsuite/libphobos.config/config.exp
libphobos/testsuite/libphobos.config/test22523.d [new file with mode: 0644]

index d7f714760f7aafd4f43a9e0936da85e256ef0ac1..00169a743a1b881843c2d3b52e47084ad8b85b56 100644 (file)
@@ -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 \
index 04b9791ab1bfb55ae7594dc2cd6ef6b1eb98e0ad..5c9f569d1c4c60c46b4d1e3e86eaa32665900a0a 100644 (file)
@@ -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());
index c082ac5ab80fd73da87ff3d468a5ac178e6cc000..39c3c6ce987b864193fa5abac2b4afcb904899d0 100644 (file)
@@ -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)),
index 3df40073ac5470d041ab9e408cf0a50a6e976f36..c1e78c0a5debcc5fd7351b0d5ae483c70906a59c 100644 (file)
@@ -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;
     }
index 576eefcc01f21ae2cbbe99d4795cb87cc442aa2d..2c5d206a95fa69193f320ab8055d86d4fe8a0cf7 100644 (file)
@@ -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;
index 58b3fe138b2bf5d3e0c013075de86963c4f285e0..4e867a7db4a53979819e993b0af14edd0167cb8b 100644 (file)
@@ -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:
index 21417dddf78139908e85d46575dceb1bd41e3156..dd244f1211981a5b8bd0251b4126aa3d1b9210a2 100644 (file)
@@ -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;
 
index c69f5664e8cf0bdef5ac5e99da430e3b9df5c0be..bbde4a669e45b0d00995601e1f9bbd50d57d2f37 100644 (file)
@@ -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 ());
 }
index d23e1fedba4821db9501d045e8d2af869ac6dc6b..4bae16c86eb97fa0c54286ff20c7371abfbb8c6e 100644 (file)
@@ -1,4 +1,4 @@
-568496d5b6ed02d577dfa86f73c7bb4edee05813
+3982604c54e8770585985a33577fbf19b9b5c9ce
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
index 944c9d3e124521da4538b1ce061c0dab0243f0ad..d8a65179a9e3fc550358b107a0ce3dfa572b0522 100644 (file)
@@ -201,7 +201,7 @@ bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
     {
         // Do access check
         ClassDeclaration cd = tc.sym;
-        if (e.op == TOK.super_)
+        if (e.op == EXP.super_)
         {
             if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration())
                 cd = cd2;
index 1fe8e809aa552d36d12eca6751d7919574ddaaf2..dc772e8eeac6d6c58a5c351ced6cd9963936019c 100644 (file)
@@ -472,7 +472,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         }
         foreach (e; *elements)
         {
-            if (e && e.op == TOK.error)
+            if (e && e.op == EXP.error)
                 return false;
         }
 
@@ -565,6 +565,18 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
 
     override final Type getType()
     {
+        /* Apply storage classes to forward references. (Issue 22254)
+         * Note: Avoid interfaces for now. Implementing qualifiers on interface
+         * definitions exposed some issues in their TypeInfo generation in DMD.
+         * Related PR: https://github.com/dlang/dmd/pull/13312
+         */
+        if (semanticRun == PASS.init && !isInterfaceDeclaration())
+        {
+            auto stc = storage_class;
+            if (_scope)
+                stc |= _scope.stc;
+            type = type.addSTC(stc);
+        }
         return type;
     }
 
index e048cdc2e1b4a2896547585b993185b36d47054c..80db47ded1d9eda77c89dad1f5d4188ed499399e 100644 (file)
@@ -91,7 +91,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
         if (ad.aliasthis)
         {
             Loc loc = e.loc;
-            Type tthis = (e.op == TOK.type ? e.type : null);
+            Type tthis = (e.op == EXP.type ? e.type : null);
             const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0);
             uint olderrors = gag ? global.startGagging() : 0;
             e = dotExp(e.type, sc, e, ad.aliasthis.ident, flags);
@@ -100,7 +100,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
 
             if (tthis && ad.aliasthis.sym.needThis())
             {
-                if (e.op == TOK.variable)
+                if (e.op == EXP.variable)
                 {
                     if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
                     {
index e2b33194f060417a891e3fbe222f57382ff91208..a234501075ceb6a41d58c694ece1f3d3666207ed 100644 (file)
@@ -23,6 +23,7 @@ import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
+import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
@@ -37,9 +38,9 @@ import dmd.visitor;
 bool isArrayOpValid(Expression e)
 {
     //printf("isArrayOpValid() %s\n", e.toChars());
-    if (e.op == TOK.slice)
+    if (e.op == EXP.slice)
         return true;
-    if (e.op == TOK.arrayLiteral)
+    if (e.op == EXP.arrayLiteral)
     {
         Type t = e.type.toBasetype();
         while (t.ty == Tarray || t.ty == Tsarray)
@@ -53,17 +54,17 @@ bool isArrayOpValid(Expression e)
         {
             return isArrayOpValid((cast(UnaExp)e).e1);
         }
-        if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign)
+        if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign)
         {
             BinExp be = cast(BinExp)e;
             return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
         }
-        if (e.op == TOK.construct)
+        if (e.op == EXP.construct)
         {
             BinExp be = cast(BinExp)e;
-            return be.e1.op == TOK.slice && isArrayOpValid(be.e2);
+            return be.e1.op == EXP.slice && isArrayOpValid(be.e2);
         }
-        // if (e.op == TOK.call)
+        // if (e.op == EXP.call)
         // {
         // TODO: Decide if [] is required after arrayop calls.
         // }
@@ -74,7 +75,7 @@ bool isArrayOpValid(Expression e)
 
 bool isNonAssignmentArrayOp(Expression e)
 {
-    if (e.op == TOK.slice)
+    if (e.op == EXP.slice)
         return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
 
     Type tb = e.type.toBasetype();
@@ -166,11 +167,11 @@ Expression arrayOp(BinAssignExp e, Scope* sc)
     if (tn && (!tn.isMutable() || !tn.isAssignable()))
     {
         e.error("slice `%s` is not mutable", e.e1.toChars());
-        if (e.op == TOK.addAssign)
+        if (e.op == EXP.addAssign)
             checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp);
         return ErrorExp.get();
     }
-    if (e.e1.op == TOK.arrayLiteral)
+    if (e.e1.op == EXP.arrayLiteral)
     {
         return e.e1.modifiableLvalue(sc, e.e1);
     }
@@ -228,7 +229,7 @@ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions*
                 // RPN, prefix unary ops with u
                 OutBuffer buf;
                 buf.writestring("u");
-                buf.writestring(Token.toString(e.op));
+                buf.writestring(EXPtoString(e.op));
                 e.e1.accept(this);
                 tiargs.push(new StringExp(Loc.initial, buf.extractSlice()).expressionSemantic(sc));
             }
@@ -246,7 +247,7 @@ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions*
                 // RPN
                 e.e1.accept(this);
                 e.e2.accept(this);
-                tiargs.push(new StringExp(Loc.initial, Token.toString(e.op)).expressionSemantic(sc));
+                tiargs.push(new StringExp(Loc.initial, EXPtoString(e.op)).expressionSemantic(sc));
             }
         }
     }
@@ -274,12 +275,12 @@ bool isArrayOpImplicitCast(TypeDArray tfrom, TypeDArray tto)
 /***********************************************
  * Test if expression is a unary array op.
  */
-bool isUnaArrayOp(TOK op)
+bool isUnaArrayOp(EXP op)
 {
     switch (op)
     {
-    case TOK.negate:
-    case TOK.tilde:
+    case EXP.negate:
+    case EXP.tilde:
         return true;
     default:
         break;
@@ -290,19 +291,19 @@ bool isUnaArrayOp(TOK op)
 /***********************************************
  * Test if expression is a binary array op.
  */
-bool isBinArrayOp(TOK op)
+bool isBinArrayOp(EXP op)
 {
     switch (op)
     {
-    case TOK.add:
-    case TOK.min:
-    case TOK.mul:
-    case TOK.div:
-    case TOK.mod:
-    case TOK.xor:
-    case TOK.and:
-    case TOK.or:
-    case TOK.pow:
+    case EXP.add:
+    case EXP.min:
+    case EXP.mul:
+    case EXP.div:
+    case EXP.mod:
+    case EXP.xor:
+    case EXP.and:
+    case EXP.or:
+    case EXP.pow:
         return true;
     default:
         break;
@@ -313,19 +314,19 @@ bool isBinArrayOp(TOK op)
 /***********************************************
  * Test if expression is a binary assignment array op.
  */
-bool isBinAssignArrayOp(TOK op)
+bool isBinAssignArrayOp(EXP op)
 {
     switch (op)
     {
-    case TOK.addAssign:
-    case TOK.minAssign:
-    case TOK.mulAssign:
-    case TOK.divAssign:
-    case TOK.modAssign:
-    case TOK.xorAssign:
-    case TOK.andAssign:
-    case TOK.orAssign:
-    case TOK.powAssign:
+    case EXP.addAssign:
+    case EXP.minAssign:
+    case EXP.mulAssign:
+    case EXP.divAssign:
+    case EXP.modAssign:
+    case EXP.xorAssign:
+    case EXP.andAssign:
+    case EXP.orAssign:
+    case EXP.powAssign:
         return true;
     default:
         break;
@@ -339,9 +340,9 @@ bool isBinAssignArrayOp(TOK op)
 bool isArrayOpOperand(Expression e)
 {
     //printf("Expression.isArrayOpOperand() %s\n", e.toChars());
-    if (e.op == TOK.slice)
+    if (e.op == EXP.slice)
         return true;
-    if (e.op == TOK.arrayLiteral)
+    if (e.op == EXP.arrayLiteral)
     {
         Type t = e.type.toBasetype();
         while (t.ty == Tarray || t.ty == Tsarray)
@@ -354,7 +355,7 @@ bool isArrayOpOperand(Expression e)
         return (isUnaArrayOp(e.op) ||
                 isBinArrayOp(e.op) ||
                 isBinAssignArrayOp(e.op) ||
-                e.op == TOK.assign);
+                e.op == EXP.assign);
     }
     return false;
 }
@@ -371,9 +372,9 @@ bool isArrayOpOperand(Expression e)
 ErrorExp arrayOpInvalidError(Expression e)
 {
     e.error("invalid array operation `%s` (possible missing [])", e.toChars());
-    if (e.op == TOK.add)
+    if (e.op == EXP.add)
         checkPossibleAddCatError!(AddExp, CatExp)(e.isAddExp());
-    else if (e.op == TOK.addAssign)
+    else if (e.op == EXP.addAssign)
         checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp());
     return ErrorExp.get();
 }
index df88bb97bdf7836cdab6017f15e7a80a1c2c2552..f6387651e5f0842be7ec53ba61c33655b5ca39b4 100644 (file)
@@ -62,7 +62,7 @@ enum STC : ulong  // transfer changes to declaration.h
     foreach_            = 0x4000,   /// variable for foreach loop
     variadic            = 0x8000,   /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
 
-    ctorinit            = 0x1_0000,   /// can only be set inside constructor
+    //                  = 0x1_0000,
     templateparameter   = 0x2_0000,   /// template parameter
     ref_                = 0x4_0000,   /// `ref`
     scope_              = 0x8_0000,   /// `scope`
@@ -74,7 +74,7 @@ enum STC : ulong  // transfer changes to declaration.h
 
     returninferred      = 0x100_0000,   /// `return` has been inferred and should not be part of mangling, `return_` must also be set
     immutable_          = 0x200_0000,   /// `immutable`
-    init                = 0x400_0000,   /// has explicit initializer
+    //                  = 0x400_0000,
     manifest            = 0x800_0000,   /// manifest constant
 
     nodtor              = 0x1000_0000,   /// do not run destructor
index 0bf40ef9a728d4cce3518269c3f58c49930a5ebc..e8704aabf73098c9fe3e326f0e5973d7dd1f1734 100644 (file)
@@ -929,12 +929,13 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
             (*args)[0] = e;
         }
 
-        if (e.isBool(true))
+        const opt = e.toBool();
+        if (opt.isEmpty())
+            return PINLINE.default_;
+        else if (opt.get())
             return PINLINE.always;
-        else if (e.isBool(false))
-            return PINLINE.never;
         else
-            return PINLINE.default_;
+            return PINLINE.never;
     }
 
     override const(char)* kind() const
@@ -1198,7 +1199,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
 
         // expand static foreach
         import dmd.statementsem: makeTupleForeach;
-        Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion).decl;
+        Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
         if (d) // process generated declarations
         {
             // Add members lazily.
index 0ecd6351f7d6181aed48000c9d226c5ac2461024..5945644482a281ecefbfb69ab644963ba7d08fb8 100644 (file)
@@ -94,15 +94,15 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
             result = BE.fallthru;
             if (s.exp)
             {
-                if (s.exp.op == TOK.halt)
+                if (s.exp.op == EXP.halt)
                 {
                     result = BE.halt;
                     return;
                 }
-                if (s.exp.op == TOK.assert_)
+                if (s.exp.op == EXP.assert_)
                 {
                     AssertExp a = cast(AssertExp)s.exp;
-                    if (a.e1.isBool(false)) // if it's an assert(0)
+                    if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
                     {
                         result = BE.halt;
                         return;
@@ -216,7 +216,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
             {
                 if (canThrow(s.condition, func, mustNotThrow))
                     result |= BE.throw_;
-                if (!(result & BE.break_) && s.condition.isBool(true))
+                if (!(result & BE.break_) && s.condition.toBool().hasValue(true))
                     result &= ~BE.fallthru;
             }
             result &= ~(BE.break_ | BE.continue_);
@@ -235,9 +235,10 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
             {
                 if (canThrow(s.condition, func, mustNotThrow))
                     result |= BE.throw_;
-                if (s.condition.isBool(true))
+                const opt = s.condition.toBool();
+                if (opt.hasValue(true))
                     result &= ~BE.fallthru;
-                else if (s.condition.isBool(false))
+                else if (opt.hasValue(false))
                     return;
             }
             else
@@ -274,11 +275,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
             result = BE.none;
             if (canThrow(s.condition, func, mustNotThrow))
                 result |= BE.throw_;
-            if (s.condition.isBool(true))
+
+            const opt = s.condition.toBool();
+            if (opt.hasValue(true))
             {
                 result |= blockExit(s.ifbody, func, mustNotThrow);
             }
-            else if (s.condition.isBool(false))
+            else if (opt.hasValue(false))
             {
                 result |= blockExit(s.elsebody, func, mustNotThrow);
             }
@@ -534,4 +537,3 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
     s.accept(be);
     return be.result;
 }
-
index c4f84b129686ed0e2b81f24d9cc699beeba6d099..2f5b6c734a68c778fda721e26d273b3dcaa9deeb 100644 (file)
@@ -13,8 +13,6 @@
 
 module dmd.builtin;
 
-import core.stdc.math;
-import core.stdc.string;
 import dmd.arraytypes;
 import dmd.expression;
 import dmd.func;
index ed05af6ac7cb31c6c66878e30134772da6872e0e..b67a9d14dd4c6855bfab8d095a326bf31d8b1799 100644 (file)
@@ -150,7 +150,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
         override void visit(AssignExp ae)
         {
             // blit-init cannot throw
-            if (ae.op == TOK.blit)
+            if (ae.op == EXP.blit)
                 return;
             /* Element-wise assignment could invoke postblits.
              */
index da66812b954843c622d4053f9879015a490101bb..c536d25f0a3b79319055bc70f4a95e1306598d14 100644 (file)
@@ -578,7 +578,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
     fop.generated = true;
     Expression e1 = new IdentifierExp(loc, Id.p);
     Expression e2 = new IdentifierExp(loc, Id.q);
-    Expression e = new EqualExp(TOK.equal, loc, e1, e2);
+    Expression e = new EqualExp(EXP.equal, loc, e1, e2);
     fop.fbody = new ReturnStatement(loc, e);
     uint errors = global.startGagging(); // Do not report errors
     Scope* sc2 = sc.push();
@@ -642,13 +642,13 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
                 Dsymbol s = null;
                 switch (e.op)
                 {
-                case TOK.overloadSet:
+                case EXP.overloadSet:
                     s = (cast(OverExp)e).vars;
                     break;
-                case TOK.scope_:
+                case EXP.scope_:
                     s = (cast(ScopeExp)e).sds;
                     break;
-                case TOK.variable:
+                case EXP.variable:
                     s = (cast(VarExp)e).var;
                     break;
                 default:
index a5e3f9c541d7d60a0dbab0583060ea5b346b309c..ce23436d782f0a29a2c33815b4ed2690c03661d0 100644 (file)
@@ -49,7 +49,7 @@ public:
     void reserve(d_size_t nbytes);
     void setsize(d_size_t size);
     void reset();
-    void write(const void *data, size_t nbytes);
+    void write(const void *data, d_size_t nbytes);
     void writestring(const char *string);
     void prependstring(const char *string);
     void writenl();                     // write newline
index 05bd4bd550d1c69ab70d6a75e99d29fa2cbaaba0..abf28144c41baa8c8e70f724c8d71f31e058a3f6 100644 (file)
@@ -152,7 +152,7 @@ extern (C++) final class StaticForeach : RootObject
         sc = sc.endCTFE();
         el = el.optimize(WANTvalue);
         el = el.ctfeInterpret();
-        if (el.op == TOK.int64)
+        if (el.op == EXP.int64)
         {
             Expressions *es = void;
             if (auto ale = aggr.isArrayLiteralExp())
index 1dada60de3b4a4f754e59ed7196d04c0d43b03b8..3ca23f24d7e5ffa1dd74b6e6e0a6c750e3a09b03 100644 (file)
@@ -56,13 +56,13 @@ int isConst(Expression e)
     //printf("Expression::isConst(): %s\n", e.toChars());
     switch (e.op)
     {
-    case TOK.int64:
-    case TOK.float64:
-    case TOK.complex80:
+    case EXP.int64:
+    case EXP.float64:
+    case EXP.complex80:
         return 1;
-    case TOK.null_:
+    case EXP.null_:
         return 0;
-    case TOK.symbolOffset:
+    case EXP.symbolOffset:
         return 2;
     default:
         return 0;
@@ -71,13 +71,13 @@ int isConst(Expression e)
 }
 
 /**********************************
- * Initialize a TOK.cantExpression Expression.
+ * Initialize a EXP.cantExpression Expression.
  * Params:
  *      ue = where to write it
  */
 void cantExp(out UnionExp ue)
 {
-    emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+    emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
 }
 
 /* =============================== constFold() ============================== */
@@ -120,7 +120,7 @@ UnionExp Not(Type type, Expression e1)
 {
     UnionExp ue = void;
     Loc loc = e1.loc;
-    emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type);
+    emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
     return ue;
 }
 
@@ -128,7 +128,7 @@ private UnionExp Bool(Type type, Expression e1)
 {
     UnionExp ue = void;
     Loc loc = e1.loc;
-    emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type);
+    emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(true) ? 1 : 0, type);
     return ue;
 }
 
@@ -222,13 +222,13 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
         }
         emplaceExp!(ComplexExp)(&ue, loc, v, type);
     }
-    else if (e1.op == TOK.symbolOffset)
+    else if (e1.op == EXP.symbolOffset)
     {
         SymOffExp soe = cast(SymOffExp)e1;
         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
         ue.exp().type = type;
     }
-    else if (e2.op == TOK.symbolOffset)
+    else if (e2.op == EXP.symbolOffset)
     {
         SymOffExp soe = cast(SymOffExp)e2;
         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
@@ -325,7 +325,7 @@ UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
         }
         emplaceExp!(ComplexExp)(&ue, loc, v, type);
     }
-    else if (e1.op == TOK.symbolOffset)
+    else if (e1.op == EXP.symbolOffset)
     {
         SymOffExp soe = cast(SymOffExp)e1;
         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
@@ -722,26 +722,26 @@ UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
     return ue;
 }
 
-/* Also returns TOK.cantExpression if cannot be computed.
+/* Also returns EXP.cantExpression if cannot be computed.
  */
-UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
 {
     UnionExp ue = void;
     int cmp = 0;
     real_t r1 = CTFloat.zero;
     real_t r2 = CTFloat.zero;
     //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
-    assert(op == TOK.equal || op == TOK.notEqual);
-    if (e1.op == TOK.null_)
+    assert(op == EXP.equal || op == EXP.notEqual);
+    if (e1.op == EXP.null_)
     {
-        if (e2.op == TOK.null_)
+        if (e2.op == EXP.null_)
             cmp = 1;
-        else if (e2.op == TOK.string_)
+        else if (e2.op == EXP.string_)
         {
             StringExp es2 = cast(StringExp)e2;
             cmp = (0 == es2.len);
         }
-        else if (e2.op == TOK.arrayLiteral)
+        else if (e2.op == EXP.arrayLiteral)
         {
             ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
             cmp = !es2.elements || (0 == es2.elements.dim);
@@ -752,14 +752,14 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
             return ue;
         }
     }
-    else if (e2.op == TOK.null_)
+    else if (e2.op == EXP.null_)
     {
-        if (e1.op == TOK.string_)
+        if (e1.op == EXP.string_)
         {
             StringExp es1 = cast(StringExp)e1;
             cmp = (0 == es1.len);
         }
-        else if (e1.op == TOK.arrayLiteral)
+        else if (e1.op == EXP.arrayLiteral)
         {
             ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
             cmp = !es1.elements || (0 == es1.elements.dim);
@@ -770,7 +770,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
             return ue;
         }
     }
-    else if (e1.op == TOK.string_ && e2.op == TOK.string_)
+    else if (e1.op == EXP.string_ && e2.op == EXP.string_)
     {
         StringExp es1 = cast(StringExp)e1;
         StringExp es2 = cast(StringExp)e2;
@@ -787,7 +787,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
         else
             cmp = 0;
     }
-    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral)
+    else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
     {
         ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
         ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
@@ -803,7 +803,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
             {
                 auto ee1 = es1[i];
                 auto ee2 = es2[i];
-                ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
+                ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
                 if (CTFEExp.isCantExp(ue.exp()))
                     return ue;
                 cmp = cast(int)ue.exp().toInteger();
@@ -812,7 +812,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
             }
         }
     }
-    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.string_)
+    else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_)
     {
         // Swap operands and use common code
         Expression etmp = e1;
@@ -820,7 +820,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
         e2 = etmp;
         goto Lsa;
     }
-    else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral)
+    else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
     {
     Lsa:
         StringExp es1 = cast(StringExp)e1;
@@ -847,7 +847,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
             }
         }
     }
-    else if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
+    else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
     {
         StructLiteralExp es1 = cast(StructLiteralExp)e1;
         StructLiteralExp es2 = cast(StructLiteralExp)e2;
@@ -873,8 +873,8 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
                     cmp = 0;
                     break;
                 }
-                ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
-                if (ue.exp().op == TOK.cantExpression)
+                ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
+                if (ue.exp().op == EXP.cantExpression)
                     return ue;
                 cmp = cast(int)ue.exp().toInteger();
                 if (cmp == 0)
@@ -920,25 +920,25 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e
         cantExp(ue);
         return ue;
     }
-    if (op == TOK.notEqual)
+    if (op == EXP.notEqual)
         cmp ^= 1;
     emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
     return ue;
 }
 
-UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
 {
     UnionExp ue = void;
     int cmp;
-    if (e1.op == TOK.null_)
+    if (e1.op == EXP.null_)
     {
-        cmp = (e2.op == TOK.null_);
+        cmp = (e2.op == EXP.null_);
     }
-    else if (e2.op == TOK.null_)
+    else if (e2.op == EXP.null_)
     {
         cmp = 0;
     }
-    else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
+    else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
     {
         SymOffExp es1 = cast(SymOffExp)e1;
         SymOffExp es2 = cast(SymOffExp)e2;
@@ -962,24 +962,24 @@ UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expressio
         }
         else
         {
-            ue = Equal((op == TOK.identity) ? TOK.equal : TOK.notEqual, loc, type, e1, e2);
+            ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
             return ue;
         }
     }
-    if (op == TOK.notIdentity)
+    if (op == EXP.notIdentity)
         cmp ^= 1;
     emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
     return ue;
 }
 
-UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
 {
     UnionExp ue = void;
     dinteger_t n;
     real_t r1 = CTFloat.zero;
     real_t r2 = CTFloat.zero;
     //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
-    if (e1.op == TOK.string_ && e2.op == TOK.string_)
+    if (e1.op == EXP.string_ && e2.op == EXP.string_)
     {
         StringExp es1 = cast(StringExp)e1;
         StringExp es2 = cast(StringExp)e2;
@@ -1032,7 +1032,7 @@ UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
     return ue;
 }
 
-/* Also returns TOK.cantExpression if cannot be computed.
+/* Also returns EXP.cantExpression if cannot be computed.
  *  to: type to cast to
  *  type: type to paint the result
  */
@@ -1048,7 +1048,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
         emplaceExp!(UnionExp)(&ue, e1);
         return ue;
     }
-    if (e1.op == TOK.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
+    if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
     {
         Expression ex = (cast(VectorExp)e1).e1;
         emplaceExp!(UnionExp)(&ue, ex);
@@ -1067,14 +1067,14 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
     }
     /* Allow casting from one string type to another
      */
-    if (e1.op == TOK.string_)
+    if (e1.op == EXP.string_)
     {
         if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
         {
             goto L1;
         }
     }
-    if (e1.op == TOK.arrayLiteral && typeb == tb)
+    if (e1.op == EXP.arrayLiteral && typeb == tb)
     {
     L1:
         Expression ex = expType(to, e1);
@@ -1157,7 +1157,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
     {
         cantExp(ue);
     }
-    else if (tb.ty == Tstruct && e1.op == TOK.int64)
+    else if (tb.ty == Tstruct && e1.op == EXP.int64)
     {
         // Struct = 0;
         StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
@@ -1169,7 +1169,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
             UnionExp zero;
             emplaceExp!(IntegerExp)(&zero, 0);
             ue = Cast(loc, v.type, v.type, zero.exp());
-            if (ue.exp().op == TOK.cantExpression)
+            if (ue.exp().op == EXP.cantExpression)
                 return ue;
             elements.push(ue.exp().copy());
         }
@@ -1193,18 +1193,18 @@ UnionExp ArrayLength(Type type, Expression e1)
 {
     UnionExp ue = void;
     Loc loc = e1.loc;
-    if (e1.op == TOK.string_)
+    if (e1.op == EXP.string_)
     {
         StringExp es1 = cast(StringExp)e1;
         emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
     }
-    else if (e1.op == TOK.arrayLiteral)
+    else if (e1.op == EXP.arrayLiteral)
     {
         ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
         size_t dim = ale.elements ? ale.elements.dim : 0;
         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
     }
-    else if (e1.op == TOK.assocArrayLiteral)
+    else if (e1.op == EXP.assocArrayLiteral)
     {
         AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
         size_t dim = ale.keys.dim;
@@ -1220,7 +1220,7 @@ UnionExp ArrayLength(Type type, Expression e1)
     return ue;
 }
 
-/* Also return TOK.cantExpression if this fails
+/* Also return EXP.cantExpression if this fails
  */
 UnionExp Index(Type type, Expression e1, Expression e2)
 {
@@ -1228,7 +1228,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
     Loc loc = e1.loc;
     //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
     assert(e1.type);
-    if (e1.op == TOK.string_ && e2.op == TOK.int64)
+    if (e1.op == EXP.string_ && e2.op == EXP.int64)
     {
         StringExp es1 = cast(StringExp)e1;
         uinteger_t i = e2.toInteger();
@@ -1242,7 +1242,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
             emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
         }
     }
-    else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOK.int64)
+    else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
     {
         TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
         uinteger_t length = tsa.dim.toInteger();
@@ -1252,7 +1252,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
             e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
             emplaceExp!(ErrorExp)(&ue);
         }
-        else if (e1.op == TOK.arrayLiteral)
+        else if (e1.op == EXP.arrayLiteral)
         {
             ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
             auto e = ale[cast(size_t)i];
@@ -1266,10 +1266,10 @@ UnionExp Index(Type type, Expression e1, Expression e2)
         else
             cantExp(ue);
     }
-    else if (e1.type.toBasetype().ty == Tarray && e2.op == TOK.int64)
+    else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
     {
         uinteger_t i = e2.toInteger();
-        if (e1.op == TOK.arrayLiteral)
+        if (e1.op == EXP.arrayLiteral)
         {
             ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
             if (i >= ale.elements.dim)
@@ -1291,7 +1291,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
         else
             cantExp(ue);
     }
-    else if (e1.op == TOK.assocArrayLiteral)
+    else if (e1.op == EXP.assocArrayLiteral)
     {
         AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
         /* Search the keys backwards, in case there are duplicate keys
@@ -1300,10 +1300,10 @@ UnionExp Index(Type type, Expression e1, Expression e2)
         {
             i--;
             Expression ekey = (*ae.keys)[i];
-            ue = Equal(TOK.equal, loc, Type.tbool, ekey, e2);
+            ue = Equal(EXP.equal, loc, Type.tbool, ekey, e2);
             if (CTFEExp.isCantExp(ue.exp()))
                 return ue;
-            if (ue.exp().isBool(true))
+            if (ue.exp().toBool().hasValue(true))
             {
                 Expression e = (*ae.values)[i];
                 e.type = type;
@@ -1322,7 +1322,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
     return ue;
 }
 
-/* Also return TOK.cantExpression if this fails
+/* Also return EXP.cantExpression if this fails
  */
 UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
 {
@@ -1347,7 +1347,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
                  newupr <= upr);
     }
 
-    if (e1.op == TOK.string_ && lwr.op == TOK.int64 && upr.op == TOK.int64)
+    if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
     {
         StringExp es1 = cast(StringExp)e1;
         const uinteger_t ilwr = lwr.toInteger();
@@ -1367,7 +1367,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
             es.type = type;
         }
     }
-    else if (e1.op == TOK.arrayLiteral && lwr.op == TOK.int64 && upr.op == TOK.int64 && !hasSideEffect(e1))
+    else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
     {
         ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
         const uinteger_t ilwr = lwr.toInteger();
@@ -1480,14 +1480,14 @@ private Expressions* copyElements(Expression e1, Expression e2 = null)
         }
     }
 
-    if (e1.op == TOK.arrayLiteral)
+    if (e1.op == EXP.arrayLiteral)
         append(cast(ArrayLiteralExp)e1);
     else
         elems.push(e1);
 
     if (e2)
     {
-        if (e2.op == TOK.arrayLiteral)
+        if (e2.op == EXP.arrayLiteral)
             append(cast(ArrayLiteralExp)e2);
         else
             elems.push(e2);
@@ -1496,7 +1496,7 @@ private Expressions* copyElements(Expression e1, Expression e2 = null)
     return elems;
 }
 
-/* Also return TOK.cantExpression if this fails
+/* Also return EXP.cantExpression if this fails
  */
 UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
 {
@@ -1507,13 +1507,13 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
     Type t2 = e2.type.toBasetype();
     //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
     //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
-    if (e1.op == TOK.null_ && (e2.op == TOK.int64 || e2.op == TOK.structLiteral))
+    if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
     {
         e = e2;
         t = t1;
         goto L2;
     }
-    else if ((e1.op == TOK.int64 || e1.op == TOK.structLiteral) && e2.op == TOK.null_)
+    else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
     {
         e = e1;
         t = t2;
@@ -1547,7 +1547,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.null_ && e2.op == TOK.null_)
+    else if (e1.op == EXP.null_ && e2.op == EXP.null_)
     {
         if (type == e1.type)
         {
@@ -1575,7 +1575,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.string_ && e2.op == TOK.string_)
+    else if (e1.op == EXP.string_ && e2.op == EXP.string_)
     {
         // Concatenate the strings
         StringExp es1 = cast(StringExp)e1;
@@ -1604,7 +1604,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
+    else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
     {
         // [chars] ~ string --> [chars]
         StringExp es = cast(StringExp)e2;
@@ -1621,7 +1621,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
+    else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
     {
         // string ~ [chars] --> [chars]
         StringExp es = cast(StringExp)e1;
@@ -1638,7 +1638,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.string_ && e2.op == TOK.int64)
+    else if (e1.op == EXP.string_ && e2.op == EXP.int64)
     {
         // string ~ char --> string
         StringExp es1 = cast(StringExp)e1;
@@ -1663,7 +1663,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.int64 && e2.op == TOK.string_)
+    else if (e1.op == EXP.int64 && e2.op == EXP.string_)
     {
         // [w|d]?char ~ string --> string
         // We assume that we only ever prepend one char of the same type
@@ -1684,7 +1684,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+    else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
     {
         // Concatenate the arrays
         auto elems = copyElements(e1, e2);
@@ -1701,12 +1701,12 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
+    else if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
     {
         e = e1;
         goto L3;
     }
-    else if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+    else if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
     {
         e = e2;
     L3:
@@ -1725,9 +1725,9 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if ((e1.op == TOK.arrayLiteral || e1.op == TOK.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
+    else if ((e1.op == EXP.arrayLiteral || e1.op == EXP.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
     {
-        auto elems = (e1.op == TOK.arrayLiteral)
+        auto elems = (e1.op == EXP.arrayLiteral)
                 ? copyElements(e1) : new Expressions();
         elems.push(e2);
 
@@ -1743,7 +1743,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e2.op == TOK.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
+    else if (e2.op == EXP.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
     {
         auto elems = copyElements(e1, e2);
 
@@ -1759,13 +1759,13 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         assert(ue.exp().type);
         return ue;
     }
-    else if (e1.op == TOK.null_ && e2.op == TOK.string_)
+    else if (e1.op == EXP.null_ && e2.op == EXP.string_)
     {
         t = e1.type;
         e = e2;
         goto L1;
     }
-    else if (e1.op == TOK.string_ && e2.op == TOK.null_)
+    else if (e1.op == EXP.string_ && e2.op == EXP.null_)
     {
         e = e1;
         t = e2.type;
@@ -1801,13 +1801,13 @@ UnionExp Ptr(Type type, Expression e1)
 {
     //printf("Ptr(e1 = %s)\n", e1.toChars());
     UnionExp ue = void;
-    if (e1.op == TOK.add)
+    if (e1.op == EXP.add)
     {
         AddExp ae = cast(AddExp)e1;
-        if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
+        if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
         {
             AddrExp ade = cast(AddrExp)ae.e1;
-            if (ade.e1.op == TOK.structLiteral)
+            if (ade.e1.op == EXP.structLiteral)
             {
                 StructLiteralExp se = cast(StructLiteralExp)ade.e1;
                 uint offset = cast(uint)ae.e2.toInteger();
index 7d8ab67ee6acd9061e638ee9336dec73e3225a0c..dfc45e0bc31ee76822783ab80b93e46ed7ec4f97 100644 (file)
@@ -212,7 +212,7 @@ final class CParser(AST) : Parser!AST
         case TOK.sizeof_:
         Lexp:
             auto exp = cparseExpression();
-            if (token.value == TOK.identifier && exp.op == TOK.identifier)
+            if (token.value == TOK.identifier && exp.op == EXP.identifier)
             {
                 error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
                 nextToken();
@@ -781,11 +781,11 @@ final class CParser(AST) : Parser!AST
                 break;
 
             case TOK.plusPlus:
-                e = new AST.PostExp(TOK.plusPlus, loc, e);
+                e = new AST.PostExp(EXP.plusPlus, loc, e);
                 break;
 
             case TOK.minusMinus:
-                e = new AST.PostExp(TOK.minusMinus, loc, e);
+                e = new AST.PostExp(EXP.minusMinus, loc, e);
                 break;
 
             case TOK.leftParenthesis:
@@ -841,14 +841,14 @@ final class CParser(AST) : Parser!AST
             // Parse `++` as an unary operator so that cast expressions only give
             // an error for being non-lvalues.
             e = cparseCastExp();
-            e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+            e = new AST.PreExp(EXP.prePlusPlus, loc, e);
             break;
 
         case TOK.minusMinus:
             nextToken();
             // Parse `--` as an unary operator, same as prefix increment.
             e = cparseCastExp();
-            e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+            e = new AST.PreExp(EXP.preMinusMinus, loc, e);
             break;
 
         case TOK.and:
@@ -1122,14 +1122,15 @@ final class CParser(AST) : Parser!AST
         const loc = token.loc;
 
         auto e = cparseShiftExp();
-        TOK op = token.value;
 
-        switch (op)
+        EXP op = EXP.reserved;
+        switch (token.value)
         {
-        case TOK.lessThan:
-        case TOK.lessOrEqual:
-        case TOK.greaterThan:
-        case TOK.greaterOrEqual:
+        case TOK.lessThan:       op = EXP.lessThan; goto Lcmp;
+        case TOK.lessOrEqual:    op = EXP.lessOrEqual; goto Lcmp;
+        case TOK.greaterThan:    op = EXP.greaterThan; goto Lcmp;
+        case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
+        Lcmp:
             nextToken();
             auto e2 = cparseShiftExp();
             e = new AST.CmpExp(op, loc, e, e2);
@@ -1153,12 +1154,13 @@ final class CParser(AST) : Parser!AST
         const loc = token.loc;
 
         auto e = cparseRelationalExp();
-        const TOK op = token.value;
 
-        switch (op)
+        EXP op = EXP.reserved;
+        switch (token.value)
         {
-        case TOK.equal:
-        case TOK.notEqual:
+        case TOK.equal:         op = EXP.equal;    goto Lequal;
+        case TOK.notEqual:      op = EXP.notEqual; goto Lequal;
+        Lequal:
             nextToken();
             auto e2 = cparseRelationalExp();
             e = new AST.EqualExp(op, loc, e, e2);
@@ -1245,7 +1247,7 @@ final class CParser(AST) : Parser!AST
         {
             nextToken();
             auto e2 = cparseOrExp();
-            e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+            e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
         }
         return e;
     }
@@ -1265,7 +1267,7 @@ final class CParser(AST) : Parser!AST
         {
             nextToken();
             auto e2 = cparseAndAndExp();
-            e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+            e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
         }
         return e;
     }
@@ -1693,7 +1695,11 @@ final class CParser(AST) : Parser!AST
             switch (token.value)
             {
                 case TOK.identifier:
-                    error("missing comma");
+                    if (s)
+                    {
+                        error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars());
+                        goto Lend;
+                    }
                     goto default;
 
                 case TOK.semicolon:
@@ -1707,7 +1713,8 @@ final class CParser(AST) : Parser!AST
                     break;
 
                 default:
-                    error("`=`, `;` or `,` expected");
+                    error("`=`, `;` or `,` expected to end declaration instead of `%s`", token.toChars());
+                Lend:
                     while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
                         nextToken();
                     nextToken();
index df742c0bd8f7f814ccc8585463e0a0a0505ef88f..4ad79da02f296f8b84f0635a5e03f0beba14458f 100644 (file)
@@ -490,7 +490,7 @@ private final class CppMangleVisitor : Visitor
                 mangle_function(d.isFuncDeclaration());
                 buf.writestring("EE");
             }
-            else if (e && e.op == TOK.variable && (cast(VarExp)e).var.isVarDeclaration())
+            else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration())
             {
                 VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration();
                 buf.writeByte('L');
index 7f76d7565e0d0db834b6c208720843017cddab68..9cd09bab643b24a9face25c49d680016cfd7f371 100644 (file)
@@ -46,7 +46,7 @@ extern (C++) final class ClassReferenceExp : Expression
 
     extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type)
     {
-        super(loc, TOK.classReference, __traits(classInstanceSize, ClassReferenceExp));
+        super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp));
         assert(lit && lit.sd && lit.sd.isClassDeclaration());
         this.value = lit;
         this.type = type;
@@ -131,7 +131,7 @@ extern (C++) final class ThrownExceptionExp : Expression
 
     extern (D) this(const ref Loc loc, ClassReferenceExp victim)
     {
-        super(loc, TOK.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
+        super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
         this.thrown = victim;
         this.type = victim.type;
     }
@@ -167,7 +167,7 @@ extern (C++) final class ThrownExceptionExp : Expression
  */
 extern (C++) final class CTFEExp : Expression
 {
-    extern (D) this(TOK tok)
+    extern (D) this(EXP tok)
     {
         super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp));
         type = Type.tvoid;
@@ -177,17 +177,17 @@ extern (C++) final class CTFEExp : Expression
     {
         switch (op)
         {
-        case TOK.cantExpression:
+        case EXP.cantExpression:
             return "<cant>";
-        case TOK.voidExpression:
+        case EXP.voidExpression:
             return "cast(void)0";
-        case TOK.showCtfeContext:
+        case EXP.showCtfeContext:
             return "<error>";
-        case TOK.break_:
+        case EXP.break_:
             return "<break>";
-        case TOK.continue_:
+        case EXP.continue_:
             return "<continue>";
-        case TOK.goto_:
+        case EXP.goto_:
             return "<goto>";
         default:
             assert(0);
@@ -206,19 +206,19 @@ extern (C++) final class CTFEExp : Expression
 
     extern (D) static bool isCantExp(const Expression e)
     {
-        return e && e.op == TOK.cantExpression;
+        return e && e.op == EXP.cantExpression;
     }
 
     extern (D) static bool isGotoExp(const Expression e)
     {
-        return e && e.op == TOK.goto_;
+        return e && e.op == EXP.goto_;
     }
 }
 
 // True if 'e' is CTFEExp::cantexp, or an exception
 bool exceptionOrCantInterpret(const Expression e)
 {
-    return e && (e.op == TOK.cantExpression || e.op == TOK.thrownException || e.op == TOK.showCtfeContext);
+    return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext);
 }
 
 /************** Aggregate literals (AA/string/array/struct) ******************/
@@ -231,29 +231,29 @@ bool needToCopyLiteral(const Expression expr)
     {
         switch (e.op)
         {
-        case TOK.arrayLiteral:
+        case EXP.arrayLiteral:
             return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
-        case TOK.assocArrayLiteral:
+        case EXP.assocArrayLiteral:
             return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
-        case TOK.structLiteral:
+        case EXP.structLiteral:
             return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code;
-        case TOK.string_:
-        case TOK.this_:
-        case TOK.variable:
+        case EXP.string_:
+        case EXP.this_:
+        case EXP.variable:
             return false;
-        case TOK.assign:
+        case EXP.assign:
             return false;
-        case TOK.index:
-        case TOK.dotVariable:
-        case TOK.slice:
-        case TOK.cast_:
+        case EXP.index:
+        case EXP.dotVariable:
+        case EXP.slice:
+        case EXP.cast_:
             e = (cast(UnaExp)e).e1;
             continue;
-        case TOK.concatenate:
+        case EXP.concatenate:
             return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2);
-        case TOK.concatenateAssign:
-        case TOK.concatenateElemAssign:
-        case TOK.concatenateDcharAssign:
+        case EXP.concatenateAssign:
+        case EXP.concatenateElemAssign:
+        case EXP.concatenateDcharAssign:
             e = (cast(BinExp)e).e2;
             continue;
         default:
@@ -358,7 +358,7 @@ UnionExp copyLiteral(Expression e)
         r.origin = sle.origin;
         return ue;
     }
-    if (e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.symbolOffset || e.op == TOK.null_ || e.op == TOK.variable || e.op == TOK.dotVariable || e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.char_ || e.op == TOK.complex80 || e.op == TOK.void_ || e.op == TOK.vector || e.op == TOK.typeid_)
+    if (e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.symbolOffset || e.op == EXP.null_ || e.op == EXP.variable || e.op == EXP.dotVariable || e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.char_ || e.op == EXP.complex80 || e.op == EXP.void_ || e.op == EXP.vector || e.op == EXP.typeid_)
     {
         // Simple value types
         // Keep e1 for DelegateExp and DotVarExp
@@ -372,7 +372,7 @@ UnionExp copyLiteral(Expression e)
         if (se.type.toBasetype().ty == Tsarray)
         {
             // same with resolveSlice()
-            if (se.e1.op == TOK.null_)
+            if (se.e1.op == EXP.null_)
             {
                 emplaceExp!(NullExp)(&ue, se.loc, se.type);
                 return ue;
@@ -415,7 +415,7 @@ UnionExp copyLiteral(Expression e)
         emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type);
         return ue;
     }
-    if (e.op == TOK.error)
+    if (e.op == EXP.error)
     {
         emplaceExp!(UnionExp)(&ue, e);
         return ue;
@@ -468,11 +468,11 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
     {
         emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2);
     }
-    else if (lit.op == TOK.arrayLiteral)
+    else if (lit.op == EXP.arrayLiteral)
     {
         emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
     }
-    else if (lit.op == TOK.string_)
+    else if (lit.op == EXP.string_)
     {
         // For strings, we need to introduce another level of indirection
         emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
@@ -490,7 +490,7 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
     {
         // Can't type paint from struct to struct*; this needs another
         // level of indirection
-        if (lit.op == TOK.structLiteral && isPointer(type))
+        if (lit.op == EXP.structLiteral && isPointer(type))
             lit.error("CTFE internal error: painting `%s`", type.toChars());
         ue = copyLiteral(lit);
     }
@@ -511,7 +511,7 @@ Expression resolveSlice(Expression e, UnionExp* pue = null)
     SliceExp se = e.isSliceExp();
     if (!se)
         return e;
-    if (se.e1.op == TOK.null_)
+    if (se.e1.op == EXP.null_)
         return se.e1;
     if (pue)
     {
@@ -531,13 +531,13 @@ uinteger_t resolveArrayLength(const Expression e)
 {
     switch (e.op)
     {
-        case TOK.vector:
+        case EXP.vector:
             return e.isVectorExp().dim;
 
-        case TOK.null_:
+        case EXP.null_:
             return 0;
 
-        case TOK.slice:
+        case EXP.slice:
         {
             auto se = cast(SliceExp)e;
             const ilo = se.lwr.toInteger();
@@ -545,16 +545,16 @@ uinteger_t resolveArrayLength(const Expression e)
             return iup - ilo;
         }
 
-        case TOK.string_:
+        case EXP.string_:
             return e.isStringExp().len;
 
-        case TOK.arrayLiteral:
+        case EXP.arrayLiteral:
         {
             const ale = e.isArrayLiteralExp();
             return ale.elements ? ale.elements.dim : 0;
         }
 
-        case TOK.assocArrayLiteral:
+        case EXP.assocArrayLiteral:
         {
             return e.isAssocArrayLiteralExp().keys.dim;
         }
@@ -667,7 +667,7 @@ bool isPointer(Type t)
 // For CTFE only. Returns true if 'e' is true or a non-null pointer.
 bool isTrueBool(Expression e)
 {
-    return e.isBool(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != TOK.null_);
+    return e.toBool().hasValue(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != EXP.null_);
 }
 
 /* Is it safe to convert from srcPointee* to destPointee* ?
@@ -725,12 +725,12 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
         const ex = dve.e1;
         const v = dve.var.isVarDeclaration();
         assert(v);
-        StructLiteralExp se = (ex.op == TOK.classReference)
+        StructLiteralExp se = (ex.op == EXP.classReference)
             ? (cast(ClassReferenceExp)ex).value
             : cast(StructLiteralExp)ex;
 
         // We can't use getField, because it makes a copy
-        const i = (ex.op == TOK.classReference)
+        const i = (ex.op == EXP.classReference)
             ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset)
             : se.getFieldIndex(e.type, v.offset);
         e = (*se.elements)[i];
@@ -738,7 +738,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
     if (auto ie = e.isIndexExp())
     {
         // Note that each AA element is part of its own memory block
-        if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == TOK.string_ || ie.e1.op == TOK.arrayLiteral) && ie.e2.op == TOK.int64)
+        if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64)
         {
             *ofs = ie.e2.toInteger();
             return ie.e1;
@@ -747,7 +747,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
     if (auto se = e.isSliceExp())
     {
         if (se && e.type.toBasetype().ty == Tsarray &&
-           (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral) && se.lwr.op == TOK.int64)
+           (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64)
         {
             *ofs = se.lwr.toInteger();
             return se.e1;
@@ -773,17 +773,17 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
         return true;
     // For integers cast to pointers, we regard them as non-comparable
     // unless they are identical. (This may be overly strict).
-    if (agg1.op == TOK.int64 && agg2.op == TOK.int64 && agg1.toInteger() == agg2.toInteger())
+    if (agg1.op == EXP.int64 && agg2.op == EXP.int64 && agg1.toInteger() == agg2.toInteger())
     {
         return true;
     }
     // Note that type painting can occur with VarExp, so we
     // must compare the variables being pointed to.
-    if (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
+    if (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
     {
         return true;
     }
-    if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+    if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
     {
         return true;
     }
@@ -803,14 +803,14 @@ UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expressi
         const sz = pointee.size();
         emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
     }
-    else if (agg1.op == TOK.string_ && agg2.op == TOK.string_ &&
+    else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
              (cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
     {
         Type pointee = (cast(TypePointer)agg1.type).next;
         const sz = pointee.size();
         emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
     }
-    else if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset &&
+    else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
              (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
     {
         emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type);
@@ -818,28 +818,28 @@ UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expressi
     else
     {
         error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars());
-        emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+        emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
     }
     return ue;
 }
 
 // Return eptr op e2, where eptr is a pointer, e2 is an integer,
-// and op is TOK.add or TOK.min
-UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr, Expression e2)
+// and op is EXP.add or EXP.min
+UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
 {
     UnionExp ue;
     if (eptr.type.nextOf().ty == Tvoid)
     {
         error(loc, "cannot perform arithmetic on `void*` pointers at compile time");
     Lcant:
-        emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+        emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
         return ue;
     }
-    if (eptr.op == TOK.address)
+    if (eptr.op == EXP.address)
         eptr = (cast(AddrExp)eptr).e1;
     dinteger_t ofs1;
     Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
-    if (agg1.op == TOK.symbolOffset)
+    if (agg1.op == EXP.symbolOffset)
     {
         if ((cast(SymOffExp)agg1).var.type.ty != Tsarray)
         {
@@ -847,7 +847,7 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr
             goto Lcant;
         }
     }
-    else if (agg1.op != TOK.string_ && agg1.op != TOK.arrayLiteral)
+    else if (agg1.op != EXP.string_ && agg1.op != EXP.arrayLiteral)
     {
         error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
         goto Lcant;
@@ -857,7 +857,7 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr
     dinteger_t sz = pointee.size();
     sinteger_t indx;
     dinteger_t len;
-    if (agg1.op == TOK.symbolOffset)
+    if (agg1.op == EXP.symbolOffset)
     {
         indx = ofs1 / sz;
         len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger();
@@ -869,9 +869,9 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr
         indx = ofs1;
         len = dollar.toInteger();
     }
-    if (op == TOK.add || op == TOK.addAssign || op == TOK.plusPlus)
+    if (op == EXP.add || op == EXP.addAssign || op == EXP.plusPlus)
         indx += ofs2 / sz;
-    else if (op == TOK.min || op == TOK.minAssign || op == TOK.minusMinus)
+    else if (op == EXP.min || op == EXP.minAssign || op == EXP.minusMinus)
         indx -= ofs2 / sz;
     else
     {
@@ -883,14 +883,14 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr
         error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len);
         goto Lcant;
     }
-    if (agg1.op == TOK.symbolOffset)
+    if (agg1.op == EXP.symbolOffset)
     {
         emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz);
         SymOffExp se = cast(SymOffExp)ue.exp();
         se.type = type;
         return ue;
     }
-    if (agg1.op != TOK.arrayLiteral && agg1.op != TOK.string_)
+    if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_)
     {
         error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
         goto Lcant;
@@ -918,31 +918,31 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr
 
 // Return 1 if true, 0 if false
 // -1 if comparison is illegal because they point to non-comparable memory blocks
-int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
+int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
 {
     if (pointToSameMemoryBlock(agg1, agg2))
     {
         int n;
         switch (op)
         {
-        case TOK.lessThan:
+        case EXP.lessThan:
             n = (ofs1 < ofs2);
             break;
-        case TOK.lessOrEqual:
+        case EXP.lessOrEqual:
             n = (ofs1 <= ofs2);
             break;
-        case TOK.greaterThan:
+        case EXP.greaterThan:
             n = (ofs1 > ofs2);
             break;
-        case TOK.greaterOrEqual:
+        case EXP.greaterOrEqual:
             n = (ofs1 >= ofs2);
             break;
-        case TOK.identity:
-        case TOK.equal:
+        case EXP.identity:
+        case EXP.equal:
             n = (ofs1 == ofs2);
             break;
-        case TOK.notIdentity:
-        case TOK.notEqual:
+        case EXP.notIdentity:
+        case EXP.notEqual:
             n = (ofs1 != ofs2);
             break;
         default:
@@ -950,29 +950,29 @@ int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, d
         }
         return n;
     }
-    const null1 = (agg1.op == TOK.null_);
-    const null2 = (agg2.op == TOK.null_);
+    const null1 = (agg1.op == EXP.null_);
+    const null2 = (agg2.op == EXP.null_);
     int cmp;
     if (null1 || null2)
     {
         switch (op)
         {
-        case TOK.lessThan:
+        case EXP.lessThan:
             cmp = null1 && !null2;
             break;
-        case TOK.greaterThan:
+        case EXP.greaterThan:
             cmp = !null1 && null2;
             break;
-        case TOK.lessOrEqual:
+        case EXP.lessOrEqual:
             cmp = null1;
             break;
-        case TOK.greaterOrEqual:
+        case EXP.greaterOrEqual:
             cmp = null2;
             break;
-        case TOK.identity:
-        case TOK.equal:
-        case TOK.notIdentity: // 'cmp' gets inverted below
-        case TOK.notEqual:
+        case EXP.identity:
+        case EXP.equal:
+        case EXP.notIdentity: // 'cmp' gets inverted below
+        case EXP.notEqual:
             cmp = (null1 == null2);
             break;
         default:
@@ -983,17 +983,17 @@ int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, d
     {
         switch (op)
         {
-        case TOK.identity:
-        case TOK.equal:
-        case TOK.notIdentity: // 'cmp' gets inverted below
-        case TOK.notEqual:
+        case EXP.identity:
+        case EXP.equal:
+        case EXP.notIdentity: // 'cmp' gets inverted below
+        case EXP.notEqual:
             cmp = 0;
             break;
         default:
             return -1; // memory blocks are different
         }
     }
-    if (op == TOK.notIdentity || op == TOK.notEqual)
+    if (op == EXP.notIdentity || op == EXP.notEqual)
         cmp ^= 1;
     return cmp;
 }
@@ -1019,35 +1019,35 @@ Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to)
 /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
 bool isCtfeComparable(Expression e)
 {
-    if (e.op == TOK.slice)
+    if (e.op == EXP.slice)
         e = (cast(SliceExp)e).e1;
     if (e.isConst() != 1)
     {
-        if (e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.arrayLiteral || e.op == TOK.structLiteral || e.op == TOK.assocArrayLiteral || e.op == TOK.classReference)
+        if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference)
         {
             return true;
         }
         // https://issues.dlang.org/show_bug.cgi?id=14123
         // TypeInfo object is comparable in CTFE
-        if (e.op == TOK.typeid_)
+        if (e.op == EXP.typeid_)
             return true;
         return false;
     }
     return true;
 }
 
-/// Map TOK comparison ops
-private bool numCmp(N)(TOK op, N n1, N n2)
+/// Map EXP comparison ops
+private bool numCmp(N)(EXP op, N n1, N n2)
 {
     switch (op)
     {
-    case TOK.lessThan:
+    case EXP.lessThan:
         return n1 < n2;
-    case TOK.lessOrEqual:
+    case EXP.lessOrEqual:
         return n1 <= n2;
-    case TOK.greaterThan:
+    case EXP.greaterThan:
         return n1 > n2;
-    case TOK.greaterOrEqual:
+    case EXP.greaterOrEqual:
         return n1 >= n2;
 
     default:
@@ -1056,35 +1056,35 @@ private bool numCmp(N)(TOK op, N n1, N n2)
 }
 
 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool specificCmp(TOK op, int rawCmp)
+bool specificCmp(EXP op, int rawCmp)
 {
     return numCmp!int(op, rawCmp, 0);
 }
 
 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
+bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2)
 {
     return numCmp!dinteger_t(op, n1, n2);
 }
 
 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
+bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2)
 {
     return numCmp!sinteger_t(op, n1, n2);
 }
 
 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool realCmp(TOK op, real_t r1, real_t r2)
+bool realCmp(EXP op, real_t r1, real_t r2)
 {
     // Don't rely on compiler, handle NAN arguments separately
     if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
     {
         switch (op)
         {
-        case TOK.lessThan:
-        case TOK.lessOrEqual:
-        case TOK.greaterThan:
-        case TOK.greaterOrEqual:
+        case EXP.lessThan:
+        case EXP.lessOrEqual:
+        case EXP.greaterThan:
+        case EXP.greaterOrEqual:
             return false;
 
         default:
@@ -1128,7 +1128,7 @@ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte
     auto se2 = x2.isStringExp();
     auto ae2 = x2.isArrayLiteralExp();
 
-    // Now both must be either TOK.arrayLiteral or TOK.string_
+    // Now both must be either EXP.arrayLiteral or EXP.string_
     if (se1 && se2)
         return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
     if (se1 && ae2)
@@ -1171,13 +1171,13 @@ private FuncDeclaration funcptrOf(Expression e)
         return de.func;
     if (auto fe = e.isFuncExp())
         return fe.fd;
-    assert(e.op == TOK.null_);
+    assert(e.op == EXP.null_);
     return null;
 }
 
 private bool isArray(const Expression e)
 {
-    return e.op == TOK.arrayLiteral || e.op == TOK.string_ || e.op == TOK.slice || e.op == TOK.null_;
+    return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_;
 }
 
 /*****
@@ -1192,14 +1192,14 @@ private bool isArray(const Expression e)
  */
 private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false)
 {
-    if (e1.op == TOK.classReference || e2.op == TOK.classReference)
+    if (e1.op == EXP.classReference || e2.op == EXP.classReference)
     {
-        if (e1.op == TOK.classReference && e2.op == TOK.classReference &&
+        if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
             (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value)
             return 0;
         return 1;
     }
-    if (e1.op == TOK.typeid_ && e2.op == TOK.typeid_)
+    if (e1.op == EXP.typeid_ && e2.op == EXP.typeid_)
     {
         // printf("e1: %s\n", e1.toChars());
         // printf("e2: %s\n", e2.toChars());
@@ -1210,7 +1210,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
         return t1 != t2;
     }
     // null == null, regardless of type
-    if (e1.op == TOK.null_ && e2.op == TOK.null_)
+    if (e1.op == EXP.null_ && e2.op == EXP.null_)
         return 0;
     if (e1.type.ty == Tpointer && e2.type.ty == Tpointer)
     {
@@ -1218,7 +1218,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
         dinteger_t ofs1, ofs2;
         Expression agg1 = getAggregateFromPointer(e1, &ofs1);
         Expression agg2 = getAggregateFromPointer(e2, &ofs2);
-        if ((agg1 == agg2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+        if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
         {
             if (ofs1 == ofs2)
                 return 0;
@@ -1232,17 +1232,17 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
             return 1;
         // If both are delegate literals, assume they have the
         // same closure pointer. TODO: We don't support closures yet!
-        if (e1.op == TOK.function_ && e2.op == TOK.function_)
+        if (e1.op == EXP.function_ && e2.op == EXP.function_)
             return 0;
-        assert(e1.op == TOK.delegate_ && e2.op == TOK.delegate_);
+        assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_);
         // Same .funcptr. Do they have the same .ptr?
         Expression ptr1 = (cast(DelegateExp)e1).e1;
         Expression ptr2 = (cast(DelegateExp)e2).e1;
         dinteger_t ofs1, ofs2;
         Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
         Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
-        // If they are TOK.variable, it means they are FuncDeclarations
-        if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+        // If they are EXP.variable, it means they are FuncDeclarations
+        if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
         {
             return 0;
         }
@@ -1293,7 +1293,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
         }
         return c1 != c2;
     }
-    if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
+    if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
     {
         StructLiteralExp es1 = cast(StructLiteralExp)e1;
         StructLiteralExp es2 = cast(StructLiteralExp)e2;
@@ -1314,7 +1314,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
                 Expression ee2 = (*es2.elements)[i];
 
                 // https://issues.dlang.org/show_bug.cgi?id=16284
-                if (ee1.op == TOK.void_ && ee2.op == TOK.void_) // if both are VoidInitExp
+                if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp
                     continue;
 
                 if (ee1 == ee2)
@@ -1328,7 +1328,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
             return 0; // All elements are equal
         }
     }
-    if (e1.op == TOK.assocArrayLiteral && e2.op == TOK.assocArrayLiteral)
+    if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
     {
         AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1;
         AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2;
@@ -1367,27 +1367,27 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
 }
 
 /// Evaluate ==, !=.  Resolves slices before comparing. Returns 0 or 1
-bool ctfeEqual(const ref Loc loc, TOK op, Expression e1, Expression e2)
+bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2)
 {
-    return !ctfeRawCmp(loc, e1, e2) ^ (op == TOK.notEqual);
+    return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual);
 }
 
 /// Evaluate is, !is.  Resolves slices before comparing. Returns 0 or 1
-bool ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2)
+bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
 {
     //printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars());
-    //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
-    //    Token::toChars(e1.op), e1.toChars(), Token::toChars(e2.op), e1.toChars());
+    //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr,
+    //    EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars());
     bool cmp;
-    if (e1.op == TOK.null_)
+    if (e1.op == EXP.null_)
     {
-        cmp = (e2.op == TOK.null_);
+        cmp = (e2.op == EXP.null_);
     }
-    else if (e2.op == TOK.null_)
+    else if (e2.op == EXP.null_)
     {
         cmp = false;
     }
-    else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
+    else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
     {
         SymOffExp es1 = cast(SymOffExp)e1;
         SymOffExp es2 = cast(SymOffExp)e2;
@@ -1407,13 +1407,13 @@ bool ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2)
     {
         cmp = !ctfeRawCmp(loc, e1, e2, true);
     }
-    if (op == TOK.notIdentity || op == TOK.notEqual)
+    if (op == EXP.notIdentity || op == EXP.notEqual)
         cmp ^= true;
     return cmp;
 }
 
 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
-bool ctfeCmp(const ref Loc loc, TOK op, Expression e1, Expression e2)
+bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2)
 {
     Type t1 = e1.type.toBasetype();
     Type t2 = e2.type.toBasetype();
@@ -1435,7 +1435,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
     Type t1 = e1.type.toBasetype();
     Type t2 = e2.type.toBasetype();
     UnionExp ue;
-    if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
+    if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
     {
         // [chars] ~ string => string (only valid for CTFE)
         StringExp es1 = cast(StringExp)e2;
@@ -1448,9 +1448,9 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         foreach (size_t i; 0 .. es2.elements.dim)
         {
             Expression es2e = (*es2.elements)[i];
-            if (es2e.op != TOK.int64)
+            if (es2e.op != EXP.int64)
             {
-                emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+                emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
                 return ue;
             }
             dinteger_t v = es2e.toInteger();
@@ -1464,7 +1464,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         es.type = type;
         return ue;
     }
-    if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
+    if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
     {
         // string ~ [chars] => string (only valid for CTFE)
         // Concatenate the strings
@@ -1478,9 +1478,9 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         foreach (size_t i; 0 .. es2.elements.dim)
         {
             Expression es2e = (*es2.elements)[i];
-            if (es2e.op != TOK.int64)
+            if (es2e.op != EXP.int64)
             {
-                emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+                emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
                 return ue;
             }
             const v = es2e.toInteger();
@@ -1495,7 +1495,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         es.type = type;
         return ue;
     }
-    if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+    if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
     {
         //  [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
         ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
@@ -1505,13 +1505,13 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
         return ue;
     }
-    if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
+    if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
     {
         //  [ e1 ] ~ null ----> [ e1 ].dup
         ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
         return ue;
     }
-    if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+    if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
     {
         //  null ~ [ e2 ] ----> [ e2 ].dup
         ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
@@ -1532,7 +1532,7 @@ Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2
     {
         --i;
         Expression ekey = (*ae.keys)[i];
-        const int eq = ctfeEqual(loc, TOK.equal, ekey, e2);
+        const int eq = ctfeEqual(loc, EXP.equal, ekey, e2);
         if (eq)
         {
             return (*ae.values)[i];
@@ -1581,10 +1581,10 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres
         return paintTypeOntoLiteral(pue, to, e);
     }
 
-    if (e.op == TOK.null_)
+    if (e.op == EXP.null_)
         return paint();
 
-    if (e.op == TOK.classReference)
+    if (e.op == EXP.classReference)
     {
         // Disallow reinterpreting class casts. Do this by ensuring that
         // the original class can implicitly convert to the target class
@@ -1603,7 +1603,7 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres
         return paint();
 
     // Allow casting away const for struct literals
-    if (e.op == TOK.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
+    if (e.op == EXP.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
         return paint();
 
     Expression r;
@@ -1647,14 +1647,14 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres
  */
 void assignInPlace(Expression dest, Expression src)
 {
-    if (!(dest.op == TOK.structLiteral || dest.op == TOK.arrayLiteral || dest.op == TOK.string_))
+    if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_))
     {
         printf("invalid op %d %d\n", src.op, dest.op);
         assert(0);
     }
     Expressions* oldelems;
     Expressions* newelems;
-    if (dest.op == TOK.structLiteral)
+    if (dest.op == EXP.structLiteral)
     {
         assert(dest.op == src.op);
         oldelems = (cast(StructLiteralExp)dest).elements;
@@ -1666,22 +1666,22 @@ void assignInPlace(Expression dest, Expression src)
             foreach (_; 0 .. newelems.dim - oldelems.dim)
                 oldelems.push(null);
     }
-    else if (dest.op == TOK.arrayLiteral && src.op == TOK.arrayLiteral)
+    else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
     {
         oldelems = (cast(ArrayLiteralExp)dest).elements;
         newelems = (cast(ArrayLiteralExp)src).elements;
     }
-    else if (dest.op == TOK.string_ && src.op == TOK.string_)
+    else if (dest.op == EXP.string_ && src.op == EXP.string_)
     {
         sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0);
         return;
     }
-    else if (dest.op == TOK.arrayLiteral && src.op == TOK.string_)
+    else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
     {
         sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0);
         return;
     }
-    else if (src.op == TOK.arrayLiteral && dest.op == TOK.string_)
+    else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
     {
         sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0);
         return;
@@ -1696,12 +1696,12 @@ void assignInPlace(Expression dest, Expression src)
     {
         Expression e = (*newelems)[i];
         Expression o = (*oldelems)[i];
-        if (e.op == TOK.structLiteral)
+        if (e.op == EXP.structLiteral)
         {
             assert(o.op == e.op);
             assignInPlace(o, e);
         }
-        else if (e.type.ty == Tsarray && e.op != TOK.void_ && o.type.ty == Tsarray)
+        else if (e.type.ty == Tsarray && e.op != EXP.void_ && o.type.ty == Tsarray)
         {
             assignInPlace(o, e);
         }
@@ -1724,7 +1724,7 @@ Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae,
     {
         j--;
         Expression ekey = (*aae.keys)[j];
-        int eq = ctfeEqual(loc, TOK.equal, ekey, index);
+        int eq = ctfeEqual(loc, EXP.equal, ekey, index);
         if (eq)
         {
             (*valuesx)[j] = newval;
@@ -1752,13 +1752,13 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres
     auto elements = new Expressions(newlen);
     // Resolve slices
     size_t indxlo = 0;
-    if (oldval.op == TOK.slice)
+    if (oldval.op == EXP.slice)
     {
         indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger();
         oldval = (cast(SliceExp)oldval).e1;
     }
     size_t copylen = oldlen < newlen ? oldlen : newlen;
-    if (oldval.op == TOK.string_)
+    if (oldval.op == EXP.string_)
     {
         StringExp oldse = cast(StringExp)oldval;
         void* s = mem.xcalloc(newlen + 1, oldse.sz);
@@ -1793,7 +1793,7 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres
     {
         if (oldlen != 0)
         {
-            assert(oldval.op == TOK.arrayLiteral);
+            assert(oldval.op == EXP.arrayLiteral);
             ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval;
             foreach (size_t i; 0 .. copylen)
                 (*elements)[i] = (*ae.elements)[indxlo + i];
@@ -1825,13 +1825,13 @@ bool isCtfeValueValid(Expression newval)
     Type tb = newval.type.toBasetype();
     switch (newval.op)
     {
-        case TOK.int64:
-        case TOK.float64:
-        case TOK.char_:
-        case TOK.complex80:
+        case EXP.int64:
+        case EXP.float64:
+        case EXP.char_:
+        case EXP.complex80:
             return tb.isscalar();
 
-        case TOK.null_:
+        case EXP.null_:
             return tb.ty == Tnull    ||
                    tb.ty == Tpointer ||
                    tb.ty == Tarray   ||
@@ -1839,75 +1839,75 @@ bool isCtfeValueValid(Expression newval)
                    tb.ty == Tclass   ||
                    tb.ty == Tdelegate;
 
-        case TOK.string_:
+        case EXP.string_:
             return true; // CTFE would directly use the StringExp in AST.
 
-        case TOK.arrayLiteral:
+        case EXP.arrayLiteral:
             return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
 
-        case TOK.assocArrayLiteral:
+        case EXP.assocArrayLiteral:
             return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
 
-        case TOK.structLiteral:
+        case EXP.structLiteral:
             return true; //((StructLiteralExp *)newval)->ownedByCtfe;
 
-        case TOK.classReference:
+        case EXP.classReference:
             return true;
 
-        case TOK.type:
+        case EXP.type:
             return true;
 
-        case TOK.vector:
+        case EXP.vector:
             return true; // vector literal
 
-        case TOK.function_:
+        case EXP.function_:
             return true; // function literal or delegate literal
 
-        case TOK.delegate_:
+        case EXP.delegate_:
         {
             // &struct.func or &clasinst.func
             // &nestedfunc
             Expression ethis = (cast(DelegateExp)newval).e1;
-            return (ethis.op == TOK.structLiteral || ethis.op == TOK.classReference || ethis.op == TOK.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
+            return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
         }
 
-        case TOK.symbolOffset:
+        case EXP.symbolOffset:
         {
             // function pointer, or pointer to static variable
             Declaration d = (cast(SymOffExp)newval).var;
             return d.isFuncDeclaration() || d.isDataseg();
         }
 
-        case TOK.typeid_:
+        case EXP.typeid_:
         {
             // always valid
             return true;
         }
 
-        case TOK.address:
+        case EXP.address:
         {
             // e1 should be a CTFE reference
             Expression e1 = (cast(AddrExp)newval).e1;
             return tb.ty == Tpointer &&
             (
-                (e1.op == TOK.structLiteral || e1.op == TOK.arrayLiteral) && isCtfeValueValid(e1) ||
-                 e1.op == TOK.variable ||
-                 e1.op == TOK.dotVariable && isCtfeReferenceValid(e1) ||
-                 e1.op == TOK.index && isCtfeReferenceValid(e1) ||
-                 e1.op == TOK.slice && e1.type.toBasetype().ty == Tsarray
+                (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
+                 e1.op == EXP.variable ||
+                 e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) ||
+                 e1.op == EXP.index && isCtfeReferenceValid(e1) ||
+                 e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray
             );
         }
 
-        case TOK.slice:
+        case EXP.slice:
         {
             // e1 should be an array aggregate
             const SliceExp se = cast(SliceExp)newval;
-            assert(se.lwr && se.lwr.op == TOK.int64);
-            assert(se.upr && se.upr.op == TOK.int64);
-            return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral);
+            assert(se.lwr && se.lwr.op == EXP.int64);
+            assert(se.upr && se.upr.op == EXP.int64);
+            return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
         }
 
-        case TOK.void_:
+        case EXP.void_:
             return true; // uninitialized value
 
         default:
@@ -1920,10 +1920,10 @@ bool isCtfeReferenceValid(Expression newval)
 {
     switch (newval.op)
     {
-        case TOK.this_:
+        case EXP.this_:
             return true;
 
-        case TOK.variable:
+        case EXP.variable:
         {
             const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration();
             assert(v);
@@ -1931,16 +1931,16 @@ bool isCtfeReferenceValid(Expression newval)
             return true;
         }
 
-        case TOK.index:
+        case EXP.index:
         {
             const Expression eagg = (cast(IndexExp)newval).e1;
-            return eagg.op == TOK.string_ || eagg.op == TOK.arrayLiteral || eagg.op == TOK.assocArrayLiteral;
+            return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
         }
 
-        case TOK.dotVariable:
+        case EXP.dotVariable:
         {
             Expression eagg = (cast(DotVarExp)newval).e1;
-            return (eagg.op == TOK.structLiteral || eagg.op == TOK.classReference) && isCtfeValueValid(eagg);
+            return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
         }
 
         default:
@@ -1959,44 +1959,44 @@ void showCtfeExpr(Expression e, int level = 0)
     // We need the struct definition to detect block assignment
     StructDeclaration sd = null;
     ClassDeclaration cd = null;
-    if (e.op == TOK.structLiteral)
+    if (e.op == EXP.structLiteral)
     {
         elements = (cast(StructLiteralExp)e).elements;
         sd = (cast(StructLiteralExp)e).sd;
         printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
     }
-    else if (e.op == TOK.classReference)
+    else if (e.op == EXP.classReference)
     {
         elements = (cast(ClassReferenceExp)e).value.elements;
         cd = (cast(ClassReferenceExp)e).originalClass();
         printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value);
     }
-    else if (e.op == TOK.arrayLiteral)
+    else if (e.op == EXP.arrayLiteral)
     {
         elements = (cast(ArrayLiteralExp)e).elements;
         printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
     }
-    else if (e.op == TOK.assocArrayLiteral)
+    else if (e.op == EXP.assocArrayLiteral)
     {
         printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e);
     }
-    else if (e.op == TOK.string_)
+    else if (e.op == EXP.string_)
     {
         printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr);
     }
-    else if (e.op == TOK.slice)
+    else if (e.op == EXP.slice)
     {
         printf("SLICE %p: %s\n", e, e.toChars());
         showCtfeExpr((cast(SliceExp)e).e1, level + 1);
     }
-    else if (e.op == TOK.variable)
+    else if (e.op == EXP.variable)
     {
         printf("VAR %p %s\n", e, e.toChars());
         VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
         if (v && getValue(v))
             showCtfeExpr(getValue(v), level + 1);
     }
-    else if (e.op == TOK.address)
+    else if (e.op == EXP.address)
     {
         // This is potentially recursive. We mustn't try to print the thing we're pointing to.
         printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars());
@@ -2069,7 +2069,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var)
         Expression elem = voidInitLiteral(tsa.next, var).copy();
         // For aggregate value types (structs, static arrays) we must
         // create an a separate copy for each element.
-        const mustCopy = (elem.op == TOK.arrayLiteral || elem.op == TOK.structLiteral);
+        const mustCopy = (elem.op == EXP.arrayLiteral || elem.op == EXP.structLiteral);
         const d = cast(size_t)tsa.dim.toInteger();
         auto elements = new Expressions(d);
         foreach (i; 0 .. d)
index 87c3adae9e60ef90ceaee4a0038b576b7b2c1b5e..2e5a79d0febba7ae62a66ca6ad950d8fd5a9a1c7 100644 (file)
@@ -29,6 +29,7 @@ import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
+import dmd.hdrgen;
 import dmd.impcnvtab;
 import dmd.id;
 import dmd.importc;
@@ -994,7 +995,7 @@ MATCH implicitConvTo(Expression e, Type t)
             Type typeb = e.type.toBasetype();
 
             // Look for pointers to functions where the functions are overloaded.
-            if (e.e1.op == TOK.overloadSet &&
+            if (e.e1.op == EXP.overloadSet &&
                 (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
             {
                 OverExp eo = e.e1.isOverExp();
@@ -1019,7 +1020,7 @@ MATCH implicitConvTo(Expression e, Type t)
                 }
             }
 
-            if (e.e1.op == TOK.variable &&
+            if (e.e1.op == EXP.variable &&
                 typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
                 tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
             {
@@ -1443,7 +1444,7 @@ MATCH implicitConvTo(Expression e, Type t)
             }
 
             // Enhancement 10724
-            if (tb.ty == Tpointer && e.e1.op == TOK.string_)
+            if (tb.ty == Tpointer && e.e1.op == EXP.string_)
                 e.e1.accept(this);
         }
 
@@ -1564,7 +1565,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 result = e;
                 return;
             }
-            if (e.op == TOK.variable)
+            if (e.op == EXP.variable)
             {
                 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
                 if (v && v.storage_class & STC.manifest)
@@ -1728,6 +1729,11 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                     }
                     const fsize = t1b.nextOf().size();
                     const tsize = tob.nextOf().size();
+                    if (fsize == SIZE_INVALID || tsize == SIZE_INVALID)
+                    {
+                        result = ErrorExp.get();
+                        return;
+                    }
                     if (fsize != tsize)
                     {
                         const dim = t1b.isTypeSArray().dim.toInteger();
@@ -1846,7 +1852,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         override void visit(StructLiteralExp e)
         {
             visit(cast(Expression)e);
-            if (result.op == TOK.structLiteral)
+            if (result.op == EXP.structLiteral)
                 (cast(StructLiteralExp)result).stype = t; // commit type
         }
 
@@ -1868,6 +1874,13 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             }
 
             StringExp se = e;
+
+            void lcast()
+            {
+                result = new CastExp(e.loc, se, t);
+                result.type = t; // so semantic() won't be run on e
+            }
+
             if (!e.committed)
             {
                 se = cast(StringExp)e.copy();
@@ -1942,7 +1955,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                     se = cast(StringExp)e.copy();
                     copied = 1;
                 }
-                goto Lcast;
+                return lcast();
             }
             if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer)
             {
@@ -1951,10 +1964,16 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                     se = cast(StringExp)e.copy();
                     copied = 1;
                 }
-                goto Lcast;
+                return lcast();
             }
 
-            if (typeb.nextOf().size() == tb.nextOf().size())
+            const nextSz = typeb.nextOf().size();
+            if (nextSz == SIZE_INVALID)
+            {
+                result = ErrorExp.get();
+                return;
+            }
+            if (nextSz == tb.nextOf().size())
             {
                 if (!copied)
                 {
@@ -2135,7 +2154,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             }
 
             // Look for pointers to functions where the functions are overloaded.
-            if (e.e1.op == TOK.overloadSet &&
+            if (e.e1.op == EXP.overloadSet &&
                 (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
             {
                 OverExp eo = cast(OverExp)e.e1;
@@ -2169,7 +2188,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 }
             }
 
-            if (e.e1.op == TOK.variable &&
+            if (e.e1.op == EXP.variable &&
                 typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
                 tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
             {
@@ -2621,7 +2640,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 if (e.e1.implicitConvTo(t1b) > MATCH.nomatch)
                 {
                     Expression e1x = e.e1.implicitCastTo(sc, t1b);
-                    assert(e1x.op != TOK.error);
+                    assert(e1x.op != EXP.error);
                     e = cast(SliceExp)e.copy();
                     e.e1 = e1x;
                     e.type = t;
@@ -2732,10 +2751,10 @@ Expression inferType(Expression e, Type t, int flag = 0)
 
     if (t) switch (e.op)
     {
-        case TOK.arrayLiteral:      return visitAle(cast(ArrayLiteralExp) e);
-        case TOK.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e);
-        case TOK.function_:         return visitFun(cast(FuncExp) e);
-        case TOK.question:          return visitTer(cast(CondExp) e);
+        case EXP.arrayLiteral:      return visitAle(cast(ArrayLiteralExp) e);
+        case EXP.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e);
+        case EXP.function_:         return visitFun(cast(FuncExp) e);
+        case EXP.question:          return visitTer(cast(CondExp) e);
         default:
     }
     return e;
@@ -2789,7 +2808,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
     if (sc.func && !sc.intypeof)
     {
         eoff = eoff.optimize(WANTvalue);
-        if (eoff.op == TOK.int64 && eoff.toInteger() == 0)
+        if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
         {
         }
         else if (sc.func.setUnsafe())
@@ -2811,7 +2830,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
  */
 private bool isVoidArrayLiteral(Expression e, Type other)
 {
-    while (e.op == TOK.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1))
+    while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1))
     {
         auto ale = cast(ArrayLiteralExp)e;
         e = ale[0];
@@ -2823,7 +2842,7 @@ private bool isVoidArrayLiteral(Expression e, Type other)
     if (other.ty != Tsarray && other.ty != Tarray)
         return false;
     Type t = e.type;
-    return (e.op == TOK.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
+    return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
 }
 
 /**
@@ -2833,7 +2852,7 @@ private bool isVoidArrayLiteral(Expression e, Type other)
  *
  * Params:
  *     sc  = Current scope
- *     op  = Operator such as `e1 op e2`. In practice, either TOK.question
+ *     op  = Operator such as `e1 op e2`. In practice, either EXP.question
  *           or one of the binary operator.
  *     pe1 = The LHS of the operation, will be rewritten
  *     pe2 = The RHS of the operation, will be rewritten
@@ -2841,7 +2860,7 @@ private bool isVoidArrayLiteral(Expression e, Type other)
  * Returns:
  *      The resulting type in case of success, `null` in case of error
  */
-Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
+Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2)
 {
     //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
 
@@ -2906,9 +2925,9 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
         }
     }
 
-    if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
+    if (op != EXP.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
     {
-        if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
+        if (op == EXP.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
         {
             e1 = e1.castTo(sc, Type.tdchar);
             e2 = e2.castTo(sc, Type.tdchar);
@@ -3077,7 +3096,7 @@ Lagain:
         return null;
     }
 
-    if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
+    if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
     {
         /*  (T[n] op void*)   => T[]
          *  (T[]  op void*)   => T[]
@@ -3089,7 +3108,7 @@ Lagain:
         return coerce(t1.nextOf().arrayOf());
     }
 
-    if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
+    if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
     {
         /*  (void*   op T[n]) => T[]
          *  (void*   op T[])  => T[]
@@ -3107,9 +3126,9 @@ Lagain:
         // Tsarray op [x, y, ...] should to be Tsarray
         // https://issues.dlang.org/show_bug.cgi?id=14737
         // Tsarray ~ [x, y, ...] should to be Tarray
-        if (t1.ty == Tsarray && e2.op == TOK.arrayLiteral && op != TOK.concatenate)
+        if (t1.ty == Tsarray && e2.op == EXP.arrayLiteral && op != EXP.concatenate)
             return convert(e2, t1);
-        if (m == MATCH.constant && (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign || op == TOK.andAssign || op == TOK.orAssign || op == TOK.xorAssign))
+        if (m == MATCH.constant && (op == EXP.addAssign || op == EXP.minAssign || op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || op == EXP.powAssign || op == EXP.andAssign || op == EXP.orAssign || op == EXP.xorAssign))
         {
             // Don't make the lvalue const
             return Lret(t2);
@@ -3121,7 +3140,7 @@ Lagain:
     {
         // https://issues.dlang.org/show_bug.cgi?id=7285
         // https://issues.dlang.org/show_bug.cgi?id=14737
-        if (t2.ty == Tsarray && e1.op == TOK.arrayLiteral && op != TOK.concatenate)
+        if (t2.ty == Tsarray && e1.op == EXP.arrayLiteral && op != EXP.concatenate)
             return convert(e1, t2);
         return convert(e2, t1);
     }
@@ -3134,9 +3153,9 @@ Lagain:
         Type t1n = t1.nextOf();
         Type t2n = t2.nextOf();
         ubyte mod;
-        if (e1.op == TOK.null_ && e2.op != TOK.null_)
+        if (e1.op == EXP.null_ && e2.op != EXP.null_)
             mod = t2n.mod;
-        else if (e1.op != TOK.null_ && e2.op == TOK.null_)
+        else if (e1.op != EXP.null_ && e2.op == EXP.null_)
             mod = t1n.mod;
         else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
             return null;
@@ -3161,9 +3180,9 @@ Lagain:
         if (t1.mod != t2.mod)
         {
             ubyte mod;
-            if (e1.op == TOK.null_ && e2.op != TOK.null_)
+            if (e1.op == EXP.null_ && e2.op != EXP.null_)
                 mod = t2.mod;
-            else if (e1.op != TOK.null_ && e2.op == TOK.null_)
+            else if (e1.op != EXP.null_ && e2.op == EXP.null_)
                 mod = t1.mod;
             else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
                 return null;
@@ -3352,9 +3371,9 @@ Lagain:
         goto Lagain;
     }
 
-    if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
+    if ((e1.op == EXP.string_ || e1.op == EXP.null_) && e1.implicitConvTo(t2))
         return convert(e1, t2);
-    if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1))
+    if ((e2.op == EXP.string_ || e2.op == EXP.null_) && e2.implicitConvTo(t1))
         return convert(e2, t1);
     if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf()))
         return coerce(t1.nextOf().arrayOf());
@@ -3427,6 +3446,69 @@ LmodCompare:
     if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray))
         return convert(e1, t2);
 
+    /// Covers array operations for user-defined types
+    Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc)
+    {
+        // scalar op scalar - we shouldn't be here
+        if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray)
+            return null;
+
+        // only supporting slices and array literals
+        if (!e1.isSliceExp() && !e1.isArrayLiteralExp() && !e2.isSliceExp() && !e2.isArrayLiteralExp())
+            return null;
+
+        // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal,
+        // replace it with the first element of the array
+        Expression lhs = e1;
+        Expression rhs = e2;
+
+        // T[x .. y] op ?
+        if (e1.isSliceExp())
+            lhs = new IndexExp(Loc.initial, (cast(UnaExp)e1).e1, IntegerExp.literal!0);
+
+        // [t1, t2, .. t3] op ?
+        if (e1.isArrayLiteralExp())
+            lhs = (cast(ArrayLiteralExp)e1).opIndex(0);
+
+        // ? op U[z .. t]
+        if (e2.isSliceExp())
+            rhs = new IndexExp(Loc.initial, (cast(UnaExp)e2).e1, IntegerExp.literal!0);
+
+        // ? op [u1, u2, .. u3]
+        if (e2.isArrayLiteralExp())
+            rhs = (cast(ArrayLiteralExp)e2).opIndex(0);
+
+        // create a new binary expression with the new lhs and rhs (at this stage, at least
+        // one of lhs/rhs has been replaced with the 0'th element of the array it was before)
+        Expression exp;
+        switch (op)
+        {
+            case EXP.add:
+                exp = new AddExp(Loc.initial, lhs, rhs); break;
+            case EXP.min:
+                exp = new MinExp(Loc.initial, lhs, rhs); break;
+            case EXP.mul:
+                exp = new MulExp(Loc.initial, lhs, rhs); break;
+            case EXP.div:
+                exp = new DivExp(Loc.initial, lhs, rhs); break;
+            case EXP.pow:
+                exp = new PowExp(Loc.initial, lhs, rhs); break;
+            default:
+                exp = null;
+        }
+
+        if (exp)
+        {
+            // if T op U is valid and has type V
+            // then T[] op U and T op U[] should be valid and have type V[]
+            Expression e = exp.trySemantic(sc);
+            if (e && e.type)
+                return e.type.arrayOf;
+        }
+
+        return null;
+    }
+
     if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
     {
         if (e2.implicitConvTo(t1.nextOf()))
@@ -3463,8 +3545,12 @@ LmodCompare:
                     e2 = e2.castTo(sc, t);
                 return Lret(t);
             }
-            return null;
         }
+
+        t = checkArrayOpType(e1, e2, op, sc);
+        if (t !is null)
+            return Lret(t);
+
         return null;
     }
     else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
@@ -3483,15 +3569,19 @@ LmodCompare:
             t = e1.type.arrayOf();
         }
         else
-            return null;
+        {
+            t = checkArrayOpType(e1, e2, op, sc);
+            if (t is null)
+                return null;
+        }
 
-        //printf("test %s\n", Token::toChars(op));
+        //printf("test %s\n", EXPtoString(op).ptr);
         e1 = e1.optimize(WANTvalue);
         if (isCommutative(op) && e1.isConst())
         {
             /* Swap operands to minimize number of functions generated
              */
-            //printf("swap %s\n", Token::toChars(op));
+            //printf("swap %s\n", EXPtoString(op).ptr);
             Expression tmp = e1;
             e1 = e2;
             e2 = tmp;
@@ -3512,7 +3602,7 @@ Expression typeCombine(BinExp be, Scope* sc)
     Expression errorReturn()
     {
         Expression ex = be.incompatibleTypes();
-        if (ex.op == TOK.error)
+        if (ex.op == EXP.error)
             return ex;
         return ErrorExp.get();
     }
@@ -3520,7 +3610,7 @@ Expression typeCombine(BinExp be, Scope* sc)
     Type t1 = be.e1.type.toBasetype();
     Type t2 = be.e2.type.toBasetype();
 
-    if (be.op == TOK.min || be.op == TOK.add)
+    if (be.op == EXP.min || be.op == EXP.add)
     {
         // struct+struct, and class+class are errors
         if (t1.ty == Tstruct && t2.ty == Tstruct)
@@ -3540,9 +3630,9 @@ Expression typeCombine(BinExp be, Scope* sc)
         return errorReturn();
 
     // If the types have no value, return an error
-    if (be.e1.op == TOK.error)
+    if (be.e1.op == EXP.error)
         return be.e1;
-    if (be.e2.op == TOK.error)
+    if (be.e2.op == EXP.error)
         return be.e2;
     return null;
 }
@@ -3606,8 +3696,8 @@ void fix16997(Scope* sc, UnaExp ue)
             case Tchar:
             case Twchar:
             case Tdchar:
-                ue.deprecation("integral promotion not done for `%s`, use '-preview=intpromote' switch or `%scast(int)(%s)`",
-                    ue.toChars(), Token.toChars(ue.op), ue.e1.toChars());
+                ue.deprecation("integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`",
+                    ue.toChars(), EXPtoString(ue.op).ptr, ue.e1.toChars());
                 break;
 
             default:
index e3f135a03d8b8bbc93da86d63a694c0458c1a117..18c8ca2da749a21588b5350d862a02c931a315d3 100644 (file)
@@ -94,7 +94,7 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
             ((fd.isCtorDeclaration() && var.isField()) ||
              (fd.isStaticCtorDeclaration() && !var.isField())) &&
             fd.toParentDecl() == var.toParent2() &&
-            (!e1 || e1.op == TOK.this_))
+            (!e1 || e1.op == EXP.this_))
         {
             bool result = true;
 
@@ -250,7 +250,10 @@ extern (C++) abstract class Declaration : Dsymbol
     override final d_uns64 size(const ref Loc loc)
     {
         assert(type);
-        return type.size();
+        const sz = type.size();
+        if (sz == SIZE_INVALID)
+            errors = true;
+        return sz;
     }
 
     /**
@@ -371,7 +374,7 @@ extern (C++) abstract class Declaration : Dsymbol
             }
         }
 
-        if (e1 && e1.op == TOK.this_ && isField())
+        if (e1 && e1.op == EXP.this_ && isField())
         {
             VarDeclaration vthis = (cast(ThisExp)e1).var;
             for (Scope* scx = sc; scx; scx = scx.enclosing)
@@ -385,7 +388,7 @@ extern (C++) abstract class Declaration : Dsymbol
             }
         }
 
-        if (v && (isCtorinit() || isField()))
+        if (v && (v.isCtorinit() || isField()))
         {
             // It's only modifiable if inside the right constructor
             if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
@@ -434,11 +437,6 @@ extern (C++) abstract class Declaration : Dsymbol
         return false;
     }
 
-    final bool isCtorinit() const pure nothrow @nogc @safe
-    {
-        return (storage_class & STC.ctorinit) != 0;
-    }
-
     final bool isFinal() const pure nothrow @nogc @safe
     {
         return (storage_class & STC.final_) != 0;
@@ -655,7 +653,7 @@ extern (C++) final class TupleDeclaration : Declaration
             if (o.dyncast() == DYNCAST.expression)
             {
                 Expression e = cast(Expression)o;
-                if (e.op == TOK.dSymbol)
+                if (e.op == EXP.dSymbol)
                 {
                     DsymbolExp ve = cast(DsymbolExp)e;
                     Declaration d = ve.s.isDeclaration();
@@ -1062,6 +1060,7 @@ extern (C++) class VarDeclaration : Declaration
     bool ctorinit;                  // it has been initialized in a ctor
     bool iscatchvar;                // this is the exception object variable in catch() clause
     bool isowner;                   // this is an Owner, despite it being `scope`
+    bool setInCtorOnly;             // field can only be set in a constructor, as it is const or immutable
 
     // Both these mean the var is not rebindable once assigned,
     // and the destructor gets run when it goes out of scope
@@ -1131,7 +1130,7 @@ extern (C++) class VarDeclaration : Declaration
                 RootObject o = (*v2.objects)[i];
                 assert(o.dyncast() == DYNCAST.expression);
                 Expression e = cast(Expression)o;
-                assert(e.op == TOK.dSymbol);
+                assert(e.op == EXP.dSymbol);
                 DsymbolExp se = cast(DsymbolExp)e;
                 se.s.setFieldOffset(ad, fieldState, isunion);
             }
@@ -1250,6 +1249,11 @@ extern (C++) class VarDeclaration : Declaration
         return false;
     }
 
+    final bool isCtorinit() const pure nothrow @nogc @safe
+    {
+        return setInCtorOnly;
+    }
+
     /*******************************
      * Does symbol go into data segment?
      * Includes extern variables.
@@ -1607,7 +1611,7 @@ extern (C++) class VarDeclaration : Declaration
             ExpInitializer ez = _init.isExpInitializer();
             assert(ez);
             Expression e = ez.exp;
-            if (e.op == TOK.construct || e.op == TOK.blit)
+            if (e.op == EXP.construct || e.op == EXP.blit)
                 e = (cast(AssignExp)e).e2;
             return lambdaCheckForNestedRef(e, sc);
         }
@@ -1670,11 +1674,11 @@ extern (C++) class VarDeclaration : Declaration
         assert(this.loc != Loc.initial);
         assert(v.loc != Loc.initial);
 
-        if (auto ld = this.loc.linnum - v.loc.linnum)
-            return ld < 0;
+        if (this.loc.linnum != v.loc.linnum)
+            return this.loc.linnum < v.loc.linnum;
 
-        if (auto cd = this.loc.charnum - v.loc.charnum)
-            return cd < 0;
+        if (this.loc.charnum != v.loc.charnum)
+            return this.loc.charnum < v.loc.charnum;
 
         // Default fallback
         return this.sequenceNumber < v.sequenceNumber;
@@ -1930,9 +1934,9 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
  */
 extern (C++) final class SymbolDeclaration : Declaration
 {
-    StructDeclaration dsym;
+    AggregateDeclaration dsym;
 
-    extern (D) this(const ref Loc loc, StructDeclaration dsym)
+    extern (D) this(const ref Loc loc, AggregateDeclaration dsym)
     {
         super(loc, dsym.ident);
         this.dsym = dsym;
index 4a4c35304177c3a62b84f3281ec9353165a86e19..884146e141669c0ca7f9a582943a330e540e4dd3 100644 (file)
@@ -53,7 +53,7 @@ struct IntRange;
     #define STCforeach            0x4000ULL    /// variable for foreach loop
     #define STCvariadic           0x8000ULL    /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
 
-    #define STCctorinit           0x10000ULL    /// can only be set inside constructor
+    //                            0x10000ULL
     #define STCtemplateparameter  0x20000ULL    /// template parameter
     #define STCref                0x40000ULL    /// `ref`
     #define STCscope              0x80000ULL    /// `scope`
@@ -65,7 +65,7 @@ struct IntRange;
 
     #define STCreturninferred     0x1000000ULL    /// `return` has been inferred and should not be part of mangling, `return` must also be set
     #define STCimmutable          0x2000000ULL    /// `immutable`
-    #define STCinit               0x4000000ULL    /// has explicit initializer
+    //                            0x4000000ULL
     #define STCmanifest           0x8000000ULL    /// manifest constant
 
     #define STCnodtor             0x10000000ULL    /// do not run destructor
@@ -131,7 +131,6 @@ public:
     virtual bool isDataseg();
     virtual bool isThreadlocal();
     virtual bool isCodeseg() const;
-    bool isCtorinit() const     { return (storage_class & STCctorinit) != 0; }
     bool isFinal() const        { return (storage_class & STCfinal) != 0; }
     virtual bool isAbstract()   { return (storage_class & STCabstract) != 0; }
     bool isConst() const        { return (storage_class & STCconst) != 0; }
@@ -247,6 +246,7 @@ public:
     bool ctorinit;              // it has been initialized in a ctor
     bool iscatchvar;            // this is the exception object variable in catch() clause
     bool isowner;               // this is an Owner, despite it being `scope`
+    bool setInCtorOnly;         // field can only be set in a constructor, as it is const or immutable
     bool onstack;               // it is a class that was allocated on the stack
     bool mynew;                 // it is a class new'd with custom operator new
     char canassign;             // it can be assigned to
@@ -266,6 +266,7 @@ public:
     bool needThis();
     bool isExport() const;
     bool isImportedSymbol() const;
+    bool isCtorinit() const;
     bool isDataseg();
     bool isThreadlocal();
     bool isCTFE();
@@ -303,7 +304,7 @@ public:
 class SymbolDeclaration : public Declaration
 {
 public:
-    StructDeclaration *dsym;
+    AggregateDeclaration *dsym;
 
     // Eliminate need for dynamic_cast
     SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
index a1f36c0c48f9259e9f7a8a8bde479d65ec1ec9a1..891adb3c6bdc677823a127ff5641946603ec3d8a 100644 (file)
@@ -34,6 +34,7 @@ import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
+import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.init;
@@ -63,26 +64,26 @@ public Expression ctfeInterpret(Expression e)
 {
     switch (e.op)
     {
-        case TOK.int64:
-        case TOK.float64:
-        case TOK.complex80:
-        case TOK.null_:
-        case TOK.void_:
-        case TOK.string_:
-        case TOK.this_:
-        case TOK.super_:
-        case TOK.type:
-        case TOK.typeid_:
-        case TOK.template_:              // non-eponymous template/instance
-        case TOK.scope_:                 // ditto
-        case TOK.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
-        case TOK.dotTemplateInstance:    // ditto
-        case TOK.dot:                    // ditto
+        case EXP.int64:
+        case EXP.float64:
+        case EXP.complex80:
+        case EXP.null_:
+        case EXP.void_:
+        case EXP.string_:
+        case EXP.this_:
+        case EXP.super_:
+        case EXP.type:
+        case EXP.typeid_:
+        case EXP.template_:              // non-eponymous template/instance
+        case EXP.scope_:                 // ditto
+        case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
+        case EXP.dotTemplateInstance:    // ditto
+        case EXP.dot:                    // ditto
              if (e.type.ty == Terror)
                 return ErrorExp.get();
-            goto case TOK.error;
+            goto case EXP.error;
 
-        case TOK.error:
+        case EXP.error:
             return e;
 
         default:
@@ -115,7 +116,7 @@ public Expression ctfeInterpret(Expression e)
  */
 public Expression ctfeInterpretForPragmaMsg(Expression e)
 {
-    if (e.op == TOK.error || e.op == TOK.type)
+    if (e.op == EXP.error || e.op == EXP.type)
         return e;
 
     // It's also OK for it to be a function declaration (happens only with
@@ -410,7 +411,7 @@ private struct InterState
  *      thisarg   = 'this', if a needThis() function, NULL if not.
  *
  * Returns:
- * result expression if successful, TOK.cantExpression if not,
+ * result expression if successful, EXP.cantExpression if not,
  * or CTFEExp if function returned void.
  */
 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
@@ -507,7 +508,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
             /* Struct literals are passed by value, but we don't need to
              * copy them if they are passed as const
              */
-            if (earg.op == TOK.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
+            if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
                 earg = copyLiteral(earg).copy();
         }
         if (auto tee = earg.isThrownExceptionExp())
@@ -563,7 +564,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
         }
         ctfeGlobals.stack.push(v);
 
-        if (fparam.isReference() && earg.op == TOK.variable &&
+        if (fparam.isReference() && earg.op == EXP.variable &&
             earg.isVarExp().var.toParent2() == fd)
         {
             VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
@@ -660,16 +661,16 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
         }
         else
         {
-            assert(!e || (e.op != TOK.continue_ && e.op != TOK.break_));
+            assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
             break;
         }
     }
     // If fell off the end of a void function, return void
     if (!e && tf.next.ty == Tvoid)
         e = CTFEExp.voidexp;
-    if (tf.isref && e.op == TOK.variable && e.isVarExp().var == fd.vthis)
+    if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
         e = thisarg;
-    if (tf.isref && fd.isThis2 && e.op == TOK.index)
+    if (tf.isref && fd.isThis2 && e.op == EXP.index)
     {
         auto ie = e.isIndexExp();
         auto pe = ie.e1.isPtrExp();
@@ -733,14 +734,14 @@ public:
         this.goal = goal;
     }
 
-    // If e is TOK.throw_exception or TOK.cantExpression,
+    // If e is EXP.throw_exception or EXP.cantExpression,
     // set it to 'result' and returns true.
     bool exceptionOrCant(Expression e)
     {
         if (exceptionOrCantInterpret(e))
         {
             // Make sure e is not pointing to a stack temporary
-            result = (e.op == TOK.cantExpression) ? CTFEExp.cantexp : e;
+            result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
             return true;
         }
         return false;
@@ -839,7 +840,7 @@ public:
                 continue;
             if (exceptionOrCant(e))
                 return;
-            if (e.op == TOK.break_)
+            if (e.op == EXP.break_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -850,7 +851,7 @@ public:
                 result = null;
                 return;
             }
-            if (e.op == TOK.continue_)
+            if (e.op == EXP.continue_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -894,7 +895,7 @@ public:
 
         if (isTrueBool(e))
             result = interpret(pue, s.ifbody, istate);
-        else if (e.isBool(false))
+        else if (e.toBool().hasValue(false))
             result = interpret(pue, s.elsebody, istate);
         else
         {
@@ -935,7 +936,7 @@ public:
             if (auto eaddr = e.isAddrExp())
                 x = eaddr.e1;
             VarDeclaration v;
-            while (x.op == TOK.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
+            while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
             {
                 if (v.storage_class & STC.ref_)
                 {
@@ -952,7 +953,7 @@ public:
                 else
                     break;
             }
-            // TODO: If it is a TOK.dotVariable or TOK.index, we should check that it is not
+            // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
             // pointing to a local struct or static array.
         }
         if (auto se = e.isStructLiteralExp())
@@ -1023,7 +1024,7 @@ public:
             return;
         }
 
-        // We need to treat pointers specially, because TOK.symbolOffset can be used to
+        // We need to treat pointers specially, because EXP.symbolOffset can be used to
         // return a value OR a pointer
         Expression e = interpret(pue, s.exp, istate);
         if (exceptionOrCant(e))
@@ -1122,7 +1123,7 @@ public:
 
             if (exceptionOrCant(e))
                 return;
-            if (e && e.op == TOK.break_)
+            if (e && e.op == EXP.break_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -1132,7 +1133,7 @@ public:
                 istate.gotoTarget = null;
                 break;
             }
-            if (e && e.op == TOK.continue_)
+            if (e && e.op == EXP.continue_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -1158,7 +1159,7 @@ public:
                 result = CTFEExp.cantexp;
                 return;
             }
-            if (e.isBool(false))
+            if (e.toBool().hasValue(false))
                 break;
             assert(isTrueBool(e));
         }
@@ -1189,7 +1190,7 @@ public:
                 Expression e = interpret(&ue, s.condition, istate);
                 if (exceptionOrCant(e))
                     return;
-                if (e.isBool(false))
+                if (e.toBool().hasValue(false))
                     break;
                 assert(isTrueBool(e));
             }
@@ -1201,7 +1202,7 @@ public:
 
             if (exceptionOrCant(e))
                 return;
-            if (e && e.op == TOK.break_)
+            if (e && e.op == EXP.break_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -1211,7 +1212,7 @@ public:
                 istate.gotoTarget = null;
                 break;
             }
-            if (e && e.op == TOK.continue_)
+            if (e && e.op == EXP.continue_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -1263,7 +1264,7 @@ public:
                 return;
             if (exceptionOrCant(e))
                 return;
-            if (e && e.op == TOK.break_)
+            if (e && e.op == EXP.break_)
             {
                 if (istate.gotoTarget && istate.gotoTarget != s)
                 {
@@ -1290,7 +1291,7 @@ public:
                 Expression ecase = interpret(&uecase, cs.exp, istate);
                 if (exceptionOrCant(ecase))
                     return;
-                if (ctfeEqual(cs.exp.loc, TOK.equal, econdition, ecase))
+                if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
                 {
                     scase = cs;
                     break;
@@ -1310,7 +1311,7 @@ public:
         istate.start = scase;
         Expression e = interpret(pue, s._body, istate);
         assert(!istate.start); // jump must not fail
-        if (e && e.op == TOK.break_)
+        if (e && e.op == EXP.break_)
         {
             if (istate.gotoTarget && istate.gotoTarget != s)
             {
@@ -1515,7 +1516,7 @@ public:
             (*collateral.value.elements)[bypass] = boss;
             return newest;
         }
-        while ((*boss.value.elements)[next].op == TOK.classReference)
+        while ((*boss.value.elements)[next].op == EXP.classReference)
         {
             boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
         }
@@ -1606,7 +1607,7 @@ public:
         if (exceptionOrCant(e))
             return;
 
-        assert(e.op == TOK.classReference);
+        assert(e.op == EXP.classReference);
         result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
     }
 
@@ -1630,7 +1631,7 @@ public:
         }
 
         // If it is with(Enum) {...}, just execute the body.
-        if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
+        if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
         {
             result = interpret(pue, s._body, istate);
             return;
@@ -1707,7 +1708,7 @@ public:
     {
         debug (LOG)
         {
-            printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
+            printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
             printf("type = %s\n", e.type.toChars());
             showCtfeExpr(e);
         }
@@ -1755,9 +1756,9 @@ public:
         {
             if (istate && istate.fd.isThis2)
             {
-                assert(result.op == TOK.address);
+                assert(result.op == EXP.address);
                 result = (cast(AddrExp)result).e1;
-                assert(result.op == TOK.arrayLiteral);
+                assert(result.op == EXP.arrayLiteral);
                 result = (*(cast(ArrayLiteralExp)result).elements)[0];
                 if (e.type.ty == Tstruct)
                 {
@@ -1765,7 +1766,7 @@ public:
                 }
                 return;
             }
-            assert(result.op == TOK.structLiteral || result.op == TOK.classReference || result.op == TOK.type);
+            assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
             return;
         }
         e.error("value of `this` is not known at compile time");
@@ -1909,7 +1910,7 @@ public:
             dinteger_t indx = e.offset / sz;
             assert(sz * indx == e.offset);
             Expression aggregate = null;
-            if (val.op == TOK.arrayLiteral || val.op == TOK.string_)
+            if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
             {
                 aggregate = val;
             }
@@ -2054,13 +2055,13 @@ public:
                     return CTFEExp.cantexp;
                 assert(e.type);
 
-                if (e.op == TOK.construct || e.op == TOK.blit)
+                if (e.op == EXP.construct || e.op == EXP.blit)
                 {
                     AssignExp ae = cast(AssignExp)e;
                     e = ae.e2;
                 }
 
-                if (e.op == TOK.error)
+                if (e.op == EXP.error)
                 {
                     // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
                 }
@@ -2142,12 +2143,20 @@ public:
         }
         else if (SymbolDeclaration s = d.isSymbolDeclaration())
         {
+            // exclude void[]-typed `__traits(initSymbol)`
+            if (auto ta = s.type.toBasetype().isTypeDArray())
+            {
+                assert(ta.next.ty == Tvoid);
+                error(loc, "cannot determine the address of the initializer symbol during CTFE");
+                return CTFEExp.cantexp;
+            }
+
             // Struct static initializers, for example
             e = s.dsym.type.defaultInitLiteral(loc);
-            if (e.op == TOK.error)
+            if (e.op == EXP.error)
                 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
             e = e.expressionSemantic(null);
-            if (e.op == TOK.error)
+            if (e.op == EXP.error)
                 e = CTFEExp.cantexp;
             else // Convert NULL to CTFEExp
                 e = interpret(e, istate, goal);
@@ -2195,10 +2204,10 @@ public:
                 {
                     // Strip off the nest of ref variables
                     Expression ev = getValue(v);
-                    if (ev.op == TOK.variable ||
-                        ev.op == TOK.index ||
-                        (ev.op == TOK.slice && ev.type.toBasetype().ty == Tsarray) ||
-                        ev.op == TOK.dotVariable)
+                    if (ev.op == EXP.variable ||
+                        ev.op == EXP.index ||
+                        (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
+                        ev.op == EXP.dotVariable)
                     {
                         result = interpret(pue, ev, istate, goal);
                         return;
@@ -2363,13 +2372,13 @@ public:
             if (exceptionOrCant(ex))
                 return;
 
-            if (result.op == TOK.null_)
+            if (result.op == EXP.null_)
             {
                 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
                 result = CTFEExp.cantexp;
                 return;
             }
-            if (result.op != TOK.classReference)
+            if (result.op != EXP.classReference)
             {
                 e.error("CTFE internal error: determining classinfo");
                 result = CTFEExp.cantexp;
@@ -2406,7 +2415,7 @@ public:
             // A tuple of assignments can contain void (Bug 5676).
             if (goal == CTFEGoal.Nothing)
                 continue;
-            if (ex.op == TOK.voidExpression)
+            if (ex.op == EXP.voidExpression)
             {
                 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
                 assert(0);
@@ -2464,7 +2473,7 @@ public:
             else
             {
                 // segfault bug 6250
-                assert(exp.op != TOK.index || (cast(IndexExp)exp).e1 != e);
+                assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
 
                 ex = interpretRegion(exp, istate);
                 if (exceptionOrCant(ex))
@@ -2569,7 +2578,7 @@ public:
             for (size_t j = i; j < keysx.dim; j++)
             {
                 auto ekey2 = (*keysx)[j];
-                if (!ctfeEqual(e.loc, TOK.equal, ekey, ekey2))
+                if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
                     continue;
 
                 // Remove ekey
@@ -2904,15 +2913,15 @@ public:
             return;
         switch (e.op)
         {
-        case TOK.negate:
+        case EXP.negate:
             *pue = Neg(e.type, e1);
             break;
 
-        case TOK.tilde:
+        case EXP.tilde:
             *pue = Com(e.type, e1);
             break;
 
-        case TOK.not:
+        case EXP.not:
             *pue = Not(e.type, e1);
             break;
 
@@ -2948,7 +2957,7 @@ public:
         {
             printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
         }
-        if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == TOK.min)
+        if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
         {
             UnionExp ue1 = void;
             Expression e1 = interpret(&ue1, e.e1, istate);
@@ -2976,7 +2985,7 @@ public:
             result = (*pue).exp();
             return;
         }
-        if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == TOK.add)
+        if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
         {
             UnionExp ue1 = void;
             Expression e1 = interpret(&ue1, e.e1, istate);
@@ -3015,7 +3024,7 @@ public:
         if (!evalOperand(&ue2, e.e2, e2))
             return;
 
-        if (e.op == TOK.rightShift || e.op == TOK.leftShift || e.op == TOK.unsignedRightShift)
+        if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
         {
             const sinteger_t i2 = e2.toInteger();
             const d_uns64 sz = e1.type.size() * 8;
@@ -3073,13 +3082,13 @@ public:
             {
                 // The following should really be an assert()
                 e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
-                emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+                emplaceExp!CTFEExp(&ue, EXP.cantExpression);
                 return ue;
             }
             if (e2.isConst() != 1)
             {
                 e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
-                emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+                emplaceExp!CTFEExp(&ue, EXP.cantExpression);
                 return ue;
             }
 
@@ -3116,7 +3125,7 @@ public:
             const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
             if (cmp == -1)
             {
-                char dir = (e.op == TOK.greaterThan || e.op == TOK.greaterOrEqual) ? '<' : '>';
+                char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
                 e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
                 result = CTFEExp.cantexp;
                 return;
@@ -3162,73 +3171,73 @@ public:
     {
         switch (e.op)
         {
-        case TOK.add:
+        case EXP.add:
             interpretCommon(e, &Add);
             return;
 
-        case TOK.min:
+        case EXP.min:
             interpretCommon(e, &Min);
             return;
 
-        case TOK.mul:
+        case EXP.mul:
             interpretCommon(e, &Mul);
             return;
 
-        case TOK.div:
+        case EXP.div:
             interpretCommon(e, &Div);
             return;
 
-        case TOK.mod:
+        case EXP.mod:
             interpretCommon(e, &Mod);
             return;
 
-        case TOK.leftShift:
+        case EXP.leftShift:
             interpretCommon(e, &Shl);
             return;
 
-        case TOK.rightShift:
+        case EXP.rightShift:
             interpretCommon(e, &Shr);
             return;
 
-        case TOK.unsignedRightShift:
+        case EXP.unsignedRightShift:
             interpretCommon(e, &Ushr);
             return;
 
-        case TOK.and:
+        case EXP.and:
             interpretCommon(e, &And);
             return;
 
-        case TOK.or:
+        case EXP.or:
             interpretCommon(e, &Or);
             return;
 
-        case TOK.xor:
+        case EXP.xor:
             interpretCommon(e, &Xor);
             return;
 
-        case TOK.pow:
+        case EXP.pow:
             interpretCommon(e, &Pow);
             return;
 
-        case TOK.equal:
-        case TOK.notEqual:
+        case EXP.equal:
+        case EXP.notEqual:
             interpretCompareCommon(e, &ctfeEqual);
             return;
 
-        case TOK.identity:
-        case TOK.notIdentity:
+        case EXP.identity:
+        case EXP.notIdentity:
             interpretCompareCommon(e, &ctfeIdentity);
             return;
 
-        case TOK.lessThan:
-        case TOK.lessOrEqual:
-        case TOK.greaterThan:
-        case TOK.greaterOrEqual:
+        case EXP.lessThan:
+        case EXP.lessOrEqual:
+        case EXP.greaterThan:
+        case EXP.greaterOrEqual:
             interpretCompareCommon(e, &ctfeCmp);
             return;
 
         default:
-            printf("be = '%s' %s at [%s]\n", Token.toChars(e.op), e.toChars(), e.loc.toChars());
+            printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
             assert(0);
         }
     }
@@ -3286,7 +3295,7 @@ public:
          * So we need to recurse to determine if it is a block assignment.
          */
         bool isBlockAssignment = false;
-        if (e1.op == TOK.slice)
+        if (e1.op == EXP.slice)
         {
             // a[] = e can have const e. So we compare the naked types.
             Type tdst = e1.type.toBasetype();
@@ -3306,7 +3315,7 @@ public:
         //      Deal with reference assignment
         // ---------------------------------------
         // If it is a construction of a ref variable, it is a ref assignment
-        if ((e.op == TOK.construct || e.op == TOK.blit) &&
+        if ((e.op == EXP.construct || e.op == EXP.blit) &&
             ((cast(AssignExp)e).memset == MemorySet.referenceInit))
         {
             assert(!fp);
@@ -3329,7 +3338,7 @@ public:
 
         if (fp)
         {
-            while (e1.op == TOK.cast_)
+            while (e1.op == EXP.cast_)
             {
                 CastExp ce = cast(CastExp)e1;
                 e1 = ce.e1;
@@ -3342,7 +3351,7 @@ public:
         AssocArrayLiteralExp existingAA = null;
         Expression lastIndex = null;
         Expression oldval = null;
-        if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+        if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
         {
             // ---------------------------------------
             //      Deal with AA index assignment
@@ -3356,7 +3365,7 @@ public:
              */
             IndexExp ie = cast(IndexExp)e1;
             int depth = 0; // how many nested AA indices are there?
-            while (ie.e1.op == TOK.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
+            while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
             {
                 assert(ie.modifiable);
                 ie = cast(IndexExp)ie.e1;
@@ -3430,7 +3439,7 @@ public:
                 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
 
                 Expression newaae = oldval;
-                while (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+                while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
                 {
                     Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
                     if (exceptionOrCant(ekey))
@@ -3465,13 +3474,13 @@ public:
             assert(existingAA && lastIndex);
             e1 = null; // stomp
         }
-        else if (e1.op == TOK.arrayLength)
+        else if (e1.op == EXP.arrayLength)
         {
             oldval = interpretRegion(e1, istate);
             if (exceptionOrCant(oldval))
                 return;
         }
-        else if (e.op == TOK.construct || e.op == TOK.blit)
+        else if (e.op == EXP.construct || e.op == EXP.blit)
         {
             // Unless we have a simple var assignment, we're
             // only modifying part of the variable. So we need to make sure
@@ -3501,10 +3510,10 @@ public:
             if (exceptionOrCant(e1))
                 return;
 
-            if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+            if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
             {
                 IndexExp ie = cast(IndexExp)e1;
-                assert(ie.e1.op == TOK.assocArrayLiteral);
+                assert(ie.e1.op == EXP.assocArrayLiteral);
                 existingAA = cast(AssocArrayLiteralExp)ie.e1;
                 lastIndex = ie.e2;
             }
@@ -3516,7 +3525,7 @@ public:
         Expression newval = interpretRegion(e.e2, istate);
         if (exceptionOrCant(newval))
             return;
-        if (e.op == TOK.blit && newval.op == TOK.int64)
+        if (e.op == EXP.blit && newval.op == EXP.int64)
         {
             Type tbn = e.type.baseElemOf();
             if (tbn.ty == Tstruct)
@@ -3524,7 +3533,7 @@ public:
                 /* Look for special case of struct being initialized with 0.
                  */
                 newval = e.type.defaultInitLiteral(e.loc);
-                if (newval.op == TOK.error)
+                if (newval.op == EXP.error)
                 {
                     result = CTFEExp.cantexp;
                     return;
@@ -3554,7 +3563,7 @@ public:
             if (e.e1.type.ty != Tpointer)
             {
                 // ~= can create new values (see bug 6052)
-                if (e.op == TOK.concatenateAssign || e.op == TOK.concatenateElemAssign || e.op == TOK.concatenateDcharAssign)
+                if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
                 {
                     // We need to dup it and repaint the type. For a dynamic array
                     // we can skip duplication, because it gets copied later anyway.
@@ -3574,10 +3583,10 @@ public:
                 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
             }
             else if (e.e2.type.isintegral() &&
-                     (e.op == TOK.addAssign ||
-                      e.op == TOK.minAssign ||
-                      e.op == TOK.plusPlus ||
-                      e.op == TOK.minusMinus))
+                     (e.op == EXP.addAssign ||
+                      e.op == EXP.minAssign ||
+                      e.op == EXP.plusPlus ||
+                      e.op == EXP.minusMinus))
             {
                 newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
             }
@@ -3612,7 +3621,7 @@ public:
             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
             return;
         }
-        if (e1.op == TOK.arrayLength)
+        if (e1.op == EXP.arrayLength)
         {
             /* Change the assignment from:
              *  arr.length = n;
@@ -3692,11 +3701,11 @@ public:
 
         /* Block assignment or element-wise assignment.
          */
-        if (e1.op == TOK.slice ||
-            e1.op == TOK.vector ||
-            e1.op == TOK.arrayLiteral ||
-            e1.op == TOK.string_ ||
-            e1.op == TOK.null_ && e1.type.toBasetype().ty == Tarray)
+        if (e1.op == EXP.slice ||
+            e1.op == EXP.vector ||
+            e1.op == EXP.arrayLiteral ||
+            e1.op == EXP.string_ ||
+            e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
         {
             // Note that slice assignments don't support things like ++, so
             // we don't need to remember 'returnValue'.
@@ -3709,8 +3718,8 @@ public:
                 if (auto dve = e1x.isDotVarExp())
                 {
                     auto ex = dve.e1;
-                    auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
-                             : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
+                    auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
+                             : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
                              : null;
                     auto v = dve.var.isVarDeclaration();
                     if (!sle || !v)
@@ -3745,7 +3754,7 @@ public:
             if (v is v2 || !v.isOverlappedWith(v2))
                 continue;
             auto e = (*sle.elements)[i];
-            if (e.op != TOK.void_)
+            if (e.op != EXP.void_)
                 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
         }
     }
@@ -3768,8 +3777,8 @@ public:
              *  e.v = newval
              */
             auto ex = dve.e1;
-            auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
-                     : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
+            auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
+                     : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
                      : null;
             auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
             if (!sle || !v)
@@ -3783,7 +3792,7 @@ public:
                 return CTFEExp.cantexp;
             }
 
-            int fieldi = ex.op == TOK.structLiteral ? findFieldIndexByName(sle.sd, v)
+            int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
                        : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
             if (fieldi == -1)
             {
@@ -3820,7 +3829,7 @@ public:
                 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
                 return null;
             }
-            if (aggregate.op != TOK.arrayLiteral)
+            if (aggregate.op != EXP.arrayLiteral)
             {
                 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
                 return CTFEExp.cantexp;
@@ -3848,7 +3857,7 @@ public:
         if (auto ve = newval.isVectorExp())
         {
             // Ensure ve is an array literal, and not a broadcast
-            if (ve.e1.op == TOK.int64 || ve.e1.op == TOK.float64) // if broadcast
+            if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
             {
                 UnionExp ue = void;
                 Expression ex = interpretVectorToArray(&ue, ve);
@@ -3856,13 +3865,13 @@ public:
             }
         }
 
-        if (newval.op == TOK.structLiteral && oldval)
+        if (newval.op == EXP.structLiteral && oldval)
         {
-            assert(oldval.op == TOK.structLiteral || oldval.op == TOK.arrayLiteral || oldval.op == TOK.string_);
+            assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
             newval = copyLiteral(newval).copy();
             assignInPlace(oldval, newval);
         }
-        else if (wantCopy && e.op == TOK.assign)
+        else if (wantCopy && e.op == EXP.assign)
         {
             // Currently postblit/destructor calls on static array are done
             // in the druntime internal functions so they don't appear in AST.
@@ -3878,8 +3887,8 @@ public:
                     return CTFEExp.cantexp;
                 }
             }
-            assert(oldval.op == TOK.arrayLiteral);
-            assert(newval.op == TOK.arrayLiteral);
+            assert(oldval.op == EXP.arrayLiteral);
+            assert(newval.op == EXP.arrayLiteral);
 
             Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
             Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
@@ -3907,7 +3916,7 @@ public:
             if (wantCopy)
                 newval = copyLiteral(newval).copy();
 
-            if (t1b.ty == Tsarray && e.op == TOK.construct && e.e2.isLvalue())
+            if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
             {
                 // https://issues.dlang.org/show_bug.cgi?id=9245
                 if (Expression ex = evaluatePostblit(istate, newval))
@@ -3923,7 +3932,7 @@ public:
             *payload = oldval;
 
         // Blit assignment should return the newly created value.
-        if (e.op == TOK.blit)
+        if (e.op == EXP.blit)
             return oldval;
 
         return null;
@@ -3938,7 +3947,7 @@ public:
      * This could be a slice assignment or a block assignment, and
      * dest could be either an array literal, or a string.
      *
-     * Returns TOK.cantExpression on failure. If there are no errors,
+     * Returns EXP.cantExpression on failure. If there are no errors,
      * it returns aggregate[low..upp], except that as an optimisation,
      * if goal == CTFEGoal.Nothing, it will return NULL
      */
@@ -4024,7 +4033,7 @@ public:
                 lowerbound = 0;
                 upperbound = se.len;
             }
-            else if (e1.op == TOK.null_)
+            else if (e1.op == EXP.null_)
             {
                 lowerbound = 0;
                 upperbound = 0;
@@ -4088,7 +4097,7 @@ public:
                         return CTFEExp.cantexp;
                     }
                 }
-                assert(newval.op != TOK.slice);
+                assert(newval.op != EXP.slice);
             }
             if (auto se = newval.isStringExp())
             {
@@ -4126,7 +4135,7 @@ public:
                 return CTFEExp.cantexp;
             }
 
-            if (newval.op == TOK.slice && !isBlockAssignment)
+            if (newval.op == EXP.slice && !isBlockAssignment)
             {
                 auto se = cast(SliceExp)newval;
                 auto aggr2 = se.e1;
@@ -4142,7 +4151,7 @@ public:
                     // Currently overlapping for struct array is allowed.
                     // The order of elements processing depends on the overlapping.
                     // https://issues.dlang.org/show_bug.cgi?id=14024
-                    assert(aggr2.op == TOK.arrayLiteral);
+                    assert(aggr2.op == EXP.arrayLiteral);
                     Expressions* oldelems = existingAE.elements;
                     Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
 
@@ -4210,9 +4219,9 @@ public:
                 }
                 // no overlapping
                 //length?
-                assert(newval.op != TOK.slice);
+                assert(newval.op != EXP.slice);
             }
-            if (newval.op == TOK.string_ && !isBlockAssignment)
+            if (newval.op == EXP.string_ && !isBlockAssignment)
             {
                 /* Mixed slice: it was initialized as an array literal of chars/integers.
                  * Now a slice of it is being set with a string.
@@ -4220,12 +4229,12 @@ public:
                 sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex);
                 return newval;
             }
-            if (newval.op == TOK.arrayLiteral && !isBlockAssignment)
+            if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
             {
                 Expressions* oldelems = existingAE.elements;
                 Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
                 Type elemtype = existingAE.type.nextOf();
-                bool needsPostblit = e.op != TOK.blit && e.e2.isLvalue();
+                bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
                 foreach (j, newelem; *newelems)
                 {
                     newelem = paintTypeOntoLiteral(elemtype, newelem);
@@ -4265,7 +4274,7 @@ public:
                     bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
                     for (size_t k = lwr; k < upr; k++)
                     {
-                        if (!directblk && (*w)[k].op == TOK.arrayLiteral)
+                        if (!directblk && (*w)[k].op == EXP.arrayLiteral)
                         {
                             // Multidimensional array block assign
                             if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
@@ -4303,7 +4312,7 @@ public:
 
             Type tn = newval.type.toBasetype();
             bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
-            bool cow = newval.op != TOK.structLiteral && newval.op != TOK.arrayLiteral && newval.op != TOK.string_;
+            bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
             Type tb = tn.baseElemOf();
             StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
 
@@ -4311,8 +4320,8 @@ public:
             rb.istate = istate;
             rb.newval = newval;
             rb.refCopy = wantRef || cow;
-            rb.needsPostblit = sd && sd.postblit && e.op != TOK.blit && e.e2.isLvalue();
-            rb.needsDtor = sd && sd.dtor && e.op == TOK.assign;
+            rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
+            rb.needsDtor = sd && sd.dtor && e.op == EXP.assign;
             if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
                 return ex;
 
@@ -4338,57 +4347,57 @@ public:
     {
         switch (e.op)
         {
-        case TOK.addAssign:
+        case EXP.addAssign:
             interpretAssignCommon(e, &Add);
             return;
 
-        case TOK.minAssign:
+        case EXP.minAssign:
             interpretAssignCommon(e, &Min);
             return;
 
-        case TOK.concatenateAssign:
-        case TOK.concatenateElemAssign:
-        case TOK.concatenateDcharAssign:
+        case EXP.concatenateAssign:
+        case EXP.concatenateElemAssign:
+        case EXP.concatenateDcharAssign:
             interpretAssignCommon(e, &ctfeCat);
             return;
 
-        case TOK.mulAssign:
+        case EXP.mulAssign:
             interpretAssignCommon(e, &Mul);
             return;
 
-        case TOK.divAssign:
+        case EXP.divAssign:
             interpretAssignCommon(e, &Div);
             return;
 
-        case TOK.modAssign:
+        case EXP.modAssign:
             interpretAssignCommon(e, &Mod);
             return;
 
-        case TOK.leftShiftAssign:
+        case EXP.leftShiftAssign:
             interpretAssignCommon(e, &Shl);
             return;
 
-        case TOK.rightShiftAssign:
+        case EXP.rightShiftAssign:
             interpretAssignCommon(e, &Shr);
             return;
 
-        case TOK.unsignedRightShiftAssign:
+        case EXP.unsignedRightShiftAssign:
             interpretAssignCommon(e, &Ushr);
             return;
 
-        case TOK.andAssign:
+        case EXP.andAssign:
             interpretAssignCommon(e, &And);
             return;
 
-        case TOK.orAssign:
+        case EXP.orAssign:
             interpretAssignCommon(e, &Or);
             return;
 
-        case TOK.xorAssign:
+        case EXP.xorAssign:
             interpretAssignCommon(e, &Xor);
             return;
 
-        case TOK.powAssign:
+        case EXP.powAssign:
             interpretAssignCommon(e, &Pow);
             return;
 
@@ -4403,7 +4412,7 @@ public:
         {
             printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
         }
-        if (e.op == TOK.plusPlus)
+        if (e.op == EXP.plusPlus)
             interpretAssignCommon(e, &Add, 1);
         else
             interpretAssignCommon(e, &Min, 1);
@@ -4421,19 +4430,19 @@ public:
     static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
     {
         int ret = 1;
-        while (e.op == TOK.not)
+        while (e.op == EXP.not)
         {
             ret *= -1;
             e = (cast(NotExp)e).e1;
         }
         switch (e.op)
         {
-        case TOK.lessThan:
-        case TOK.lessOrEqual:
+        case EXP.lessThan:
+        case EXP.lessOrEqual:
             ret *= -1;
             goto case; /+ fall through +/
-        case TOK.greaterThan:
-        case TOK.greaterOrEqual:
+        case EXP.greaterThan:
+        case EXP.greaterOrEqual:
             *p1 = (cast(BinExp)e).e1;
             *p2 = (cast(BinExp)e).e2;
             if (!(isPointer((*p1).type) && isPointer((*p2).type)))
@@ -4465,7 +4474,7 @@ public:
      */
     private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
     {
-        assert(e.op == TOK.andAnd || e.op == TOK.orOr);
+        assert(e.op == EXP.andAnd || e.op == EXP.orOr);
 
         /*  It can only be an isInside expression, if both e1 and e2 are
          *  directional pointer comparisons.
@@ -4506,7 +4515,7 @@ public:
         Expression agg1 = getAggregateFromPointer(p1, &ofs1);
         Expression agg2 = getAggregateFromPointer(p2, &ofs2);
 
-        if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != TOK.null_ && agg2.op != TOK.null_)
+        if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
         {
             // Here it is either CANT_INTERPRET,
             // or an IsInside comparison returning false.
@@ -4545,7 +4554,7 @@ public:
                 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
             {
                 // it's a legal two-sided comparison
-                emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
+                emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
                 result = pue.exp();
                 return;
             }
@@ -4582,29 +4591,29 @@ public:
          * Returns:
          *      negate operator
          */
-        static TOK negateRelation(TOK op) pure
+        static EXP negateRelation(EXP op) pure
         {
             switch (op)
             {
-                case TOK.greaterOrEqual:  op = TOK.lessThan;       break;
-                case TOK.greaterThan:     op = TOK.lessOrEqual;    break;
-                case TOK.lessOrEqual:     op = TOK.greaterThan;    break;
-                case TOK.lessThan:        op = TOK.greaterOrEqual; break;
+                case EXP.greaterOrEqual:  op = EXP.lessThan;       break;
+                case EXP.greaterThan:     op = EXP.lessOrEqual;    break;
+                case EXP.lessOrEqual:     op = EXP.greaterThan;    break;
+                case EXP.lessThan:        op = EXP.greaterOrEqual; break;
                 default:                  assert(0);
             }
             return op;
         }
 
-        const TOK cmpop = nott ? negateRelation(ex.op) : ex.op;
+        const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
         const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
         // We already know this is a valid comparison.
         assert(cmp >= 0);
-        if (e.op == TOK.andAnd && cmp == 1 || e.op == TOK.orOr && cmp == 0)
+        if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
         {
             result = interpret(pue, e.e2, istate);
             return;
         }
-        emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
+        emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
         result = pue.exp();
     }
 
@@ -4625,22 +4634,22 @@ public:
             return;
 
         bool res;
-        const andand = e.op == TOK.andAnd;
-        if (andand ? result.isBool(false) : isTrueBool(result))
+        const andand = e.op == EXP.andAnd;
+        if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
             res = !andand;
-        else if (andand ? isTrueBool(result) : result.isBool(false))
+        else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
         {
             UnionExp ue2 = void;
             result = interpret(&ue2, e.e2, istate);
             if (exceptionOrCant(result))
                 return;
-            if (result.op == TOK.voidExpression)
+            if (result.op == EXP.voidExpression)
             {
                 assert(e.type.ty == Tvoid);
                 result = null;
                 return;
             }
-            if (result.isBool(false))
+            if (result.toBool().hasValue(false))
                 res = false;
             else if (isTrueBool(result))
                 res = true;
@@ -4762,8 +4771,8 @@ public:
                 if (auto ce = ea.isCastExp())
                     ea = ce.e1;
 
-                // printf("2 ea = %s, %s %s\n", ea.type.toChars(), Token.toChars(ea.op), ea.toChars());
-                if (ea.op == TOK.variable || ea.op == TOK.symbolOffset)
+                // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
+                if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
                     result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
                 else if (auto ae = ea.isAddrExp())
                     result = interpretRegion(ae.e1, istate);
@@ -4805,6 +4814,29 @@ public:
                 result = interpretRegion(ae, istate);
                 return;
             }
+            else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor)
+            {
+                // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`.
+                // The following code will rewrite it back to `ea = eb` and then interpret that expression.
+                if (fd.ident == Id._d_arraysetctor)
+                    assert(e.arguments.dim == 2);
+                else
+                    assert(e.arguments.dim == 3);
+
+                Expression ea = (*e.arguments)[0];
+                if (ea.isCastExp)
+                    ea = ea.isCastExp.e1;
+
+                Expression eb = (*e.arguments)[1];
+                if (eb.isCastExp && fd.ident == Id._d_arrayctor)
+                    eb = eb.isCastExp.e1;
+
+                ConstructExp ce = new ConstructExp(e.loc, ea, eb);
+                ce.type = ea.type;
+
+                result = interpret(ce, istate);
+                return;
+            }
         }
         else if (auto soe = ecall.isSymOffExp())
         {
@@ -4848,7 +4880,7 @@ public:
             // Currently this is satisfied because closure is not yet supported.
             assert(!fd.isNested() || fd.needThis());
 
-            if (pthis.op == TOK.typeid_)
+            if (pthis.op == EXP.typeid_)
             {
                 pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
                 result = CTFEExp.cantexp;
@@ -4856,7 +4888,7 @@ public:
             }
             assert(pthis);
 
-            if (pthis.op == TOK.null_)
+            if (pthis.op == EXP.null_)
             {
                 assert(pthis.type.toBasetype().ty == Tclass);
                 e.error("function call through null class reference `%s`", pthis.toChars());
@@ -4864,7 +4896,7 @@ public:
                 return;
             }
 
-            assert(pthis.op == TOK.structLiteral || pthis.op == TOK.classReference || pthis.op == TOK.type);
+            assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
 
             if (fd.isVirtual() && !e.directcall)
             {
@@ -4899,7 +4931,7 @@ public:
         }
 
         result = interpretFunction(pue, fd, istate, e.arguments, pthis);
-        if (result.op == TOK.voidExpression)
+        if (result.op == EXP.voidExpression)
             return;
         if (!exceptionOrCantInterpret(result))
         {
@@ -4929,7 +4961,7 @@ public:
         // If it creates a variable, and there's no context for
         // the variable to be created in, we need to create one now.
         InterState istateComma;
-        if (!istate && firstComma(e.e1).op == TOK.declaration)
+        if (!istate && firstComma(e.e1).op == EXP.declaration)
         {
             ctfeGlobals.stack.startFrame(null);
             istate = &istateComma;
@@ -4946,8 +4978,8 @@ public:
 
         // If the comma returns a temporary variable, it needs to be an lvalue
         // (this is particularly important for struct constructors)
-        if (e.e1.op == TOK.declaration &&
-            e.e2.op == TOK.variable &&
+        if (e.e1.op == EXP.declaration &&
+            e.e2.op == EXP.variable &&
             e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
             e.e2.isVarExp().var.storage_class & STC.ctfe)
         {
@@ -4967,7 +4999,7 @@ public:
                 newval = interpretRegion(newval, istate);
                 if (exceptionOrCant(newval))
                     return endTempStackFrame();
-                if (newval.op != TOK.voidExpression)
+                if (newval.op != EXP.voidExpression)
                 {
                     // v isn't necessarily null.
                     setValueWithoutChecking(v, copyLiteral(newval).copy());
@@ -4999,7 +5031,7 @@ public:
 
         if (isPointer(e.econd.type))
         {
-            if (econd.op != TOK.null_)
+            if (econd.op != EXP.null_)
             {
                 econd = IntegerExp.createBool(true);
             }
@@ -5010,7 +5042,7 @@ public:
             result = interpret(pue, e.e1, istate, goal);
             incUsageCtfe(istate, e.e1.loc);
         }
-        else if (econd.isBool(false))
+        else if (econd.toBool().hasValue(false))
         {
             result = interpret(pue, e.e2, istate, goal);
             incUsageCtfe(istate, e.e2.loc);
@@ -5033,7 +5065,7 @@ public:
         assert(e1);
         if (exceptionOrCant(e1))
             return;
-        if (e1.op != TOK.string_ && e1.op != TOK.arrayLiteral && e1.op != TOK.slice && e1.op != TOK.null_)
+        if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
         {
             e.error("`%s` cannot be evaluated at compile time", e.toChars());
             result = CTFEExp.cantexp;
@@ -5055,7 +5087,7 @@ public:
     {
         if (auto ale = e.e1.isArrayLiteralExp())
             return ale;         // it's already an array literal
-        if (e.e1.op == TOK.int64 || e.e1.op == TOK.float64)
+        if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
         {
             // Convert literal __vector(int) -> __vector([array])
             auto elements = new Expressions(e.dim);
@@ -5086,7 +5118,7 @@ public:
         assert(e1);
         if (exceptionOrCant(e1))
             return;
-        if (e1.op != TOK.arrayLiteral && e1.op != TOK.int64 && e1.op != TOK.float64)
+        if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
         {
             e.error("`%s` cannot be evaluated at compile time", e.toChars());
             result = CTFEExp.cantexp;
@@ -5115,7 +5147,7 @@ public:
         if (auto ve = e1.isVectorExp())
         {
             result = interpretVectorToArray(pue, ve);
-            if (result.op != TOK.vector)
+            if (result.op != EXP.vector)
                 return;
         }
         e.error("`%s` cannot be evaluated at compile time", e.toChars());
@@ -5169,24 +5201,24 @@ public:
             dinteger_t ofs;
             Expression agg = getAggregateFromPointer(e1, &ofs);
 
-            if (agg.op == TOK.null_)
+            if (agg.op == EXP.null_)
             {
                 e.error("cannot index through null pointer `%s`", e.e1.toChars());
                 return false;
             }
-            if (agg.op == TOK.int64)
+            if (agg.op == EXP.int64)
             {
                 e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
                 return false;
             }
             // Pointer to a non-array variable
-            if (agg.op == TOK.symbolOffset)
+            if (agg.op == EXP.symbolOffset)
             {
                 e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars());
                 return false;
             }
 
-            if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_)
+            if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
             {
                 dinteger_t len = resolveArrayLength(agg);
                 if (ofs + indx >= len)
@@ -5211,7 +5243,7 @@ public:
         Expression e1 = interpretRegion(e.e1, istate);
         if (exceptionOrCantInterpret(e1))
             return false;
-        if (e1.op == TOK.null_)
+        if (e1.op == EXP.null_)
         {
             e.error("cannot index null array `%s`", e.e1.toChars());
             return false;
@@ -5225,11 +5257,11 @@ public:
 
         // Set the $ variable, and find the array literal to modify
         dinteger_t len;
-        if (e1.op == TOK.variable && e1.type.toBasetype().ty == Tsarray)
+        if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
             len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
         else
         {
-            if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.slice && e1.op != TOK.vector)
+            if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
             {
                 e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
                 return false;
@@ -5248,7 +5280,7 @@ public:
             ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
         if (exceptionOrCantInterpret(e2))
             return false;
-        if (e2.op != TOK.int64)
+        if (e2.op != EXP.int64)
         {
             e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
             return false;
@@ -5297,7 +5329,7 @@ public:
                 result = CTFEExp.cantexp;
                 return;
             }
-            if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_)
+            if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
             {
                 if (goal == CTFEGoal.LValue)
                 {
@@ -5327,7 +5359,7 @@ public:
             Expression e1 = interpretRegion(e.e1, istate);
             if (exceptionOrCant(e1))
                 return;
-            if (e1.op == TOK.null_)
+            if (e1.op == EXP.null_)
             {
                 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
                 {
@@ -5355,7 +5387,7 @@ public:
                 return;
             }
 
-            assert(e1.op == TOK.assocArrayLiteral);
+            assert(e1.op == EXP.assocArrayLiteral);
             UnionExp e2tmp = void;
             e2 = resolveSlice(e2, &e2tmp);
             result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
@@ -5387,7 +5419,7 @@ public:
         result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
         if (exceptionOrCant(result))
             return;
-        if (result.op == TOK.void_)
+        if (result.op == EXP.void_)
         {
             e.error("`%s` is used before initialized", e.toChars());
             errorSupplemental(result.loc, "originally uninitialized here");
@@ -5410,7 +5442,7 @@ public:
             Expression e1 = interpretRegion(e.e1, istate);
             if (exceptionOrCant(e1))
                 return;
-            if (e1.op == TOK.int64)
+            if (e1.op == EXP.int64)
             {
                 e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
                 result = CTFEExp.cantexp;
@@ -5432,7 +5464,7 @@ public:
             Expression agg = getAggregateFromPointer(e1, &ofs);
             ilwr += ofs;
             iupr += ofs;
-            if (agg.op == TOK.null_)
+            if (agg.op == EXP.null_)
             {
                 if (iupr == ilwr)
                 {
@@ -5444,19 +5476,19 @@ public:
                 result = CTFEExp.cantexp;
                 return;
             }
-            if (agg.op == TOK.symbolOffset)
+            if (agg.op == EXP.symbolOffset)
             {
                 e.error("slicing pointers to static variables is not supported in CTFE");
                 result = CTFEExp.cantexp;
                 return;
             }
-            if (agg.op != TOK.arrayLiteral && agg.op != TOK.string_)
+            if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
             {
                 e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
                 result = CTFEExp.cantexp;
                 return;
             }
-            assert(agg.op == TOK.arrayLiteral || agg.op == TOK.string_);
+            assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
             dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
             //Type *pointee = ((TypePointer *)agg.type)->next;
             if (iupr > (len + 1) || iupr < ilwr)
@@ -5503,11 +5535,11 @@ public:
         /* Set dollar to the length of the array
          */
         uinteger_t dollar;
-        if ((e1.op == TOK.variable || e1.op == TOK.dotVariable) && e1.type.toBasetype().ty == Tsarray)
+        if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
             dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
         else
         {
-            if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.null_ && e1.op != TOK.slice && e1.op != TOK.vector)
+            if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
             {
                 e.error("cannot determine length of `%s` at compile time", e1.toChars());
                 result = CTFEExp.cantexp;
@@ -5546,7 +5578,7 @@ public:
 
         uinteger_t ilwr = lwr.toInteger();
         uinteger_t iupr = upr.toInteger();
-        if (e1.op == TOK.null_)
+        if (e1.op == EXP.null_)
         {
             if (ilwr == 0 && iupr == 0)
             {
@@ -5578,7 +5610,7 @@ public:
             result.type = e.type;
             return;
         }
-        if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_)
+        if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
         {
             if (iupr < ilwr || dollar < iupr)
             {
@@ -5604,13 +5636,13 @@ public:
         Expression e2 = interpretRegion(e.e2, istate);
         if (exceptionOrCant(e2))
             return;
-        if (e2.op == TOK.null_)
+        if (e2.op == EXP.null_)
         {
             emplaceExp!(NullExp)(pue, e.loc, e.type);
             result = pue.exp();
             return;
         }
-        if (e2.op != TOK.assocArrayLiteral)
+        if (e2.op != EXP.assocArrayLiteral)
         {
             e.error("`%s` cannot be interpreted at compile time", e.toChars());
             result = CTFEExp.cantexp;
@@ -5663,7 +5695,7 @@ public:
          * 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 == TOK.string_ && e2.op == TOK.string_))
+        if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
         {
             if (e1 == ue1.exp())
                 e1 = ue1.copy();
@@ -5706,7 +5738,7 @@ public:
         if (exceptionOrCant(result))
             return;
 
-        if (result.op == TOK.null_)
+        if (result.op == EXP.null_)
         {
             result = CTFEExp.voidexp;
             return;
@@ -5716,7 +5748,7 @@ public:
         switch (tb.ty)
         {
         case Tclass:
-            if (result.op != TOK.classReference)
+            if (result.op != EXP.classReference)
             {
                 e.error("`delete` on invalid class reference `%s`", result.toChars());
                 result = CTFEExp.cantexp;
@@ -5752,8 +5784,8 @@ public:
             tb = (cast(TypePointer)tb).next.toBasetype();
             if (tb.ty == Tstruct)
             {
-                if (result.op != TOK.address ||
-                    (cast(AddrExp)result).e1.op != TOK.structLiteral)
+                if (result.op != EXP.address ||
+                    (cast(AddrExp)result).e1.op != EXP.structLiteral)
                 {
                     e.error("`delete` on invalid struct pointer `%s`", result.toChars());
                     result = CTFEExp.cantexp;
@@ -5776,7 +5808,7 @@ public:
             auto tv = tb.nextOf().baseElemOf();
             if (tv.ty == Tstruct)
             {
-                if (result.op != TOK.arrayLiteral)
+                if (result.op != EXP.arrayLiteral)
                 {
                     e.error("`delete` on invalid struct array `%s`", result.toChars());
                     result = CTFEExp.cantexp;
@@ -5819,11 +5851,11 @@ public:
             result = CTFEExp.voidexp;
             return;
         }
-        if (e.to.ty == Tpointer && e1.op != TOK.null_)
+        if (e.to.ty == Tpointer && e1.op != EXP.null_)
         {
             Type pointee = (cast(TypePointer)e.type).next;
             // Implement special cases of normally-unsafe casts
-            if (e1.op == TOK.int64)
+            if (e1.op == EXP.int64)
             {
                 // Happens with Windows HANDLEs, for example.
                 result = paintTypeOntoLiteral(pue, e.to, e1);
@@ -5869,7 +5901,7 @@ public:
 
             if (auto se = e1.isSliceExp())
             {
-                if (se.e1.op == TOK.null_)
+                if (se.e1.op == EXP.null_)
                 {
                     result = paintTypeOntoLiteral(pue, e.type, se.e1);
                     return;
@@ -5881,7 +5913,7 @@ public:
                 result = pue.exp();
                 return;
             }
-            if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_)
+            if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
             {
                 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
@@ -5890,7 +5922,7 @@ public:
                 result = pue.exp();
                 return;
             }
-            if (e1.op == TOK.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
+            if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
             {
                 // type painting operation
                 IndexExp ie = cast(IndexExp)e1;
@@ -5899,7 +5931,7 @@ public:
                     // get the original type. For strings, it's just the type...
                     Type origType = ie.e1.type.nextOf();
                     // ..but for arrays of type void*, it's the type of the element
-                    if (ie.e1.op == TOK.arrayLiteral && ie.e2.op == TOK.int64)
+                    if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
                     {
                         ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
                         const indx = cast(size_t)ie.e2.toInteger();
@@ -5939,7 +5971,7 @@ public:
                     return;
                 }
 
-                if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == TOK.index)
+                if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
                 {
                     // &val[idx]
                     dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
@@ -5956,7 +5988,7 @@ public:
                 }
             }
 
-            if (e1.op == TOK.variable || e1.op == TOK.symbolOffset)
+            if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
             {
                 // type painting operation
                 Type origType = (cast(SymbolExp)e1).var.type;
@@ -5977,7 +6009,7 @@ public:
 
             // Check if we have a null pointer (eg, inside a struct)
             e1 = interpretRegion(e1, istate);
-            if (e1.op != TOK.null_)
+            if (e1.op != EXP.null_)
             {
                 e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
                 result = CTFEExp.cantexp;
@@ -5990,10 +6022,10 @@ public:
             e1 = interpretRegion(e.e1, istate);
             if (exceptionOrCant(e1))
                 return;
-            assert(e1.op == TOK.vector);
+            assert(e1.op == EXP.vector);
             e1 = interpretVectorToArray(pue, e1.isVectorExp());
         }
-        if (e.to.ty == Tarray && e1.op == TOK.slice)
+        if (e.to.ty == Tarray && e1.op == EXP.slice)
         {
             // Note that the slice may be void[], so when checking for dangerous
             // casts, we need to use the original type, which is se.e1.
@@ -6023,11 +6055,11 @@ public:
         auto tobt = e.to.toBasetype();
         if (tobt.ty == Tbool && e1.type.ty == Tpointer)
         {
-            emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to);
+            emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
             result = pue.exp();
             return;
         }
-        else if (tobt.isTypeBasic() && e1.op == TOK.null_)
+        else if (tobt.isTypeBasic() && e1.op == EXP.null_)
         {
             if (tobt.isintegral())
                 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
@@ -6051,7 +6083,7 @@ public:
         if (isTrueBool(e1))
         {
         }
-        else if (e1.isBool(false))
+        else if (e1.toBool().hasValue(false))
         {
             if (e.msg)
             {
@@ -6106,7 +6138,7 @@ public:
         // Constant fold *(&structliteral + offset)
         if (auto ae = e.e1.isAddExp())
         {
-            if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
+            if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
             {
                 AddrExp ade = cast(AddrExp)ae.e1;
                 Expression ex = interpretRegion(ade.e1, istate);
@@ -6128,7 +6160,7 @@ public:
         if (exceptionOrCant(result))
             return;
 
-        if (result.op == TOK.function_)
+        if (result.op == EXP.function_)
             return;
         if (auto soe = result.isSymOffExp())
         {
@@ -6142,9 +6174,9 @@ public:
         if (result.isStringExp())
             return;
 
-        if (result.op != TOK.address)
+        if (result.op != EXP.address)
         {
-            if (result.op == TOK.null_)
+            if (result.op == EXP.null_)
                 e.error("dereference of null pointer `%s`", e.e1.toChars());
             else
                 e.error("dereference of invalid pointer `%s`", result.toChars());
@@ -6155,7 +6187,7 @@ public:
         // *(&x) ==> x
         result = (cast(AddrExp)result).e1;
 
-        if (result.op == TOK.slice && e.type.toBasetype().ty == Tsarray)
+        if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
         {
             /* aggr[lwr..upr]
              * upr may exceed the upper boundary of aggr, but the check is deferred
@@ -6212,7 +6244,7 @@ public:
             return;
         }
 
-        if (ex.op == TOK.null_)
+        if (ex.op == EXP.null_)
         {
             if (ex.type.toBasetype().ty == Tclass)
                 e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
@@ -6225,18 +6257,18 @@ public:
         StructLiteralExp se;
         int i;
 
-        if (ex.op != TOK.structLiteral && ex.op != TOK.classReference && ex.op != TOK.typeid_)
+        if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
         {
             return notImplementedYet();
         }
 
         // We can't use getField, because it makes a copy
-        if (ex.op == TOK.classReference)
+        if (ex.op == EXP.classReference)
         {
             se = (cast(ClassReferenceExp)ex).value;
             i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
         }
-        else if (ex.op == TOK.typeid_)
+        else if (ex.op == EXP.typeid_)
         {
             if (v.ident == Identifier.idPool("name"))
             {
@@ -6336,7 +6368,7 @@ public:
         Expression index = interpret(e.e2, istate);
         if (exceptionOrCant(index))
             return;
-        if (agg.op == TOK.null_)
+        if (agg.op == EXP.null_)
         {
             result = CTFEExp.voidexp;
             return;
@@ -6349,7 +6381,7 @@ public:
         foreach (j, evalue; *valuesx)
         {
             Expression ekey = (*keysx)[j];
-            int eq = ctfeEqual(e.loc, TOK.equal, ekey, index);
+            int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
             if (eq)
                 ++removed;
             else if (removed != 0)
@@ -6435,11 +6467,11 @@ Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTF
     // mimicking UnionExp.copy, but with region allocation
     switch (uexp.op)
     {
-        case TOK.cantExpression: return CTFEExp.cantexp;
-        case TOK.voidExpression: return CTFEExp.voidexp;
-        case TOK.break_:         return CTFEExp.breakexp;
-        case TOK.continue_:      return CTFEExp.continueexp;
-        case TOK.goto_:          return CTFEExp.gotoexp;
+        case EXP.cantExpression: return CTFEExp.cantexp;
+        case EXP.voidExpression: return CTFEExp.voidexp;
+        case EXP.break_:         return CTFEExp.breakexp;
+        case EXP.continue_:      return CTFEExp.continueexp;
+        case EXP.goto_:          return CTFEExp.gotoexp;
         default:                 break;
     }
     auto p = ctfeGlobals.region.malloc(uexp.size);
@@ -6454,7 +6486,7 @@ Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTF
  *    istate = context
  * Returns:
  *      NULL    continue to next statement
- *      TOK.cantExpression      cannot interpret statement at compile time
+ *      EXP.cantExpression      cannot interpret statement at compile time
  *      !NULL   expression from return statement, or thrown exception
  */
 Expression interpret(UnionExp* pue, Statement s, InterState* istate)
@@ -6490,7 +6522,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e)
      */
     static bool isVoid(const Expression e, bool checkArrayType = false) pure
     {
-        if (e.op == TOK.void_)
+        if (e.op == EXP.void_)
             return true;
 
         static bool isEntirelyVoid(const Expressions* elems)
@@ -6539,7 +6571,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e)
             else
             {
                 e = scrubReturnValue(loc, e);
-                if (CTFEExp.isCantExp(e) || e.op == TOK.error)
+                if (CTFEExp.isCantExp(e) || e.op == EXP.error)
                     return e;
             }
         }
@@ -6560,7 +6592,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e)
         return null;
     }
 
-    if (e.op == TOK.classReference)
+    if (e.op == EXP.classReference)
     {
         StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
         if (auto ex = scrubSE(sle))
@@ -6640,7 +6672,7 @@ private Expression scrubCacheValue(Expression e)
         return null;
     }
 
-    if (e.op == TOK.classReference)
+    if (e.op == EXP.classReference)
     {
         if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
             return ex;
@@ -6717,14 +6749,14 @@ private Expression copyRegionExp(Expression e)
 
     switch (e.op)
     {
-        case TOK.classReference:
+        case EXP.classReference:
         {
             auto cre = e.isClassReferenceExp();
             cre.value = copyRegionExp(cre.value).isStructLiteralExp();
             break;
         }
 
-        case TOK.structLiteral:
+        case EXP.structLiteral:
         {
             auto sle = e.isStructLiteralExp();
 
@@ -6754,7 +6786,7 @@ private Expression copyRegionExp(Expression e)
             return slec;
         }
 
-        case TOK.arrayLiteral:
+        case EXP.arrayLiteral:
         {
             auto ale = e.isArrayLiteralExp();
             ale.basis = copyRegionExp(ale.basis);
@@ -6762,12 +6794,12 @@ private Expression copyRegionExp(Expression e)
             break;
         }
 
-        case TOK.assocArrayLiteral:
+        case EXP.assocArrayLiteral:
             copyArray(e.isAssocArrayLiteralExp().keys);
             copyArray(e.isAssocArrayLiteralExp().values);
             break;
 
-        case TOK.slice:
+        case EXP.slice:
         {
             auto se = e.isSliceExp();
             se.e1  = copyRegionExp(se.e1);
@@ -6776,7 +6808,7 @@ private Expression copyRegionExp(Expression e)
             break;
         }
 
-        case TOK.tuple:
+        case EXP.tuple:
         {
             auto te = e.isTupleExp();
             te.e0 = copyRegionExp(te.e0);
@@ -6784,17 +6816,17 @@ private Expression copyRegionExp(Expression e)
             break;
         }
 
-        case TOK.address:
-        case TOK.delegate_:
-        case TOK.vector:
-        case TOK.dotVariable:
+        case EXP.address:
+        case EXP.delegate_:
+        case EXP.vector:
+        case EXP.dotVariable:
         {
             UnaExp ue = cast(UnaExp)e;
             ue.e1 = copyRegionExp(ue.e1);
             break;
         }
 
-        case TOK.index:
+        case EXP.index:
         {
             BinExp be = cast(BinExp)e;
             be.e1 = copyRegionExp(be.e1);
@@ -6802,30 +6834,30 @@ private Expression copyRegionExp(Expression e)
             break;
         }
 
-        case TOK.this_:
-        case TOK.super_:
-        case TOK.variable:
-        case TOK.type:
-        case TOK.function_:
-        case TOK.typeid_:
-        case TOK.string_:
-        case TOK.int64:
-        case TOK.error:
-        case TOK.float64:
-        case TOK.complex80:
-        case TOK.null_:
-        case TOK.void_:
-        case TOK.symbolOffset:
-        case TOK.char_:
+        case EXP.this_:
+        case EXP.super_:
+        case EXP.variable:
+        case EXP.type:
+        case EXP.function_:
+        case EXP.typeid_:
+        case EXP.string_:
+        case EXP.int64:
+        case EXP.error:
+        case EXP.float64:
+        case EXP.complex80:
+        case EXP.null_:
+        case EXP.void_:
+        case EXP.symbolOffset:
+        case EXP.char_:
             break;
 
-        case TOK.cantExpression:
-        case TOK.voidExpression:
-        case TOK.showCtfeContext:
+        case EXP.cantExpression:
+        case EXP.voidExpression:
+        case EXP.showCtfeContext:
             return e;
 
         default:
-            printf("e: %s, %s\n", Token.toChars(e.op), e.toChars());
+            printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
             assert(0);
     }
 
@@ -6848,7 +6880,7 @@ private Expression interpret_length(UnionExp* pue, InterState* istate, Expressio
     if (auto aae = earg.isAssocArrayLiteralExp())
         len = aae.keys.dim;
     else
-        assert(earg.op == TOK.null_);
+        assert(earg.op == EXP.null_);
     emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
     return pue.exp();
 }
@@ -6862,12 +6894,12 @@ private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression
     earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
-    if (earg.op == TOK.null_)
+    if (earg.op == EXP.null_)
     {
         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
         return pue.exp();
     }
-    if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+    if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
         return null;
     AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
     auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
@@ -6885,12 +6917,12 @@ private Expression interpret_values(UnionExp* pue, InterState* istate, Expressio
     earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
-    if (earg.op == TOK.null_)
+    if (earg.op == EXP.null_)
     {
         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
         return pue.exp();
     }
-    if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+    if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
         return null;
     auto aae = earg.isAssocArrayLiteralExp();
     auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
@@ -6909,12 +6941,12 @@ private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression e
     earg = interpret(pue, earg, istate);
     if (exceptionOrCantInterpret(earg))
         return earg;
-    if (earg.op == TOK.null_)
+    if (earg.op == EXP.null_)
     {
         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
         return pue.exp();
     }
-    if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+    if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
         return null;
     auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
     for (size_t i = 0; i < aae.keys.dim; i++)
@@ -6935,7 +6967,7 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi
     aa = interpret(aa, istate);
     if (exceptionOrCantInterpret(aa))
         return aa;
-    if (aa.op != TOK.assocArrayLiteral)
+    if (aa.op != EXP.assocArrayLiteral)
     {
         emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
         return pue.exp();
@@ -7316,7 +7348,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const re
     }
     if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
     {
-        if (pthis.op == TOK.classReference && fd.parent.ident == Id.Throwable)
+        if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
         {
             // At present, the constructors just copy their arguments into the struct.
             // But we might need some magic if stack tracing gets added to druntime.
@@ -7383,7 +7415,7 @@ private Expression evaluatePostblit(InterState* istate, Expression e)
         }
         return null;
     }
-    if (e.op == TOK.structLiteral)
+    if (e.op == EXP.structLiteral)
     {
         // e.__postblit()
         UnionExp ue = void;
@@ -7412,7 +7444,7 @@ private Expression evaluateDtor(InterState* istate, Expression e)
         foreach_reverse (elem; *ale.elements)
             e = evaluateDtor(istate, elem);
     }
-    else if (e.op == TOK.structLiteral)
+    else if (e.op == EXP.structLiteral)
     {
         // e.__dtor()
         e = interpretFunction(&ue, sd.dtor, istate, null, e);
index c417f93c353b9dd2c71a658359aff4b6c0dea3bf..065968025a63325a880b8f7a272a69a97736071f 100644 (file)
@@ -979,7 +979,7 @@ public:
                     goto Lsa;
                 }
                 buf.writeByte('V');
-                if (ea.op == TOK.tuple)
+                if (ea.op == EXP.tuple)
                 {
                     ea.error("tuple is not a valid template value argument");
                     continue;
@@ -987,7 +987,7 @@ public:
                 // Now that we know it is not an alias, we MUST obtain a value
                 uint olderr = global.errors;
                 ea = ea.ctfeInterpret();
-                if (ea.op == TOK.error || olderr != global.errors)
+                if (ea.op == EXP.error || olderr != global.errors)
                     continue;
 
                 /* Use type mangling that matches what it would be for a function parameter
index 0925e7cd38a2d1510a9d05599e9ee26d1a68f7c0..1f05642d301d99a58b7583241361502c7bafccee 100644 (file)
@@ -522,14 +522,14 @@ private bool _isZeroInit(Expression exp)
 {
     switch (exp.op)
     {
-        case TOK.int64:
+        case EXP.int64:
             return exp.toInteger() == 0;
 
-        case TOK.null_:
-        case TOK.false_:
+        case EXP.null_:
+        case EXP.false_:
             return true;
 
-        case TOK.structLiteral:
+        case EXP.structLiteral:
         {
             auto sle = cast(StructLiteralExp) exp;
             foreach (i; 0 .. sle.sd.fields.dim)
@@ -546,7 +546,7 @@ private bool _isZeroInit(Expression exp)
             return true;
         }
 
-        case TOK.arrayLiteral:
+        case EXP.arrayLiteral:
         {
             auto ale = cast(ArrayLiteralExp)exp;
 
@@ -566,7 +566,7 @@ private bool _isZeroInit(Expression exp)
             return true;
         }
 
-        case TOK.string_:
+        case EXP.string_:
         {
             StringExp se = cast(StringExp)exp;
 
@@ -581,14 +581,14 @@ private bool _isZeroInit(Expression exp)
             return true;
         }
 
-        case TOK.vector:
+        case EXP.vector:
         {
             auto ve = cast(VectorExp) exp;
             return _isZeroInit(ve.e1);
         }
 
-        case TOK.float64:
-        case TOK.complex80:
+        case EXP.float64:
+        case EXP.complex80:
         {
             import dmd.root.ctfloat : CTFloat;
             return (exp.toReal()      is CTFloat.zero) &&
index 9aa435d646381eea4c2ad874ebe247d9e107eda2..b1d1b1d8d7c39ba4c6c65ee194f0e341388d372d 100644 (file)
@@ -1785,11 +1785,11 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
         Expression eold = null;
         for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e))
         {
-            if (e.op == TOK.scope_)
+            if (e.op == EXP.scope_)
             {
                 s = (cast(ScopeExp)e).sds;
             }
-            else if (e.op == TOK.type)
+            else if (e.op == EXP.type)
             {
                 s = e.type.toDsymbol(null);
             }
@@ -1826,14 +1826,14 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
 {
     // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
-    // Discriminated using DYNCAST and, for expressions, also TOK
+    // Discriminated using DYNCAST and, for expressions, also EXP
     private RootObject arrayContent;
     Scope* sc;
 
     extern (D) this(Scope* sc, Expression exp)
     {
         super(exp.loc, null);
-        assert(exp.op == TOK.index || exp.op == TOK.slice || exp.op == TOK.array);
+        assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
         this.sc = sc;
         this.arrayContent = exp;
     }
@@ -1950,7 +1950,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
             else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
             {
                 // Look for opDollar
-                assert(exp.op == TOK.array || exp.op == TOK.slice);
+                assert(exp.op == EXP.array || exp.op == EXP.slice);
                 AggregateDeclaration ad = isAggregate(t);
                 assert(ad);
                 Dsymbol s = ad.search(loc, Id.opDollar);
@@ -1962,11 +1962,11 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
                 if (TemplateDeclaration td = s.isTemplateDeclaration())
                 {
                     dinteger_t dim = 0;
-                    if (exp.op == TOK.array)
+                    if (exp.op == EXP.array)
                     {
                         dim = (cast(ArrayExp)exp).currentDimension;
                     }
-                    else if (exp.op == TOK.slice)
+                    else if (exp.op == EXP.slice)
                     {
                         dim = 0; // slices are currently always one-dimensional
                     }
@@ -1987,7 +1987,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
                      * Note that it's impossible to have both template & function opDollar,
                      * because both take no arguments.
                      */
-                    if (exp.op == TOK.array && (cast(ArrayExp)exp).arguments.dim != 1)
+                    if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.dim != 1)
                     {
                         exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
                         return null;
index 047c1eb6f69ffdadc54e994915050b58b013948b..0bf9a80f37d16a64e66ddae514faa756e9ab2c04 100644 (file)
@@ -133,7 +133,7 @@ AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc)
         e = e.ctfeInterpret();
         exp = e;                // could be re-evaluated if exps are assigned to more than one AlignDeclaration by CParser.applySpecifier(),
                                 // e.g. `_Alignas(8) int a, b;`
-        if (e.op == TOK.error)
+        if (e.op == EXP.error)
             errors = true;
         else
         {
@@ -611,7 +611,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         Lnomatch:
 
-            if (ie && ie.op == TOK.tuple)
+            if (ie && ie.op == EXP.tuple)
             {
                 auto te = ie.isTupleExp();
                 size_t tedim = te.exps.dim;
@@ -652,6 +652,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     storage_class |= arg.storageClass;
                 auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class);
                 //printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars());
+                v.overlapped = dsym.overlapped;
+
                 v.dsymbolSemantic(sc);
 
                 if (sc.scopesym)
@@ -879,11 +881,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         if ((!dsym._init || dsym._init.isVoidInitializer) && !fd)
         {
             // If not mutable, initializable by constructor only
-            dsym.storage_class |= STC.ctorinit;
+            dsym.setInCtorOnly = true;
         }
 
         if (dsym._init)
-            dsym.storage_class |= STC.init; // remember we had an explicit initializer
+        { } // remember we had an explicit initializer
         else if (dsym.storage_class & STC.manifest)
             dsym.error("manifest constants must have initializers");
 
@@ -1013,7 +1015,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     exp = exp.expressionSemantic(sc);
                     dsym.canassign--;
                     exp = exp.optimize(WANTvalue);
-                    if (exp.op == TOK.error)
+                    if (exp.op == EXP.error)
                     {
                         dsym._init = new ErrorInitializer();
                         ei = null;
@@ -1024,7 +1026,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     if (ei && dsym.isScope())
                     {
                         Expression ex = ei.exp.lastComma();
-                        if (ex.op == TOK.blit || ex.op == TOK.construct)
+                        if (ex.op == EXP.blit || ex.op == EXP.construct)
                             ex = (cast(AssignExp)ex).e2;
                         if (auto ne = ex.isNewExp())
                         {
@@ -1057,7 +1059,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     // Don't run CTFE for the temporary variables inside typeof
                     dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret);
                     const init_err = dsym._init.isExpInitializer();
-                    if (init_err && init_err.exp.op == TOK.showCtfeContext)
+                    if (init_err && init_err.exp.op == EXP.showCtfeContext)
                     {
                          errorSupplemental(dsym.loc, "compile time context created here");
                     }
@@ -1085,7 +1087,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     dsym.inuse++;
                     // Bug 20549. Don't try this on modules or packages, syntaxCopy
                     // could crash (inf. recursion) on a mod/pkg referencing itself
-                    if (ei && (ei.exp.op != TOK.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
+                    if (ei && (ei.exp.op != EXP.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
                     {
                         if (ei.exp.type)
                         {
@@ -1241,7 +1243,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             width.error("bit-field `%s` has zero width", dsym.toChars());
             dsym.errors = true;
         }
-        const max_width = dsym.type.size() * 8;
+        const sz = dsym.type.size();
+        if (sz == SIZE_INVALID)
+            dsym.errors = true;
+        const max_width = sz * 8;
         if (uwidth > max_width)
         {
             width.error("width `%lld` of bit-field `%s` does not fit in type `%s`", cast(long)uwidth, dsym.toChars(), dsym.type.toChars());
@@ -1459,7 +1464,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     override void visit(AnonDeclaration scd)
     {
-        //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+        //printf("\tAnonDeclaration::semantic isunion:%d ptr:%p\n", scd.isunion, scd);
         assert(sc.parent);
         auto p = sc.parent.pastMixin();
         auto ad = p.isAggregateDeclaration();
@@ -1479,6 +1484,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             for (size_t i = 0; i < scd.decl.dim; i++)
             {
                 Dsymbol s = (*scd.decl)[i];
+                if (auto var = s.isVarDeclaration)
+                {
+                    if (scd.isunion)
+                        var.overlapped = true;
+                }
                 s.dsymbolSemantic(sc);
             }
             sc = sc.pop();
@@ -1651,7 +1661,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     e = resolveProperties(sc, e);
                     sc = sc.endCTFE();
                     e = ctfeInterpretForPragmaMsg(e);
-                    if (e.op == TOK.error)
+                    if (e.op == EXP.error)
                     {
                         errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars());
                         return;
@@ -2185,7 +2195,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     e = resolveProperties(sc, e);
                     e = e.integralPromotions(sc);
                     e = e.ctfeInterpret();
-                    if (e.op == TOK.error)
+                    if (e.op == EXP.error)
                         return errorReturn(em);
                     auto ie = e.isIntegerExp();
                     if (!ie)
@@ -2303,7 +2313,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             e = e.expressionSemantic(sc);
             e = resolveProperties(sc, e);
             e = e.ctfeInterpret();
-            if (e.op == TOK.error)
+            if (e.op == EXP.error)
                 return errorReturn();
             if (first && !em.ed.memtype && !em.ed.isAnonymous())
             {
@@ -2331,7 +2341,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         ev = ev.implicitCastTo(sc, em.ed.memtype);
                         ev = ev.ctfeInterpret();
                         ev = ev.castTo(sc, em.ed.type);
-                        if (ev.op == TOK.error)
+                        if (ev.op == EXP.error)
                             em.ed.errors = true;
                         enm.value = ev;
                     });
@@ -2429,7 +2439,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             // Set value to (eprev + 1).
             // But first check that (eprev != emax)
             assert(eprev);
-            Expression e = new EqualExp(TOK.equal, em.loc, eprev, emax);
+            Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax);
             e = e.expressionSemantic(sc);
             e = e.ctfeInterpret();
             if (e.toInteger())
@@ -2446,7 +2456,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             e = e.ctfeInterpret();
 
             // save origValue (without cast) for better json output
-            if (e.op != TOK.error) // avoid duplicate diagnostics
+            if (e.op != EXP.error) // avoid duplicate diagnostics
             {
                 assert(emprev.origValue);
                 em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1);
@@ -2454,12 +2464,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 em.origValue = em.origValue.ctfeInterpret();
             }
 
-            if (e.op == TOK.error)
+            if (e.op == EXP.error)
                 return errorReturn();
             if (e.type.isfloating())
             {
                 // Check that e != eprev (not always true for floats)
-                Expression etest = new EqualExp(TOK.equal, em.loc, e, eprev);
+                Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev);
                 etest = etest.expressionSemantic(sc);
                 etest = etest.ctfeInterpret();
                 if (etest.toInteger())
@@ -4162,7 +4172,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
             Expression e = new IdentifierExp(Loc.initial, v.ident);
             e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!1);
-            e = new EqualExp(TOK.notEqual, Loc.initial, e, IntegerExp.literal!1);
+            e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!1);
             s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
 
             sa.push(s);
@@ -4239,7 +4249,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
             Expression e = new IdentifierExp(Loc.initial, v.ident);
             e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!(-1));
-            e = new EqualExp(TOK.notEqual, Loc.initial, e, IntegerExp.literal!0);
+            e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!0);
             s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
 
             sa.push(s);
@@ -4616,6 +4626,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         if (cldec.errors)
             cldec.type = Type.terror;
+        if (cldec.semanticRun == PASS.init)
+            cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class);
         cldec.type = cldec.type.typeSemantic(cldec.loc, sc);
         if (auto tc = cldec.type.isTypeClass())
             if (tc.sym != cldec)
@@ -6422,7 +6434,7 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
                 s = getDsymbol(e);
                 if (!s)
                 {
-                    if (e.op != TOK.error)
+                    if (e.op != EXP.error)
                         ds.error("cannot alias an expression `%s`", e.toChars());
                     return errorRet();
                 }
@@ -6606,7 +6618,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
                 s = getDsymbol(e);
                 if (!s)
                 {
-                    if (e.op != TOK.error)
+                    if (e.op != EXP.error)
                         ds.error("cannot alias an expression `%s`", e.toChars());
                     return errorRet();
                 }
index 9d7957a975d3a18a8dbca03dd7371ebfcce6867c..5dedcba562771bd7fa0a7c9e653bed177b180b8f 100644 (file)
@@ -144,7 +144,7 @@ extern (C++) bool isError(const RootObject o)
     if (const t = isType(o))
         return (t.ty == Terror);
     if (const e = isExpression(o))
-        return (e.op == TOK.error || !e.type || e.type.ty == Terror);
+        return (e.op == EXP.error || !e.type || e.type.ty == Terror);
     if (const v = isTuple(o))
         return arrayObjectIsError(&v.objects);
     const s = isDsymbol(o);
@@ -297,8 +297,8 @@ private bool match(RootObject o1, RootObject o2)
 
         static if (log)
         {
-            printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", Token.toChars(e1.op), e1.toChars());
-            printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", Token.toChars(e2.op), e2.toChars());
+            printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars());
+            printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars());
         }
 
         // two expressions can be equal although they do not have the same
@@ -421,26 +421,26 @@ private size_t expressionHash(Expression e)
 
     switch (e.op)
     {
-    case TOK.int64:
+    case EXP.int64:
         return cast(size_t) e.isIntegerExp().getInteger();
 
-    case TOK.float64:
+    case EXP.float64:
         return CTFloat.hash(e.isRealExp().value);
 
-    case TOK.complex80:
+    case EXP.complex80:
         auto ce = e.isComplexExp();
         return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary));
 
-    case TOK.identifier:
+    case EXP.identifier:
         return cast(size_t)cast(void*) e.isIdentifierExp().ident;
 
-    case TOK.null_:
+    case EXP.null_:
         return cast(size_t)cast(void*) e.isNullExp().type;
 
-    case TOK.string_:
+    case EXP.string_:
         return calcHash(e.isStringExp.peekData());
 
-    case TOK.tuple:
+    case EXP.tuple:
     {
         auto te = e.isTupleExp();
         size_t hash = 0;
@@ -450,7 +450,7 @@ private size_t expressionHash(Expression e)
         return hash;
     }
 
-    case TOK.arrayLiteral:
+    case EXP.arrayLiteral:
     {
         auto ae = e.isArrayLiteralExp();
         size_t hash;
@@ -459,7 +459,7 @@ private size_t expressionHash(Expression e)
         return hash;
     }
 
-    case TOK.assocArrayLiteral:
+    case EXP.assocArrayLiteral:
     {
         auto ae = e.isAssocArrayLiteralExp();
         size_t hash;
@@ -469,7 +469,7 @@ private size_t expressionHash(Expression e)
         return hash;
     }
 
-    case TOK.structLiteral:
+    case EXP.structLiteral:
     {
         auto se = e.isStructLiteralExp();
         size_t hash;
@@ -478,10 +478,10 @@ private size_t expressionHash(Expression e)
         return hash;
     }
 
-    case TOK.variable:
+    case EXP.variable:
         return cast(size_t)cast(void*) e.isVarExp().var;
 
-    case TOK.function_:
+    case EXP.function_:
         return cast(size_t)cast(void*) e.isFuncExp().fd;
 
     default:
@@ -1629,7 +1629,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                             farg = (*fargs)[argi + i];
 
                             // Check invalid arguments to detect errors early.
-                            if (farg.op == TOK.error || farg.type.ty == Terror)
+                            if (farg.op == EXP.error || farg.type.ty == Terror)
                                 return nomatch();
 
                             if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid)
@@ -1825,7 +1825,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                 }
                 {
                     // Check invalid arguments to detect errors early.
-                    if (farg.op == TOK.error || farg.type.ty == Terror)
+                    if (farg.op == EXP.error || farg.type.ty == Terror)
                         return nomatch();
 
                     Type att = null;
@@ -1837,7 +1837,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     }
                     Type argtype = farg.type;
 
-                    if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != TOK.function_)
+                    if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != EXP.function_)
                         return nomatch();
 
                     // https://issues.dlang.org/show_bug.cgi?id=12876
@@ -1853,17 +1853,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                         Type taai;
                         if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
                         {
-                            if (farg.op == TOK.string_)
+                            if (farg.op == EXP.string_)
                             {
                                 StringExp se = cast(StringExp)farg;
                                 argtype = se.type.nextOf().sarrayOf(se.len);
                             }
-                            else if (farg.op == TOK.arrayLiteral)
+                            else if (farg.op == EXP.arrayLiteral)
                             {
                                 ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
                                 argtype = ae.type.nextOf().sarrayOf(ae.elements.dim);
                             }
-                            else if (farg.op == TOK.slice)
+                            else if (farg.op == EXP.slice)
                             {
                                 SliceExp se = cast(SliceExp)farg;
                                 if (Type tsa = toStaticArrayType(se))
@@ -1939,7 +1939,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     {
                         if (!farg.isLvalue())
                         {
-                            if ((farg.op == TOK.string_ || farg.op == TOK.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
+                            if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
                             {
                                 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
                             }
@@ -2280,13 +2280,13 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
         Declaration d;
         VarDeclaration v = null;
 
-        if (ea && ea.op == TOK.type)
+        if (ea && ea.op == EXP.type)
             ta = ea.type;
-        else if (ea && ea.op == TOK.scope_)
+        else if (ea && ea.op == EXP.scope_)
             sa = (cast(ScopeExp)ea).sds;
-        else if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_))
+        else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
             sa = (cast(ThisExp)ea).var;
-        else if (ea && ea.op == TOK.function_)
+        else if (ea && ea.op == EXP.function_)
         {
             if ((cast(FuncExp)ea).td)
                 sa = (cast(FuncExp)ea).td;
@@ -3826,7 +3826,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 if (tparam.ty == Tsarray)
                 {
                     TypeSArray tsa = cast(TypeSArray)tparam;
-                    if (tsa.dim.op == TOK.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
+                    if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
                     {
                         Identifier id = (cast(VarExp)tsa.dim).var.ident;
                         i = templateIdentifierLookup(id, parameters);
@@ -4209,7 +4209,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                         /* If it is one of the template parameters for this template,
                          * we should not attempt to interpret it. It already has a value.
                          */
-                        if (e2.op == TOK.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
+                        if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
                         {
                             /*
                              * (T:Number!(e2), int e2)
@@ -4847,9 +4847,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 // Reset inference target for the later re-semantic
                 e.fd.treq = null;
 
-                if (ex.op == TOK.error)
+                if (ex.op == EXP.error)
                     return;
-                if (ex.op != TOK.function_)
+                if (ex.op != EXP.function_)
                     return;
                 visit(ex.type);
                 return;
@@ -6642,13 +6642,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             else if (ea)
             {
             Lexpr:
-                //printf("+[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars());
+                //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
                 if (flags & 1) // only used by __traits
                 {
                     ea = ea.expressionSemantic(sc);
 
                     // must not interpret the args, excepting template parameters
-                    if (ea.op != TOK.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
+                    if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
                     {
                         ea = ea.optimize(WANTvalue);
                     }
@@ -6659,7 +6659,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                     ea = ea.expressionSemantic(sc);
                     sc = sc.endCTFE();
 
-                    if (ea.op == TOK.variable)
+                    if (ea.op == EXP.variable)
                     {
                         /* If the parameter is a function that is not called
                          * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
@@ -6687,8 +6687,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                             ea = ErrorExp.get();
                     }
                 }
-                //printf("-[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars());
-                if (ea.op == TOK.tuple)
+                //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
+                if (ea.op == EXP.tuple)
                 {
                     // Expand tuple
                     TupleExp te = cast(TupleExp)ea;
@@ -6703,24 +6703,24 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                     j--;
                     continue;
                 }
-                if (ea.op == TOK.error)
+                if (ea.op == EXP.error)
                 {
                     err = true;
                     continue;
                 }
                 (*tiargs)[j] = ea;
 
-                if (ea.op == TOK.type)
+                if (ea.op == EXP.type)
                 {
                     ta = ea.type;
                     goto Ltype;
                 }
-                if (ea.op == TOK.scope_)
+                if (ea.op == EXP.scope_)
                 {
                     sa = (cast(ScopeExp)ea).sds;
                     goto Ldsym;
                 }
-                if (ea.op == TOK.function_)
+                if (ea.op == EXP.function_)
                 {
                     FuncExp fe = cast(FuncExp)ea;
                     /* A function literal, that is passed to template and
@@ -6741,24 +6741,24 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                         //goto Ldsym;
                     }
                 }
-                if (ea.op == TOK.dotVariable && !(flags & 1))
+                if (ea.op == EXP.dotVariable && !(flags & 1))
                 {
                     // translate expression to dsymbol.
                     sa = (cast(DotVarExp)ea).var;
                     goto Ldsym;
                 }
-                if (ea.op == TOK.template_)
+                if (ea.op == EXP.template_)
                 {
                     sa = (cast(TemplateExp)ea).td;
                     goto Ldsym;
                 }
-                if (ea.op == TOK.dotTemplateDeclaration && !(flags & 1))
+                if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
                 {
                     // translate expression to dsymbol.
                     sa = (cast(DotTemplateExp)ea).td;
                     goto Ldsym;
                 }
-                if (ea.op == TOK.dot)
+                if (ea.op == EXP.dot)
                 {
                     if (auto se = (cast(DotExp)ea).e2.isScopeExp())
                     {
@@ -7256,17 +7256,17 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             Tuple va = isTuple(o);
             if (ea)
             {
-                if (ea.op == TOK.variable)
+                if (ea.op == EXP.variable)
                 {
                     sa = (cast(VarExp)ea).var;
                     goto Lsa;
                 }
-                if (ea.op == TOK.this_)
+                if (ea.op == EXP.this_)
                 {
                     sa = (cast(ThisExp)ea).var;
                     goto Lsa;
                 }
-                if (ea.op == TOK.function_)
+                if (ea.op == EXP.function_)
                 {
                     if ((cast(FuncExp)ea).td)
                         sa = (cast(FuncExp)ea).td;
@@ -7275,7 +7275,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                     goto Lsa;
                 }
                 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
-                if (ea.op != TOK.int64 && ea.op != TOK.float64 && ea.op != TOK.complex80 && ea.op != TOK.null_ && ea.op != TOK.string_ && ea.op != TOK.arrayLiteral && ea.op != TOK.assocArrayLiteral && ea.op != TOK.structLiteral)
+                if (ea.op != EXP.int64 && ea.op != EXP.float64 && ea.op != EXP.complex80 && ea.op != EXP.null_ && ea.op != EXP.string_ && ea.op != EXP.arrayLiteral && ea.op != EXP.assocArrayLiteral && ea.op != EXP.structLiteral)
                 {
                     ea.error("expression `%s` is not a valid template value argument", ea.toChars());
                     errors = true;
@@ -7319,6 +7319,19 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                                 goto L1; // dparent is most nested
                             }
                         }
+                        //https://issues.dlang.org/show_bug.cgi?id=17870
+                        if (dparent.isClassDeclaration() && enclosing.isClassDeclaration())
+                        {
+                            auto pc = dparent.isClassDeclaration();
+                            auto ec = enclosing.isClassDeclaration();
+                            if (pc.isBaseOf(ec, null))
+                                goto L1;
+                            else if (ec.isBaseOf(pc, null))
+                            {
+                                enclosing = dparent;
+                                goto L1;
+                            }
+                        }
                         error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars());
                         errors = true;
                     }
@@ -7584,15 +7597,15 @@ void unSpeculative(Scope* sc, RootObject o)
 bool definitelyValueParameter(Expression e)
 {
     // None of these can be value parameters
-    if (e.op == TOK.tuple || e.op == TOK.scope_ ||
-        e.op == TOK.type || e.op == TOK.dotType ||
-        e.op == TOK.template_ || e.op == TOK.dotTemplateDeclaration ||
-        e.op == TOK.function_ || e.op == TOK.error ||
-        e.op == TOK.this_ || e.op == TOK.super_ ||
-        e.op == TOK.dot)
+    if (e.op == EXP.tuple || e.op == EXP.scope_ ||
+        e.op == EXP.type || e.op == EXP.dotType ||
+        e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration ||
+        e.op == EXP.function_ || e.op == EXP.error ||
+        e.op == EXP.this_ || e.op == EXP.super_ ||
+        e.op == EXP.dot)
         return false;
 
-    if (e.op != TOK.dotVariable)
+    if (e.op != EXP.dotVariable)
         return true;
 
     /* Template instantiations involving a DotVar expression are difficult.
@@ -7606,20 +7619,20 @@ bool definitelyValueParameter(Expression e)
     if (f)
         return false;
 
-    while (e.op == TOK.dotVariable)
+    while (e.op == EXP.dotVariable)
     {
         e = (cast(DotVarExp)e).e1;
     }
     // this.x.y and super.x.y couldn't possibly be valid values.
-    if (e.op == TOK.this_ || e.op == TOK.super_)
+    if (e.op == EXP.this_ || e.op == EXP.super_)
         return false;
 
     // e.type.x could be an alias
-    if (e.op == TOK.dotType)
+    if (e.op == EXP.dotType)
         return false;
 
     // var.x.y is the only other possible form of alias
-    if (e.op != TOK.variable)
+    if (e.op != EXP.variable)
         return true;
 
     VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
@@ -8010,7 +8023,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
             uint olderrors = global.startGagging();
             ei = resolveProperties(sc, ei);
             ei = ei.ctfeInterpret();
-            if (global.endGagging(olderrors) || ei.op == TOK.error)
+            if (global.endGagging(olderrors) || ei.op == EXP.error)
                 return matchArgNoMatch();
 
             /* https://issues.dlang.org/show_bug.cgi?id=14520
@@ -8032,7 +8045,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
             m = MATCH.convert;
         }
 
-        if (ei && ei.op == TOK.variable)
+        if (ei && ei.op == EXP.variable)
         {
             // Resolve const variables that we had skipped earlier
             ei = ei.ctfeInterpret();
@@ -8110,9 +8123,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
         Type ta = isType(oarg);
         RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
         Expression ea = isExpression(oarg);
-        if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_))
+        if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
             sa = (cast(ThisExp)ea).var;
-        else if (ea && ea.op == TOK.scope_)
+        else if (ea && ea.op == EXP.scope_)
             sa = (cast(ScopeExp)ea).sds;
         if (sa)
         {
index e19adfc4b149729bc976b21cf4f042c862d0d27d..51f53c8402fb8e8466ce67941ed7022580d105ca 100644 (file)
@@ -21,6 +21,7 @@ import dmd.attrib;
 import dmd.dsymbol;
 import dmd.errors;
 import dmd.globals;
+import dmd.hdrgen;
 import dmd.identifier;
 import dmd.root.filename;
 import dmd.visitor;
@@ -2395,7 +2396,7 @@ public:
     {
         debug (Debug_DtoH) mixin(traceVisit!e);
 
-        buf.writestring(tokToString(e.op));
+        buf.writestring(expToString(e.op));
         e.e1.accept(this);
     }
 
@@ -2405,20 +2406,20 @@ public:
 
         e.e1.accept(this);
         buf.writeByte(' ');
-        buf.writestring(tokToString(e.op));
+        buf.writestring(expToString(e.op));
         buf.writeByte(' ');
         e.e2.accept(this);
     }
 
     /// Translates operator `op` into the C++ representation
-    private extern(D) static string tokToString(const TOK op)
+    private extern(D) static string expToString(const EXP op)
     {
-        switch (op) with (TOK)
+        switch (op) with (EXP)
         {
             case identity:      return "==";
             case notIdentity:   return "!=";
             default:
-                return Token.toString(op);
+                return EXPtoString(op);
         }
     }
 
index d502f80975b37dec6de5356b5f9ca791adc6b1b2..62f87e506ab69515cace5608893625467cfc8b89 100644 (file)
@@ -536,8 +536,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 {
     enum log = false;
     if (log) printf("checkAssignEscape(e: %s)\n", e.toChars());
-    if (e.op != TOK.assign && e.op != TOK.blit && e.op != TOK.construct &&
-        e.op != TOK.concatenateAssign && e.op != TOK.concatenateElemAssign && e.op != TOK.concatenateDcharAssign)
+    if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct &&
+        e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign)
         return false;
     auto ae = cast(BinExp)e;
     Expression e1 = ae.e1;
@@ -568,7 +568,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
     VarDeclaration va = expToVariable(e1);
 
-    if (va && e.op == TOK.concatenateElemAssign)
+    if (va && e.op == EXP.concatenateElemAssign)
     {
         /* https://issues.dlang.org/show_bug.cgi?id=17842
          * Draw an equivalence between:
@@ -596,11 +596,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
     FuncDeclaration fd = sc.func;
 
-    // Try to infer 'scope' for va if in a function not marked @system
-    bool inferScope = false;
-    if (va && fd && fd.type && fd.type.isTypeFunction())
-        inferScope = fd.type.isTypeFunction().trust != TRUST.system;
-    //printf("inferScope = %d, %d\n", inferScope, (va.storage_class & STCmaybescope) != 0);
 
     // Determine if va is a parameter that is an indirect reference
     const bool vaIsRef = va && va.storage_class & STC.parameter &&
@@ -677,7 +672,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
                 if (va.isScope())
                     continue;
 
-                if (inferScope && !va.doNotInferScope)
+                if (!va.doNotInferScope)
                 {
                     if (log) printf("inferring scope for lvalue %s\n", va.toChars());
                     va.storage_class |= STC.scope_ | STC.scopeinferred;
@@ -713,7 +708,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
             if (va && !va.isDataseg() && !va.doNotInferScope)
             {
-                if (!va.isScope() && inferScope)
+                if (!va.isScope())
                 {   /* v is scope, and va is not scope, so va needs to
                      * infer scope
                      */
@@ -749,7 +744,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
             {
                 if (va && !va.isDataseg() && !va.doNotInferScope)
                 {
-                    if (!va.isScope() && inferScope)
+                    if (!va.isScope())
                     {   //printf("inferring scope for %s\n", va.toChars());
                         va.storage_class |= STC.scope_ | STC.scopeinferred;
                     }
@@ -840,7 +835,7 @@ ByRef:
 
         if (va && !va.isDataseg() && !va.doNotInferScope)
         {
-            if (!va.isScope() && inferScope)
+            if (!va.isScope())
             {   //printf("inferring scope for %s\n", va.toChars());
                 va.storage_class |= STC.scope_ | STC.scopeinferred;
             }
@@ -848,7 +843,7 @@ ByRef:
                 va.storage_class |= STC.return_ | STC.returninferred;
             continue;
         }
-        if (e1.op == TOK.structLiteral)
+        if (e1.op == EXP.structLiteral)
             continue;
         if (fd.setUnsafe())
         {
@@ -890,7 +885,7 @@ ByRef:
                 /* Don't infer STC.scope_ for va, because then a closure
                  * won't be generated for fd.
                  */
-                //if (!va.isScope() && inferScope)
+                //if (!va.isScope())
                     //va.storage_class |= STC.scope_ | STC.scopeinferred;
                 continue;
             }
@@ -909,7 +904,7 @@ ByRef:
 
         /* Do not allow slicing of a static array returned by a function
          */
-        if (ee.op == TOK.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
+        if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
             !(va && va.storage_class & STC.temp))
         {
             if (!gag)
@@ -919,7 +914,7 @@ ByRef:
             continue;
         }
 
-        if (ee.op == TOK.call && ee.type.toBasetype().isTypeStruct() &&
+        if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() &&
             (!va || !(va.storage_class & STC.temp)) &&
             fd.setUnsafe())
         {
@@ -930,7 +925,7 @@ ByRef:
             continue;
         }
 
-        if (ee.op == TOK.structLiteral &&
+        if (ee.op == EXP.structLiteral &&
             (!va || !(va.storage_class & STC.temp)) &&
             fd.setUnsafe())
         {
@@ -943,7 +938,7 @@ ByRef:
 
         if (va && !va.isDataseg() && !va.doNotInferScope)
         {
-            if (!va.isScope() && inferScope)
+            if (!va.isScope())
             {   //printf("inferring scope for %s\n", va.toChars());
                 va.storage_class |= STC.scope_ | STC.scopeinferred;
             }
@@ -993,17 +988,13 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag)
         if (v.isScope() && !v.iscatchvar)       // special case: allow catch var to be rethrown
                                                 // despite being `scope`
         {
-            if (sc._module && sc._module.isRoot())
+            if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
             {
-                // Only look for errors if in module listed on command line
-                if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
-                {
-                    if (!gag)
-                        error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
-                    result = true;
-                }
-                continue;
+                if (!gag)
+                    error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
+                result = true;
             }
+            continue;
         }
         else
         {
@@ -1051,7 +1042,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
 
         if (v.isScope())
         {
-            if (sc._module && sc._module.isRoot() &&
+            if (
                 /* This case comes up when the ReturnStatement of a __foreachbody is
                  * checked for escapes by the caller of __foreachbody. Skip it.
                  *
@@ -1128,9 +1119,6 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
         if (!v.isReference())
             continue;
 
-        if (!sc._module || !sc._module.isRoot())
-            continue;
-
         // https://dlang.org/spec/function.html#return-ref-parameters
         // Only look for errors if in module listed on command line
         if (p == sc.func)
@@ -1264,7 +1252,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                 continue;
 
             auto pfunc = p.isFuncDeclaration();
-            if (pfunc && sc._module && sc._module.isRoot() &&
+            if (pfunc &&
                 /* This case comes up when the ReturnStatement of a __foreachbody is
                  * checked for escapes by the caller of __foreachbody. Skip it.
                  *
@@ -1284,7 +1272,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                )
             {
                 // Only look for errors if in module listed on command line
-                if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
+                // https://issues.dlang.org/show_bug.cgi?id=17029
+                if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
                 {
                     if (!gag)
                         error(e.loc, "scope variable `%s` may not be returned", v.toChars());
@@ -1398,7 +1387,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             {
                 inferReturn(sc.func, v);        // infer addition of 'return'
             }
-            else if (sc._module && sc._module.isRoot())
+            else
             {
                 // https://dlang.org/spec/function.html#return-ref-parameters
                 // Only look for errors if in module listed on command line
@@ -1528,7 +1517,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
              * allowed, but CTFE can generate one out of a new expression,
              * but it'll be placed in static data so no need to check it.
              */
-            if (e.e1.op != TOK.structLiteral)
+            if (e.e1.op != EXP.structLiteral)
                 escapeByRef(e.e1, er, live);
         }
 
@@ -1768,7 +1757,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
                 }
             }
             // If 'this' is returned, check it too
-            if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
+            if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
             {
                 DotVarExp dve = e.e1.isDotVarExp();
                 FuncDeclaration fd = dve.var.isFuncDeclaration();
@@ -2024,7 +2013,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                     }
                 }
                 // If 'this' is returned by ref, check it too
-                if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
+                if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
                 {
                     DotVarExp dve = e.e1.isDotVarExp();
 
@@ -2051,7 +2040,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                     }
                 }
                 // If it's a delegate, check it too
-                if (e.e1.op == TOK.variable && t1.ty == Tdelegate)
+                if (e.e1.op == EXP.variable && t1.ty == Tdelegate)
                 {
                     escapeByValue(e.e1, er, live);
                 }
index 2a6233244547a5f5a178695e3b0c52ced8992f71..e6b7e3014f18894ea0e32628931f962db27b5188 100644 (file)
@@ -60,6 +60,7 @@ import dmd.optimize;
 import dmd.root.ctfloat;
 import dmd.root.filename;
 import dmd.common.outbuffer;
+import dmd.root.optional;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.root.string;
@@ -116,7 +117,7 @@ enum ModifyFlags
 inout(Expression) firstComma(inout Expression e)
 {
     Expression ex = cast()e;
-    while (ex.op == TOK.comma)
+    while (ex.op == EXP.comma)
         ex = (cast(CommaExp)ex).e1;
     return cast(inout)ex;
 
@@ -133,7 +134,7 @@ inout(Expression) firstComma(inout Expression e)
 inout(Expression) lastComma(inout Expression e)
 {
     Expression ex = cast()e;
-    while (ex.op == TOK.comma)
+    while (ex.op == EXP.comma)
         ex = (cast(CommaExp)ex).e2;
     return cast(inout)ex;
 
@@ -286,7 +287,7 @@ extern (C++) void expandTuples(Expressions* exps)
         }
 
         // Inline expand all the tuples
-        while (arg.op == TOK.tuple)
+        while (arg.op == EXP.tuple)
         {
             TupleExp te = cast(TupleExp)arg;
             exps.remove(i); // remove arg
@@ -356,7 +357,7 @@ int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
                 printf("expansion ->\n");
                 foreach (e; exps)
                 {
-                    printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars());
+                    printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
                 }
             }
             return cast(int)u;
@@ -528,15 +529,15 @@ extern (C++) struct UnionExp
     extern (C++) Expression copy()
     {
         Expression e = exp();
-        //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op));
+        //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
         assert(e.size <= u.sizeof);
         switch (e.op)
         {
-            case TOK.cantExpression:    return CTFEExp.cantexp;
-            case TOK.voidExpression:    return CTFEExp.voidexp;
-            case TOK.break_:            return CTFEExp.breakexp;
-            case TOK.continue_:         return CTFEExp.continueexp;
-            case TOK.goto_:             return CTFEExp.gotoexp;
+            case EXP.cantExpression:    return CTFEExp.cantexp;
+            case EXP.voidExpression:    return CTFEExp.voidexp;
+            case EXP.break_:            return CTFEExp.breakexp;
+            case EXP.continue_:         return CTFEExp.continueexp;
+            case EXP.goto_:             return CTFEExp.gotoexp;
             default:                    return e.copy();
         }
     }
@@ -610,14 +611,14 @@ VarDeclaration expToVariable(Expression e)
     {
         switch (e.op)
         {
-            case TOK.variable:
+            case EXP.variable:
                 return (cast(VarExp)e).var.isVarDeclaration();
 
-            case TOK.dotVariable:
+            case EXP.dotVariable:
                 e = (cast(DotVarExp)e).e1;
                 continue;
 
-            case TOK.index:
+            case EXP.index:
             {
                 IndexExp ei = cast(IndexExp)e;
                 e = ei.e1;
@@ -627,7 +628,7 @@ VarDeclaration expToVariable(Expression e)
                 return null;
             }
 
-            case TOK.slice:
+            case EXP.slice:
             {
                 SliceExp ei = cast(SliceExp)e;
                 e = ei.e1;
@@ -637,8 +638,8 @@ VarDeclaration expToVariable(Expression e)
                 return null;
             }
 
-            case TOK.this_:
-            case TOK.super_:
+            case EXP.this_:
+            case EXP.super_:
                 return (cast(ThisExp)e).var.isVarDeclaration();
 
             default:
@@ -662,13 +663,13 @@ enum WANTexpand = 1;    // expand const/immutable variables if possible
  */
 extern (C++) abstract class Expression : ASTNode
 {
-    const TOK op;   // to minimize use of dynamic_cast
+    const EXP op;   // to minimize use of dynamic_cast
     ubyte size;     // # of bytes in Expression so we can copy() it
     ubyte parens;   // if this is a parenthesized expression
     Type type;      // !=null means that semantic() has been run
     Loc loc;        // file location
 
-    extern (D) this(const ref Loc loc, TOK op, int size)
+    extern (D) this(const ref Loc loc, EXP op, int size)
     {
         //printf("Expression::Expression(op = %d) this = %p\n", op, this);
         this.loc = loc;
@@ -678,12 +679,12 @@ extern (C++) abstract class Expression : ASTNode
 
     static void _init()
     {
-        CTFEExp.cantexp = new CTFEExp(TOK.cantExpression);
-        CTFEExp.voidexp = new CTFEExp(TOK.voidExpression);
-        CTFEExp.breakexp = new CTFEExp(TOK.break_);
-        CTFEExp.continueexp = new CTFEExp(TOK.continue_);
-        CTFEExp.gotoexp = new CTFEExp(TOK.goto_);
-        CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
+        CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
+        CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
+        CTFEExp.breakexp = new CTFEExp(EXP.break_);
+        CTFEExp.continueexp = new CTFEExp(EXP.continue_);
+        CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
+        CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
     }
 
     /**
@@ -874,13 +875,13 @@ extern (C++) abstract class Expression : ASTNode
      */
     extern (D) static Expression extractLast(Expression e, out Expression e0)
     {
-        if (e.op != TOK.comma)
+        if (e.op != EXP.comma)
         {
             return e;
         }
 
         CommaExp ce = cast(CommaExp)e;
-        if (ce.e2.op != TOK.comma)
+        if (ce.e2.op != EXP.comma)
         {
             e0 = ce.e1;
             return ce.e2;
@@ -890,11 +891,11 @@ extern (C++) abstract class Expression : ASTNode
             e0 = e;
 
             Expression* pce = &ce.e2;
-            while ((cast(CommaExp)(*pce)).e2.op == TOK.comma)
+            while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
             {
                 pce = &(cast(CommaExp)(*pce)).e2;
             }
-            assert((*pce).op == TOK.comma);
+            assert((*pce).op == EXP.comma);
             ce = cast(CommaExp)(*pce);
             *pce = ce.e1;
 
@@ -918,14 +919,14 @@ extern (C++) abstract class Expression : ASTNode
 
     dinteger_t toInteger()
     {
-        //printf("Expression %s\n", Token::toChars(op));
+        //printf("Expression %s\n", EXPtoString(op).ptr);
         error("integer constant expression expected instead of `%s`", toChars());
         return 0;
     }
 
     uinteger_t toUInteger()
     {
-        //printf("Expression %s\n", Token::toChars(op));
+        //printf("Expression %s\n", EXPtoString(op).ptr);
         return cast(uinteger_t)toInteger();
     }
 
@@ -976,7 +977,7 @@ extern (C++) abstract class Expression : ASTNode
         else if (!loc.isValid())
             loc = e.loc;
 
-        if (e.op == TOK.type)
+        if (e.op == EXP.type)
             error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
         else
             error("`%s` is not an lvalue and cannot be modified", e.toChars());
@@ -1079,7 +1080,7 @@ extern (C++) abstract class Expression : ASTNode
 
     extern (D) final bool checkScalar()
     {
-        if (op == TOK.error)
+        if (op == EXP.error)
             return true;
         if (type.toBasetype().ty == Terror)
             return true;
@@ -1093,7 +1094,7 @@ extern (C++) abstract class Expression : ASTNode
 
     extern (D) final bool checkNoBool()
     {
-        if (op == TOK.error)
+        if (op == EXP.error)
             return true;
         if (type.toBasetype().ty == Terror)
             return true;
@@ -1107,7 +1108,7 @@ extern (C++) abstract class Expression : ASTNode
 
     extern (D) final bool checkIntegral()
     {
-        if (op == TOK.error)
+        if (op == EXP.error)
             return true;
         if (type.toBasetype().ty == Terror)
             return true;
@@ -1121,7 +1122,7 @@ extern (C++) abstract class Expression : ASTNode
 
     extern (D) final bool checkArithmetic()
     {
-        if (op == TOK.error)
+        if (op == EXP.error)
             return true;
         if (type.toBasetype().ty == Terror)
             return true;
@@ -1492,9 +1493,9 @@ extern (C++) abstract class Expression : ASTNode
 
     extern (D) final bool checkRightThis(Scope* sc)
     {
-        if (op == TOK.error)
+        if (op == EXP.error)
             return true;
-        if (op == TOK.variable && type.ty != Terror)
+        if (op == EXP.variable && type.ty != Terror)
         {
             VarExp ve = cast(VarExp)this;
             if (isNeedThisScope(sc, ve.var))
@@ -1513,7 +1514,7 @@ extern (C++) abstract class Expression : ASTNode
      * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
      * Returns true if error occurs.
      */
-    extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null)
+    extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
     {
         //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
         if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
@@ -1522,13 +1523,13 @@ extern (C++) abstract class Expression : ASTNode
         // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
         switch (rmwOp)
         {
-        case TOK.plusPlus:
-        case TOK.prePlusPlus:
-            rmwOp = TOK.addAssign;
+        case EXP.plusPlus:
+        case EXP.prePlusPlus:
+            rmwOp = EXP.addAssign;
             break;
-        case TOK.minusMinus:
-        case TOK.preMinusMinus:
-            rmwOp = TOK.minAssign;
+        case EXP.minusMinus:
+        case EXP.preMinusMinus:
+            rmwOp = EXP.minAssign;
             break;
         default:
             break;
@@ -1536,7 +1537,7 @@ extern (C++) abstract class Expression : ASTNode
 
         error("read-modify-write operations are not allowed for `shared` variables");
         errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
-                          Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1");
+                          EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
         return true;
     }
 
@@ -1558,7 +1559,7 @@ extern (C++) abstract class Expression : ASTNode
         //printf("Expression::addressOf()\n");
         debug
         {
-            assert(op == TOK.error || isLvalue());
+            assert(op == EXP.error || isLvalue());
         }
         Expression e = new AddrExp(loc, this, type.pointerTo());
         return e;
@@ -1597,12 +1598,11 @@ extern (C++) abstract class Expression : ASTNode
         return .isConst(this);
     }
 
-    /********************************
-     * Does this expression statically evaluate to a boolean 'result' (true or false)?
-     */
-    bool isBool(bool result)
+    /// Statically evaluate this expression to a `bool` if possible
+    /// Returns: an optional thath either contains the value or is empty
+    Optional!bool toBool()
     {
-        return false;
+        return typeof(return)();
     }
 
     bool hasCode()
@@ -1612,127 +1612,127 @@ extern (C++) abstract class Expression : ASTNode
 
     final pure inout nothrow @nogc @safe
     {
-        inout(IntegerExp)   isIntegerExp() { return op == TOK.int64 ? cast(typeof(return))this : null; }
-        inout(ErrorExp)     isErrorExp() { return op == TOK.error ? cast(typeof(return))this : null; }
-        inout(VoidInitExp)  isVoidInitExp() { return op == TOK.void_ ? cast(typeof(return))this : null; }
-        inout(RealExp)      isRealExp() { return op == TOK.float64 ? cast(typeof(return))this : null; }
-        inout(ComplexExp)   isComplexExp() { return op == TOK.complex80 ? cast(typeof(return))this : null; }
-        inout(IdentifierExp) isIdentifierExp() { return op == TOK.identifier ? cast(typeof(return))this : null; }
-        inout(DollarExp)    isDollarExp() { return op == TOK.dollar ? cast(typeof(return))this : null; }
-        inout(DsymbolExp)   isDsymbolExp() { return op == TOK.dSymbol ? cast(typeof(return))this : null; }
-        inout(ThisExp)      isThisExp() { return op == TOK.this_ ? cast(typeof(return))this : null; }
-        inout(SuperExp)     isSuperExp() { return op == TOK.super_ ? cast(typeof(return))this : null; }
-        inout(NullExp)      isNullExp() { return op == TOK.null_ ? cast(typeof(return))this : null; }
-        inout(StringExp)    isStringExp() { return op == TOK.string_ ? cast(typeof(return))this : null; }
-        inout(TupleExp)     isTupleExp() { return op == TOK.tuple ? cast(typeof(return))this : null; }
-        inout(ArrayLiteralExp) isArrayLiteralExp() { return op == TOK.arrayLiteral ? cast(typeof(return))this : null; }
-        inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == TOK.assocArrayLiteral ? cast(typeof(return))this : null; }
-        inout(StructLiteralExp) isStructLiteralExp() { return op == TOK.structLiteral ? cast(typeof(return))this : null; }
-        inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == TOK.compoundLiteral ? cast(typeof(return))this : null; }
-        inout(TypeExp)      isTypeExp() { return op == TOK.type ? cast(typeof(return))this : null; }
-        inout(ScopeExp)     isScopeExp() { return op == TOK.scope_ ? cast(typeof(return))this : null; }
-        inout(TemplateExp)  isTemplateExp() { return op == TOK.template_ ? cast(typeof(return))this : null; }
-        inout(NewExp) isNewExp() { return op == TOK.new_ ? cast(typeof(return))this : null; }
-        inout(NewAnonClassExp) isNewAnonClassExp() { return op == TOK.newAnonymousClass ? cast(typeof(return))this : null; }
-        inout(SymOffExp)    isSymOffExp() { return op == TOK.symbolOffset ? cast(typeof(return))this : null; }
-        inout(VarExp)       isVarExp() { return op == TOK.variable ? cast(typeof(return))this : null; }
-        inout(OverExp)      isOverExp() { return op == TOK.overloadSet ? cast(typeof(return))this : null; }
-        inout(FuncExp)      isFuncExp() { return op == TOK.function_ ? cast(typeof(return))this : null; }
-        inout(DeclarationExp) isDeclarationExp() { return op == TOK.declaration ? cast(typeof(return))this : null; }
-        inout(TypeidExp)    isTypeidExp() { return op == TOK.typeid_ ? cast(typeof(return))this : null; }
-        inout(TraitsExp)    isTraitsExp() { return op == TOK.traits ? cast(typeof(return))this : null; }
-        inout(HaltExp)      isHaltExp() { return op == TOK.halt ? cast(typeof(return))this : null; }
-        inout(IsExp)        isExp() { return op == TOK.is_ ? cast(typeof(return))this : null; }
-        inout(MixinExp)     isMixinExp() { return op == TOK.mixin_ ? cast(typeof(return))this : null; }
-        inout(ImportExp)    isImportExp() { return op == TOK.import_ ? cast(typeof(return))this : null; }
-        inout(AssertExp)    isAssertExp() { return op == TOK.assert_ ? cast(typeof(return))this : null; }
-        inout(DotIdExp)     isDotIdExp() { return op == TOK.dotIdentifier ? cast(typeof(return))this : null; }
-        inout(DotTemplateExp) isDotTemplateExp() { return op == TOK.dotTemplateDeclaration ? cast(typeof(return))this : null; }
-        inout(DotVarExp)    isDotVarExp() { return op == TOK.dotVariable ? cast(typeof(return))this : null; }
-        inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == TOK.dotTemplateInstance ? cast(typeof(return))this : null; }
-        inout(DelegateExp)  isDelegateExp() { return op == TOK.delegate_ ? cast(typeof(return))this : null; }
-        inout(DotTypeExp)   isDotTypeExp() { return op == TOK.dotType ? cast(typeof(return))this : null; }
-        inout(CallExp)      isCallExp() { return op == TOK.call ? cast(typeof(return))this : null; }
-        inout(AddrExp)      isAddrExp() { return op == TOK.address ? cast(typeof(return))this : null; }
-        inout(PtrExp)       isPtrExp() { return op == TOK.star ? cast(typeof(return))this : null; }
-        inout(NegExp)       isNegExp() { return op == TOK.negate ? cast(typeof(return))this : null; }
-        inout(UAddExp)      isUAddExp() { return op == TOK.uadd ? cast(typeof(return))this : null; }
-        inout(ComExp)       isComExp() { return op == TOK.tilde ? cast(typeof(return))this : null; }
-        inout(NotExp)       isNotExp() { return op == TOK.not ? cast(typeof(return))this : null; }
-        inout(DeleteExp)    isDeleteExp() { return op == TOK.delete_ ? cast(typeof(return))this : null; }
-        inout(CastExp)      isCastExp() { return op == TOK.cast_ ? cast(typeof(return))this : null; }
-        inout(VectorExp)    isVectorExp() { return op == TOK.vector ? cast(typeof(return))this : null; }
-        inout(VectorArrayExp) isVectorArrayExp() { return op == TOK.vectorArray ? cast(typeof(return))this : null; }
-        inout(SliceExp)     isSliceExp() { return op == TOK.slice ? cast(typeof(return))this : null; }
-        inout(ArrayLengthExp) isArrayLengthExp() { return op == TOK.arrayLength ? cast(typeof(return))this : null; }
-        inout(ArrayExp)     isArrayExp() { return op == TOK.array ? cast(typeof(return))this : null; }
-        inout(DotExp)       isDotExp() { return op == TOK.dot ? cast(typeof(return))this : null; }
-        inout(CommaExp)     isCommaExp() { return op == TOK.comma ? cast(typeof(return))this : null; }
-        inout(IntervalExp)  isIntervalExp() { return op == TOK.interval ? cast(typeof(return))this : null; }
-        inout(DelegatePtrExp)     isDelegatePtrExp() { return op == TOK.delegatePointer ? cast(typeof(return))this : null; }
-        inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == TOK.delegateFunctionPointer ? cast(typeof(return))this : null; }
-        inout(IndexExp)     isIndexExp() { return op == TOK.index ? cast(typeof(return))this : null; }
-        inout(PostExp)      isPostExp()  { return (op == TOK.plusPlus || op == TOK.minusMinus) ? cast(typeof(return))this : null; }
-        inout(PreExp)       isPreExp()   { return (op == TOK.prePlusPlus || op == TOK.preMinusMinus) ? cast(typeof(return))this : null; }
-        inout(AssignExp)    isAssignExp()    { return op == TOK.assign ? cast(typeof(return))this : null; }
-        inout(ConstructExp) isConstructExp() { return op == TOK.construct ? cast(typeof(return))this : null; }
-        inout(BlitExp)      isBlitExp()      { return op == TOK.blit ? cast(typeof(return))this : null; }
-        inout(AddAssignExp) isAddAssignExp() { return op == TOK.addAssign ? cast(typeof(return))this : null; }
-        inout(MinAssignExp) isMinAssignExp() { return op == TOK.minAssign ? cast(typeof(return))this : null; }
-        inout(MulAssignExp) isMulAssignExp() { return op == TOK.mulAssign ? cast(typeof(return))this : null; }
-
-        inout(DivAssignExp) isDivAssignExp() { return op == TOK.divAssign ? cast(typeof(return))this : null; }
-        inout(ModAssignExp) isModAssignExp() { return op == TOK.modAssign ? cast(typeof(return))this : null; }
-        inout(AndAssignExp) isAndAssignExp() { return op == TOK.andAssign ? cast(typeof(return))this : null; }
-        inout(OrAssignExp)  isOrAssignExp()  { return op == TOK.orAssign ? cast(typeof(return))this : null; }
-        inout(XorAssignExp) isXorAssignExp() { return op == TOK.xorAssign ? cast(typeof(return))this : null; }
-        inout(PowAssignExp) isPowAssignExp() { return op == TOK.powAssign ? cast(typeof(return))this : null; }
-
-        inout(ShlAssignExp)  isShlAssignExp()  { return op == TOK.leftShiftAssign ? cast(typeof(return))this : null; }
-        inout(ShrAssignExp)  isShrAssignExp()  { return op == TOK.rightShiftAssign ? cast(typeof(return))this : null; }
-        inout(UshrAssignExp) isUshrAssignExp() { return op == TOK.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
-
-        inout(CatAssignExp) isCatAssignExp() { return op == TOK.concatenateAssign
+        inout(IntegerExp)   isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
+        inout(ErrorExp)     isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
+        inout(VoidInitExp)  isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
+        inout(RealExp)      isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
+        inout(ComplexExp)   isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
+        inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
+        inout(DollarExp)    isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
+        inout(DsymbolExp)   isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
+        inout(ThisExp)      isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
+        inout(SuperExp)     isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
+        inout(NullExp)      isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
+        inout(StringExp)    isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
+        inout(TupleExp)     isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
+        inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
+        inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
+        inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
+        inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
+        inout(TypeExp)      isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
+        inout(ScopeExp)     isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
+        inout(TemplateExp)  isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
+        inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
+        inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
+        inout(SymOffExp)    isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
+        inout(VarExp)       isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
+        inout(OverExp)      isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
+        inout(FuncExp)      isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
+        inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
+        inout(TypeidExp)    isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
+        inout(TraitsExp)    isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
+        inout(HaltExp)      isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
+        inout(IsExp)        isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
+        inout(MixinExp)     isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
+        inout(ImportExp)    isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
+        inout(AssertExp)    isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
+        inout(DotIdExp)     isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
+        inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
+        inout(DotVarExp)    isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
+        inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
+        inout(DelegateExp)  isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
+        inout(DotTypeExp)   isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
+        inout(CallExp)      isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
+        inout(AddrExp)      isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
+        inout(PtrExp)       isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
+        inout(NegExp)       isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
+        inout(UAddExp)      isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
+        inout(ComExp)       isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
+        inout(NotExp)       isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
+        inout(DeleteExp)    isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
+        inout(CastExp)      isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
+        inout(VectorExp)    isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
+        inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
+        inout(SliceExp)     isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
+        inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
+        inout(ArrayExp)     isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
+        inout(DotExp)       isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
+        inout(CommaExp)     isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
+        inout(IntervalExp)  isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
+        inout(DelegatePtrExp)     isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
+        inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
+        inout(IndexExp)     isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
+        inout(PostExp)      isPostExp()  { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
+        inout(PreExp)       isPreExp()   { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
+        inout(AssignExp)    isAssignExp()    { return op == EXP.assign ? cast(typeof(return))this : null; }
+        inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
+        inout(BlitExp)      isBlitExp()      { return op == EXP.blit ? cast(typeof(return))this : null; }
+        inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
+        inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
+        inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
+
+        inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
+        inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
+        inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
+        inout(OrAssignExp)  isOrAssignExp()  { return op == EXP.orAssign ? cast(typeof(return))this : null; }
+        inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
+        inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
+
+        inout(ShlAssignExp)  isShlAssignExp()  { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
+        inout(ShrAssignExp)  isShrAssignExp()  { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
+        inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
+
+        inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
                                                 ? cast(typeof(return))this
                                                 : null; }
 
-        inout(CatElemAssignExp) isCatElemAssignExp() { return op == TOK.concatenateElemAssign
+        inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
                                                 ? cast(typeof(return))this
                                                 : null; }
 
-        inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == TOK.concatenateDcharAssign
+        inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
                                                 ? cast(typeof(return))this
                                                 : null; }
 
-        inout(AddExp)      isAddExp() { return op == TOK.add ? cast(typeof(return))this : null; }
-        inout(MinExp)      isMinExp() { return op == TOK.min ? cast(typeof(return))this : null; }
-        inout(CatExp)      isCatExp() { return op == TOK.concatenate ? cast(typeof(return))this : null; }
-        inout(MulExp)      isMulExp() { return op == TOK.mul ? cast(typeof(return))this : null; }
-        inout(DivExp)      isDivExp() { return op == TOK.div ? cast(typeof(return))this : null; }
-        inout(ModExp)      isModExp() { return op == TOK.mod ? cast(typeof(return))this : null; }
-        inout(PowExp)      isPowExp() { return op == TOK.pow ? cast(typeof(return))this : null; }
-        inout(ShlExp)      isShlExp() { return op == TOK.leftShift ? cast(typeof(return))this : null; }
-        inout(ShrExp)      isShrExp() { return op == TOK.rightShift ? cast(typeof(return))this : null; }
-        inout(UshrExp)     isUshrExp() { return op == TOK.unsignedRightShift ? cast(typeof(return))this : null; }
-        inout(AndExp)      isAndExp() { return op == TOK.and ? cast(typeof(return))this : null; }
-        inout(OrExp)       isOrExp() { return op == TOK.or ? cast(typeof(return))this : null; }
-        inout(XorExp)      isXorExp() { return op == TOK.xor ? cast(typeof(return))this : null; }
-        inout(LogicalExp)  isLogicalExp() { return (op == TOK.andAnd || op == TOK.orOr) ? cast(typeof(return))this : null; }
-        //inout(CmpExp)    isCmpExp() { return op == TOK. ? cast(typeof(return))this : null; }
-        inout(InExp)       isInExp() { return op == TOK.in_ ? cast(typeof(return))this : null; }
-        inout(RemoveExp)   isRemoveExp() { return op == TOK.remove ? cast(typeof(return))this : null; }
-        inout(EqualExp)    isEqualExp() { return (op == TOK.equal || op == TOK.notEqual) ? cast(typeof(return))this : null; }
-        inout(IdentityExp) isIdentityExp() { return (op == TOK.identity || op == TOK.notIdentity) ? cast(typeof(return))this : null; }
-        inout(CondExp)     isCondExp() { return op == TOK.question ? cast(typeof(return))this : null; }
-        inout(GenericExp)  isGenericExp() { return op == TOK._Generic ? cast(typeof(return))this : null; }
+        inout(AddExp)      isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
+        inout(MinExp)      isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
+        inout(CatExp)      isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
+        inout(MulExp)      isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
+        inout(DivExp)      isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
+        inout(ModExp)      isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
+        inout(PowExp)      isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
+        inout(ShlExp)      isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
+        inout(ShrExp)      isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
+        inout(UshrExp)     isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
+        inout(AndExp)      isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
+        inout(OrExp)       isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
+        inout(XorExp)      isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
+        inout(LogicalExp)  isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
+        //inout(CmpExp)    isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
+        inout(InExp)       isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
+        inout(RemoveExp)   isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
+        inout(EqualExp)    isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
+        inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
+        inout(CondExp)     isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
+        inout(GenericExp)  isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
         inout(DefaultInitExp)    isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
-        inout(FileInitExp)       isFileInitExp() { return (op == TOK.file || op == TOK.fileFullPath) ? cast(typeof(return))this : null; }
-        inout(LineInitExp)       isLineInitExp() { return op == TOK.line ? cast(typeof(return))this : null; }
-        inout(ModuleInitExp)     isModuleInitExp() { return op == TOK.moduleString ? cast(typeof(return))this : null; }
-        inout(FuncInitExp)       isFuncInitExp() { return op == TOK.functionString ? cast(typeof(return))this : null; }
-        inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == TOK.prettyFunction ? cast(typeof(return))this : null; }
-        inout(ClassReferenceExp) isClassReferenceExp() { return op == TOK.classReference ? cast(typeof(return))this : null; }
-        inout(ThrownExceptionExp) isThrownExceptionExp() { return op == TOK.thrownException ? cast(typeof(return))this : null; }
+        inout(FileInitExp)       isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
+        inout(LineInitExp)       isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
+        inout(ModuleInitExp)     isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
+        inout(FuncInitExp)       isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
+        inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
+        inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
+        inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
     }
 
     inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
@@ -1754,7 +1754,7 @@ extern (C++) final class IntegerExp : Expression
 
     extern (D) this(const ref Loc loc, dinteger_t value, Type type)
     {
-        super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp));
+        super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp));
         //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
         assert(type);
         if (!type.isscalar())
@@ -1770,7 +1770,7 @@ extern (C++) final class IntegerExp : Expression
 
     extern (D) this(dinteger_t value)
     {
-        super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp));
+        super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp));
         this.type = Type.tint32;
         this.value = cast(d_int32)value;
     }
@@ -1827,10 +1827,10 @@ extern (C++) final class IntegerExp : Expression
         return complex_t(toReal());
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
         bool r = toInteger() != 0;
-        return result ? r : !r;
+        return typeof(return)(r);
     }
 
     override Expression toLvalue(Scope* sc, Expression e)
@@ -1969,7 +1969,7 @@ extern (C++) final class ErrorExp : Expression
 {
     private extern (D) this()
     {
-        super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp));
+        super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp));
         type = Type.terror;
     }
 
@@ -2015,7 +2015,7 @@ extern (C++) final class VoidInitExp : Expression
 
     extern (D) this(VarDeclaration var)
     {
-        super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp));
+        super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp));
         this.var = var;
         this.type = var.type;
     }
@@ -2040,7 +2040,7 @@ extern (C++) final class RealExp : Expression
 
     extern (D) this(const ref Loc loc, real_t value, Type type)
     {
-        super(loc, TOK.float64, __traits(classInstanceSize, RealExp));
+        super(loc, EXP.float64, __traits(classInstanceSize, RealExp));
         //printf("RealExp::RealExp(%Lg)\n", value);
         this.value = value;
         this.type = type;
@@ -2096,9 +2096,9 @@ extern (C++) final class RealExp : Expression
         return complex_t(toReal(), toImaginary());
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return result ? cast(bool)value : !cast(bool)value;
+        return typeof(return)(!!value);
     }
 
     override void accept(Visitor v)
@@ -2115,7 +2115,7 @@ extern (C++) final class ComplexExp : Expression
 
     extern (D) this(const ref Loc loc, complex_t value, Type type)
     {
-        super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp));
+        super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp));
         this.value = value;
         this.type = type;
         //printf("ComplexExp::ComplexExp(%s)\n", toChars());
@@ -2171,12 +2171,9 @@ extern (C++) final class ComplexExp : Expression
         return value;
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        if (result)
-            return cast(bool)value;
-        else
-            return !value;
+        return typeof(return)(!!value);
     }
 
     override void accept(Visitor v)
@@ -2193,7 +2190,7 @@ extern (C++) class IdentifierExp : Expression
 
     extern (D) this(const ref Loc loc, Identifier ident)
     {
-        super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp));
+        super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp));
         this.ident = ident;
     }
 
@@ -2243,7 +2240,7 @@ extern (C++) final class DsymbolExp : Expression
 
     extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
     {
-        super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp));
+        super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp));
         this.s = s;
         this.hasOverloads = hasOverloads;
     }
@@ -2273,11 +2270,11 @@ extern (C++) class ThisExp : Expression
 
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.this_, __traits(classInstanceSize, ThisExp));
+        super(loc, EXP.this_, __traits(classInstanceSize, ThisExp));
         //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
     }
 
-    this(const ref Loc loc, const TOK tok)
+    this(const ref Loc loc, const EXP tok)
     {
         super(loc, tok, __traits(classInstanceSize, ThisExp));
         //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
@@ -2292,9 +2289,10 @@ extern (C++) class ThisExp : Expression
         return r;
     }
 
-    override final bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return result;
+        // `this` is never null (what about structs?)
+        return typeof(return)(true);
     }
 
     override final bool isLvalue()
@@ -2326,7 +2324,7 @@ extern (C++) final class SuperExp : ThisExp
 {
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.super_);
+        super(loc, EXP.super_);
     }
 
     override void accept(Visitor v)
@@ -2342,7 +2340,7 @@ extern (C++) final class NullExp : Expression
 {
     extern (D) this(const ref Loc loc, Type type = null)
     {
-        super(loc, TOK.null_, __traits(classInstanceSize, NullExp));
+        super(loc, EXP.null_, __traits(classInstanceSize, NullExp));
         this.type = type;
     }
 
@@ -2350,7 +2348,7 @@ extern (C++) final class NullExp : Expression
     {
         if (auto e = o.isExpression())
         {
-            if (e.op == TOK.null_ && type.equals(e.type))
+            if (e.op == EXP.null_ && type.equals(e.type))
             {
                 return true;
             }
@@ -2358,9 +2356,10 @@ extern (C++) final class NullExp : Expression
         return false;
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return result ? false : true;
+        // null in any type is false
+        return typeof(return)(false);
     }
 
     override StringExp toStringExp()
@@ -2400,7 +2399,7 @@ extern (C++) final class StringExp : Expression
 
     extern (D) this(const ref Loc loc, const(void)[] string)
     {
-        super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
+        super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
         this.string = cast(char*)string.ptr; // note that this.string should be const
         this.len = string.length;
         this.sz = 1;                    // work around LDC bug #1286
@@ -2408,7 +2407,7 @@ extern (C++) final class StringExp : Expression
 
     extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
     {
-        super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
+        super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
         this.string = cast(char*)string.ptr; // note that this.string should be const
         this.len = len;
         this.sz = sz;
@@ -2681,9 +2680,11 @@ extern (C++) final class StringExp : Expression
         return cast(int)(len1 - len2);
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return result;
+        // Keep the old behaviour for this refactoring
+        // Should probably match language spec instead and check for length
+        return typeof(return)(true);
     }
 
     override bool isLvalue()
@@ -2810,7 +2811,7 @@ extern (C++) final class TupleExp : Expression
 
     extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
     {
-        super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+        super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
         //printf("TupleExp(this = %p)\n", this);
         this.e0 = e0;
         this.exps = exps;
@@ -2818,14 +2819,14 @@ extern (C++) final class TupleExp : Expression
 
     extern (D) this(const ref Loc loc, Expressions* exps)
     {
-        super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+        super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
         //printf("TupleExp(this = %p)\n", this);
         this.exps = exps;
     }
 
     extern (D) this(const ref Loc loc, TupleDeclaration tup)
     {
-        super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+        super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
         this.exps = new Expressions();
 
         this.exps.reserve(tup.objects.dim);
@@ -2919,14 +2920,14 @@ extern (C++) final class ArrayLiteralExp : Expression
 
     extern (D) this(const ref Loc loc, Type type, Expressions* elements)
     {
-        super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+        super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
         this.type = type;
         this.elements = elements;
     }
 
     extern (D) this(const ref Loc loc, Type type, Expression e)
     {
-        super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+        super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
         this.type = type;
         elements = new Expressions();
         elements.push(e);
@@ -2934,7 +2935,7 @@ extern (C++) final class ArrayLiteralExp : Expression
 
     extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
     {
-        super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+        super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
         this.type = type;
         this.basis = basis;
         this.elements = elements;
@@ -3000,10 +3001,10 @@ extern (C++) final class ArrayLiteralExp : Expression
         return el ? el : basis;
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
         size_t dim = elements ? elements.dim : 0;
-        return result ? (dim != 0) : (dim == 0);
+        return typeof(return)(dim != 0);
     }
 
     override StringExp toStringExp()
@@ -3023,7 +3024,7 @@ extern (C++) final class ArrayLiteralExp : Expression
                 foreach (i; 0 .. elements.dim)
                 {
                     auto ch = this[i];
-                    if (ch.op != TOK.int64)
+                    if (ch.op != EXP.int64)
                         return null;
                     if (sz == 1)
                         buf.writeByte(cast(uint)ch.toInteger());
@@ -3079,7 +3080,7 @@ extern (C++) final class AssocArrayLiteralExp : Expression
 
     extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
     {
-        super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
+        super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
         assert(keys.dim == values.dim);
         this.keys = keys;
         this.values = values;
@@ -3119,10 +3120,10 @@ extern (C++) final class AssocArrayLiteralExp : Expression
         return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
         size_t dim = keys.dim;
-        return result ? (dim != 0) : (dim == 0);
+        return typeof(return)(dim != 0);
     }
 
     override void accept(Visitor v)
@@ -3172,7 +3173,7 @@ extern (C++) final class StructLiteralExp : Expression
 
     extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
     {
-        super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp));
+        super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp));
         this.sd = sd;
         if (!elements)
             elements = new Expressions();
@@ -3278,9 +3279,12 @@ extern (C++) final class StructLiteralExp : Expression
          */
         if (elements.dim)
         {
+            const sz = type.size();
+            if (sz == SIZE_INVALID)
+                return -1;
             foreach (i, v; sd.fields)
             {
-                if (offset == v.offset && type.size() == v.type.size())
+                if (offset == v.offset && sz == v.type.size())
                 {
                     /* context fields might not be filled. */
                     if (i >= sd.nonHiddenFields())
@@ -3348,7 +3352,7 @@ extern (C++) final class CompoundLiteralExp : Expression
 
     extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
     {
-        super(loc, TOK.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
+        super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
         super.type = type_name;
         this.initializer = initializer;
         //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
@@ -3367,7 +3371,7 @@ extern (C++) final class TypeExp : Expression
 {
     extern (D) this(const ref Loc loc, Type type)
     {
-        super(loc, TOK.type, __traits(classInstanceSize, TypeExp));
+        super(loc, EXP.type, __traits(classInstanceSize, TypeExp));
         //printf("TypeExp::TypeExp(%s)\n", type.toChars());
         this.type = type;
     }
@@ -3409,7 +3413,7 @@ extern (C++) final class ScopeExp : Expression
 
     extern (D) this(const ref Loc loc, ScopeDsymbol sds)
     {
-        super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp));
+        super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp));
         //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
         //static int count; if (++count == 38) *(char*)0=0;
         this.sds = sds;
@@ -3464,7 +3468,7 @@ extern (C++) final class TemplateExp : Expression
 
     extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
     {
-        super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp));
+        super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp));
         //printf("TemplateExp(): %s\n", td.toChars());
         this.td = td;
         this.fd = fd;
@@ -3519,7 +3523,7 @@ extern (C++) final class NewExp : Expression
 
     extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
     {
-        super(loc, TOK.new_, __traits(classInstanceSize, NewExp));
+        super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
         this.thisexp = thisexp;
         this.newargs = newargs;
         this.newtype = newtype;
@@ -3558,7 +3562,7 @@ extern (C++) final class NewAnonClassExp : Expression
 
     extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
     {
-        super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
+        super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
         this.thisexp = thisexp;
         this.newargs = newargs;
         this.cd = cd;
@@ -3584,7 +3588,7 @@ extern (C++) class SymbolExp : Expression
     Dsymbol originalScope; // original scope before inlining
     bool hasOverloads;
 
-    extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads)
+    extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads)
     {
         super(loc, op, size);
         assert(var);
@@ -3615,13 +3619,13 @@ extern (C++) final class SymOffExp : SymbolExp
                 .error(loc, "need `this` for address of `%s`", v.toChars());
             hasOverloads = false;
         }
-        super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
+        super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
         this.offset = offset;
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return result ? true : false;
+        return typeof(return)(true);
     }
 
     override void accept(Visitor v)
@@ -3641,7 +3645,7 @@ extern (C++) final class VarExp : SymbolExp
         if (var.isVarDeclaration())
             hasOverloads = false;
 
-        super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
+        super(loc, EXP.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
         //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
         //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
         this.type = var.type;
@@ -3725,7 +3729,7 @@ extern (C++) final class OverExp : Expression
 
     extern (D) this(const ref Loc loc, OverloadSet s)
     {
-        super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp));
+        super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp));
         //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
         vars = s;
         type = Type.tvoid;
@@ -3755,11 +3759,11 @@ extern (C++) final class FuncExp : Expression
 {
     FuncLiteralDeclaration fd;
     TemplateDeclaration td;
-    TOK tok;
+    TOK tok;  // TOK.reserved, TOK.delegate_, TOK.function_
 
     extern (D) this(const ref Loc loc, Dsymbol s)
     {
-        super(loc, TOK.function_, __traits(classInstanceSize, FuncExp));
+        super(loc, EXP.function_, __traits(classInstanceSize, FuncExp));
         this.td = s.isTemplateDeclaration();
         this.fd = s.isFuncLiteralDeclaration();
         if (td)
@@ -3927,7 +3931,7 @@ extern (C++) final class FuncExp : Expression
             // Reset inference target for the later re-semantic
             fd.treq = null;
 
-            if (ex.op == TOK.error)
+            if (ex.op == EXP.error)
                 return MATCH.nomatch;
             if (auto ef = ex.isFuncExp())
                 return ef.matchType(to, sc, presult, flag);
@@ -4057,7 +4061,7 @@ extern (C++) final class DeclarationExp : Expression
 
     extern (D) this(const ref Loc loc, Dsymbol declaration)
     {
-        super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp));
+        super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp));
         this.declaration = declaration;
     }
 
@@ -4090,7 +4094,7 @@ extern (C++) final class TypeidExp : Expression
 
     extern (D) this(const ref Loc loc, RootObject o)
     {
-        super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp));
+        super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp));
         this.obj = o;
     }
 
@@ -4115,7 +4119,7 @@ extern (C++) final class TraitsExp : Expression
 
     extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
     {
-        super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp));
+        super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp));
         this.ident = ident;
         this.args = args;
     }
@@ -4137,7 +4141,7 @@ extern (C++) final class HaltExp : Expression
 {
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.halt, __traits(classInstanceSize, HaltExp));
+        super(loc, EXP.halt, __traits(classInstanceSize, HaltExp));
     }
 
     override void accept(Visitor v)
@@ -4161,7 +4165,7 @@ extern (C++) final class IsExp : Expression
 
     extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
     {
-        super(loc, TOK.is_, __traits(classInstanceSize, IsExp));
+        super(loc, EXP.is_, __traits(classInstanceSize, IsExp));
         this.targ = targ;
         this.id = id;
         this.tok = tok;
@@ -4196,7 +4200,7 @@ extern (C++) abstract class UnaExp : Expression
     Expression e1;
     Type att1;      // Save alias this type to detect recursion
 
-    extern (D) this(const ref Loc loc, TOK op, int size, Expression e1)
+    extern (D) this(const ref Loc loc, EXP op, int size, Expression e1)
     {
         super(loc, op, size);
         this.e1 = e1;
@@ -4221,13 +4225,13 @@ extern (C++) abstract class UnaExp : Expression
         if (e1.type.toBasetype() == Type.terror)
             return e1;
 
-        if (e1.op == TOK.type)
+        if (e1.op == EXP.type)
         {
-            error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op));
+            error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
         }
         else
         {
-            error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars());
+            error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
         }
         return ErrorExp.get();
     }
@@ -4257,7 +4261,7 @@ extern (C++) abstract class UnaExp : Expression
 }
 
 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
-alias fp2_t = bool function(const ref Loc loc, TOK, Expression, Expression);
+alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
 
 /***********************************************************
  */
@@ -4268,7 +4272,7 @@ extern (C++) abstract class BinExp : Expression
     Type att1;      // Save alias this type to detect recursion
     Type att2;      // Save alias this type to detect recursion
 
-    extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
+    extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
     {
         super(loc, op, size);
         this.e1 = e1;
@@ -4298,22 +4302,22 @@ extern (C++) abstract class BinExp : Expression
             return e2;
 
         // CondExp uses 'a ? b : c' but we're comparing 'b : c'
-        TOK thisOp = (op == TOK.question) ? TOK.colon : op;
-        if (e1.op == TOK.type || e2.op == TOK.type)
+        const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
+        if (e1.op == EXP.type || e2.op == EXP.type)
         {
             error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
-                e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op));
+                e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
         }
         else if (e1.type.equals(e2.type))
         {
             error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
-                e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars());
+                e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
         }
         else
         {
             auto ts = toAutoQualChars(e1.type, e2.type);
             error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
-                e1.toChars(), Token.toChars(thisOp), e2.toChars(), ts[0], ts[1]);
+                e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
         }
         return ErrorExp.get();
     }
@@ -4327,22 +4331,22 @@ extern (C++) abstract class BinExp : Expression
         // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
         // See issue 3841.
         // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
-        if (op == TOK.addAssign || op == TOK.minAssign ||
-            op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign ||
-            op == TOK.powAssign)
+        if (op == EXP.addAssign || op == EXP.minAssign ||
+            op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
+            op == EXP.powAssign)
         {
             if ((type.isintegral() && t2.isfloating()))
             {
-                warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars());
+                warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
             }
         }
 
         // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
-        if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign)
+        if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
         {
             // Any multiplication by an imaginary or complex number yields a complex result.
             // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
-            const(char)* opstr = Token.toChars(op);
+            const(char)* opstr = EXPtoString(op).ptr;
             if (t1.isreal() && t2.iscomplex())
             {
                 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
@@ -4361,13 +4365,13 @@ extern (C++) abstract class BinExp : Expression
         }
 
         // generate an error if this is a nonsensical += or -=, eg real += imaginary
-        if (op == TOK.addAssign || op == TOK.minAssign)
+        if (op == EXP.addAssign || op == EXP.minAssign)
         {
             // Addition or subtraction of a real and an imaginary is a complex result.
             // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
             if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
             {
-                error("`%s %s %s` is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars());
+                error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
                 return ErrorExp.get();
             }
             if (type.isreal() || type.isimaginary())
@@ -4376,7 +4380,7 @@ extern (C++) abstract class BinExp : Expression
                 e2 = e2.castTo(sc, t1);
             }
         }
-        if (op == TOK.mulAssign)
+        if (op == EXP.mulAssign)
         {
             if (t2.isfloating())
             {
@@ -4413,7 +4417,7 @@ extern (C++) abstract class BinExp : Expression
                 }
             }
         }
-        else if (op == TOK.divAssign)
+        else if (op == EXP.divAssign)
         {
             if (t2.isimaginary())
             {
@@ -4454,7 +4458,7 @@ extern (C++) abstract class BinExp : Expression
                 }
             }
         }
-        else if (op == TOK.modAssign)
+        else if (op == EXP.modAssign)
         {
             if (t2.iscomplex())
             {
@@ -4558,7 +4562,7 @@ extern (C++) abstract class BinExp : Expression
  */
 extern (C++) class BinAssignExp : BinExp
 {
-    extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
+    extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
     {
         super(loc, op, size, e1, e2);
     }
@@ -4600,7 +4604,7 @@ extern (C++) final class MixinExp : Expression
 
     extern (D) this(const ref Loc loc, Expressions* exps)
     {
-        super(loc, TOK.mixin_, __traits(classInstanceSize, MixinExp));
+        super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp));
         this.exps = exps;
     }
 
@@ -4643,7 +4647,7 @@ extern (C++) final class ImportExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e);
+        super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e);
     }
 
     override void accept(Visitor v)
@@ -4661,7 +4665,7 @@ extern (C++) final class AssertExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
     {
-        super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e);
+        super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e);
         this.msg = msg;
     }
 
@@ -4687,7 +4691,7 @@ extern (C++) final class DotIdExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Identifier ident)
     {
-        super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
+        super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
         this.ident = ident;
     }
 
@@ -4711,7 +4715,7 @@ extern (C++) final class DotTemplateExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
     {
-        super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
+        super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
         this.td = td;
     }
 
@@ -4745,7 +4749,7 @@ extern (C++) final class DotVarExp : UnaExp
         if (var.isVarDeclaration())
             hasOverloads = false;
 
-        super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e);
+        super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e);
         //printf("DotVarExp()\n");
         this.var = var;
         this.hasOverloads = hasOverloads;
@@ -4753,7 +4757,7 @@ extern (C++) final class DotVarExp : UnaExp
 
     override bool isLvalue()
     {
-        if (e1.op != TOK.structLiteral)
+        if (e1.op != EXP.structLiteral)
             return true;
         auto vd = var.isVarDeclaration();
         return !(vd && vd.isField());
@@ -4772,7 +4776,7 @@ extern (C++) final class DotVarExp : UnaExp
         }
         if (!isLvalue())
             return Expression.toLvalue(sc, e);
-        if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
+        if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
         {
             if (VarDeclaration vd = var.isVarDeclaration())
             {
@@ -4826,14 +4830,14 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
     {
-        super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+        super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
         //printf("DotTemplateInstanceExp()\n");
         this.ti = new TemplateInstance(loc, name, tiargs);
     }
 
     extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
     {
-        super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+        super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
         this.ti = ti;
     }
 
@@ -4853,29 +4857,29 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
 
         Expression e = new DotIdExp(loc, e1, ti.name);
         e = e.expressionSemantic(sc);
-        if (e.op == TOK.dot)
+        if (e.op == EXP.dot)
             e = (cast(DotExp)e).e2;
 
         Dsymbol s = null;
         switch (e.op)
         {
-        case TOK.overloadSet:
+        case EXP.overloadSet:
             s = (cast(OverExp)e).vars;
             break;
 
-        case TOK.dotTemplateDeclaration:
+        case EXP.dotTemplateDeclaration:
             s = (cast(DotTemplateExp)e).td;
             break;
 
-        case TOK.scope_:
+        case EXP.scope_:
             s = (cast(ScopeExp)e).sds;
             break;
 
-        case TOK.dotVariable:
+        case EXP.dotVariable:
             s = (cast(DotVarExp)e).var;
             break;
 
-        case TOK.variable:
+        case EXP.variable:
             s = (cast(VarExp)e).var;
             break;
 
@@ -4926,7 +4930,7 @@ extern (C++) final class DelegateExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
     {
-        super(loc, TOK.delegate_, __traits(classInstanceSize, DelegateExp), e);
+        super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e);
         this.func = f;
         this.hasOverloads = hasOverloads;
         this.vthis2 = vthis2;
@@ -4946,7 +4950,7 @@ extern (C++) final class DotTypeExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
     {
-        super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e);
+        super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e);
         this.sym = s;
     }
 
@@ -4969,18 +4973,18 @@ extern (C++) final class CallExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
     {
-        super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+        super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
         this.arguments = exps;
     }
 
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+        super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
     }
 
     extern (D) this(const ref Loc loc, Expression e, Expression earg1)
     {
-        super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+        super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
         this.arguments = new Expressions();
         if (earg1)
             this.arguments.push(earg1);
@@ -4988,7 +4992,7 @@ extern (C++) final class CallExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
     {
-        super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+        super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
         auto arguments = new Expressions(2);
         (*arguments)[0] = earg1;
         (*arguments)[1] = earg2;
@@ -5143,7 +5147,7 @@ extern (C++) final class AddrExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e);
+        super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e);
     }
 
     extern (D) this(const ref Loc loc, Expression e, Type t)
@@ -5164,14 +5168,14 @@ extern (C++) final class PtrExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
+        super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
         //if (e.type)
         //  type = ((TypePointer *)e.type).next;
     }
 
     extern (D) this(const ref Loc loc, Expression e, Type t)
     {
-        super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
+        super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
         type = t;
     }
 
@@ -5216,7 +5220,7 @@ extern (C++) final class NegExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e);
+        super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e);
     }
 
     override void accept(Visitor v)
@@ -5231,7 +5235,7 @@ extern (C++) final class UAddExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e);
+        super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
     }
 
     override void accept(Visitor v)
@@ -5246,7 +5250,7 @@ extern (C++) final class ComExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e);
+        super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e);
     }
 
     override void accept(Visitor v)
@@ -5261,7 +5265,7 @@ extern (C++) final class NotExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e)
     {
-        super(loc, TOK.not, __traits(classInstanceSize, NotExp), e);
+        super(loc, EXP.not, __traits(classInstanceSize, NotExp), e);
     }
 
     override void accept(Visitor v)
@@ -5278,7 +5282,7 @@ extern (C++) final class DeleteExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, bool isRAII)
     {
-        super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e);
+        super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e);
         this.isRAII = isRAII;
     }
 
@@ -5298,7 +5302,7 @@ extern (C++) final class CastExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Type t)
     {
-        super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
+        super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
         this.to = t;
     }
 
@@ -5306,7 +5310,7 @@ extern (C++) final class CastExp : UnaExp
      */
     extern (D) this(const ref Loc loc, Expression e, ubyte mod)
     {
-        super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
+        super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
         this.mod = mod;
     }
 
@@ -5360,7 +5364,7 @@ extern (C++) final class VectorExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e, Type t)
     {
-        super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e);
+        super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e);
         assert(t.ty == Tvector);
         to = cast(TypeVector)t;
     }
@@ -5396,7 +5400,7 @@ extern (C++) final class VectorArrayExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e1)
     {
-        super(loc, TOK.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
+        super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
     }
 
     override bool isLvalue()
@@ -5434,14 +5438,14 @@ extern (C++) final class SliceExp : UnaExp
     /************************************************************/
     extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
     {
-        super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
+        super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
         this.upr = ie ? ie.upr : null;
         this.lwr = ie ? ie.lwr : null;
     }
 
     extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
     {
-        super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
+        super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
         this.upr = upr;
         this.lwr = lwr;
     }
@@ -5473,9 +5477,9 @@ extern (C++) final class SliceExp : UnaExp
         return this;
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return e1.isBool(result);
+        return e1.toBool();
     }
 
     override void accept(Visitor v)
@@ -5490,7 +5494,7 @@ extern (C++) final class ArrayLengthExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e1)
     {
-        super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
+        super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
     }
 
     override void accept(Visitor v)
@@ -5513,7 +5517,7 @@ extern (C++) final class ArrayExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
     {
-        super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
+        super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
         arguments = new Expressions();
         if (index)
             arguments.push(index);
@@ -5521,7 +5525,7 @@ extern (C++) final class ArrayExp : UnaExp
 
     extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
     {
-        super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
+        super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
         arguments = args;
     }
 
@@ -5558,7 +5562,7 @@ extern (C++) final class DotExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.dot, __traits(classInstanceSize, DotExp), e1, e2);
+        super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -5584,7 +5588,7 @@ extern (C++) final class CommaExp : BinExp
 
     extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
     {
-        super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2);
+        super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2);
         allowCommaExp = isGenerated = generated;
     }
 
@@ -5605,9 +5609,9 @@ extern (C++) final class CommaExp : BinExp
         return this;
     }
 
-    override bool isBool(bool result)
+    override Optional!bool toBool()
     {
-        return e2.isBool(result);
+        return e2.toBool();
     }
 
     override Expression addDtorHook(Scope* sc)
@@ -5653,7 +5657,7 @@ extern (C++) final class IntervalExp : Expression
 
     extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
     {
-        super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp));
+        super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp));
         this.lwr = lwr;
         this.upr = upr;
     }
@@ -5673,7 +5677,7 @@ extern (C++) final class DelegatePtrExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e1)
     {
-        super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
+        super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
     }
 
     override bool isLvalue()
@@ -5709,7 +5713,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp
 {
     extern (D) this(const ref Loc loc, Expression e1)
     {
-        super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
+        super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
     }
 
     override bool isLvalue()
@@ -5750,7 +5754,7 @@ extern (C++) final class IndexExp : BinExp
 
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2);
+        super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
         //printf("IndexExp::IndexExp('%s')\n", toChars());
     }
 
@@ -5763,10 +5767,10 @@ extern (C++) final class IndexExp : BinExp
 
     override bool isLvalue()
     {
-        if (e1.op == TOK.assocArrayLiteral)
+        if (e1.op == EXP.assocArrayLiteral)
             return false;
         if (e1.type.ty == Tsarray ||
-            (e1.op == TOK.index && e1.type.ty != Tarray))
+            (e1.op == EXP.index && e1.type.ty != Tarray))
         {
             return e1.isLvalue();
         }
@@ -5784,7 +5788,7 @@ extern (C++) final class IndexExp : BinExp
     {
         //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
         Expression ex = markSettingAAElem();
-        if (ex.op == TOK.error)
+        if (ex.op == EXP.error)
             return ex;
 
         return Expression.modifiableLvalue(sc, e);
@@ -5805,7 +5809,7 @@ extern (C++) final class IndexExp : BinExp
             if (auto ie = e1.isIndexExp())
             {
                 Expression ex = ie.markSettingAAElem();
-                if (ex.op == TOK.error)
+                if (ex.op == EXP.error)
                     return ex;
                 assert(ex == e1);
             }
@@ -5824,10 +5828,10 @@ extern (C++) final class IndexExp : BinExp
  */
 extern (C++) final class PostExp : BinExp
 {
-    extern (D) this(TOK op, const ref Loc loc, Expression e)
+    extern (D) this(EXP op, const ref Loc loc, Expression e)
     {
         super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
-        assert(op == TOK.minusMinus || op == TOK.plusPlus);
+        assert(op == EXP.minusMinus || op == EXP.plusPlus);
     }
 
     override void accept(Visitor v)
@@ -5841,10 +5845,10 @@ extern (C++) final class PostExp : BinExp
  */
 extern (C++) final class PreExp : UnaExp
 {
-    extern (D) this(TOK op, const ref Loc loc, Expression e)
+    extern (D) this(EXP op, const ref Loc loc, Expression e)
     {
         super(loc, op, __traits(classInstanceSize, PreExp), e);
-        assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus);
+        assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
     }
 
     override void accept(Visitor v)
@@ -5867,13 +5871,13 @@ extern (C++) class AssignExp : BinExp
     MemorySet memset;
 
     /************************************************************/
-    /* op can be TOK.assign, TOK.construct, or TOK.blit */
+    /* op can be EXP.assign, EXP.construct, or EXP.blit */
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2);
+        super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2);
     }
 
-    this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
+    this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
     {
         super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
     }
@@ -5882,7 +5886,7 @@ extern (C++) class AssignExp : BinExp
     {
         // Array-op 'x[] = y[]' should make an rvalue.
         // Setting array length 'x.length = v' should make an rvalue.
-        if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
+        if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
         {
             return false;
         }
@@ -5891,7 +5895,7 @@ extern (C++) class AssignExp : BinExp
 
     override final Expression toLvalue(Scope* sc, Expression ex)
     {
-        if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
+        if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
         {
             return Expression.toLvalue(sc, ex);
         }
@@ -5915,7 +5919,7 @@ extern (C++) final class ConstructExp : AssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.construct, e1, e2);
+        super(loc, EXP.construct, e1, e2);
     }
 
     // Internal use only. If `v` is a reference variable, the assignment
@@ -5925,7 +5929,7 @@ extern (C++) final class ConstructExp : AssignExp
         auto ve = new VarExp(loc, v);
         assert(v.type && ve.type);
 
-        super(loc, TOK.construct, ve, e2);
+        super(loc, EXP.construct, ve, e2);
 
         if (v.isReference())
             memset = MemorySet.referenceInit;
@@ -5943,7 +5947,7 @@ extern (C++) final class BlitExp : AssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.blit, e1, e2);
+        super(loc, EXP.blit, e1, e2);
     }
 
     // Internal use only. If `v` is a reference variable, the assinment
@@ -5953,7 +5957,7 @@ extern (C++) final class BlitExp : AssignExp
         auto ve = new VarExp(loc, v);
         assert(v.type && ve.type);
 
-        super(loc, TOK.blit, ve, e2);
+        super(loc, EXP.blit, ve, e2);
 
         if (v.isReference())
             memset = MemorySet.referenceInit;
@@ -5971,7 +5975,7 @@ extern (C++) final class AddAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
+        super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -5986,7 +5990,7 @@ extern (C++) final class MinAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
+        super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6001,7 +6005,7 @@ extern (C++) final class MulAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
+        super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6016,7 +6020,7 @@ extern (C++) final class DivAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
+        super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6031,7 +6035,7 @@ extern (C++) final class ModAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
+        super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6046,7 +6050,7 @@ extern (C++) final class AndAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
+        super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6061,7 +6065,7 @@ extern (C++) final class OrAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
+        super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6076,7 +6080,7 @@ extern (C++) final class XorAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
+        super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6091,7 +6095,7 @@ extern (C++) final class PowAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
+        super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6106,7 +6110,7 @@ extern (C++) final class ShlAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
+        super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6121,7 +6125,7 @@ extern (C++) final class ShrAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
+        super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6136,7 +6140,7 @@ extern (C++) final class UshrAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
+        super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6148,21 +6152,21 @@ extern (C++) final class UshrAssignExp : BinAssignExp
 /***********************************************************
  * The ~= operator. It can have one of the following operators:
  *
- * TOK.concatenateAssign      - appending T[] to T[]
- * TOK.concatenateElemAssign  - appending T to T[]
- * TOK.concatenateDcharAssign - appending dchar to T[]
+ * EXP.concatenateAssign      - appending T[] to T[]
+ * EXP.concatenateElemAssign  - appending T to T[]
+ * EXP.concatenateDcharAssign - appending dchar to T[]
  *
- * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which
+ * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
  * of the three it will be set to.
  */
 extern (C++) class CatAssignExp : BinAssignExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
+        super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
     }
 
-    extern (D) this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
+    extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
     {
         super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
     }
@@ -6178,7 +6182,7 @@ extern (C++) final class CatElemAssignExp : CatAssignExp
 {
     extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
     {
-        super(loc, TOK.concatenateElemAssign, e1, e2);
+        super(loc, EXP.concatenateElemAssign, e1, e2);
         this.type = type;
     }
 
@@ -6193,7 +6197,7 @@ extern (C++) final class CatDcharAssignExp : CatAssignExp
 {
     extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
     {
-        super(loc, TOK.concatenateDcharAssign, e1, e2);
+        super(loc, EXP.concatenateDcharAssign, e1, e2);
         this.type = type;
     }
 
@@ -6210,7 +6214,7 @@ extern (C++) final class AddExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.add, __traits(classInstanceSize, AddExp), e1, e2);
+        super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6225,7 +6229,7 @@ extern (C++) final class MinExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.min, __traits(classInstanceSize, MinExp), e1, e2);
+        super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6241,7 +6245,7 @@ extern (C++) final class CatExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
+        super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
     }
 
     override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -6264,7 +6268,7 @@ extern (C++) final class MulExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.mul, __traits(classInstanceSize, MulExp), e1, e2);
+        super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6280,7 +6284,7 @@ extern (C++) final class DivExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.div, __traits(classInstanceSize, DivExp), e1, e2);
+        super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6296,7 +6300,7 @@ extern (C++) final class ModExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.mod, __traits(classInstanceSize, ModExp), e1, e2);
+        super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6312,7 +6316,7 @@ extern (C++) final class PowExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.pow, __traits(classInstanceSize, PowExp), e1, e2);
+        super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6327,7 +6331,7 @@ extern (C++) final class ShlExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
+        super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6342,7 +6346,7 @@ extern (C++) final class ShrExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
+        super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6357,7 +6361,7 @@ extern (C++) final class UshrExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
+        super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6372,7 +6376,7 @@ extern (C++) final class AndExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.and, __traits(classInstanceSize, AndExp), e1, e2);
+        super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6387,7 +6391,7 @@ extern (C++) final class OrExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.or, __traits(classInstanceSize, OrExp), e1, e2);
+        super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6402,7 +6406,7 @@ extern (C++) final class XorExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.xor, __traits(classInstanceSize, XorExp), e1, e2);
+        super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6417,10 +6421,10 @@ extern (C++) final class XorExp : BinExp
  */
 extern (C++) final class LogicalExp : BinExp
 {
-    extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2)
+    extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2)
     {
         super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
-        assert(op == TOK.andAnd || op == TOK.orOr);
+        assert(op == EXP.andAnd || op == EXP.orOr);
     }
 
     override void accept(Visitor v)
@@ -6431,16 +6435,16 @@ extern (C++) final class LogicalExp : BinExp
 
 /***********************************************************
  * `op` is one of:
- *      TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual
+ *      EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
  *
  * http://dlang.org/spec/expression.html#relation_expressions
  */
 extern (C++) final class CmpExp : BinExp
 {
-    extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+    extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
     {
         super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
-        assert(op == TOK.lessThan || op == TOK.lessOrEqual || op == TOK.greaterThan || op == TOK.greaterOrEqual);
+        assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
     }
 
     override void accept(Visitor v)
@@ -6455,7 +6459,7 @@ extern (C++) final class InExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.in_, __traits(classInstanceSize, InExp), e1, e2);
+        super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2);
     }
 
     override void accept(Visitor v)
@@ -6471,7 +6475,7 @@ extern (C++) final class RemoveExp : BinExp
 {
     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
-        super(loc, TOK.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
+        super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
         type = Type.tbool;
     }
 
@@ -6484,16 +6488,16 @@ extern (C++) final class RemoveExp : BinExp
 /***********************************************************
  * `==` and `!=`
  *
- * TOK.equal and TOK.notEqual
+ * EXP.equal and EXP.notEqual
  *
  * http://dlang.org/spec/expression.html#equality_expressions
  */
 extern (C++) final class EqualExp : BinExp
 {
-    extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+    extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
     {
         super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
-        assert(op == TOK.equal || op == TOK.notEqual);
+        assert(op == EXP.equal || op == EXP.notEqual);
     }
 
     override void accept(Visitor v)
@@ -6505,16 +6509,16 @@ extern (C++) final class EqualExp : BinExp
 /***********************************************************
  * `is` and `!is`
  *
- * TOK.identity and TOK.notIdentity
+ * EXP.identity and EXP.notIdentity
  *
  *  http://dlang.org/spec/expression.html#identity_expressions
  */
 extern (C++) final class IdentityExp : BinExp
 {
-    extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+    extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
     {
         super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
-        assert(op == TOK.identity || op == TOK.notIdentity);
+        assert(op == EXP.identity || op == EXP.notIdentity);
     }
 
     override void accept(Visitor v)
@@ -6534,7 +6538,7 @@ extern (C++) final class CondExp : BinExp
 
     extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
     {
-        super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2);
+        super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2);
         this.econd = econd;
     }
 
@@ -6623,9 +6627,9 @@ extern (C++) final class CondExp : BinExp
                         //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
                         Expression ve = new VarExp(vcond.loc, vcond);
                         if (isThen)
-                            v.edtor = new LogicalExp(v.edtor.loc, TOK.andAnd, ve, v.edtor);
+                            v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
                         else
-                            v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor);
+                            v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
                         v.edtor = v.edtor.expressionSemantic(sc);
                         //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
                     }
@@ -6649,18 +6653,18 @@ extern (C++) final class CondExp : BinExp
 }
 
 /// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
-bool isDefaultInitOp(TOK op) pure nothrow @safe @nogc
+bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc
 {
-    return  op == TOK.prettyFunction    || op == TOK.functionString ||
-            op == TOK.line              || op == TOK.moduleString   ||
-            op == TOK.file              || op == TOK.fileFullPath   ;
+    return  op == EXP.prettyFunction    || op == EXP.functionString ||
+            op == EXP.line              || op == EXP.moduleString   ||
+            op == EXP.file              || op == EXP.fileFullPath   ;
 }
 
 /***********************************************************
  */
 extern (C++) class DefaultInitExp : Expression
 {
-    extern (D) this(const ref Loc loc, TOK op, int size)
+    extern (D) this(const ref Loc loc, EXP op, int size)
     {
         super(loc, op, size);
     }
@@ -6675,7 +6679,7 @@ extern (C++) class DefaultInitExp : Expression
  */
 extern (C++) final class FileInitExp : DefaultInitExp
 {
-    extern (D) this(const ref Loc loc, TOK tok)
+    extern (D) this(const ref Loc loc, EXP tok)
     {
         super(loc, tok, __traits(classInstanceSize, FileInitExp));
     }
@@ -6684,7 +6688,7 @@ extern (C++) final class FileInitExp : DefaultInitExp
     {
         //printf("FileInitExp::resolve() %s\n", toChars());
         const(char)* s;
-        if (op == TOK.fileFullPath)
+        if (op == EXP.fileFullPath)
             s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
         else
             s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
@@ -6707,7 +6711,7 @@ extern (C++) final class LineInitExp : DefaultInitExp
 {
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.line, __traits(classInstanceSize, LineInitExp));
+        super(loc, EXP.line, __traits(classInstanceSize, LineInitExp));
     }
 
     override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -6729,7 +6733,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp
 {
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp));
+        super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp));
     }
 
     override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -6753,7 +6757,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp
 {
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp));
+        super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp));
     }
 
     override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -6783,7 +6787,7 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp
 {
     extern (D) this(const ref Loc loc)
     {
-        super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
+        super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
     }
 
     override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -6828,7 +6832,7 @@ extern (C++) final class ObjcClassReferenceExp : Expression
 
     extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
     {
-        super(loc, TOK.objcClassReference,
+        super(loc, EXP.objcClassReference,
             __traits(classInstanceSize, ObjcClassReferenceExp));
         this.classDeclaration = classDeclaration;
         type = objc.getRuntimeMetaclass(classDeclaration).getType();
@@ -6852,7 +6856,7 @@ extern (C++) final class GenericExp : Expression
 
     extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
     {
-        super(loc, TOK._Generic, __traits(classInstanceSize, GenericExp));
+        super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp));
         this.cntlExp = cntlExp;
         this.types = types;
         this.exps = exps;
@@ -6883,18 +6887,18 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag
 {
     switch(exp.op)
     {
-        case TOK.variable:
+        case EXP.variable:
             auto varExp = cast(VarExp)exp;
 
             //printf("VarExp::checkModifiable %s", varExp.toChars());
             assert(varExp.type);
             return varExp.var.checkModify(varExp.loc, sc, null, flag);
 
-        case TOK.dotVariable:
+        case EXP.dotVariable:
             auto dotVarExp = cast(DotVarExp)exp;
 
             //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
-            if (dotVarExp.e1.op == TOK.this_)
+            if (dotVarExp.e1.op == EXP.this_)
                 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
 
             /* https://issues.dlang.org/show_bug.cgi?id=12764
@@ -6925,13 +6929,13 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag
                             onlyUnion = false;
 
                         // Another DotVarExp left?
-                        if (!dve.e1 || dve.e1.op != TOK.dotVariable)
+                        if (!dve.e1 || dve.e1.op != EXP.dotVariable)
                             break;
 
                         dve = cast(DotVarExp) dve.e1;
                     }
 
-                    if (dve.e1.op == TOK.this_)
+                    if (dve.e1.op == EXP.this_)
                     {
                         scope v = dve.var.isVarDeclaration();
                         /* if v is a struct member field with no initializer, no default construction
@@ -6968,7 +6972,7 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag
             //printf("\te1 = %s\n", e1.toChars());
             return dotVarExp.e1.checkModifiable(sc, flag);
 
-        case TOK.star:
+        case EXP.star:
             auto ptrExp = cast(PtrExp)exp;
             if (auto se = ptrExp.e1.isSymOffExp())
             {
@@ -6980,33 +6984,33 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag
             }
             return Modifiable.yes;
 
-        case TOK.slice:
+        case EXP.slice:
             auto sliceExp = cast(SliceExp)exp;
 
             //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
             auto e1 = sliceExp.e1;
-            if (e1.type.ty == Tsarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice)
+            if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
             {
                 return e1.checkModifiable(sc, flag);
             }
             return Modifiable.yes;
 
-        case TOK.comma:
+        case EXP.comma:
             return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
 
-        case TOK.index:
+        case EXP.index:
             auto indexExp = cast(IndexExp)exp;
             auto e1 = indexExp.e1;
             if (e1.type.ty == Tsarray ||
                 e1.type.ty == Taarray ||
-                (e1.op == TOK.index && e1.type.ty != Tarray) ||
-                e1.op == TOK.slice)
+                (e1.op == EXP.index && e1.type.ty != Tarray) ||
+                e1.op == EXP.slice)
             {
                 return e1.checkModifiable(sc, flag);
             }
             return Modifiable.yes;
 
-        case TOK.question:
+        case EXP.question:
             auto condExp = cast(CondExp)exp;
             if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
                 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
index 691364cb265de0fc3db6b41304b21b85858cb742..411822cb9d6b3a1f1f7b8a24077f15c3b7e1763f 100644 (file)
@@ -18,6 +18,7 @@
 #include "tokens.h"
 
 #include "root/dcompat.h"
+#include "root/optional.h"
 
 class Type;
 class TypeVector;
@@ -76,7 +77,7 @@ enum class ModifyFlags
 class Expression : public ASTNode
 {
 public:
-    TOK op;                     // to minimize use of dynamic_cast
+    EXP op;                     // to minimize use of dynamic_cast
     unsigned char size;         // # of bytes in Expression so we can copy() it
     unsigned char parens;       // if this is a parenthesized expression
     Type *type;                 // !=NULL means that semantic() has been run
@@ -121,8 +122,7 @@ public:
     // A compile-time result is required. Give an error if not possible
     Expression *ctfeInterpret();
     int isConst();
-    virtual bool isBool(bool result);
-
+    virtual Optional<bool> toBool();
     virtual bool hasCode()
     {
         return true;
@@ -249,7 +249,7 @@ public:
     real_t toReal();
     real_t toImaginary();
     complex_t toComplex();
-    bool isBool(bool result);
+    Optional<bool> toBool();
     Expression *toLvalue(Scope *sc, Expression *e);
     void accept(Visitor *v) { v->visit(this); }
     dinteger_t getInteger() { return value; }
@@ -280,7 +280,7 @@ public:
     real_t toReal();
     real_t toImaginary();
     complex_t toComplex();
-    bool isBool(bool result);
+    Optional<bool> toBool();
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -297,7 +297,7 @@ public:
     real_t toReal();
     real_t toImaginary();
     complex_t toComplex();
-    bool isBool(bool result);
+    Optional<bool> toBool();
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -336,7 +336,7 @@ public:
     VarDeclaration *var;
 
     ThisExp *syntaxCopy();
-    bool isBool(bool result);
+    Optional<bool> toBool();
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
 
@@ -353,7 +353,7 @@ class NullExp : public Expression
 {
 public:
     bool equals(const RootObject *o) const;
-    bool isBool(bool result);
+    Optional<bool> toBool();
     StringExp *toStringExp();
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -374,7 +374,7 @@ public:
     bool equals(const RootObject *o) const;
     StringExp *toStringExp();
     StringExp *toUTF8(Scope *sc);
-    bool isBool(bool result);
+    Optional<bool> toBool();
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -420,7 +420,7 @@ public:
     bool equals(const RootObject *o) const;
     Expression *getElement(d_size_t i); // use opIndex instead
     Expression *opIndex(d_size_t i);
-    bool isBool(bool result);
+    Optional<bool> toBool();
     StringExp *toStringExp();
 
     void accept(Visitor *v) { v->visit(this); }
@@ -435,7 +435,7 @@ public:
 
     bool equals(const RootObject *o) const;
     AssocArrayLiteralExp *syntaxCopy();
-    bool isBool(bool result);
+    Optional<bool> toBool();
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -567,7 +567,7 @@ class SymOffExp : public SymbolExp
 public:
     dinteger_t offset;
 
-    bool isBool(bool result);
+    Optional<bool> toBool();
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -926,7 +926,7 @@ public:
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
-    bool isBool(bool result);
+    Optional<bool> toBool();
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -997,7 +997,7 @@ public:
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
-    bool isBool(bool result);
+    Optional<bool> toBool();
     Expression *addDtorHook(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
index 8e152d6a1fcce2a81362f49ddcfcbcbe7f1869a6..ec2bce47b47174b6a1072fafcd10f8e0634fb406 100644 (file)
@@ -108,7 +108,7 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
 
         // allowed to contain types as well as expressions
         auto e4 = ctfeInterpretForPragmaMsg(e3);
-        if (!e4 || e4.op == TOK.error)
+        if (!e4 || e4.op == EXP.error)
             return true;
 
         // expand tuple
@@ -153,14 +153,14 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s)
     exp = resolveProperties(sc, exp);
     sc = sc.endCTFE();
 
-    if (exp.op == TOK.error)
+    if (exp.op == EXP.error)
         return null;
 
     auto e = exp;
     if (exp.type.isString())
     {
         e = e.ctfeInterpret();
-        if (e.op == TOK.error)
+        if (e.op == EXP.error)
             return null;
     }
 
@@ -215,7 +215,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
         if (i == 0)
             *pe0 = extractOpDollarSideEffect(sc, ae);
 
-        if (e.op == TOK.interval && !(slice && slice.isTemplateDeclaration()))
+        if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
         {
         Lfallback:
             if (ae.arguments.dim == 1)
@@ -273,7 +273,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
             ae.error("`%s` has no value", e.toChars());
             e = ErrorExp.get();
         }
-        if (e.op == TOK.error)
+        if (e.op == EXP.error)
             return e;
 
         (*ae.arguments)[i] = e;
@@ -342,9 +342,9 @@ bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors =
             if (e)
             {
                 auto e2 = e.expressionSemantic(sc);
-                if (e2.op == TOK.error)
+                if (e2.op == EXP.error)
                     err = true;
-                if (preserveErrors || e2.op != TOK.error)
+                if (preserveErrors || e2.op != EXP.error)
                     e = e2;
             }
         }
@@ -531,7 +531,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
         {
             if (Expression ey = die.semanticY(sc, 1))
             {
-                if (ey.op == TOK.error)
+                if (ey.op == EXP.error)
                     return ey;
                 ce.e1 = ey;
                 if (isDotOpDispatch(ey))
@@ -1024,7 +1024,7 @@ L1:
     Type t = e1.type.toBasetype();
     //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
 
-    if (e1.op == TOK.objcClassReference)
+    if (e1.op == EXP.objcClassReference)
     {
         // We already have an Objective-C class reference, just use that as 'this'.
         return e1;
@@ -1040,7 +1040,7 @@ L1:
      * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
      * class B {int m; inc() { new A().inc!m(); } }
      */
-    if (e1.op == TOK.this_)
+    if (e1.op == EXP.this_)
     {
         FuncDeclaration f = hasThis(sc);
         if (f && f.isThis2)
@@ -1051,7 +1051,7 @@ L1:
                 e1 = new PtrExp(loc, e1);
                 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
                 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
-                if (e1.op == TOK.error)
+                if (e1.op == EXP.error)
                     return e1;
                 goto L1;
             }
@@ -1089,7 +1089,7 @@ L1:
                 // Skip up over nested functions, and get the enclosing
                 // class type.
                 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
-                if (e1.op == TOK.error)
+                if (e1.op == EXP.error)
                     return e1;
                 goto L1;
             }
@@ -1110,7 +1110,7 @@ L1:
  */
 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
 {
-    //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token.toChars(e1.op), e1.toChars(), e2 ? e2.toChars() : null);
+    //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
     Loc loc = e1.loc;
 
     OverloadSet os;
@@ -1138,7 +1138,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         if (e2)
         {
             e2 = e2.expressionSemantic(sc);
-            if (e2.op == TOK.error)
+            if (e2.op == EXP.error)
                 return ErrorExp.get();
             e2 = resolveProperties(sc, e2);
 
@@ -1233,7 +1233,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         tthis = null;
         goto Lfd;
     }
-    else if (e1.op == TOK.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
+    else if (e1.op == EXP.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
     {
         DotVarExp dve = cast(DotVarExp)e1;
         s = dve.var;
@@ -1241,11 +1241,11 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         tthis = dve.e1.type;
         goto Lfd;
     }
-    else if (sc && sc.flags & SCOPE.Cfile && e1.op == TOK.variable && !e2)
+    else if (sc && sc.flags & SCOPE.Cfile && e1.op == EXP.variable && !e2)
     {
         // ImportC: do not implicitly call function if no ( ) are present
     }
-    else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
+    else if (e1.op == EXP.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
     {
         s = (cast(VarExp)e1).var;
         tiargs = null;
@@ -1255,7 +1255,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         if (e2)
         {
             e2 = e2.expressionSemantic(sc);
-            if (e2.op == TOK.error)
+            if (e2.op == EXP.error)
                 return ErrorExp.get();
             e2 = resolveProperties(sc, e2);
 
@@ -1316,7 +1316,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         if (e2)
             goto Leprop;
     }
-    if (e1.op == TOK.variable)
+    if (e1.op == EXP.variable)
     {
         VarExp ve = cast(VarExp)e1;
         VarDeclaration v = ve.var.isVarDeclaration();
@@ -1326,7 +1326,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
     if (e2)
         return null;
 
-    if (e1.type && e1.op != TOK.type) // function type is not a property
+    if (e1.type && e1.op != EXP.type) // function type is not a property
     {
         /* Look for e1 being a lazy parameter; rewrite as delegate call
          * only if the symbol wasn't already treated as a delegate
@@ -1337,13 +1337,13 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                 Expression e = new CallExp(loc, e1);
                 return e.expressionSemantic(sc);
         }
-        else if (e1.op == TOK.dotVariable)
+        else if (e1.op == EXP.dotVariable)
         {
             // Check for reading overlapped pointer field in @safe code.
             if (checkUnsafeAccess(sc, e1, true, true))
                 return ErrorExp.get();
         }
-        else if (e1.op == TOK.call)
+        else if (e1.op == EXP.call)
         {
             CallExp ce = cast(CallExp)e1;
             // Check for reading overlapped pointer field in @safe code.
@@ -1409,7 +1409,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
             t0 = Type.terror;
             continue;
         }
-        if (e.op == TOK.type)
+        if (e.op == EXP.type)
         {
             foundType = true; // do not break immediately, there might be more errors
             e.checkValue(); // report an error "type T has no value"
@@ -1440,9 +1440,9 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
             condexp.e2 = e;
             condexp.loc = e.loc;
             Expression ex = condexp.expressionSemantic(sc);
-            if (ex.op == TOK.error)
+            if (ex.op == EXP.error)
                 e = ex;
-            else if (e.op == TOK.function_ || e.op == TOK.delegate_)
+            else if (e.op == EXP.function_ || e.op == EXP.delegate_)
             {
                 // https://issues.dlang.org/show_bug.cgi?id=21285
                 // Functions and delegates don't convert correctly with castTo below
@@ -1458,7 +1458,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
         }
         e0 = e;
         t0 = e.type;
-        if (e.op != TOK.error)
+        if (e.op != EXP.error)
             exps[i] = e;
     }
 
@@ -1477,7 +1477,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
             continue;
 
         e = e.implicitCastTo(sc, t0);
-        if (e.op == TOK.error)
+        if (e.op == EXP.error)
         {
             /* https://issues.dlang.org/show_bug.cgi?id=13024
              * a workaround for the bug in typeMerge -
@@ -1491,52 +1491,52 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
     return t0;
 }
 
-private Expression opAssignToOp(const ref Loc loc, TOK op, Expression e1, Expression e2)
+private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
 {
     Expression e;
     switch (op)
     {
-    case TOK.addAssign:
+    case EXP.addAssign:
         e = new AddExp(loc, e1, e2);
         break;
 
-    case TOK.minAssign:
+    case EXP.minAssign:
         e = new MinExp(loc, e1, e2);
         break;
 
-    case TOK.mulAssign:
+    case EXP.mulAssign:
         e = new MulExp(loc, e1, e2);
         break;
 
-    case TOK.divAssign:
+    case EXP.divAssign:
         e = new DivExp(loc, e1, e2);
         break;
 
-    case TOK.modAssign:
+    case EXP.modAssign:
         e = new ModExp(loc, e1, e2);
         break;
 
-    case TOK.andAssign:
+    case EXP.andAssign:
         e = new AndExp(loc, e1, e2);
         break;
 
-    case TOK.orAssign:
+    case EXP.orAssign:
         e = new OrExp(loc, e1, e2);
         break;
 
-    case TOK.xorAssign:
+    case EXP.xorAssign:
         e = new XorExp(loc, e1, e2);
         break;
 
-    case TOK.leftShiftAssign:
+    case EXP.leftShiftAssign:
         e = new ShlExp(loc, e1, e2);
         break;
 
-    case TOK.rightShiftAssign:
+    case EXP.rightShiftAssign:
         e = new ShrExp(loc, e1, e2);
         break;
 
-    case TOK.unsignedRightShiftAssign:
+    case EXP.unsignedRightShiftAssign:
         e = new UshrExp(loc, e1, e2);
         break;
 
@@ -1559,9 +1559,9 @@ private Expression rewriteOpAssign(BinExp exp)
 {
     Expression e;
 
-    assert(exp.e1.op == TOK.arrayLength);
+    assert(exp.e1.op == EXP.arrayLength);
     ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1;
-    if (ale.e1.op == TOK.variable)
+    if (ale.e1.op == EXP.variable)
     {
         e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
         e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
@@ -1604,12 +1604,12 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo
             Expression arg = (*exps)[i];
             arg = resolveProperties(sc, arg);
             arg = arg.arrayFuncConv(sc);
-            if (arg.op == TOK.type)
+            if (arg.op == EXP.type)
             {
                 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
                 arg = resolveAliasThis(sc, arg);
 
-                if (arg.op == TOK.type)
+                if (arg.op == EXP.type)
                 {
                     if (reportErrors)
                     {
@@ -2056,7 +2056,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                 /* Argument value cannot escape from the called function.
                  */
                 Expression a = arg;
-                if (a.op == TOK.cast_)
+                if (a.op == EXP.cast_)
                     a = (cast(CastExp)a).e1;
 
                 ArrayLiteralExp ale;
@@ -2071,7 +2071,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                     arg = CommaExp.combine(declareTmp, castToSlice);
                     arg = arg.expressionSemantic(sc);
                 }
-                else if (a.op == TOK.function_)
+                else if (a.op == EXP.function_)
                 {
                     /* Function literals can only appear once, so if this
                      * appearance was scoped, there cannot be any others.
@@ -2079,14 +2079,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                     FuncExp fe = cast(FuncExp)a;
                     fe.fd.tookAddressOf = 0;
                 }
-                else if (a.op == TOK.delegate_)
+                else if (a.op == EXP.delegate_)
                 {
                     /* For passing a delegate to a scoped parameter,
                      * this doesn't count as taking the address of it.
                      * We only worry about 'escaping' references to the function.
                      */
                     DelegateExp de = cast(DelegateExp)a;
-                    if (de.e1.op == TOK.variable)
+                    if (de.e1.op == EXP.variable)
                     {
                         VarExp ve = cast(VarExp)de.e1;
                         FuncDeclaration f = ve.var.isFuncDeclaration();
@@ -2185,7 +2185,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                 //arg = callCpCtor(sc, arg);
             }
             // Give error for overloaded function addresses
-            if (arg.op == TOK.symbolOffset)
+            if (arg.op == EXP.symbolOffset)
             {
                 SymOffExp se = cast(SymOffExp)arg;
                 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
@@ -2357,7 +2357,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                         // edtor => (__gate || edtor)
                         assert(tmp.edtor);
                         Expression e = tmp.edtor;
-                        e = new LogicalExp(e.loc, TOK.orOr, new VarExp(e.loc, gate), e);
+                        e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
                         tmp.edtor = e.expressionSemantic(sc);
                         //printf("edtor: %s\n", tmp.edtor.toChars());
                     }
@@ -2766,7 +2766,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     }
                 }
                 // Try Type.opDispatch (so the static version)
-                else if (ss.withstate.exp && ss.withstate.exp.op == TOK.type)
+                else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
                 {
                     if (Type t = ss.withstate.exp.isTypeExp().type)
                     {
@@ -3077,7 +3077,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 exp.error("`%s` has no value", e.toChars());
                 err = true;
             }
-            else if (e.op == TOK.error)
+            else if (e.op == EXP.error)
                 err = true;
             else
                 (*exp.exps)[i] = e;
@@ -3110,7 +3110,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         if (e.basis)
             e.basis = e.basis.expressionSemantic(sc);
-        if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == TOK.error))
+        if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == EXP.error))
             return setError();
 
         expandTuples(e.elements);
@@ -3474,7 +3474,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (exp.thisexp)
         {
             exp.thisexp = exp.thisexp.expressionSemantic(sc);
-            if (exp.thisexp.op == TOK.error)
+            if (exp.thisexp.op == EXP.error)
                 return setError();
 
             cdthis = exp.thisexp.type.isClassHandle();
@@ -3619,7 +3619,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         }
 
                         exp.thisexp = exp.thisexp.expressionSemantic(sc);
-                        if (exp.thisexp.op == TOK.error)
+                        if (exp.thisexp.op == EXP.error)
                             return setError();
                         cdthis = exp.thisexp.type.isClassHandle();
                     }
@@ -3666,9 +3666,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 if (AggregateDeclaration ad2 = cd.isMember2())
                 {
                     Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
-                    if (te.op != TOK.error)
+                    if (te.op != EXP.error)
                         te = getRightThis(exp.loc, sc, ad2, te, cd);
-                    if (te.op == TOK.error)
+                    if (te.op == EXP.error)
                     {
                         exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
                         return setError();
@@ -3764,7 +3764,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
 
-            if (sd.ctor && nargs)
+            if (sd.hasRegularCtor() && nargs)
             {
                 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
                 if (!f || f.errors)
@@ -3842,10 +3842,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 Expression arg = (*exp.arguments)[i];
                 arg = resolveProperties(sc, arg);
                 arg = arg.implicitCastTo(sc, Type.tsize_t);
-                if (arg.op == TOK.error)
+                if (arg.op == EXP.error)
                     return setError();
                 arg = arg.optimize(WANTvalue);
-                if (arg.op == TOK.int64 && cast(sinteger_t)arg.toInteger() < 0)
+                if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0)
                 {
                     exp.error("negative array index `%s`", arg.toChars());
                     return setError();
@@ -4104,7 +4104,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 *   auto foo(void function() fp) { return 1; }
                 *   assert(foo({}) == 1);
                 *
-                * So, should keep fd.tok == TOKreserve if fd.treq == NULL.
+                * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
                 */
             if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
             {
@@ -4135,7 +4135,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             for (size_t k = 0; k < arguments.dim; k++)
             {
                 Expression checkarg = (*arguments)[k];
-                if (checkarg.op == TOK.error)
+                if (checkarg.op == EXP.error)
                     return checkarg;
             }
 
@@ -4213,7 +4213,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         Type tthis = null;
         Expression e1org = exp.e1;
 
-        if (exp.e1.op == TOK.comma)
+        if (exp.e1.op == EXP.comma)
         {
             /* Rewrite (a,b)(args) as (a,(b(args)))
              */
@@ -4223,14 +4223,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             result = ce.expressionSemantic(sc);
             return;
         }
-        if (exp.e1.op == TOK.delegate_)
+        if (exp.e1.op == EXP.delegate_)
         {
             DelegateExp de = cast(DelegateExp)exp.e1;
             exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
             visit(exp);
             return;
         }
-        if (exp.e1.op == TOK.function_)
+        if (exp.e1.op == EXP.function_)
         {
             if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
                 return setError();
@@ -4238,7 +4238,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             // Run e1 semantic even if arguments have any errors
             FuncExp fe = cast(FuncExp)exp.e1;
             exp.e1 = callExpSemantic(fe, sc, exp.arguments);
-            if (exp.e1.op == TOK.error)
+            if (exp.e1.op == EXP.error)
             {
                 result = exp.e1;
                 return;
@@ -4254,7 +4254,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         /* This recognizes:
          *  foo!(tiargs)(funcargs)
          */
-        if (exp.e1.op == TOK.scope_)
+        if (exp.e1.op == EXP.scope_)
         {
             ScopeExp se = cast(ScopeExp)exp.e1;
             TemplateInstance ti = se.sds.isTemplateInstance();
@@ -4288,7 +4288,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 else
                 {
                     Expression e1x = exp.e1.expressionSemantic(sc);
-                    if (e1x.op == TOK.error)
+                    if (e1x.op == EXP.error)
                     {
                         result = e1x;
                         return;
@@ -4302,7 +4302,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
          *  expr.foo!(tiargs)(funcargs)
          */
     Ldotti:
-        if (exp.e1.op == TOK.dotTemplateInstance)
+        if (exp.e1.op == EXP.dotTemplateInstance)
         {
             DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
             TemplateInstance ti = se.ti;
@@ -4330,7 +4330,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 else
                 {
                     Expression e1x = exp.e1.expressionSemantic(sc);
-                    if (e1x.op == TOK.error)
+                    if (e1x.op == EXP.error)
                     {
                         result = e1x;
                         return;
@@ -4343,13 +4343,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
     Lagain:
         //printf("Lagain: %s\n", toChars());
         exp.f = null;
-        if (exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_)
+        if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
         {
             // semantic() run later for these
         }
         else
         {
-            if (exp.e1.op == TOK.dotIdentifier)
+            if (exp.e1.op == EXP.dotIdentifier)
             {
                 DotIdExp die = cast(DotIdExp)exp.e1;
                 exp.e1 = die.expressionSemantic(sc);
@@ -4357,7 +4357,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  * We handle such earlier, so go back.
                  * Note that in the rewrite, we carefully did not run semantic() on e1
                  */
-                if (exp.e1.op == TOK.dotTemplateInstance)
+                if (exp.e1.op == EXP.dotTemplateInstance)
                 {
                     goto Ldotti;
                 }
@@ -4382,7 +4382,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             /* Look for e1 being a lazy parameter
              */
-            if (exp.e1.op == TOK.variable)
+            if (exp.e1.op == EXP.variable)
             {
                 VarExp ve = cast(VarExp)exp.e1;
                 if (ve.var.storage_class & STC.lazy_)
@@ -4400,29 +4400,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
             }
 
-            if (exp.e1.op == TOK.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
+            if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
             {
                 SymOffExp se = cast(SymOffExp)exp.e1;
                 exp.e1 = new VarExp(se.loc, se.var, true);
                 exp.e1 = exp.e1.expressionSemantic(sc);
             }
-            else if (exp.e1.op == TOK.dot)
+            else if (exp.e1.op == EXP.dot)
             {
                 DotExp de = cast(DotExp)exp.e1;
 
-                if (de.e2.op == TOK.overloadSet)
+                if (de.e2.op == EXP.overloadSet)
                 {
                     ethis = de.e1;
                     tthis = de.e1.type;
                     exp.e1 = de.e2;
                 }
             }
-            else if (exp.e1.op == TOK.star && exp.e1.type.ty == Tfunction)
+            else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
             {
                 // Rewrite (*fp)(arguments) to fp(arguments)
                 exp.e1 = (cast(PtrExp)exp.e1).e1;
             }
-            else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
+            else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
             {
                 const numArgs = exp.arguments ? exp.arguments.length : 0;
                 if (e1org.parens && numArgs >= 1)
@@ -4480,7 +4480,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
 
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
@@ -4515,7 +4515,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
 
                 // First look for constructor
-                if (exp.e1.op == TOK.type && sd.ctor)
+                if (exp.e1.op == EXP.type && sd.ctor)
                 {
                     if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim))
                         goto Lx;
@@ -4566,7 +4566,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 if (search_function(sd, Id.call))
                     goto L1;
                 // overload of opCall, therefore it's a call
-                if (exp.e1.op != TOK.type)
+                if (exp.e1.op != EXP.type)
                 {
                     if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
                     {
@@ -4595,7 +4595,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 result = e;
                 return;
             }
-            else if (exp.e1.op == TOK.type && t1.isscalar())
+            else if (exp.e1.op == EXP.type && t1.isscalar())
             {
                 Expression e;
 
@@ -4659,7 +4659,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         bool isSuper = false;
-        if (exp.e1.op == TOK.dotVariable && t1.ty == Tfunction || exp.e1.op == TOK.dotTemplateDeclaration)
+        if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
         {
             UnaExp ue = cast(UnaExp)exp.e1;
 
@@ -4667,7 +4667,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             DotVarExp dve;
             DotTemplateExp dte;
             Dsymbol s;
-            if (exp.e1.op == TOK.dotVariable)
+            if (exp.e1.op == EXP.dotVariable)
             {
                 dve = cast(DotVarExp)exp.e1;
                 dte = null;
@@ -4703,7 +4703,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             {
                 AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration();
                 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
-                if (ue.e1.op == TOK.error)
+                if (ue.e1.op == EXP.error)
                 {
                     result = ue.e1;
                     return;
@@ -4720,7 +4720,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             /* Cannot call public functions from inside invariant
              * (because then the invariant would have infinite recursion)
              */
-            if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == TOK.this_ && exp.f.addPostInvariant())
+            if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
             {
                 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
                 return setError();
@@ -4737,7 +4737,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             {
                 if (ue1old.checkRightThis(sc))
                     return setError();
-                if (exp.e1.op == TOK.dotVariable)
+                if (exp.e1.op == EXP.dotVariable)
                 {
                     dve.var = exp.f;
                     exp.e1.type = exp.f.type;
@@ -4746,7 +4746,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 {
                     exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
                     exp.e1 = exp.e1.expressionSemantic(sc);
-                    if (exp.e1.op == TOK.error)
+                    if (exp.e1.op == EXP.error)
                         return setError();
                     ue = cast(UnaExp)exp.e1;
                 }
@@ -4764,12 +4764,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 ClassDeclaration cd = ue.e1.type.isClassHandle();
                 if (ad && cd && ad.isClassDeclaration())
                 {
-                    if (ue.e1.op == TOK.dotType)
+                    if (ue.e1.op == EXP.dotType)
                     {
                         ue.e1 = (cast(DotTypeExp)ue.e1).e1;
                         exp.directcall = true;
                     }
-                    else if (ue.e1.op == TOK.super_)
+                    else if (ue.e1.op == EXP.super_)
                         exp.directcall = true;
                     else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
                         exp.directcall = true;
@@ -4791,12 +4791,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             t1 = exp.e1.type;
         }
-        else if (exp.e1.op == TOK.super_ || exp.e1.op == TOK.this_)
+        else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
         {
             auto ad = sc.func ? sc.func.isThis() : null;
             auto cd = ad ? ad.isClassDeclaration() : null;
 
-            isSuper = exp.e1.op == TOK.super_;
+            isSuper = exp.e1.op == EXP.super_;
             if (isSuper)
             {
                 // Base class constructor call
@@ -4858,7 +4858,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
             exp.e1 = exp.e1.expressionSemantic(sc);
             // https://issues.dlang.org/show_bug.cgi?id=21095
-            if (exp.e1.op == TOK.error)
+            if (exp.e1.op == EXP.error)
                 return setError();
             t1 = exp.e1.type;
 
@@ -4870,7 +4870,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
             }
         }
-        else if (exp.e1.op == TOK.overloadSet)
+        else if (exp.e1.op == EXP.overloadSet)
         {
             auto os = (cast(OverExp)exp.e1).vars;
             exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments);
@@ -4897,7 +4897,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             const(char)* p;
             Dsymbol s;
             exp.f = null;
-            if (exp.e1.op == TOK.function_)
+            if (exp.e1.op == EXP.function_)
             {
                 // function literal that direct called is always inferred.
                 assert((cast(FuncExp)exp.e1).fd);
@@ -4917,7 +4917,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 tf = tfx;
                 p = "function pointer";
             }
-            else if (exp.e1.op == TOK.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
+            else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
             {
                 DotVarExp dve = cast(DotVarExp)exp.e1;
                 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly);
@@ -4935,12 +4935,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 result = e.expressionSemantic(sc);
                 return;
             }
-            else if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
+            else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
             {
                 s = (cast(VarExp)exp.e1).var;
                 goto L2;
             }
-            else if (exp.e1.op == TOK.template_)
+            else if (exp.e1.op == EXP.template_)
             {
                 s = (cast(TemplateExp)exp.e1).td;
             L2:
@@ -5031,7 +5031,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             t1 = tf;
         }
-        else if (exp.e1.op == TOK.variable)
+        else if (exp.e1.op == EXP.variable)
         {
             // Do overload resolution
             VarExp ve = cast(VarExp)exp.e1;
@@ -5188,9 +5188,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (AggregateDeclaration ad2 = exp.f.isMember2())
             {
                 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
-                if (te.op != TOK.error)
+                if (te.op != EXP.error)
                     te = getRightThis(exp.loc, sc, ad2, te, exp.f);
-                if (te.op == TOK.error)
+                if (te.op == EXP.error)
                 {
                     exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
                     return setError();
@@ -5368,7 +5368,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 ea = ea.expressionSemantic(sc);
             ea = resolveProperties(sc, ea);
             ta = ea.type;
-            if (ea.op == TOK.type)
+            if (ea.op == EXP.type)
                 ea = null;
         }
 
@@ -5644,7 +5644,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         /* If one of the default arguments was an error,
                            don't return an invalid tuple
                          */
-                        if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == TOK.error)
+                        if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
                             return setError();
                         args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
                     }
@@ -5819,7 +5819,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.e1.op == TOK.arrayLength)
+        if (exp.e1.op == EXP.arrayLength)
         {
             // arr.length op= e2;
             e = rewriteOpAssign(exp);
@@ -5827,12 +5827,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             result = e;
             return;
         }
-        if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+        if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
         {
             if (checkNonAssignmentArrayOp(exp.e1))
                 return setError();
 
-            if (exp.e1.op == TOK.slice)
+            if (exp.e1.op == EXP.slice)
                 (cast(SliceExp)exp.e1).arrayop = true;
 
             // T[] op= ...
@@ -5869,16 +5869,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             exp.e1.checkSharedAccess(sc))
             return setError();
 
-        int arith = (exp.op == TOK.addAssign || exp.op == TOK.minAssign || exp.op == TOK.mulAssign || exp.op == TOK.divAssign || exp.op == TOK.modAssign || exp.op == TOK.powAssign);
-        int bitwise = (exp.op == TOK.andAssign || exp.op == TOK.orAssign || exp.op == TOK.xorAssign);
-        int shift = (exp.op == TOK.leftShiftAssign || exp.op == TOK.rightShiftAssign || exp.op == TOK.unsignedRightShiftAssign);
+        int arith = (exp.op == EXP.addAssign || exp.op == EXP.minAssign || exp.op == EXP.mulAssign || exp.op == EXP.divAssign || exp.op == EXP.modAssign || exp.op == EXP.powAssign);
+        int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
+        int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
 
         if (bitwise && exp.type.toBasetype().ty == Tbool)
             exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
         else if (exp.checkNoBool())
             return setError();
 
-        if ((exp.op == TOK.addAssign || exp.op == TOK.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
+        if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
         {
             result = scaleFactor(exp, sc);
             return;
@@ -5907,17 +5907,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.e1.op == TOK.error || exp.e2.op == TOK.error)
+        if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
             return setError();
 
         e = exp.checkOpAssignTypes(sc);
-        if (e.op == TOK.error)
+        if (e.op == EXP.error)
         {
             result = e;
             return;
         }
 
-        assert(e.op == TOK.assign || e == exp);
+        assert(e.op == EXP.assign || e == exp);
         result = (cast(BinExp)e).reorderSettingAAElem(sc);
     }
 
@@ -6209,9 +6209,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             Objects* tiargs;
             Loc loc = exp.e1.loc;
 
-            const tok = exp.e1.op;
+            const op = exp.e1.op;
             bool isEqualsCallExpression;
-            if (tok == TOK.call)
+            if (op == EXP.call)
             {
                 const callExp = cast(CallExp) exp.e1;
 
@@ -6225,11 +6225,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                                              callExpIdent == Id.eq;
                 }
             }
-            if (tok == TOK.equal || tok == TOK.notEqual ||
-                tok == TOK.lessThan || tok == TOK.greaterThan ||
-                tok == TOK.lessOrEqual || tok == TOK.greaterOrEqual ||
-                tok == TOK.identity || tok == TOK.notIdentity ||
-                tok == TOK.in_ ||
+            if (op == EXP.equal || op == EXP.notEqual ||
+                op == EXP.lessThan || op == EXP.greaterThan ||
+                op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
+                op == EXP.identity || op == EXP.notIdentity ||
+                op == EXP.in_ ||
                 isEqualsCallExpression)
             {
                 es = new Expressions(3);
@@ -6269,7 +6269,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
 
                 // template args
-                Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : Token.toString(exp.e1.op));
+                Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
                 comp = comp.expressionSemantic(sc);
                 (*es)[0] = comp;
                 (*tiargs)[0] = (*es)[1].type;
@@ -6277,7 +6277,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             // Format exp.e1 before any additional boolean conversion
             // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
-            else if (tok != TOK.andAnd && tok != TOK.orOr)
+            else if (op != EXP.andAnd && op != EXP.orOr)
             {
                 es = new Expressions(2);
                 tiargs = new Objects(1);
@@ -6343,7 +6343,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         exp.e1 = exp.e1.optimize(WANTvalue);
         exp.e1 = exp.e1.toBoolean(sc);
 
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
@@ -6358,7 +6358,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             checkParamArgumentEscape(sc, null, null, exp.msg, true, false);
         }
 
-        if (exp.msg && exp.msg.op == TOK.error)
+        if (exp.msg && exp.msg.op == EXP.error)
         {
             result = exp.msg;
             return;
@@ -6369,7 +6369,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (f1 || f2)
             return setError();
 
-        if (exp.e1.isBool(false))
+        if (exp.e1.toBool().hasValue(false))
         {
             /* This is an `assert(0)` which means halt program execution
              */
@@ -6688,7 +6688,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration();
         if (f.needThis())
             e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
-        if (e.e1.op == TOK.error)
+        if (e.e1.op == EXP.error)
             return setError();
 
         /* A delegate takes the address of e.e1 in order to set the .ptr field
@@ -6731,9 +6731,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (AggregateDeclaration ad2 = f.isMember2())
             {
                 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
-                if (te.op != TOK.error)
+                if (te.op != EXP.error)
                     te = getRightThis(e.loc, sc, ad2, te, f);
-                if (te.op == TOK.error)
+                if (te.op == EXP.error)
                 {
                     e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
                     return setError();
@@ -6806,9 +6806,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
         }
 
-        int wasCond = exp.e1.op == TOK.question;
+        int wasCond = exp.e1.op == EXP.question;
 
-        if (exp.e1.op == TOK.dotTemplateInstance)
+        if (exp.e1.op == EXP.dotTemplateInstance)
         {
             DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
             TemplateInstance ti = dti.ti;
@@ -6827,7 +6827,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
         }
-        else if (exp.e1.op == TOK.scope_)
+        else if (exp.e1.op == EXP.scope_)
         {
             TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
             if (ti)
@@ -6891,7 +6891,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         exp.e1 = exp.e1.toLvalue(sc, null);
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
@@ -6913,7 +6913,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else if (!exp.e1.type.deco)
         {
-            if (exp.e1.op == TOK.variable)
+            if (exp.e1.op == EXP.variable)
             {
                 VarExp ve = cast(VarExp)exp.e1;
                 Declaration d = ve.var;
@@ -6927,7 +6927,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         exp.type = exp.e1.type.pointerTo();
 
         // See if this should really be a delegate
-        if (exp.e1.op == TOK.dotVariable)
+        if (exp.e1.op == EXP.dotVariable)
         {
             DotVarExp dve = cast(DotVarExp)exp.e1;
             FuncDeclaration f = dve.var.isFuncDeclaration();
@@ -6961,7 +6961,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
         }
-        else if (exp.e1.op == TOK.variable)
+        else if (exp.e1.op == EXP.variable)
         {
             VarExp ve = cast(VarExp)exp.e1;
             VarDeclaration v = ve.var.isVarDeclaration();
@@ -7023,7 +7023,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
         }
-        else if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && global.params.useDIP1000 == FeatureState.enabled)
+        else if ((exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) && global.params.useDIP1000 == FeatureState.enabled)
         {
             if (VarDeclaration v = expToVariable(exp.e1))
             {
@@ -7031,20 +7031,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
             }
         }
-        else if (exp.e1.op == TOK.call)
+        else if (exp.e1.op == EXP.call)
         {
             CallExp ce = cast(CallExp)exp.e1;
             if (ce.e1.type.ty == Tfunction)
             {
                 TypeFunction tf = cast(TypeFunction)ce.e1.type;
-                if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+                if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
+                    && tf.next.hasPointers() && sc.func.setUnsafe())
                 {
                     exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`",
                         ce.e1.toChars(), sc.func.toChars());
                 }
             }
         }
-        else if (exp.e1.op == TOK.index)
+        else if (exp.e1.op == EXP.index)
         {
             /* For:
              *   int[3] a;
@@ -7064,12 +7065,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             /* a ? b : c was transformed to *(a ? &b : &c), but we still
              * need to do safety checks
              */
-            assert(exp.e1.op == TOK.star);
+            assert(exp.e1.op == EXP.star);
             PtrExp pe = cast(PtrExp)exp.e1;
-            assert(pe.e1.op == TOK.question);
+            assert(pe.e1.op == EXP.question);
             CondExp ce = cast(CondExp)pe.e1;
-            assert(ce.e1.op == TOK.address);
-            assert(ce.e2.op == TOK.address);
+            assert(ce.e1.op == EXP.address);
+            assert(ce.e2.op == EXP.address);
 
             // Re-run semantic on the address expressions only
             ce.e1.type = null;
@@ -7270,7 +7271,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-        if (e.e1.op == TOK.type)
+        if (e.e1.op == EXP.type)
             e.e1 = resolveAliasThis(sc, e.e1);
 
         e.e1 = resolveProperties(sc, e.e1);
@@ -7313,7 +7314,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         exp.e1 = resolveProperties(sc, exp.e1);
         exp.e1 = exp.e1.modifiableLvalue(sc, null);
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
@@ -7405,8 +7406,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         if ((sc && sc.flags & SCOPE.Cfile) &&
             exp.to && exp.to.ty == Tident &&
-            (exp.e1.op == TOK.address || exp.e1.op == TOK.star ||
-             exp.e1.op == TOK.uadd || exp.e1.op == TOK.negate))
+            (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
+             exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
         {
             /* Ambiguous cases arise from CParser if type-name is just an identifier.
              *   ( identifier ) cast-expression
@@ -7457,11 +7458,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-        if (exp.e1.op == TOK.type)
+        if (exp.e1.op == EXP.type)
             exp.e1 = resolveAliasThis(sc, exp.e1);
 
         auto e1x = resolveProperties(sc, exp.e1);
-        if (e1x.op == TOK.error)
+        if (e1x.op == EXP.error)
         {
             result = e1x;
             return;
@@ -7557,7 +7558,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         Expression ex = exp.e1.castTo(sc, exp.to);
-        if (ex.op == TOK.error)
+        if (ex.op == EXP.error)
         {
             result = ex;
             return;
@@ -7591,16 +7592,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
 
-            if(t1b.ty == Tarray && exp.e1.op != TOK.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
+            if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
             {
                 auto tFrom = t1b.nextOf();
                 auto tTo = tob.nextOf();
 
                 // https://issues.dlang.org/show_bug.cgi?id=20130
-                if (exp.e1.op != TOK.string_ || !ex.isStringExp)
+                if (exp.e1.op != EXP.string_ || !ex.isStringExp)
                 {
                     const uint fromSize = cast(uint)tFrom.size();
                     const uint toSize = cast(uint)tTo.size();
+                    if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
+                        return setError();
 
                     // If array element sizes do not match, we must adjust the dimensions
                     if (fromSize != toSize)
@@ -7664,7 +7667,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         exp.e1 = exp.e1.expressionSemantic(sc);
         exp.type = exp.to.typeSemantic(exp.loc, sc);
-        if (exp.e1.op == TOK.error || exp.type.ty == Terror)
+        if (exp.e1.op == EXP.error || exp.type.ty == Terror)
         {
             result = exp.e1;
             return;
@@ -7687,7 +7690,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         exp.e1 = exp.e1.optimize(WANTvalue);
         bool res;
-        if (exp.e1.op == TOK.arrayLiteral)
+        if (exp.e1.op == EXP.arrayLiteral)
         {
             foreach (i; 0 .. exp.dim)
             {
@@ -7712,7 +7715,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             unaSemantic(e, sc);
             e.e1 = resolveProperties(sc, e.e1);
 
-            if (e.e1.op == TOK.error)
+            if (e.e1.op == EXP.error)
             {
                 result = e.e1;
                 return;
@@ -7742,7 +7745,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
         exp.e1 = resolveProperties(sc, exp.e1);
-        if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+        if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
         {
             if (exp.lwr || exp.upr)
             {
@@ -7755,7 +7758,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         if (!exp.lwr && !exp.upr)
         {
-            if (exp.e1.op == TOK.arrayLiteral)
+            if (exp.e1.op == EXP.arrayLiteral)
             {
                 // Convert [a,b,c][] to [a,b,c]
                 Type t1b = exp.e1.type.toBasetype();
@@ -7768,7 +7771,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 result = e;
                 return;
             }
-            if (exp.e1.op == TOK.slice)
+            if (exp.e1.op == EXP.slice)
             {
                 // Convert e[][] to e[]
                 SliceExp se = cast(SliceExp)exp.e1;
@@ -7785,7 +7788,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return;
             }
         }
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
@@ -7824,10 +7827,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  */
                 if (VarDeclaration v = expToVariable(exp.e1))
                 {
-                    if (exp.e1.op == TOK.dotVariable)
+                    if (exp.e1.op == EXP.dotVariable)
                     {
                         DotVarExp dve = cast(DotVarExp)exp.e1;
-                        if ((dve.e1.op == TOK.this_ || dve.e1.op == TOK.super_) &&
+                        if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) &&
                             !(v.storage_class & STC.ref_))
                         {
                             // because it's a class
@@ -7912,13 +7915,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             TupleExp te;
             TypeTuple tup;
             size_t length;
-            if (exp.e1.op == TOK.tuple) // slicing an expression tuple
+            if (exp.e1.op == EXP.tuple) // slicing an expression tuple
             {
                 te = cast(TupleExp)exp.e1;
                 tup = null;
                 length = te.exps.dim;
             }
-            else if (exp.e1.op == TOK.type) // slicing a type tuple
+            else if (exp.e1.op == EXP.type) // slicing a type tuple
             {
                 te = null;
                 tup = cast(TypeTuple)t1b;
@@ -7936,7 +7939,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             size_t j1 = cast(size_t)i1;
             size_t j2 = cast(size_t)i2;
             Expression e;
-            if (exp.e1.op == TOK.tuple)
+            if (exp.e1.op == EXP.tuple)
             {
                 auto exps = new Expressions(j2 - j1);
                 for (size_t i = 0; i < j2 - j1; i++)
@@ -7982,29 +7985,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
                 el = el.expressionSemantic(sc);
                 el = el.optimize(WANTvalue);
-                if (el.op == TOK.int64)
+                if (el.op == EXP.int64)
                 {
                     // Array length is known at compile-time. Upper is in bounds if it fits length.
                     dinteger_t length = el.toInteger();
                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
                     exp.upperIsInBounds = bounds.contains(uprRange);
-                    if (exp.lwr.op == TOK.int64 && exp.upr.op == TOK.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
+                    if (exp.lwr.op == EXP.int64 && exp.upr.op == EXP.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
                     {
                         exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger());
                         return setError();
                     }
-                    if (exp.upr.op == TOK.int64 && exp.upr.toInteger() > length)
+                    if (exp.upr.op == EXP.int64 && exp.upr.toInteger() > length)
                     {
                         exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length);
                         return setError();
                     }
                 }
-                else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0)
+                else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
                 {
                     // Upper slice expression is '0'. Value is always in bounds.
                     exp.upperIsInBounds = true;
                 }
-                else if (exp.upr.op == TOK.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
+                else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
                 {
                     // Upper slice expression is '$'. Value is always in bounds.
                     exp.upperIsInBounds = true;
@@ -8069,7 +8072,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         if (isAggregate(exp.e1.type))
             exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
-        else if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+        else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
             exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
         else if (isIndexableNonAggregate(exp.e1.type))
             exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
@@ -8090,17 +8093,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         exp.e1 = exp.e1.expressionSemantic(sc);
         exp.e2 = exp.e2.expressionSemantic(sc);
 
-        if (exp.e1.op == TOK.type)
+        if (exp.e1.op == EXP.type)
         {
             result = exp.e2;
             return;
         }
-        if (exp.e2.op == TOK.type)
+        if (exp.e2.op == EXP.type)
         {
             result = exp.e2;
             return;
         }
-        if (exp.e2.op == TOK.template_)
+        if (exp.e2.op == EXP.template_)
         {
             auto td = (cast(TemplateExp)exp.e2).td;
             Expression e = new DotTemplateExp(exp.loc, exp.e1, td);
@@ -8169,12 +8172,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         ue = ue.expressionSemantic(sc);
         ue = resolveProperties(sc, ue);
 
-        if (le.op == TOK.error)
+        if (le.op == EXP.error)
         {
             result = le;
             return;
         }
-        if (ue.op == TOK.error)
+        if (ue.op == EXP.error)
         {
             result = ue;
             return;
@@ -8198,7 +8201,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             unaSemantic(e, sc);
             e.e1 = resolveProperties(sc, e.e1);
 
-            if (e.e1.op == TOK.error)
+            if (e.e1.op == EXP.error)
             {
                 result = e.e1;
                 return;
@@ -8218,7 +8221,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             unaSemantic(e, sc);
             e.e1 = resolveProperties(sc, e.e1);
-            if (e.e1.op == TOK.error)
+            if (e.e1.op == EXP.error)
             {
                 result = e.e1;
                 return;
@@ -8244,12 +8247,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (!exp.e1.type)
             exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
         assert(exp.e1.type); // semantic() should already be run on it
-        if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+        if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
         {
             exp.e2 = exp.e2.expressionSemantic(sc);
             exp.e2 = resolveProperties(sc, exp.e2);
             Type nt;
-            if (exp.e2.op == TOK.type)
+            if (exp.e2.op == EXP.type)
                 nt = new TypeAArray(exp.e1.type, exp.e2.type);
             else
                 nt = new TypeSArray(exp.e1.type, exp.e2);
@@ -8257,7 +8260,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             result = e.expressionSemantic(sc);
             return;
         }
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
@@ -8294,7 +8297,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         exp.e2 = resolveProperties(sc, exp.e2);
         if (t1b.ty == Ttuple)
             sc = sc.endCTFE();
-        if (exp.e2.op == TOK.tuple)
+        if (exp.e2.op == EXP.tuple)
         {
             TupleExp te = cast(TupleExp)exp.e2;
             if (te.exps && te.exps.dim == 1)
@@ -8320,7 +8323,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (exp.e2.type == Type.terror)
                 return setError();
             exp.e2 = exp.e2.optimize(WANTvalue);
-            if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0)
+            if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
             {
             }
             else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
@@ -8378,13 +8381,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 TupleExp te;
                 TypeTuple tup;
                 size_t length;
-                if (exp.e1.op == TOK.tuple)
+                if (exp.e1.op == EXP.tuple)
                 {
                     te = cast(TupleExp)exp.e1;
                     tup = null;
                     length = te.exps.dim;
                 }
-                else if (exp.e1.op == TOK.type)
+                else if (exp.e1.op == EXP.type)
                 {
                     te = null;
                     tup = cast(TypeTuple)t1b;
@@ -8399,7 +8402,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
                 }
                 Expression e;
-                if (exp.e1.op == TOK.tuple)
+                if (exp.e1.op == EXP.tuple)
                 {
                     e = (*te.exps)[cast(size_t)index];
                     e = Expression.combine(te.e0, e);
@@ -8422,7 +8425,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             Expression el = new ArrayLengthExp(exp.loc, exp.e1);
             el = el.expressionSemantic(sc);
             el = el.optimize(WANTvalue);
-            if (el.op == TOK.int64)
+            if (el.op == EXP.int64)
             {
                 exp.e2 = exp.e2.optimize(WANTvalue);
                 dinteger_t length = el.toInteger();
@@ -8455,7 +8458,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
         Expression e1x = resolveProperties(sc, exp.e1);
-        if (e1x.op == TOK.error)
+        if (e1x.op == EXP.error)
         {
             result = e1x;
             return;
@@ -8472,15 +8475,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (exp.e1.checkReadModifyWrite(exp.op))
             return setError();
 
-        if (exp.e1.op == TOK.slice)
+        if (exp.e1.op == EXP.slice)
         {
-            const(char)* s = exp.op == TOK.plusPlus ? "increment" : "decrement";
+            const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
             exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
             return setError();
         }
 
         Type t1 = exp.e1.type.toBasetype();
-        if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == TOK.arrayLength)
+        if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
         {
             /* Check for operator overloading,
              * but rewrite in terms of ++e instead of e++
@@ -8489,7 +8492,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             /* If e1 is not trivial, take a reference to it
              */
             Expression de = null;
-            if (exp.e1.op != TOK.variable && exp.e1.op != TOK.arrayLength)
+            if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
             {
                 // ref v = e1;
                 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
@@ -8504,7 +8507,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             Expression ea = new DeclarationExp(exp.loc, tmp);
 
             Expression eb = exp.e1.syntaxCopy();
-            eb = new PreExp(exp.op == TOK.plusPlus ? TOK.prePlusPlus : TOK.preMinusMinus, exp.loc, eb);
+            eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
 
             Expression ec = new VarExp(exp.loc, tmp);
 
@@ -8547,7 +8550,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         // Rewrite as e1+=1 or e1-=1
-        if (exp.op == TOK.prePlusPlus)
+        if (exp.op == EXP.prePlusPlus)
             e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
         else
             e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
@@ -8596,8 +8599,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             printf("AssignExp::semantic('%s')\n", exp.toChars());
         }
-        //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, Token.toChars(exp.e1.op));
-        //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, Token.toChars(exp.e2.op));
+        //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, EXPtoString(exp.e1.op).ptr);
+        //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, EXPtoString(exp.e2.op).ptr);
 
         void setResult(Expression e, int line = __LINE__)
         {
@@ -8640,17 +8643,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             const(bool) maybeSlice =
                 (ae.arguments.dim == 0 ||
-                 ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+                 ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
 
             IntervalExp ie = null;
             if (maybeSlice && ae.arguments.dim)
             {
-                assert((*ae.arguments)[0].op == TOK.interval);
+                assert((*ae.arguments)[0].op == EXP.interval);
                 ie = cast(IntervalExp)(*ae.arguments)[0];
             }
             while (true)
             {
-                if (ae.e1.op == TOK.error)
+                if (ae.e1.op == EXP.error)
                     return setResult(ae.e1);
 
                 Expression e0 = null;
@@ -8667,11 +8670,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     res = resolveOpDollar(sc, ae, &e0);
                     if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
                         goto Lfallback;
-                    if (res.op == TOK.error)
+                    if (res.op == EXP.error)
                         return setResult(res);
 
                     res = exp.e2.expressionSemantic(sc);
-                    if (res.op == TOK.error)
+                    if (res.op == EXP.error)
                         return setResult(res);
                     exp.e2 = res;
 
@@ -8695,11 +8698,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 {
                     // Deal with $
                     res = resolveOpDollar(sc, ae, ie, &e0);
-                    if (res.op == TOK.error)
+                    if (res.op == EXP.error)
                         return setResult(res);
 
                     res = exp.e2.expressionSemantic(sc);
-                    if (res.op == TOK.error)
+                    if (res.op == EXP.error)
                         return setResult(res);
 
                     exp.e2 = res;
@@ -8826,9 +8829,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (!t1.isTypeSArray())
                 e2x = e2x.arrayFuncConv(sc);
             e2x = resolveProperties(sc, e2x);
-            if (e2x.op == TOK.type)
+            if (e2x.op == EXP.type)
                 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
-            if (e2x.op == TOK.error)
+            if (e2x.op == EXP.error)
                 return setResult(e2x);
             // We delay checking the value for structs/classes as these might have
             // an opAssign defined.
@@ -8844,7 +8847,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             Expression e2x = exp.e2;
 
         Ltupleassign:
-            if (exp.e1.op == TOK.tuple && e2x.op == TOK.tuple)
+            if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
             {
                 TupleExp tup1 = cast(TupleExp)exp.e1;
                 TupleExp tup2 = cast(TupleExp)e2x;
@@ -8877,7 +8880,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             /* Look for form: e1 = e2.aliasthis.
              */
-            if (exp.e1.op == TOK.tuple)
+            if (exp.e1.op == EXP.tuple)
             {
                 TupleDeclaration td = isAliasThisTuple(e2x);
                 if (!td)
@@ -8915,7 +8918,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
                 e2x = new TupleExp(e2x.loc, e0, iexps);
                 e2x = e2x.expressionSemantic(sc);
-                if (e2x.op == TOK.error)
+                if (e2x.op == EXP.error)
                 {
                     result = e2x;
                     return;
@@ -8929,7 +8932,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         /* Inside constructor, if this is the first assignment of object field,
          * rewrite this to initializing the field.
          */
-        if (exp.op == TOK.assign
+        if (exp.op == EXP.assign
             && exp.e1.checkModifiable(sc) == Modifiable.initialization)
         {
             //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
@@ -8942,20 +8945,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (auto ie1 = exp.e1.isIndexExp())
             {
                 Expression e1x = ie1.markSettingAAElem();
-                if (e1x.op == TOK.error)
+                if (e1x.op == EXP.error)
                 {
                     result = e1x;
                     return;
                 }
             }
         }
-        else if (exp.op == TOK.construct && exp.e1.op == TOK.variable &&
+        else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
                  (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
         {
             exp.memset = MemorySet.referenceInit;
         }
 
-        if (exp.op == TOK.assign)  // skip TOK.blit and TOK.construct, which are initializations
+        if (exp.op == EXP.assign)  // skip EXP.blit and EXP.construct, which are initializations
         {
             exp.e1.checkSharedAccess(sc);
             checkUnsafeAccess(sc, exp.e1, false, true);
@@ -8977,7 +8980,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             auto e2x = exp.e2;
             auto sd = (cast(TypeStruct)t1).sym;
 
-            if (exp.op == TOK.construct)
+            if (exp.op == EXP.construct)
             {
                 Type t2 = e2x.type.toBasetype();
                 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
@@ -8992,12 +8995,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // Look for the form from last of comma chain.
                     auto e2y = lastComma(e2x);
 
-                    CallExp ce = (e2y.op == TOK.call) ? cast(CallExp)e2y : null;
-                    DotVarExp dve = (ce && ce.e1.op == TOK.dotVariable)
+                    CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
+                    DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
                         ? cast(DotVarExp)ce.e1 : null;
                     if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
                         // https://issues.dlang.org/show_bug.cgi?id=19389
-                        dve.e1.op != TOK.dotVariable &&
+                        dve.e1.op != EXP.dotVariable &&
                         e2y.type.implicitConvTo(t1))
                     {
                         /* Look for form of constructor call which is:
@@ -9009,7 +9012,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                          * initializer
                          */
                         Expression einit = getInitExp(sd, exp.loc, sc, t1);
-                        if (einit.op == TOK.error)
+                        if (einit.op == EXP.error)
                         {
                             result = einit;
                             return;
@@ -9043,7 +9046,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // a temporary created and an extra destructor call.
                     // AST will be rewritten to:
                     // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
-                    if (e2x.op == TOK.question)
+                    if (e2x.op == EXP.question)
                     {
                         /* Rewrite as:
                          *  a ? e1 = b : e1 = c;
@@ -9158,7 +9161,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                          * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
                          * which receives an instance of a Foo2 class
                          */
-                        if (exp.e2.op == TOK.new_)
+                        if (exp.e2.op == EXP.new_)
                         {
                             auto newExp = cast(NewExp)(exp.e2);
                             if (newExp.newtype && newExp.newtype == t1)
@@ -9193,7 +9196,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                         e2x = e2x.expressionSemantic(sc);
                         e2x = resolveProperties(sc, e2x);
-                        if (e2x.op == TOK.error)
+                        if (e2x.op == EXP.error)
                         {
                             result = e2x;
                             return;
@@ -9216,9 +9219,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     }
                 }
             }
-            else if (exp.op == TOK.assign)
+            else if (exp.op == EXP.assign)
             {
-                if (e1x.op == TOK.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
+                if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
                 {
                     /*
                      * Rewrite:
@@ -9233,12 +9236,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                      */
                     // ensure we keep the expr modifiable
                     Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
-                    if (esetting.op == TOK.error)
+                    if (esetting.op == EXP.error)
                     {
                         result = esetting;
                         return;
                     }
-                    assert(esetting.op == TOK.index);
+                    assert(esetting.op == EXP.index);
                     IndexExp ie = cast(IndexExp) esetting;
                     Type t2 = e2x.type.toBasetype();
 
@@ -9279,7 +9282,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                             ey = new ConstructExp(exp.loc, ex, ey);
                             ey = ey.expressionSemantic(sc);
-                            if (ey.op == TOK.error)
+                            if (ey.op == EXP.error)
                             {
                                 result = ey;
                                 return;
@@ -9290,7 +9293,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                             // The whole expression should have the common type
                             // of opAssign() return and assigned AA entry.
                             // Even if there's no common type, expression should be typed as void.
-                            if (!typeMerge(sc, TOK.question, ex, ey))
+                            if (!typeMerge(sc, EXP.question, ex, ey))
                             {
                                 ex = new CastExp(ex.loc, ex, Type.tvoid);
                                 ey = new CastExp(ey.loc, ey, Type.tvoid);
@@ -9314,7 +9317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
             else
-                assert(exp.op == TOK.blit);
+                assert(exp.op == EXP.blit);
 
             if (e2x.checkValue())
                 return setError();
@@ -9325,7 +9328,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         else if (t1.ty == Tclass)
         {
             // Disallow assignment operator overloads for same type
-            if (exp.op == TOK.assign && !exp.e2.implicitConvTo(exp.e1.type))
+            if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
             {
                 Expression e = exp.op_overload(sc);
                 if (e)
@@ -9340,13 +9343,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         else if (t1.ty == Tsarray)
         {
             // SliceExp cannot have static array type without context inference.
-            assert(exp.e1.op != TOK.slice);
+            assert(exp.e1.op != EXP.slice);
             Expression e1x = exp.e1;
             Expression e2x = exp.e2;
 
             if (e2x.implicitConvTo(e1x.type))
             {
-                if (exp.op != TOK.blit && (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOK.slice && e2x.isLvalue()))
+                if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue()))
                 {
                     if (e1x.checkPostblit(sc, t1))
                         return setError();
@@ -9392,7 +9395,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 // May be block or element-wise assignment, so
                 // convert e1 to e1[]
-                if (exp.op != TOK.assign)
+                if (exp.op != EXP.assign)
                 {
                     // If multidimensional static array, treat as one large array
                     //
@@ -9435,9 +9438,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 sle.arrayop = true;
                 e1x = sle.expressionSemantic(sc);
             }
-            if (e1x.op == TOK.error)
+            if (e1x.op == EXP.error)
                 return setResult(e1x);
-            if (e2x.op == TOK.error)
+            if (e2x.op == EXP.error)
                 return setResult(e2x);
 
             exp.e1 = e1x;
@@ -9451,7 +9454,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             // e1 is not an lvalue, but we let code generator handle it
 
             auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
-            if (ale1x.op == TOK.error)
+            if (ale1x.op == EXP.error)
                 return setResult(ale1x);
             ale.e1 = ale1x;
 
@@ -9466,7 +9469,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             auto lc = lastComma(exp.e2);
             lc = lc.optimize(WANTvalue);
             // use slice expression when arr.length = 0 to avoid runtime call
-            if(lc.op == TOK.int64 && lc.toInteger() == 0)
+            if(lc.op == EXP.int64 && lc.toInteger() == 0)
             {
                 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
                 Expression as = new AssignExp(ale.loc, ale.e1, se);
@@ -9507,7 +9510,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             Type tn = se.type.nextOf();
             const fun = sc.func;
-            if (exp.op == TOK.assign && !tn.isMutable() &&
+            if (exp.op == EXP.assign && !tn.isMutable() &&
                 // allow modifiation in module ctor, see
                 // https://issues.dlang.org/show_bug.cgi?id=9884
                 (!fun || (fun && !fun.isStaticCtorDeclaration())))
@@ -9516,7 +9519,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
             }
 
-            if (exp.op == TOK.assign && !tn.baseElemOf().isAssignable())
+            if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
             {
                 exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
                     exp.e1.toChars(), tn.baseElemOf().toChars());
@@ -9525,18 +9528,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
 
             // For conditional operator, both branches need conversion.
-            while (se.e1.op == TOK.slice)
+            while (se.e1.op == EXP.slice)
                 se = cast(SliceExp)se.e1;
-            if (se.e1.op == TOK.question && se.e1.type.toBasetype().ty == Tsarray)
+            if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
             {
                 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
-                if (se.e1.op == TOK.error)
+                if (se.e1.op == EXP.error)
                     return setResult(se.e1);
             }
         }
         else
         {
-            if (t1.ty == Tsarray && exp.op == TOK.assign)
+            if (t1.ty == Tsarray && exp.op == EXP.assign)
             {
                 Type tn = exp.e1.type.nextOf();
                 if (tn && !tn.baseElemOf().isAssignable())
@@ -9552,12 +9555,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             // Try to do a decent error message with the expression
             // before it gets constant folded
-            if (exp.op == TOK.assign)
+            if (exp.op == EXP.assign)
                 e1x = e1x.modifiableLvalue(sc, e1old);
 
             e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
 
-            if (e1x.op == TOK.error)
+            if (e1x.op == EXP.error)
             {
                 result = e1x;
                 return;
@@ -9576,18 +9579,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         while (telem.ty == Tarray)
             telem = telem.nextOf();
 
-        if (exp.e1.op == TOK.slice && t1.nextOf() &&
-            (telem.ty != Tvoid || e2x.op == TOK.null_) &&
+        if (exp.e1.op == EXP.slice && t1.nextOf() &&
+            (telem.ty != Tvoid || e2x.op == EXP.null_) &&
             e2x.implicitConvTo(t1.nextOf()))
         {
             // Check for block assignment. If it is of type void[], void[][], etc,
             // '= null' is the only allowable block assignment (Bug 7493)
             exp.memset = MemorySet.blockAssign;    // make it easy for back end to tell what this is
             e2x = e2x.implicitCastTo(sc, t1.nextOf());
-            if (exp.op != TOK.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
+            if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
                 return setError();
         }
-        else if (exp.e1.op == TOK.slice &&
+        else if (exp.e1.op == EXP.slice &&
                  (t2.ty == Tarray || t2.ty == Tsarray) &&
                  t2.nextOf().implicitConvTo(t1.nextOf()))
         {
@@ -9616,24 +9619,24 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
 
-            if (exp.op != TOK.blit &&
-                (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
-                 e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
-                 e2x.op != TOK.slice && e2x.isLvalue()))
+            if (exp.op != EXP.blit &&
+                (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
+                 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
+                 e2x.op != EXP.slice && e2x.isLvalue()))
             {
                 if (exp.e1.checkPostblit(sc, t1.nextOf()))
                     return setError();
             }
 
-            if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign &&
-                e2x.op != TOK.slice && e2x.op != TOK.assign &&
-                e2x.op != TOK.arrayLiteral && e2x.op != TOK.string_ &&
-                !(e2x.op == TOK.add || e2x.op == TOK.min ||
-                  e2x.op == TOK.mul || e2x.op == TOK.div ||
-                  e2x.op == TOK.mod || e2x.op == TOK.xor ||
-                  e2x.op == TOK.and || e2x.op == TOK.or ||
-                  e2x.op == TOK.pow ||
-                  e2x.op == TOK.tilde || e2x.op == TOK.negate))
+            if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
+                e2x.op != EXP.slice && e2x.op != EXP.assign &&
+                e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
+                !(e2x.op == EXP.add || e2x.op == EXP.min ||
+                  e2x.op == EXP.mul || e2x.op == EXP.div ||
+                  e2x.op == EXP.mod || e2x.op == EXP.xor ||
+                  e2x.op == EXP.and || e2x.op == EXP.or ||
+                  e2x.op == EXP.pow ||
+                  e2x.op == EXP.tilde || e2x.op == EXP.negate))
             {
                 const(char)* e1str = exp.e1.toChars();
                 const(char)* e2str = e2x.toChars();
@@ -9673,7 +9676,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  * elements need to be const at best. So we should give a chance
                  * to change code unit size for polysemous string literal.
                  */
-                if (e2x.op == TOK.string_)
+                if (e2x.op == EXP.string_)
                     e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
                 else
                     e2x = e2x.implicitCastTo(sc, exp.e1.type);
@@ -9689,19 +9692,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else
         {
-            if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign &&
+            if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
                 t1.ty == Tarray && t2.ty == Tsarray &&
-                e2x.op != TOK.slice &&
+                e2x.op != EXP.slice &&
                 t2.implicitConvTo(t1))
             {
                 // Disallow ar[] = sa (Converted to ar[] = sa[])
                 // Disallow da   = sa (Converted to da   = sa[])
                 const(char)* e1str = exp.e1.toChars();
                 const(char)* e2str = e2x.toChars();
-                const(char)* atypestr = exp.e1.op == TOK.slice ? "element-wise" : "slice";
+                const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
                 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
             }
-            if (exp.op == TOK.blit)
+            if (exp.op == EXP.blit)
                 e2x = e2x.castTo(sc, exp.e1.type);
             else
             {
@@ -9711,7 +9714,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 // If the implicit cast has failed and the assign expression is
                 // the initialization of a struct member field
-                if (e2x.op == TOK.error && exp.op == TOK.construct && t1.ty == Tstruct)
+                if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
                 {
                     scope sd = (cast(TypeStruct)t1).sym;
                     Dsymbol opAssign = search_function(sd, Id.assign);
@@ -9729,7 +9732,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
         }
-        if (e2x.op == TOK.error)
+        if (e2x.op == EXP.error)
         {
             result = e2x;
             return;
@@ -9743,11 +9746,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             // Look for valid array operations
             if (exp.memset != MemorySet.blockAssign &&
-                exp.e1.op == TOK.slice &&
+                exp.e1.op == EXP.slice &&
                 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
             {
                 exp.type = exp.e1.type;
-                if (exp.op == TOK.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
+                if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
                                         // tweak mutability of e1 element
                     exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
                 result = arrayOp(exp, sc);
@@ -9756,7 +9759,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             // Drop invalid array operations in e2
             //  d = a[] + b[], d = (a[] + b[])[0..2], etc
-            if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == TOK.assign))
+            if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
                 return setError();
 
             // Remains valid array assignments
@@ -9766,7 +9769,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         /* Don't allow assignment to classes that were allocated on the stack with:
          *      scope Class c = new Class();
          */
-        if (exp.e1.op == TOK.variable && exp.op == TOK.assign)
+        if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
         {
             VarExp ve = cast(VarExp)exp.e1;
             VarDeclaration vd = ve.var.isVarDeclaration();
@@ -9777,14 +9780,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
         }
 
-        if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
+        if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
         {
             exp.error("cannot modify compiler-generated variable `__ctfe`");
         }
 
         exp.type = exp.e1.type;
         assert(exp.type);
-        auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp;
+        auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
         Expression tmp;
         /* https://issues.dlang.org/show_bug.cgi?id=22366
          *
@@ -9792,6 +9795,84 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
          * `checkAssignExp` expects only AssignExps.
          */
         checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
+
+        if (auto ae = res.isConstructExp())
+        {
+            Type t1b = ae.e1.type.toBasetype();
+            if (t1b.ty != Tsarray && t1b.ty != Tarray)
+                return setResult(res);
+
+            /* Do not lower Rvalues and references, as they need to be moved,
+             * not copied.
+             * Skip the lowering when the RHS is an array literal, as e2ir
+             * already handles such cases more elegantly.
+             */
+            const isArrayCtor =
+                (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
+                ae.e2.isLvalue &&
+                !(ae.e1.isVarExp &&
+                    ae.e1.isVarExp.var.isVarDeclaration.isReference) &&
+                (ae.e2.isVarExp ||
+                    ae.e2.isSliceExp ||
+                    (ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) &&
+                ae.e1.type.nextOf &&
+                ae.e2.type.nextOf &&
+                ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf);
+
+            const isArraySetCtor =
+                (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
+                ae.e2.isLvalue &&
+                (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
+                ae.e1.type.nextOf &&
+                ae.e1.type.nextOf.equivalent(ae.e2.type);
+
+            if (isArrayCtor || isArraySetCtor)
+            {
+                const ts = t1b.nextOf().baseElemOf().isTypeStruct();
+                if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
+                    return setResult(res);
+
+                auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
+                const other = isArrayCtor ? "other array" : "value";
+                if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
+                    return setError();
+
+                // Lower to object._d_array{,set}ctor(e1, e2)
+                Expression id = new IdentifierExp(exp.loc, Id.empty);
+                id = new DotIdExp(exp.loc, id, Id.object);
+                id = new DotIdExp(exp.loc, id, func);
+                id = id.expressionSemantic(sc);
+
+                auto arguments = new Expressions();
+                arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc));
+                if (isArrayCtor)
+                {
+                    arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc));
+                    Expression ce = new CallExp(exp.loc, id, arguments);
+                    res = ce.expressionSemantic(sc);
+                }
+                else
+                {
+                    Expression e0;
+                    // If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access
+                    if (!ae.e2.isVarExp)
+                    {
+                        auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
+                        e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
+                        arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
+                    }
+                    else
+                        arguments.push(ae.e2);
+
+                    Expression ce = new CallExp(exp.loc, id, arguments);
+                    res = Expression.combine(e0, ce).expressionSemantic(sc);
+                }
+
+                if (global.params.verbose)
+                    message("lowered   %s =>\n          %s", exp.toChars(), res.toChars());
+            }
+        }
+
         return setResult(res);
     }
 
@@ -9814,7 +9895,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
 
         assert(exp.e1.type && exp.e2.type);
-        if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+        if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
         {
             if (checkNonAssignmentArrayOp(exp.e1))
                 return setError();
@@ -9855,7 +9936,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             e = Expression.extractLast(e, e0);
             assert(e == exp);
 
-            if (exp.e1.op == TOK.variable)
+            if (exp.e1.op == EXP.variable)
             {
                 // Rewrite: e1 = e1 ^^ e2
                 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
@@ -9895,7 +9976,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.e1.op == TOK.slice)
+        if (exp.e1.op == EXP.slice)
         {
             SliceExp se = cast(SliceExp)exp.e1;
             if (se.e1.type.toBasetype().ty == Tsarray)
@@ -9906,12 +9987,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
-        if (exp.e1.op == TOK.error)
+        if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
             return;
         }
-        if (exp.e2.op == TOK.error)
+        if (exp.e2.op == EXP.error)
         {
             result = exp.e2;
             return;
@@ -9925,9 +10006,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         Type tb2 = exp.e2.type.toBasetype();
 
         /* Possibilities:
-         * TOK.concatenateAssign: appending T[] to T[]
-         * TOK.concatenateElemAssign: appending T to T[]
-         * TOK.concatenateDcharAssign: appending dchar to T[]
+         * EXP.concatenateAssign: appending T[] to T[]
+         * EXP.concatenateElemAssign: appending T to T[]
+         * EXP.concatenateDcharAssign: appending dchar to T[]
          */
         if ((tb1.ty == Tarray) &&
             (tb2.ty == Tarray || tb2.ty == Tsarray) &&
@@ -9935,8 +10016,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
              (tb2.nextOf().implicitConvTo(tb1next) &&
               (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
         {
-            // TOK.concatenateAssign
-            assert(exp.op == TOK.concatenateAssign);
+            // EXP.concatenateAssign
+            assert(exp.op == EXP.concatenateAssign);
             if (exp.e1.checkPostblit(sc, tb1next))
                 return setError();
 
@@ -10033,7 +10114,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         exp.type = exp.e1.type;
         auto res = exp.reorderSettingAAElem(sc);
-        if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) &&
+        if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
             global.params.useDIP1000 == FeatureState.enabled)
             checkAssignEscape(sc, res, false);
         result = res;
@@ -10227,6 +10308,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 {
                     e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
                 }
+                else if (stride == cast(d_int64)SIZE_INVALID)
+                    e = ErrorExp.get();
                 else
                 {
                     e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
@@ -10336,7 +10419,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         Type tb2next = tb2.nextOf();
 
         // Check for: array ~ array
-        if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1)))
+        if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1)))
         {
             /* https://issues.dlang.org/show_bug.cgi?id=9248
              * Here to avoid the case of:
@@ -10360,14 +10443,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // Check for: array ~ element
         if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
         {
-            if (exp.e1.op == TOK.arrayLiteral)
+            if (exp.e1.op == EXP.arrayLiteral)
             {
                 exp.e2 = doCopyOrMove(sc, exp.e2);
                 // https://issues.dlang.org/show_bug.cgi?id=14686
                 // Postblit call appears in AST, and this is
                 // finally translated  to an ArrayLiteralExp in below optimize().
             }
-            else if (exp.e1.op == TOK.string_)
+            else if (exp.e1.op == EXP.string_)
             {
                 // No postblit call exists on character (integer) value.
             }
@@ -10378,7 +10461,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 // Postblit call will be done in runtime helper function
             }
 
-            if (exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
+            if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
             {
                 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
                 exp.type = tb2.arrayOf();
@@ -10403,11 +10486,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // Check for: element ~ array
         if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
         {
-            if (exp.e2.op == TOK.arrayLiteral)
+            if (exp.e2.op == EXP.arrayLiteral)
             {
                 exp.e1 = doCopyOrMove(sc, exp.e1);
             }
-            else if (exp.e2.op == TOK.string_)
+            else if (exp.e2.op == EXP.string_)
             {
             }
             else
@@ -10416,7 +10499,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
             }
 
-            if (exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
+            if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
             {
                 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
                 exp.type = tb1.arrayOf();
@@ -10444,11 +10527,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             Type t1 = tb1next.mutableOf().constOf().arrayOf();
             Type t2 = tb2next.mutableOf().constOf().arrayOf();
-            if (exp.e1.op == TOK.string_ && !(cast(StringExp)exp.e1).committed)
+            if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
                 exp.e1.type = t1;
             else
                 exp.e1 = exp.e1.castTo(sc, t1);
-            if (exp.e2.op == TOK.string_ && !(cast(StringExp)exp.e2).committed)
+            if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
                 exp.e2.type = t2;
             else
                 exp.e2 = exp.e2.castTo(sc, t2);
@@ -10804,7 +10887,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         // First, attempt to fold the expression.
         e = exp.optimize(WANTvalue);
-        if (e.op != TOK.pow)
+        if (e.op != EXP.pow)
         {
             e = e.expressionSemantic(sc);
             result = e;
@@ -10819,7 +10902,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         e = new ScopeExp(exp.loc, mmath);
 
-        if (exp.e2.op == TOK.float64 && exp.e2.toReal() == CTFloat.half)
+        if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
         {
             // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
             e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
@@ -11126,7 +11209,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         Expression e1x = exp.e1.expressionSemantic(sc);
 
         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-        if (e1x.op == TOK.type)
+        if (e1x.op == EXP.type)
             e1x = resolveAliasThis(sc, e1x);
 
         e1x = resolveProperties(sc, e1x);
@@ -11137,9 +11220,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             /* If in static if, don't evaluate e2 if we don't have to.
              */
             e1x = e1x.optimize(WANTvalue);
-            if (e1x.isBool(exp.op == TOK.orOr))
+            if (e1x.toBool().hasValue(exp.op == EXP.orOr))
             {
-                result = IntegerExp.createBool(exp.op == TOK.orOr);
+                result = IntegerExp.createBool(exp.op == EXP.orOr);
                 return;
             }
         }
@@ -11150,7 +11233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         ctorflow.freeFieldinit();
 
         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-        if (e2x.op == TOK.type)
+        if (e2x.op == EXP.type)
             e2x = resolveAliasThis(sc, e2x);
 
         e2x = resolveProperties(sc, e2x);
@@ -11164,17 +11247,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (e2x.type.ty != Tvoid)
             e2x = e2x.toBoolean(sc);
 
-        if (e2x.op == TOK.type || e2x.op == TOK.scope_)
+        if (e2x.op == EXP.type || e2x.op == EXP.scope_)
         {
             exp.error("`%s` is not an expression", exp.e2.toChars());
             return setError();
         }
-        if (e1x.op == TOK.error || e1x.type.ty == Tnoreturn)
+        if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
         {
             result = e1x;
             return;
         }
-        if (e2x.op == TOK.error)
+        if (e2x.op == EXP.error)
         {
             result = e2x;
             return;
@@ -11213,13 +11296,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         Type t1 = exp.e1.type.toBasetype();
         Type t2 = exp.e2.type.toBasetype();
-        if (t1.ty == Tclass && exp.e2.op == TOK.null_ || t2.ty == Tclass && exp.e1.op == TOK.null_)
+        if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
         {
             exp.error("do not use `null` when comparing class types");
             return setError();
         }
 
-        TOK cmpop;
+        EXP cmpop;
         if (auto e = exp.op_overload(sc, &cmpop))
         {
             if (!e.type.isscalar() && e.type.equals(exp.e1.type))
@@ -11227,7 +11310,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 exp.error("recursive `opCmp` expansion");
                 return setError();
             }
-            if (e.op == TOK.call)
+            if (e.op == EXP.call)
             {
                 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
                 e = e.expressionSemantic(sc);
@@ -11298,7 +11381,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else if (t1.ty == Taarray || t2.ty == Taarray)
         {
-            exp.error("`%s` is not defined for associative arrays", Token.toChars(exp.op));
+            exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
             return setError();
         }
         else if (!target.isVectorOpSupported(t1, exp.op, t2))
@@ -11402,7 +11485,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             result = e;
             return;
         }
-        if (exp.e1.op == TOK.type || exp.e2.op == TOK.type)
+        if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
         {
             /* https://issues.dlang.org/show_bug.cgi?id=12520
              * empty tuples are represented as types so special cases are added
@@ -11411,7 +11494,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             static auto extractTypeTupAndExpTup(Expression e)
             {
                 static struct Result { bool ttEmpty; bool te; }
-                auto tt = e.op == TOK.type ? e.isTypeExp().type.isTypeTuple() : null;
+                auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
                 return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null);
             }
             auto tups1 = extractTypeTupAndExpTup(exp.e1);
@@ -11419,19 +11502,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             // AliasSeq!() == AliasSeq!(<at least a value>)
             if (tups1.ttEmpty && tups2.te)
             {
-                result = IntegerExp.createBool(exp.op != TOK.equal);
+                result = IntegerExp.createBool(exp.op != EXP.equal);
                 return;
             }
             // AliasSeq!(<at least a value>) == AliasSeq!()
             else if (tups1.te && tups2.ttEmpty)
             {
-                result = IntegerExp.createBool(exp.op != TOK.equal);
+                result = IntegerExp.createBool(exp.op != EXP.equal);
                 return;
             }
             // AliasSeq!() == AliasSeq!()
             else if (tups1.ttEmpty && tups2.ttEmpty)
             {
-                result = IntegerExp.createBool(exp.op == TOK.equal);
+                result = IntegerExp.createBool(exp.op == EXP.equal);
                 return;
             }
             // otherwise, two types are really not comparable
@@ -11451,18 +11534,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
          * comparing the addresses of two statics. If so, we can just see
          * if they are the same symbol.
          */
-        if (exp.e1.op == TOK.address && exp.e2.op == TOK.address)
+        if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
         {
             AddrExp ae1 = cast(AddrExp)exp.e1;
             AddrExp ae2 = cast(AddrExp)exp.e2;
-            if (ae1.e1.op == TOK.variable && ae2.e1.op == TOK.variable)
+            if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
             {
                 VarExp ve1 = cast(VarExp)ae1.e1;
                 VarExp ve2 = cast(VarExp)ae2.e1;
                 if (ve1.var == ve2.var)
                 {
                     // They are the same, result is 'true' for ==, 'false' for !=
-                    result = IntegerExp.createBool(exp.op == TOK.equal);
+                    result = IntegerExp.createBool(exp.op == EXP.equal);
                     return;
                 }
             }
@@ -11555,7 +11638,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             (*arguments)[1] = exp.e2;
 
             __equals = new CallExp(exp.loc, __equals, arguments);
-            if (exp.op == TOK.notEqual)
+            if (exp.op == EXP.notEqual)
             {
                 __equals = new NotExp(exp.loc, __equals);
             }
@@ -11611,7 +11694,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (f1 || f2)
             return setError();
 
-        if (exp.e1.op == TOK.type || exp.e2.op == TOK.type)
+        if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
         {
             result = exp.incompatibleTypes();
             return;
@@ -11634,9 +11717,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.e1.op == TOK.call)
+        if (exp.e1.op == EXP.call)
             exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
-        if (exp.e2.op == TOK.call)
+        if (exp.e2.op == EXP.call)
             exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
 
         if (exp.e1.type.toBasetype().ty == Tsarray ||
@@ -11660,7 +11743,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.econd.op == TOK.dotIdentifier)
+        if (exp.econd.op == EXP.dotIdentifier)
             (cast(DotIdExp)exp.econd).noderef = true;
 
         Expression ec = exp.econd.expressionSemantic(sc);
@@ -11679,7 +11762,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         sc.merge(exp.loc, ctorflow1);
         ctorflow1.freeFieldinit();
 
-        if (ec.op == TOK.error)
+        if (ec.op == EXP.error)
         {
             result = ec;
             return;
@@ -11688,7 +11771,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
         exp.econd = ec;
 
-        if (e1x.op == TOK.error)
+        if (e1x.op == EXP.error)
         {
             result = e1x;
             return;
@@ -11697,7 +11780,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
         exp.e1 = e1x;
 
-        if (e2x.op == TOK.error)
+        if (e2x.op == EXP.error)
         {
             result = e2x;
             return;
@@ -11957,7 +12040,7 @@ Expression unaSemantic(UnaExp e, Scope* sc)
         printf("UnaExp::semantic('%s')\n", e.toChars());
     }
     Expression e1x = e.e1.expressionSemantic(sc);
-    if (e1x.op == TOK.error)
+    if (e1x.op == EXP.error)
         return e1x;
     e.e1 = e1x;
     return null;
@@ -11977,14 +12060,14 @@ Expression binSemantic(BinExp e, Scope* sc)
     Expression e2x = e.e2.expressionSemantic(sc);
 
     // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-    if (e1x.op == TOK.type)
+    if (e1x.op == EXP.type)
         e1x = resolveAliasThis(sc, e1x);
-    if (e2x.op == TOK.type)
+    if (e2x.op == EXP.type)
         e2x = resolveAliasThis(sc, e2x);
 
-    if (e1x.op == TOK.error)
+    if (e1x.op == EXP.error)
         return e1x;
-    if (e2x.op == TOK.error)
+    if (e2x.op == EXP.error)
         return e2x;
     e.e1 = e1x;
     e.e2 = e2x;
@@ -11997,9 +12080,9 @@ Expression binSemanticProp(BinExp e, Scope* sc)
         return ex;
     Expression e1x = resolveProperties(sc, e.e1);
     Expression e2x = resolveProperties(sc, e.e2);
-    if (e1x.op == TOK.error)
+    if (e1x.op == EXP.error)
         return e1x;
-    if (e2x.op == TOK.error)
+    if (e2x.op == EXP.error)
         return e2x;
     e.e1 = e1x;
     e.e2 = e2x;
@@ -12049,11 +12132,11 @@ Expression semanticX(DotIdExp exp, Scope* sc)
         Dsymbol ds;
         switch (exp.e1.op)
         {
-            case TOK.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
-            case TOK.variable:    return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
-            case TOK.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
-            case TOK.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
-            case TOK.template_:
+            case EXP.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
+            case EXP.variable:    return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
+            case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
+            case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
+            case EXP.template_:
             {
                 TemplateExp te = exp.e1.isTemplateExp();
                 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
@@ -12480,9 +12563,9 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
     }
     assert(e);
 
-    if (e.op == TOK.error)
+    if (e.op == EXP.error)
         return e;
-    if (e.op == TOK.dotVariable)
+    if (e.op == EXP.dotVariable)
     {
         DotVarExp dve = cast(DotVarExp)e;
         if (FuncDeclaration fd = dve.var.isFuncDeclaration())
@@ -12516,7 +12599,7 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
                    .expressionSemantic(sc);
         }
     }
-    else if (e.op == TOK.variable)
+    else if (e.op == EXP.variable)
     {
         VarExp ve = cast(VarExp)e;
         if (FuncDeclaration fd = ve.var.isFuncDeclaration())
@@ -12535,7 +12618,7 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
         }
     }
 
-    if (e.op == TOK.dotTemplateDeclaration)
+    if (e.op == EXP.dotTemplateDeclaration)
     {
         DotTemplateExp dte = cast(DotTemplateExp)e;
         exp.e1 = dte.e1; // pull semantic() result
@@ -12560,17 +12643,17 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
         return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
                .expressionSemantic(sc);
     }
-    else if (e.op == TOK.template_)
+    else if (e.op == EXP.template_)
     {
         exp.ti.tempdecl = (cast(TemplateExp)e).td;
         return new ScopeExp(exp.loc, exp.ti)
                .expressionSemantic(sc);
     }
-    else if (e.op == TOK.dot)
+    else if (e.op == EXP.dot)
     {
         DotExp de = cast(DotExp)e;
 
-        if (de.e2.op == TOK.overloadSet)
+        if (de.e2.op == EXP.overloadSet)
         {
             if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
             {
@@ -12593,7 +12676,7 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
                    .expressionSemantic(sc);
         }
     }
-    else if (e.op == TOK.overloadSet)
+    else if (e.op == EXP.overloadSet)
     {
         OverExp oe = cast(OverExp)e;
         exp.ti.tempdecl = oe.vars;
@@ -12873,7 +12956,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre
         }
         s = s.toParent2();
     }
-    if (n > 1 || e1.op == TOK.index)
+    if (n > 1 || e1.op == EXP.index)
         e1 = e1.expressionSemantic(sc);
     if (s && e1.type.equivalent(Type.tvoidptr))
     {
@@ -12967,7 +13050,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
         e = resolveProperties(sc, e);
         if (i >= nfields)
         {
-            if (i <= sd.fields.dim && e.op == TOK.null_)
+            if (i <= sd.fields.dim && e.op == EXP.null_)
             {
                 // CTFE sometimes creates null as hidden pointer; we'll allow this.
                 continue;
@@ -12988,7 +13071,10 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
             }
             return false;
         }
-        offset = cast(uint)(v.offset + v.type.size());
+        const vsize = v.type.size();
+        if (vsize == SIZE_INVALID)
+            return false;
+        offset = cast(uint)(v.offset + vsize);
 
         Type t = v.type;
         if (stype)
@@ -13015,7 +13101,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
          * Allow this by doing an explicit cast, which will lengthen the string
          * literal.
          */
-        if (e.op == TOK.string_ && tb.ty == Tsarray)
+        if (e.op == EXP.string_ && tb.ty == Tsarray)
         {
             StringExp se = cast(StringExp)e;
             Type typeb = se.type.toBasetype();
@@ -13042,7 +13128,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
 
         e = e.implicitCastTo(sc, t);
     L1:
-        if (e.op == TOK.error)
+        if (e.op == EXP.error)
             return false;
 
         (*elements)[i] = doCopyOrMove(sc, e);
@@ -13090,22 +13176,22 @@ Expression toBoolean(Expression exp, Scope* sc)
 {
     switch(exp.op)
     {
-        case TOK.delete_:
+        case EXP.delete_:
             exp.error("`delete` does not give a boolean result");
             return ErrorExp.get();
 
-        case TOK.comma:
+        case EXP.comma:
             auto ce = exp.isCommaExp();
             auto ex2 = ce.e2.toBoolean(sc);
-            if (ex2.op == TOK.error)
+            if (ex2.op == EXP.error)
                 return ex2;
             ce.e2 = ex2;
             ce.type = ce.e2.type;
             return ce;
 
-        case TOK.assign:
-        case TOK.construct:
-        case TOK.blit:
+        case EXP.assign:
+        case EXP.construct:
+        case EXP.blit:
             // Things like:
             //  if (a = b) ...
             // are usually mistakes.
@@ -13113,22 +13199,22 @@ Expression toBoolean(Expression exp, Scope* sc)
             return ErrorExp.get();
 
         //LogicalExp
-        case TOK.andAnd:
-        case TOK.orOr:
+        case EXP.andAnd:
+        case EXP.orOr:
             auto le = exp.isLogicalExp();
             auto ex2 = le.e2.toBoolean(sc);
-            if (ex2.op == TOK.error)
+            if (ex2.op == EXP.error)
                 return ex2;
             le.e2 = ex2;
             return le;
 
-        case TOK.question:
+        case EXP.question:
             auto ce = exp.isCondExp();
             auto ex1 = ce.e1.toBoolean(sc);
             auto ex2 = ce.e2.toBoolean(sc);
-            if (ex1.op == TOK.error)
+            if (ex1.op == EXP.error)
                 return ex1;
-            if (ex2.op == TOK.error)
+            if (ex2.op == EXP.error)
                 return ex2;
             ce.e1 = ex1;
             ce.e2 = ex2;
index 9579ac7d6a544bde97d36de6734b8105daf67c66..e9a43f9210547b7c9aaf3c6ebd074f10aaa0f762 100644 (file)
@@ -223,7 +223,7 @@ void foreachExpAndVar(Statement s,
         void visitWith(WithStatement s)
         {
             // If it is with(Enum) {...}, just execute the body.
-            if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
+            if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
             {
             }
             else
index 2d6a756178e9322c20ae46fc4c24837b7aa68a40..da33587fc88a802718c5945e3abd85ceb37c045d 100644 (file)
@@ -1306,7 +1306,14 @@ extern (C++) class FuncDeclaration : Declaration
         if (!fbody)
             return false;
 
-        if (isVirtualMethod())
+        if (isVirtualMethod() &&
+            /*
+             * https://issues.dlang.org/show_bug.cgi?id=21719
+             *
+             * If we have an auto virtual function we can infer
+             * the attributes.
+             */
+            !(inferRetType && !isCtorDeclaration()))
             return false;               // since they may be overridden
 
         if (sc.func &&
index 747a1138905aed6c2268b21b85bb69e9dbbfbd61..7409dcc290273ef489325bae58c2281db4e957cf 100644 (file)
@@ -148,7 +148,7 @@ extern (C++) struct Param
     bool betterC;           // be a "better C" compiler; no dependency on D runtime
     bool addMain;           // add a default main() function
     bool allInst;           // generate code for all template instantiations
-    bool fix16997;          // fix integral promotions for unary + - ~ operators
+    bool fix16997 = true;   // fix integral promotions for unary + - ~ operators
                             // https://issues.dlang.org/show_bug.cgi?id=16997
     bool fixAliasThis;      // if the current scope has an alias this, check it before searching upper scopes
     bool inclusiveInContracts;   // 'in' contracts of overridden methods must be a superset of parent contract
index 4ff07b5de329231275d8889a99974d36c233c272..a454298673965d7704c041fa561ff4588f6df316 100644 (file)
@@ -164,7 +164,7 @@ public:
 
     override void visit(ExpStatement s)
     {
-        if (s.exp && s.exp.op == TOK.declaration &&
+        if (s.exp && s.exp.op == EXP.declaration &&
             (cast(DeclarationExp)s.exp).declaration)
         {
             // bypass visit(DeclarationExp)
@@ -202,7 +202,7 @@ public:
         foreach (sx; *s.statements)
         {
             auto ds = sx ? sx.isExpStatement() : null;
-            if (ds && ds.exp.op == TOK.declaration)
+            if (ds && ds.exp.op == EXP.declaration)
             {
                 auto d = (cast(DeclarationExp)ds.exp).declaration;
                 assert(d.isDeclaration());
@@ -1260,7 +1260,7 @@ public:
             {
                 buf.writestring(" = ");
                 ExpInitializer ie = vd._init.isExpInitializer();
-                if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit))
+                if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
                     (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
                 else
                     vd._init.initializerToBuffer(buf, hgs);
@@ -1511,7 +1511,7 @@ public:
         {
             buf.writestring(" = ");
             auto ie = v._init.isExpInitializer();
-            if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit))
+            if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
                 (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
             else
                 v._init.initializerToBuffer(buf, hgs);
@@ -1569,7 +1569,7 @@ public:
                 buf.writestring("in");
                 if (auto es = frequire.isExpStatement())
                 {
-                    assert(es.exp && es.exp.op == TOK.assert_);
+                    assert(es.exp && es.exp.op == EXP.assert_);
                     buf.writestring(" (");
                     (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
                     buf.writeByte(')');
@@ -1592,7 +1592,7 @@ public:
                 buf.writestring("out");
                 if (auto es = fensure.ensure.isExpStatement())
                 {
-                    assert(es.exp && es.exp.op == TOK.assert_);
+                    assert(es.exp && es.exp.op == EXP.assert_);
                     buf.writestring(" (");
                     if (fensure.id)
                     {
@@ -1749,7 +1749,7 @@ public:
         buf.writestring("invariant");
         if(auto es = d.fbody.isExpStatement())
         {
-            assert(es.exp && es.exp.op == TOK.assert_);
+            assert(es.exp && es.exp.op == EXP.assert_);
             buf.writestring(" (");
             (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
             buf.writestring(");");
@@ -1812,7 +1812,7 @@ public:
     ////////////////////////////////////////////////////////////////////////////
     override void visit(Expression e)
     {
-        buf.writestring(Token.toString(e.op));
+        buf.writestring(EXPtoString(e.op));
     }
 
     override void visit(IntegerExp e)
@@ -2278,7 +2278,7 @@ public:
 
     override void visit(UnaExp e)
     {
-        buf.writestring(Token.toString(e.op));
+        buf.writestring(EXPtoString(e.op));
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
@@ -2286,7 +2286,7 @@ public:
     {
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
         buf.writeByte(' ');
-        buf.writestring(Token.toString(e.op));
+        buf.writestring(EXPtoString(e.op));
         buf.writeByte(' ');
         expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
     }
@@ -2415,7 +2415,7 @@ public:
 
     override void visit(CallExp e)
     {
-        if (e.e1.op == TOK.type)
+        if (e.e1.op == EXP.type)
         {
             /* Avoid parens around type to prevent forbidden cast syntax:
              *   (sometype)(arg1)
@@ -2540,12 +2540,12 @@ public:
     override void visit(PostExp e)
     {
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
-        buf.writestring(Token.toString(e.op));
+        buf.writestring(EXPtoString(e.op));
     }
 
     override void visit(PreExp e)
     {
-        buf.writestring(Token.toString(e.op));
+        buf.writestring(EXPtoString(e.op));
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
@@ -2568,7 +2568,7 @@ public:
 
     override void visit(DefaultInitExp e)
     {
-        buf.writestring(Token.toString(e.op));
+        buf.writestring(EXPtoString(e.op));
     }
 
     override void visit(ClassReferenceExp e)
@@ -3144,7 +3144,7 @@ private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs)
     {
         buf.writeByte('@');
 
-        bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call;
+        bool isAnonymous = p.userAttribDecl.atts.dim > 0 && !(*p.userAttribDecl.atts)[0].isCallExp();
         if (isAnonymous)
             buf.writeByte('(');
 
@@ -3253,9 +3253,9 @@ private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
 {
     if (e.type == Type.tsize_t)
     {
-        Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e);
+        Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e);
         ex = ex.optimize(WANTvalue);
-        const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1;
+        const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1;
         if (cast(sinteger_t)uval >= 0)
         {
             dinteger_t sizemax = void;
@@ -3292,7 +3292,7 @@ private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs
     debug
     {
         if (precedence[e.op] == PREC.zero)
-            printf("precedence not defined for token '%s'\n", Token.toChars(e.op));
+            printf("precedence not defined for token '%s'\n", EXPtoString(e.op).ptr);
     }
     if (e.op == 0xFF)
     {
@@ -3422,7 +3422,7 @@ private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hg
         }
         else if (Expression e = isExpression(oarg))
         {
-            if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_)
+            if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
             {
                 buf.writestring(e.toChars());
                 return;
@@ -3460,7 +3460,7 @@ private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs)
     }
     else if (auto e = isExpression(oarg))
     {
-        if (e.op == TOK.variable)
+        if (e.op == EXP.variable)
             e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375
         expToBuffer(e, PREC.assign, buf, hgs);
     }
@@ -3962,3 +3962,158 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
         case Ttag:       return visitTag(cast(TypeTag)t);
     }
 }
+
+/****************************************
+ * Convert EXP to char*.
+ */
+
+string EXPtoString(EXP op)
+{
+    static immutable char*[EXP.max + 1] strings =
+    [
+        EXP.type : "type",
+        EXP.error : "error",
+        EXP.objcClassReference : "class",
+
+        EXP.typeof_ : "typeof",
+        EXP.mixin_ : "mixin",
+
+        EXP.import_ : "import",
+        EXP.dotVariable : "dotvar",
+        EXP.scope_ : "scope",
+        EXP.identifier : "identifier",
+        EXP.this_ : "this",
+        EXP.super_ : "super",
+        EXP.int64 : "long",
+        EXP.float64 : "double",
+        EXP.complex80 : "creal",
+        EXP.null_ : "null",
+        EXP.string_ : "string",
+        EXP.arrayLiteral : "arrayliteral",
+        EXP.assocArrayLiteral : "assocarrayliteral",
+        EXP.classReference : "classreference",
+        EXP.file : "__FILE__",
+        EXP.fileFullPath : "__FILE_FULL_PATH__",
+        EXP.line : "__LINE__",
+        EXP.moduleString : "__MODULE__",
+        EXP.functionString : "__FUNCTION__",
+        EXP.prettyFunction : "__PRETTY_FUNCTION__",
+        EXP.typeid_ : "typeid",
+        EXP.is_ : "is",
+        EXP.assert_ : "assert",
+        EXP.halt : "halt",
+        EXP.template_ : "template",
+        EXP.dSymbol : "symbol",
+        EXP.function_ : "function",
+        EXP.variable : "var",
+        EXP.symbolOffset : "symoff",
+        EXP.structLiteral : "structLiteral",
+        EXP.compoundLiteral : "compoundliteral",
+        EXP.arrayLength : "arraylength",
+        EXP.delegatePointer : "delegateptr",
+        EXP.delegateFunctionPointer : "delegatefuncptr",
+        EXP.remove : "remove",
+        EXP.tuple : "tuple",
+        EXP.traits : "__traits",
+        EXP.default_ : "default",
+        EXP.overloadSet : "__overloadset",
+        EXP.void_ : "void",
+        EXP.vectorArray : "vectorarray",
+        EXP._Generic : "_Generic",
+
+        // post
+        EXP.dotTemplateInstance : "dotti",
+        EXP.dotIdentifier : "dotid",
+        EXP.dotTemplateDeclaration : "dottd",
+        EXP.dot : ".",
+        EXP.dotType : "dottype",
+        EXP.plusPlus : "++",
+        EXP.minusMinus : "--",
+        EXP.prePlusPlus : "++",
+        EXP.preMinusMinus : "--",
+        EXP.call : "call",
+        EXP.slice : "..",
+        EXP.array : "[]",
+        EXP.index : "[i]",
+
+        EXP.delegate_ : "delegate",
+        EXP.address : "&",
+        EXP.star : "*",
+        EXP.negate : "-",
+        EXP.uadd : "+",
+        EXP.not : "!",
+        EXP.tilde : "~",
+        EXP.delete_ : "delete",
+        EXP.new_ : "new",
+        EXP.newAnonymousClass : "newanonclass",
+        EXP.cast_ : "cast",
+
+        EXP.vector : "__vector",
+        EXP.pow : "^^",
+
+        EXP.mul : "*",
+        EXP.div : "/",
+        EXP.mod : "%",
+
+        EXP.add : "+",
+        EXP.min : "-",
+        EXP.concatenate : "~",
+
+        EXP.leftShift : "<<",
+        EXP.rightShift : ">>",
+        EXP.unsignedRightShift : ">>>",
+
+        EXP.lessThan : "<",
+        EXP.lessOrEqual : "<=",
+        EXP.greaterThan : ">",
+        EXP.greaterOrEqual : ">=",
+        EXP.in_ : "in",
+
+        EXP.equal : "==",
+        EXP.notEqual : "!=",
+        EXP.identity : "is",
+        EXP.notIdentity : "!is",
+
+        EXP.and : "&",
+        EXP.xor : "^",
+        EXP.or : "|",
+
+        EXP.andAnd : "&&",
+        EXP.orOr : "||",
+
+        EXP.question : "?",
+
+        EXP.assign : "=",
+        EXP.construct : "=",
+        EXP.blit : "=",
+        EXP.addAssign : "+=",
+        EXP.minAssign : "-=",
+        EXP.concatenateAssign : "~=",
+        EXP.concatenateElemAssign : "~=",
+        EXP.concatenateDcharAssign : "~=",
+        EXP.mulAssign : "*=",
+        EXP.divAssign : "/=",
+        EXP.modAssign : "%=",
+        EXP.powAssign : "^^=",
+        EXP.leftShiftAssign : "<<=",
+        EXP.rightShiftAssign : ">>=",
+        EXP.unsignedRightShiftAssign : ">>>=",
+        EXP.andAssign : "&=",
+        EXP.orAssign : "|=",
+        EXP.xorAssign : "^=",
+
+        EXP.comma : ",",
+        EXP.declaration : "declaration",
+
+        EXP.interval : "interval",
+    ];
+    const p = strings[op];
+    if (!p)
+    {
+        printf("error: EXP %d has no string\n", op);
+        return "XXXXX";
+        //assert(0);
+    }
+    assert(p);
+    return p[0 .. strlen(p)];
+}
index 3ff0e894e2ac2f04c9b40d9e41ae8eeb3a883373..cd3011731f55220ceb535f8a4ff871268d80bb1b 100644 (file)
@@ -348,7 +348,7 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
 
             e = (*s.constraints)[i];
             e = e.expressionSemantic(sc);
-            assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
+            assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
             (*s.constraints)[i] = e;
         }
     }
@@ -360,7 +360,7 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
         {
             Expression e = (*s.clobbers)[i];
             e = e.expressionSemantic(sc);
-            assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
+            assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
             (*s.clobbers)[i] = e;
         }
     }
index 1ee51533b53176e70b307bfbe40e14838f342c90..83c89c05fda1630612e97daac544de219684f252 100644 (file)
@@ -315,6 +315,8 @@ immutable Msgtable[] msgtable =
     { "dup" },
     { "_aaApply" },
     { "_aaApply2" },
+    { "_d_arrayctor" },
+    { "_d_arraysetctor" },
 
     // For pragma's
     { "Pinline", "inline" },
@@ -463,6 +465,7 @@ immutable Msgtable[] msgtable =
     { "getUnitTests" },
     { "getVirtualIndex" },
     { "getPointerBitmap" },
+    { "initSymbol" },
     { "getCppNamespaces" },
     { "isReturnOnStack" },
     { "isZeroInit" },
index 5828486c6fe43caa5fe0e288551662db13d033ea..c5aa0f46dd1fdcda39c2d0bdf9550aa61a03a396 100644 (file)
@@ -225,7 +225,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 auto tm = vd.type.addMod(t.mod);
                 auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
                 auto ex = iz.initializerToExpression();
-                if (ex.op == TOK.error)
+                if (ex.op == EXP.error)
                 {
                     errors = true;
                     elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
@@ -331,7 +331,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                     errors = true;
                 }
                 length = cast(uint)idxvalue;
-                if (idx.op == TOK.error)
+                if (idx.op == EXP.error)
                     errors = true;
             }
             Initializer val = i.value[j];
@@ -344,7 +344,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 errors = true;
             ei = val.isExpInitializer();
             // found a tuple, expand it
-            if (ei && ei.exp.op == TOK.tuple)
+            if (ei && ei.exp.op == EXP.tuple)
             {
                 TupleExp te = cast(TupleExp)ei.exp;
                 i.index.remove(j);
@@ -384,6 +384,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             return err();
 
         const sz = t.nextOf().size();
+        if (sz == SIZE_INVALID)
+            return err();
         bool overflow;
         const max = mulu(i.dim, sz, overflow);
         if (overflow || max >= amax)
@@ -403,7 +405,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         i.exp = resolveProperties(sc, i.exp);
         if (needInterpret)
             sc = sc.endCTFE();
-        if (i.exp.op == TOK.error)
+        if (i.exp.op == EXP.error)
             return err();
         uint olderrors = global.errors;
 
@@ -437,7 +439,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                  */
                 i.exp = i.exp.optimize(WANTvalue);
             i.exp = i.exp.ctfeInterpret();
-            if (i.exp.op == TOK.voidExpression)
+            if (i.exp.op == EXP.voidExpression)
                 error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
         }
         else
@@ -455,7 +457,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             i.exp = new TupleExp(i.exp.loc, new Expressions());
             i.exp.type = et;
         }
-        if (i.exp.op == TOK.type)
+        if (i.exp.op == EXP.type)
         {
             i.exp.error("initializer must be an expression, not `%s`", i.exp.toChars());
             return err();
@@ -467,7 +469,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             return err();
         }
         Type ti = i.exp.type.toBasetype();
-        if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
+        if (i.exp.op == EXP.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
         {
             return new ExpInitializer(i.loc, i.exp);
         }
@@ -477,7 +479,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
          * Allow this by doing an explicit cast, which will lengthen the string
          * literal.
          */
-        if (i.exp.op == TOK.string_ && tb.ty == Tsarray)
+        if (i.exp.op == EXP.string_ && tb.ty == Tsarray)
         {
             StringExp se = cast(StringExp)i.exp;
             Type typeb = se.type.toBasetype();
@@ -562,12 +564,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             {
                 uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger();
                 uinteger_t dim2 = dim1;
-                if (i.exp.op == TOK.arrayLiteral)
+                if (i.exp.op == EXP.arrayLiteral)
                 {
                     ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp;
                     dim2 = ale.elements ? ale.elements.dim : 0;
                 }
-                else if (i.exp.op == TOK.slice)
+                else if (i.exp.op == EXP.slice)
                 {
                     Type tx = toStaticArrayType(cast(SliceExp)i.exp);
                     if (tx)
@@ -582,7 +584,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             i.exp = i.exp.implicitCastTo(sc, t);
         }
     L1:
-        if (i.exp.op == TOK.error)
+        if (i.exp.op == EXP.error)
         {
             return i;
         }
@@ -667,7 +669,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 auto tm = vd.type.addMod(ts.mod);
                 auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
                 auto ex = iz.initializerToExpression();
-                if (ex.op == TOK.error)
+                if (ex.op == EXP.error)
                 {
                     errors = true;
                     continue;
@@ -823,6 +825,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         }
 
         const sz = tn.size(); // element size
+        if (sz == SIZE_INVALID)
+            return err();
         bool overflow;
         const max = mulu(edim, sz, overflow);
         if (overflow || max >= amax)
@@ -930,7 +934,7 @@ Initializer inferType(Initializer init, Scope* sc)
                 }
                 assert(iz.isExpInitializer());
                 (*values)[i] = (cast(ExpInitializer)iz).exp;
-                assert((*values)[i].op != TOK.error);
+                assert(!(*values)[i].isErrorExp());
             }
             Expression e = new AssocArrayLiteralExp(init.loc, keys, values);
             auto ei = new ExpInitializer(init.loc, e);
@@ -953,7 +957,7 @@ Initializer inferType(Initializer init, Scope* sc)
                 }
                 assert(iz.isExpInitializer());
                 (*elements)[i] = (cast(ExpInitializer)iz).exp;
-                assert((*elements)[i].op != TOK.error);
+                assert(!(*elements)[i].isErrorExp());
             }
             Expression e = new ArrayLiteralExp(init.loc, null, elements);
             auto ei = new ExpInitializer(init.loc, e);
@@ -977,11 +981,11 @@ Initializer inferType(Initializer init, Scope* sc)
         init.exp = init.exp.expressionSemantic(sc);
 
         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-        if (init.exp.op == TOK.type)
+        if (init.exp.op == EXP.type)
             init.exp = resolveAliasThis(sc, init.exp);
 
         init.exp = resolveProperties(sc, init.exp);
-        if (init.exp.op == TOK.scope_)
+        if (init.exp.op == EXP.scope_)
         {
             ScopeExp se = cast(ScopeExp)init.exp;
             TemplateInstance ti = se.sds.isTemplateInstance();
@@ -1006,16 +1010,16 @@ Initializer inferType(Initializer init, Scope* sc)
                 return new ErrorInitializer();
             }
         }
-        if (init.exp.op == TOK.address)
+        if (init.exp.op == EXP.address)
         {
             AddrExp ae = cast(AddrExp)init.exp;
-            if (ae.e1.op == TOK.overloadSet)
+            if (ae.e1.op == EXP.overloadSet)
             {
                 init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
                 return new ErrorInitializer();
             }
         }
-        if (init.exp.op == TOK.error)
+        if (init.exp.op == EXP.error)
         {
             return new ErrorInitializer();
         }
@@ -1125,7 +1129,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
             {
                 if (auto e = init.index[i])
                 {
-                    if (e.op == TOK.int64)
+                    if (e.op == EXP.int64)
                     {
                         const uinteger_t idxval = e.toInteger();
                         if (idxval >= amax)
@@ -1206,7 +1210,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
          */
         foreach (e; (*elements)[0 .. edim])
         {
-            if (e.op == TOK.error)
+            if (e.op == EXP.error)
             {
                 return e;
             }
@@ -1222,7 +1226,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
         {
             //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
             Type tb = itype.toBasetype();
-            Expression e = (i.exp.op == TOK.construct || i.exp.op == TOK.blit) ? (cast(AssignExp)i.exp).e2 : i.exp;
+            Expression e = (i.exp.op == EXP.construct || i.exp.op == EXP.blit) ? (cast(AssignExp)i.exp).e2 : i.exp;
             if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf()))
             {
                 TypeSArray tsa = cast(TypeSArray)tb;
@@ -1277,7 +1281,7 @@ private bool hasNonConstPointers(Expression e)
 
     if (e.type.ty == Terror)
         return false;
-    if (e.op == TOK.null_)
+    if (e.op == EXP.null_)
         return false;
     if (auto se = e.isStructLiteralExp())
     {
@@ -1318,11 +1322,11 @@ private bool hasNonConstPointers(Expression e)
     }
     if (e.type.ty == Tpointer && !e.type.isPtrToFunction())
     {
-        if (e.op == TOK.symbolOffset) // address of a global is OK
+        if (e.op == EXP.symbolOffset) // address of a global is OK
             return false;
-        if (e.op == TOK.int64) // cast(void *)int is OK
+        if (e.op == EXP.int64) // cast(void *)int is OK
             return false;
-        if (e.op == TOK.string_) // "abc".ptr is OK
+        if (e.op == EXP.string_) // "abc".ptr is OK
             return false;
         return true;
     }
index 44a6c0665070fb20a7292ed6040512371f83a06f..336f8dd80ec52d58fca8d0ceedb37e2de4b0f636 100644 (file)
@@ -26,6 +26,7 @@ import dmd.dtemplate;
 import dmd.expression;
 import dmd.func;
 import dmd.dmangle;
+import dmd.hdrgen;
 import dmd.mtype;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
@@ -337,7 +338,7 @@ public:
             return;
 
         buf.writeByte('(');
-        buf.writestring(Token.toString(exp.op));
+        buf.writestring(EXPtoString(exp.op));
         exp.e1.accept(this);
         if (buf.length != 0)
             buf.writestring(")_");
@@ -370,7 +371,7 @@ public:
             return;
 
         buf.writeByte('(');
-        buf.writestring(Token.toChars(exp.op));
+        buf.writestring(EXPtoString(exp.op).ptr);
 
         exp.e1.accept(this);
         if (buf.length == 0)
index e2b4199b80a23952120bd5c9ff82df8862325580..d38cce4ca007860675ae5e8d7f726a9dfb3cdd17 100644 (file)
@@ -386,6 +386,20 @@ class Lexer
                 // Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile.
                 return;
             case ' ':
+                // Skip 4 spaces at a time after aligning 'p' to a 4-byte boundary.
+                while ((cast(size_t)p) % uint.sizeof)
+                {
+                    if (*p != ' ')
+                        goto LendSkipFourSpaces;
+                    p++;
+                }
+                while (*(cast(uint*)p) == 0x20202020) // ' ' == 0x20
+                    p += 4;
+                // Skip over any remaining space on the line.
+                while (*p == ' ')
+                    p++;
+            LendSkipFourSpaces:
+                continue; // skip white space
             case '\t':
             case '\v':
             case '\f':
@@ -394,19 +408,11 @@ class Lexer
             case '\r':
                 p++;
                 if (*p != '\n') // if CR stands by itself
-                {
                     endOfLine();
-                    goto skipFourSpaces;
-                }
                 continue; // skip white space
             case '\n':
                 p++;
                 endOfLine();
-                skipFourSpaces:
-                while (*(cast(uint*)p) == 0x20202020) //' ' == 0x20
-                {
-                    p+=4;
-                }
                 continue; // skip white space
             case '0':
                 if (!isZeroSecond(p[1]))        // if numeric literal does not continue
index a21924b3aacb5ad77345b42af9b56bb46a4f3bae..e338a05a524cea5f165a57c62b70e96ea4bc63af 100644 (file)
@@ -515,7 +515,7 @@ extern (C++) abstract class Type : ASTNode
                         }
                         else if (tp1.ty == Tdelegate)
                         {
-                            if (tp1.implicitConvTo(tp2))
+                            if (tp2.implicitConvTo(tp1))
                                 goto Lcov;
                         }
                     }
@@ -4783,7 +4783,7 @@ extern (C++) final class TypeFunction : TypeNext
                             goto Nomatch;
                         }
 
-                        if (arg.op == TOK.string_ && tp.ty == Tsarray)
+                        if (arg.op == EXP.string_ && tp.ty == Tsarray)
                         {
                             if (ta.ty != Tsarray)
                             {
@@ -4792,7 +4792,7 @@ extern (C++) final class TypeFunction : TypeNext
                                 ta = tn.sarrayOf(dim);
                             }
                         }
-                        else if (arg.op == TOK.slice && tp.ty == Tsarray)
+                        else if (arg.op == EXP.slice && tp.ty == Tsarray)
                         {
                             // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
                             if (ta.ty != Tsarray)
@@ -4805,7 +4805,7 @@ extern (C++) final class TypeFunction : TypeNext
                         else if ((p.storageClass & STC.in_) && global.params.previewIn)
                         {
                             // Allow converting a literal to an `in` which is `ref`
-                            if (arg.op == TOK.arrayLiteral && tp.ty == Tsarray)
+                            if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
                             {
                                 Type tn = tp.nextOf();
                                 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
@@ -4988,7 +4988,7 @@ extern (C++) final class TypeFunction : TypeNext
     {
         assert(to);
 
-        if (this == to)
+        if (this.equals(to))
             return MATCH.constant;
 
         if (this.covariant(to) == Covariant.yes)
@@ -5301,7 +5301,7 @@ extern (C++) final class TypeDelegate : TypeNext
         //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
         //printf("from: %s\n", toChars());
         //printf("to  : %s\n", to.toChars());
-        if (this == to)
+        if (this.equals(to))
             return MATCH.exact;
 
         if (auto toDg = to.isTypeDelegate())
@@ -5814,7 +5814,7 @@ extern (C++) final class TypeStruct : Type
             }
             else
                 e = vd.type.defaultInitLiteral(loc);
-            if (e && e.op == TOK.error)
+            if (e && e.op == EXP.error)
                 return e;
             if (e)
                 offset = vd.offset + cast(uint)vd.type.size();
@@ -6225,7 +6225,7 @@ extern (C++) final class TypeEnum : Type
 
     override bool isZeroInit(const ref Loc loc)
     {
-        return sym.getDefaultValue(loc).isBool(false);
+        return sym.getDefaultValue(loc).toBool().hasValue(false);
     }
 
     override bool hasPointers()
index 4bb2907c9ba2b2e7dcb52278179fdf7e3f9213b2..31a25a714178a2eba0c595351c3ec5b178aa1339 100644 (file)
@@ -136,7 +136,7 @@ public:
 
     override void visit(DeleteExp e)
     {
-        if (e.e1.op == TOK.variable)
+        if (e.e1.op == EXP.variable)
         {
             VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
             if (v && v.onstack)
@@ -189,7 +189,7 @@ public:
 
     override void visit(AssignExp e)
     {
-        if (e.e1.op == TOK.arrayLength)
+        if (e.e1.op == EXP.arrayLength)
         {
             if (f.setGC())
             {
@@ -230,7 +230,7 @@ public:
 Expression checkGC(Scope* sc, Expression e)
 {
     FuncDeclaration f = sc.func;
-    if (e && e.op != TOK.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
+    if (e && e.op != EXP.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
            (f.type.ty == Tfunction &&
             (cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAG.nogcInprocess) || global.params.vgc) &&
            !(sc.flags & SCOPE.debug_))
index 605e9f3bfdd94ba55f7c07aa336b32bc2e47cda8..156428eb6991c3406fe4ad1dd380a256d8dd8373 100644 (file)
@@ -1362,7 +1362,7 @@ void genKill(ref ObState obstate, ObNode* ob)
 
             override void visit(Expression e)
             {
-                //printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
+                //printf("[%s] %s: %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
                 //assert(0);
             }
 
@@ -1644,7 +1644,7 @@ void genKill(ref ObState obstate, ObNode* ob)
                  * allowed, but CTFE can generate one out of a new expression,
                  * but it'll be placed in static data so no need to check it.
                  */
-                if (e.e1.op != TOK.structLiteral)
+                if (e.e1.op != EXP.structLiteral)
                     e.e1.accept(this);
             }
 
@@ -2378,7 +2378,7 @@ void checkObErrors(ref ObState obstate)
                  * allowed, but CTFE can generate one out of a new expression,
                  * but it'll be placed in static data so no need to check it.
                  */
-                if (e.e1.op != TOK.structLiteral)
+                if (e.e1.op != EXP.structLiteral)
                     e.e1.accept(this);
             }
 
index eb4ba1db20de663d55e35387e8ac54115e1f97e3..42363818dd813505ea7203cac047f346974b3dbf 100644 (file)
@@ -540,10 +540,10 @@ extern(C++) private final class Supported : Objc
     override void setSelector(FuncDeclaration fd, Scope* sc)
     {
         foreachUda(fd, sc, (e) {
-            if (e.op != TOK.structLiteral)
+            if (!e.isStructLiteralExp())
                 return 0;
 
-            auto literal = cast(StructLiteralExp) e;
+            auto literal = e.isStructLiteralExp();
             assert(literal.sd);
 
             if (!isCoreUda(literal.sd, Id.udaSelector))
@@ -616,10 +616,10 @@ extern(C++) private final class Supported : Objc
         int count;
 
         foreachUda(fd, sc, (e) {
-            if (e.op != TOK.type)
+            if (!e.isTypeExp())
                 return 0;
 
-            auto typeExp = cast(TypeExp) e;
+            auto typeExp = e.isTypeExp();
 
             if (typeExp.type.ty != Tenum)
                 return 0;
@@ -861,10 +861,10 @@ extern(D) private:
         arrayExpressionSemantic(udas, sc, true);
 
         return udas.each!((uda) {
-            if (uda.op != TOK.tuple)
+            if (!uda.isTupleExp())
                 return 0;
 
-            auto exps = (cast(TupleExp) uda).exps;
+            auto exps = uda.isTupleExp().exps;
 
             return exps.each!((e) {
                 assert(e);
index ff03a6e0d3cc0b6ced3a6c51398453d2d4a19e40..4d250c04771a43dd968e6f6dbc584eb6a0c88cea 100644 (file)
@@ -29,6 +29,7 @@ import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
+import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
@@ -41,23 +42,23 @@ import dmd.visitor;
  * Determine if operands of binary op can be reversed
  * to fit operator overload.
  */
-bool isCommutative(TOK op)
+bool isCommutative(EXP op)
 {
     switch (op)
     {
-    case TOK.add:
-    case TOK.mul:
-    case TOK.and:
-    case TOK.or:
-    case TOK.xor:
+    case EXP.add:
+    case EXP.mul:
+    case EXP.and:
+    case EXP.or:
+    case EXP.xor:
     // EqualExp
-    case TOK.equal:
-    case TOK.notEqual:
+    case EXP.equal:
+    case EXP.notEqual:
     // CmpExp
-    case TOK.lessThan:
-    case TOK.lessOrEqual:
-    case TOK.greaterThan:
-    case TOK.greaterOrEqual:
+    case EXP.lessThan:
+    case EXP.lessOrEqual:
+    case EXP.greaterThan:
+    case EXP.greaterOrEqual:
         return true;
     default:
         break;
@@ -72,47 +73,47 @@ private Identifier opId(Expression e)
 {
     switch (e.op)
     {
-    case TOK.uadd:                      return Id.uadd;
-    case TOK.negate:                    return Id.neg;
-    case TOK.tilde:                     return Id.com;
-    case TOK.cast_:                     return Id._cast;
-    case TOK.in_:                       return Id.opIn;
-    case TOK.plusPlus:                  return Id.postinc;
-    case TOK.minusMinus:                return Id.postdec;
-    case TOK.add:                       return Id.add;
-    case TOK.min:                       return Id.sub;
-    case TOK.mul:                       return Id.mul;
-    case TOK.div:                       return Id.div;
-    case TOK.mod:                       return Id.mod;
-    case TOK.pow:                       return Id.pow;
-    case TOK.leftShift:                 return Id.shl;
-    case TOK.rightShift:                return Id.shr;
-    case TOK.unsignedRightShift:        return Id.ushr;
-    case TOK.and:                       return Id.iand;
-    case TOK.or:                        return Id.ior;
-    case TOK.xor:                       return Id.ixor;
-    case TOK.concatenate:               return Id.cat;
-    case TOK.assign:                    return Id.assign;
-    case TOK.addAssign:                 return Id.addass;
-    case TOK.minAssign:                 return Id.subass;
-    case TOK.mulAssign:                 return Id.mulass;
-    case TOK.divAssign:                 return Id.divass;
-    case TOK.modAssign:                 return Id.modass;
-    case TOK.powAssign:                 return Id.powass;
-    case TOK.leftShiftAssign:           return Id.shlass;
-    case TOK.rightShiftAssign:          return Id.shrass;
-    case TOK.unsignedRightShiftAssign:  return Id.ushrass;
-    case TOK.andAssign:                 return Id.andass;
-    case TOK.orAssign:                  return Id.orass;
-    case TOK.xorAssign:                 return Id.xorass;
-    case TOK.concatenateAssign:         return Id.catass;
-    case TOK.equal:                     return Id.eq;
-    case TOK.lessThan:
-    case TOK.lessOrEqual:
-    case TOK.greaterThan:
-    case TOK.greaterOrEqual:            return Id.cmp;
-    case TOK.array:                     return Id.index;
-    case TOK.star:                      return Id.opStar;
+    case EXP.uadd:                      return Id.uadd;
+    case EXP.negate:                    return Id.neg;
+    case EXP.tilde:                     return Id.com;
+    case EXP.cast_:                     return Id._cast;
+    case EXP.in_:                       return Id.opIn;
+    case EXP.plusPlus:                  return Id.postinc;
+    case EXP.minusMinus:                return Id.postdec;
+    case EXP.add:                       return Id.add;
+    case EXP.min:                       return Id.sub;
+    case EXP.mul:                       return Id.mul;
+    case EXP.div:                       return Id.div;
+    case EXP.mod:                       return Id.mod;
+    case EXP.pow:                       return Id.pow;
+    case EXP.leftShift:                 return Id.shl;
+    case EXP.rightShift:                return Id.shr;
+    case EXP.unsignedRightShift:        return Id.ushr;
+    case EXP.and:                       return Id.iand;
+    case EXP.or:                        return Id.ior;
+    case EXP.xor:                       return Id.ixor;
+    case EXP.concatenate:               return Id.cat;
+    case EXP.assign:                    return Id.assign;
+    case EXP.addAssign:                 return Id.addass;
+    case EXP.minAssign:                 return Id.subass;
+    case EXP.mulAssign:                 return Id.mulass;
+    case EXP.divAssign:                 return Id.divass;
+    case EXP.modAssign:                 return Id.modass;
+    case EXP.powAssign:                 return Id.powass;
+    case EXP.leftShiftAssign:           return Id.shlass;
+    case EXP.rightShiftAssign:          return Id.shrass;
+    case EXP.unsignedRightShiftAssign:  return Id.ushrass;
+    case EXP.andAssign:                 return Id.andass;
+    case EXP.orAssign:                  return Id.orass;
+    case EXP.xorAssign:                 return Id.xorass;
+    case EXP.concatenateAssign:         return Id.catass;
+    case EXP.equal:                     return Id.eq;
+    case EXP.lessThan:
+    case EXP.lessOrEqual:
+    case EXP.greaterThan:
+    case EXP.greaterOrEqual:            return Id.cmp;
+    case EXP.array:                     return Id.index;
+    case EXP.star:                      return Id.opStar;
     default:                            assert(0);
     }
 }
@@ -125,20 +126,20 @@ private Identifier opId_r(Expression e)
 {
     switch (e.op)
     {
-    case TOK.in_:               return Id.opIn_r;
-    case TOK.add:               return Id.add_r;
-    case TOK.min:               return Id.sub_r;
-    case TOK.mul:               return Id.mul_r;
-    case TOK.div:               return Id.div_r;
-    case TOK.mod:               return Id.mod_r;
-    case TOK.pow:               return Id.pow_r;
-    case TOK.leftShift:         return Id.shl_r;
-    case TOK.rightShift:        return Id.shr_r;
-    case TOK.unsignedRightShift:return Id.ushr_r;
-    case TOK.and:               return Id.iand_r;
-    case TOK.or:                return Id.ior_r;
-    case TOK.xor:               return Id.ixor_r;
-    case TOK.concatenate:       return Id.cat_r;
+    case EXP.in_:               return Id.opIn_r;
+    case EXP.add:               return Id.add_r;
+    case EXP.min:               return Id.sub_r;
+    case EXP.mul:               return Id.mul_r;
+    case EXP.div:               return Id.div_r;
+    case EXP.mod:               return Id.mod_r;
+    case EXP.pow:               return Id.pow_r;
+    case EXP.leftShift:         return Id.shl_r;
+    case EXP.rightShift:        return Id.shr_r;
+    case EXP.unsignedRightShift:return Id.ushr_r;
+    case EXP.and:               return Id.iand_r;
+    case EXP.or:                return Id.ior_r;
+    case EXP.xor:               return Id.ixor_r;
+    case EXP.concatenate:       return Id.cat_r;
     default:                    return null;
     }
 }
@@ -146,55 +147,55 @@ private Identifier opId_r(Expression e)
 /*******************************************
  * Helper function to turn operator into template argument list
  */
-Objects* opToArg(Scope* sc, TOK op)
+Objects* opToArg(Scope* sc, EXP op)
 {
     /* Remove the = from op=
      */
     switch (op)
     {
-    case TOK.addAssign:
-        op = TOK.add;
+    case EXP.addAssign:
+        op = EXP.add;
         break;
-    case TOK.minAssign:
-        op = TOK.min;
+    case EXP.minAssign:
+        op = EXP.min;
         break;
-    case TOK.mulAssign:
-        op = TOK.mul;
+    case EXP.mulAssign:
+        op = EXP.mul;
         break;
-    case TOK.divAssign:
-        op = TOK.div;
+    case EXP.divAssign:
+        op = EXP.div;
         break;
-    case TOK.modAssign:
-        op = TOK.mod;
+    case EXP.modAssign:
+        op = EXP.mod;
         break;
-    case TOK.andAssign:
-        op = TOK.and;
+    case EXP.andAssign:
+        op = EXP.and;
         break;
-    case TOK.orAssign:
-        op = TOK.or;
+    case EXP.orAssign:
+        op = EXP.or;
         break;
-    case TOK.xorAssign:
-        op = TOK.xor;
+    case EXP.xorAssign:
+        op = EXP.xor;
         break;
-    case TOK.leftShiftAssign:
-        op = TOK.leftShift;
+    case EXP.leftShiftAssign:
+        op = EXP.leftShift;
         break;
-    case TOK.rightShiftAssign:
-        op = TOK.rightShift;
+    case EXP.rightShiftAssign:
+        op = EXP.rightShift;
         break;
-    case TOK.unsignedRightShiftAssign:
-        op = TOK.unsignedRightShift;
+    case EXP.unsignedRightShiftAssign:
+        op = EXP.unsignedRightShift;
         break;
-    case TOK.concatenateAssign:
-        op = TOK.concatenate;
+    case EXP.concatenateAssign:
+        op = EXP.concatenate;
         break;
-    case TOK.powAssign:
-        op = TOK.pow;
+    case EXP.powAssign:
+        op = EXP.pow;
         break;
     default:
         break;
     }
-    Expression e = new StringExp(Loc.initial, Token.toString(op));
+    Expression e = new StringExp(Loc.initial, EXPtoString(op));
     e = e.expressionSemantic(sc);
     auto tiargs = new Objects();
     tiargs.push(e);
@@ -216,13 +217,13 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
     BinExp be = cast(BinExp)e.copy();
     // Resolve 'alias this' but in case of assigment don't resolve properties yet
     // because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
-    bool findOnly = (e.op == TOK.assign);
+    bool findOnly = (e.op == EXP.assign);
     be.e1 = resolveAliasThis(sc, e.e1, true, findOnly);
     if (!be.e1)
         return null;
 
     Expression result;
-    if (be.op == TOK.concatenateAssign)
+    if (be.op == EXP.concatenateAssign)
         result = be.op_overload(sc);
     else
         result = be.trySemantic(sc);
@@ -247,7 +248,7 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
         return null;
 
     Expression result;
-    if (be.op == TOK.concatenateAssign)
+    if (be.op == EXP.concatenateAssign)
         result = be.op_overload(sc);
     else
         result = be.trySemantic(sc);
@@ -269,17 +270,17 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
  *      `null` if not an operator overload,
  *      otherwise the lowered expression
  */
-Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
+Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
 {
     extern (C++) final class OpOverload : Visitor
     {
         alias visit = Visitor.visit;
     public:
         Scope* sc;
-        TOK* pop;
+        EXP* pop;
         Expression result;
 
-        extern (D) this(Scope* sc, TOK* pop)
+        extern (D) this(Scope* sc, EXP* pop)
         {
             this.sc = sc;
             this.pop = pop;
@@ -293,22 +294,22 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
         override void visit(UnaExp e)
         {
             //printf("UnaExp::op_overload() (%s)\n", e.toChars());
-            if (e.e1.op == TOK.array)
+            if (e.e1.op == EXP.array)
             {
                 ArrayExp ae = cast(ArrayExp)e.e1;
                 ae.e1 = ae.e1.expressionSemantic(sc);
                 ae.e1 = resolveProperties(sc, ae.e1);
                 Expression ae1old = ae.e1;
-                const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+                const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
                 IntervalExp ie = null;
                 if (maybeSlice && ae.arguments.dim)
                 {
-                    assert((*ae.arguments)[0].op == TOK.interval);
+                    assert((*ae.arguments)[0].op == EXP.interval);
                     ie = cast(IntervalExp)(*ae.arguments)[0];
                 }
                 while (true)
                 {
-                    if (ae.e1.op == TOK.error)
+                    if (ae.e1.op == EXP.error)
                     {
                         result = ae.e1;
                         return;
@@ -326,7 +327,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                         result = resolveOpDollar(sc, ae, &e0);
                         if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
                             goto Lfallback;
-                        if (result.op == TOK.error)
+                        if (result.op == EXP.error)
                             return;
                         /* Rewrite op(a[arguments]) as:
                          *      a.opIndexUnary!(op)(arguments)
@@ -350,7 +351,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     {
                         // Deal with $
                         result = resolveOpDollar(sc, ae, ie, &e0);
-                        if (result.op == TOK.error)
+                        if (result.op == EXP.error)
                             return;
                         /* Rewrite op(a[i..j]) as:
                          *      a.opSliceUnary!(op)(i, j)
@@ -385,7 +386,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
             }
             e.e1 = e.e1.expressionSemantic(sc);
             e.e1 = resolveProperties(sc, e.e1);
-            if (e.e1.op == TOK.error)
+            if (e.e1.op == EXP.error)
             {
                 result = e.e1;
                 return;
@@ -407,7 +408,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     return;
                 }
                 // D1-style operator overloads, deprecated
-                if (e.op != TOK.prePlusPlus && e.op != TOK.preMinusMinus)
+                if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus)
                 {
                     auto id = opId(e);
                     fd = search_function(ad, id);
@@ -416,7 +417,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                         // @@@DEPRECATED_2.098@@@.
                         // Deprecated in 2.088
                         // Make an error in 2.098
-                        e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+                        e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
                         // Rewrite +e1 as e1.add()
                         result = build_overload(e.loc, sc, e.e1, null, fd);
                         return;
@@ -428,7 +429,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     /* Rewrite op(e1) as:
                      *      op(e1.aliasthis)
                      */
-                    //printf("att una %s e1 = %s\n", Token::toChars(op), this.e1.type.toChars());
+                    //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars());
                     Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
                     UnaExp ue = cast(UnaExp)e.copy();
                     ue.e1 = e1;
@@ -444,16 +445,16 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
             ae.e1 = ae.e1.expressionSemantic(sc);
             ae.e1 = resolveProperties(sc, ae.e1);
             Expression ae1old = ae.e1;
-            const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+            const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
             IntervalExp ie = null;
             if (maybeSlice && ae.arguments.dim)
             {
-                assert((*ae.arguments)[0].op == TOK.interval);
+                assert((*ae.arguments)[0].op == EXP.interval);
                 ie = cast(IntervalExp)(*ae.arguments)[0];
             }
             while (true)
             {
-                if (ae.e1.op == TOK.error)
+                if (ae.e1.op == EXP.error)
                 {
                     result = ae.e1;
                     return;
@@ -467,7 +468,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                 {
                     // If the non-aggregate expression ae.e1 is indexable or sliceable,
                     // convert it to the corresponding concrete expression.
-                    if (isIndexableNonAggregate(t1b) || ae.e1.op == TOK.type)
+                    if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type)
                     {
                         // Convert to SliceExp
                         if (maybeSlice)
@@ -492,7 +493,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     result = resolveOpDollar(sc, ae, &e0);
                     if (!result) // a[i..j] might be: a.opSlice(i, j)
                         goto Lfallback;
-                    if (result.op == TOK.error)
+                    if (result.op == EXP.error)
                         return;
                     /* Rewrite e1[arguments] as:
                      *      e1.opIndex(arguments)
@@ -511,7 +512,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     }
                 }
             Lfallback:
-                if (maybeSlice && ae.e1.op == TOK.type)
+                if (maybeSlice && ae.e1.op == EXP.type)
                 {
                     result = new SliceExp(ae.loc, ae.e1, ie);
                     result = result.expressionSemantic(sc);
@@ -522,7 +523,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                 {
                     // Deal with $
                     result = resolveOpDollar(sc, ae, ie, &e0);
-                    if (result.op == TOK.error)
+                    if (result.op == EXP.error)
                         return;
                     /* Rewrite a[i..j] as:
                      *      a.opSlice(i, j)
@@ -615,7 +616,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
             int argsset = 0;
             AggregateDeclaration ad1 = isAggregate(e.e1.type);
             AggregateDeclaration ad2 = isAggregate(e.e2.type);
-            if (e.op == TOK.assign && ad1 == ad2)
+            if (e.op == EXP.assign && ad1 == ad2)
             {
                 StructDeclaration sd = ad1.isStructDeclaration();
                 if (sd &&
@@ -632,13 +633,13 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
             Dsymbol s = null;
             Dsymbol s_r = null;
             Objects* tiargs = null;
-            if (e.op == TOK.plusPlus || e.op == TOK.minusMinus)
+            if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
             {
                 // Bug4099 fix
                 if (ad1 && search_function(ad1, Id.opUnary))
                     return;
             }
-            if (e.op != TOK.equal && e.op != TOK.notEqual && e.op != TOK.assign && e.op != TOK.plusPlus && e.op != TOK.minusMinus)
+            if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus)
             {
                 /* Try opBinary and opBinaryRight
                  */
@@ -684,9 +685,9 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                         // Deprecated in 2.088
                         // Make an error in 2.098
                         if (id == Id.postinc || id == Id.postdec)
-                            e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+                            e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
                         else
-                            e.deprecation("`%s` is deprecated.  Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+                            e.deprecation("`%s` is deprecated.  Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
                     }
                 }
                 if (ad2 && id_r)
@@ -702,7 +703,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                         // @@@DEPRECATED_2.098@@@.
                         // Deprecated in 2.088
                         // Make an error in 2.098
-                        e.deprecation("`%s` is deprecated.  Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), Token.toChars(e.op));
+                        e.deprecation("`%s` is deprecated.  Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
                     }
                 }
             }
@@ -751,7 +752,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                         goto L1;
                     m.lastf = null;
                 }
-                if (e.op == TOK.plusPlus || e.op == TOK.minusMinus)
+                if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
                 {
                     // Kludge because operator overloading regards e++ and e--
                     // as unary, but it's implemented as a binary.
@@ -855,7 +856,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
             }
 
             Expression tempResult;
-            if (!(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+            if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
             {
                 result = checkAliasThisForLhs(ad1, sc, e);
                 if (result)
@@ -871,7 +872,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                      * one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis`
                      * condition.
                      */
-                    if (e.op != TOK.assign || e.e1.op == TOK.type)
+                    if (e.op != EXP.assign || e.e1.op == EXP.type)
                         return;
 
                     if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis))
@@ -888,7 +889,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     tempResult = result;
                 }
             }
-            if (!(e.op == TOK.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+            if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
             {
                 result = checkAliasThisForRhs(ad2, sc, e);
                 if (result)
@@ -925,12 +926,12 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
 
             /* Check for class equality with null literal or typeof(null).
              */
-            if (t1.ty == Tclass && e.e2.op == TOK.null_ ||
-                t2.ty == Tclass && e.e1.op == TOK.null_)
+            if (t1.ty == Tclass && e.e2.op == EXP.null_ ||
+                t2.ty == Tclass && e.e1.op == EXP.null_)
             {
                 e.error("use `%s` instead of `%s` when comparing with `null`",
-                    Token.toChars(e.op == TOK.equal ? TOK.identity : TOK.notIdentity),
-                    Token.toChars(e.op));
+                    EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr,
+                    EXPtoString(e.op).ptr);
                 result = ErrorExp.get();
                 return;
             }
@@ -968,7 +969,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     result = new DotIdExp(e.loc, result, Id.object);
                     result = new DotIdExp(e.loc, result, Id.eq);
                     result = new CallExp(e.loc, result, e1x, e2x);
-                    if (e.op == TOK.notEqual)
+                    if (e.op == EXP.notEqual)
                         result = new NotExp(e.loc, result);
                     result = result.expressionSemantic(sc);
                     return;
@@ -978,7 +979,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
             result = compare_overload(e, sc, Id.eq, null);
             if (result)
             {
-                if (lastComma(result).op == TOK.call && e.op == TOK.notEqual)
+                if (lastComma(result).op == EXP.call && e.op == EXP.notEqual)
                 {
                     result = new NotExp(result.loc, result);
                     result = result.expressionSemantic(sc);
@@ -998,7 +999,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                  * This is just a rewriting for deterministic AST representation
                  * as the backend input.
                  */
-                auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity;
+                auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
                 result = new IdentityExp(op2, e.loc, e.e1, e.e2);
                 result = result.expressionSemantic(sc);
                 return;
@@ -1016,7 +1017,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                 if (!global.params.fieldwise && !needOpEquals(sd))
                 {
                     // Use bitwise equality.
-                    auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity;
+                    auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
                     result = new IdentityExp(op2, e.loc, e.e1, e.e2);
                     result = result.expressionSemantic(sc);
                     return;
@@ -1063,7 +1064,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
 
             /* Check for tuple equality.
              */
-            if (e.e1.op == TOK.tuple && e.e2.op == TOK.tuple)
+            if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple)
             {
                 auto tup1 = cast(TupleExp)e.e1;
                 auto tup2 = cast(TupleExp)e.e2;
@@ -1079,7 +1080,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                 if (dim == 0)
                 {
                     // zero-length tuple comparison should always return true or false.
-                    result = IntegerExp.createBool(e.op == TOK.equal);
+                    result = IntegerExp.createBool(e.op == EXP.equal);
                 }
                 else
                 {
@@ -1093,10 +1094,10 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
 
                         if (!result)
                             result = eeq;
-                        else if (e.op == TOK.equal)
-                            result = new LogicalExp(e.loc, TOK.andAnd, result, eeq);
+                        else if (e.op == EXP.equal)
+                            result = new LogicalExp(e.loc, EXP.andAnd, result, eeq);
                         else
-                            result = new LogicalExp(e.loc, TOK.orOr, result, eeq);
+                            result = new LogicalExp(e.loc, EXP.orOr, result, eeq);
                     }
                     assert(result);
                 }
@@ -1119,22 +1120,22 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
         override void visit(BinAssignExp e)
         {
             //printf("BinAssignExp::op_overload() (%s)\n", e.toChars());
-            if (e.e1.op == TOK.array)
+            if (e.e1.op == EXP.array)
             {
                 ArrayExp ae = cast(ArrayExp)e.e1;
                 ae.e1 = ae.e1.expressionSemantic(sc);
                 ae.e1 = resolveProperties(sc, ae.e1);
                 Expression ae1old = ae.e1;
-                const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+                const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
                 IntervalExp ie = null;
                 if (maybeSlice && ae.arguments.dim)
                 {
-                    assert((*ae.arguments)[0].op == TOK.interval);
+                    assert((*ae.arguments)[0].op == EXP.interval);
                     ie = cast(IntervalExp)(*ae.arguments)[0];
                 }
                 while (true)
                 {
-                    if (ae.e1.op == TOK.error)
+                    if (ae.e1.op == EXP.error)
                     {
                         result = ae.e1;
                         return;
@@ -1152,10 +1153,10 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                         result = resolveOpDollar(sc, ae, &e0);
                         if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
                             goto Lfallback;
-                        if (result.op == TOK.error)
+                        if (result.op == EXP.error)
                             return;
                         result = e.e2.expressionSemantic(sc);
-                        if (result.op == TOK.error)
+                        if (result.op == EXP.error)
                             return;
                         e.e2 = result;
                         /* Rewrite a[arguments] op= e2 as:
@@ -1181,10 +1182,10 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     {
                         // Deal with $
                         result = resolveOpDollar(sc, ae, ie, &e0);
-                        if (result.op == TOK.error)
+                        if (result.op == EXP.error)
                             return;
                         result = e.e2.expressionSemantic(sc);
-                        if (result.op == TOK.error)
+                        if (result.op == EXP.error)
                             return;
                         e.e2 = result;
                         /* Rewrite (a[i..j] op= e2) as:
@@ -1261,7 +1262,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
                     // @@@DEPRECATED_2.098@@@.
                     // Deprecated in 2.088
                     // Make an error in 2.098
-                    scope char[] op = Token.toString(e.op).dup;
+                    scope char[] op = EXPtoString(e.op).dup;
                     op[$-1] = '\0'; // remove trailing `=`
                     e.deprecation("`%s` is deprecated.  Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
                 }
@@ -1319,7 +1320,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
 /******************************************
  * Common code for overloading of EqualExp and CmpExp
  */
-private Expression compare_overload(BinExp e, Scope* sc, Identifier id, TOK* pop)
+private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop)
 {
     //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars());
     AggregateDeclaration ad1 = isAggregate(e.e1.type);
@@ -1415,7 +1416,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, TOK* pop
      * at this point, no matching opEquals was found for structs,
      * so we should not follow the alias this comparison code.
      */
-    if ((e.op == TOK.equal || e.op == TOK.notEqual) && ad1 == ad2)
+    if ((e.op == EXP.equal || e.op == EXP.notEqual) && ad1 == ad2)
         return null;
     Expression result = checkAliasThisForLhs(ad1, sc, e);
     return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
@@ -1482,7 +1483,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
         aggr = aggr.expressionSemantic(sc);
         aggr = resolveProperties(sc, aggr);
         aggr = aggr.optimize(WANTvalue);
-        if (!aggr.type || aggr.op == TOK.error)
+        if (!aggr.type || aggr.op == EXP.error)
             return false;
         Type tab = aggr.type.toBasetype();
         switch (tab.ty)
@@ -1507,7 +1508,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
                     // opApply aggregate
                     break;
                 }
-                if (feaggr.op != TOK.type)
+                if (feaggr.op != EXP.type)
                 {
                     /* See if rewriting `aggr` to `aggr[]` will work
                      */
@@ -1538,7 +1539,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
         }
 
         case Tdelegate:        // https://dlang.org/spec/statement.html#foreach_over_delegates
-            if (aggr.op == TOK.delegate_)
+            if (aggr.op == EXP.delegate_)
             {
                 sapply = (cast(DelegateExp)aggr).func;
             }
@@ -1590,7 +1591,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
             ethis = fes.aggr;
         else
         {
-            assert(tab.ty == Tdelegate && fes.aggr.op == TOK.delegate_);
+            assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_);
             ethis = (cast(DelegateExp)fes.aggr).e1;
         }
 
@@ -1854,14 +1855,14 @@ private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool
  * Returns:
  *      reverse of op
  */
-private TOK reverseRelation(TOK op) pure
+private EXP reverseRelation(EXP op) pure
 {
     switch (op)
     {
-        case TOK.greaterOrEqual:  op = TOK.lessOrEqual;    break;
-        case TOK.greaterThan:     op = TOK.lessThan;       break;
-        case TOK.lessOrEqual:     op = TOK.greaterOrEqual; break;
-        case TOK.lessThan:        op = TOK.greaterThan;    break;
+        case EXP.greaterOrEqual:  op = EXP.lessOrEqual;    break;
+        case EXP.greaterThan:     op = EXP.lessThan;       break;
+        case EXP.lessOrEqual:     op = EXP.greaterOrEqual; break;
+        case EXP.lessThan:        op = EXP.greaterThan;    break;
         default:                  break;
     }
     return op;
index 9f116fe850968e4767a54931bd7f11628f2308ea..6b2176b29112bf7ec34f0742219eca162e979482 100644 (file)
@@ -103,14 +103,14 @@ Expression expandVar(int result, VarDeclaration v)
                     }
                     return nullReturn();
                 }
-                if (ei.op == TOK.construct || ei.op == TOK.blit)
+                if (ei.op == EXP.construct || ei.op == EXP.blit)
                 {
                     AssignExp ae = cast(AssignExp)ei;
                     ei = ae.e2;
                     if (ei.isConst() == 1)
                     {
                     }
-                    else if (ei.op == TOK.string_)
+                    else if (ei.op == EXP.string_)
                     {
                         // https://issues.dlang.org/show_bug.cgi?id=14459
                         // Do not constfold the string literal
@@ -136,8 +136,8 @@ Expression expandVar(int result, VarDeclaration v)
                 }
                 else if (!(v.storage_class & STC.manifest) &&
                          ei.isConst() != 1 &&
-                         ei.op != TOK.string_ &&
-                         ei.op != TOK.address)
+                         ei.op != EXP.string_ &&
+                         ei.op != EXP.address)
                 {
                     return nullReturn();
                 }
@@ -179,9 +179,8 @@ private Expression fromConstInitializer(int result, Expression e1)
     //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars());
     //static int xx; if (xx++ == 10) assert(0);
     Expression e = e1;
-    if (e1.op == TOK.variable)
+    if (auto ve = e1.isVarExp())
     {
-        VarExp ve = cast(VarExp)e1;
         VarDeclaration v = ve.var.isVarDeclaration();
         e = expandVar(result, v);
         if (e)
@@ -189,7 +188,7 @@ private Expression fromConstInitializer(int result, Expression e1)
             // If it is a comma expression involving a declaration, we mustn't
             // perform a copy -- we'd get two declarations of the same variable.
             // See bugzilla 4465.
-            if (e.op == TOK.comma && (cast(CommaExp)e).e1.op == TOK.declaration)
+            if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp())
                 e = e1;
             else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
             {
@@ -207,9 +206,13 @@ private Expression fromConstInitializer(int result, Expression e1)
     return e;
 }
 
-/* It is possible for constant folding to change an array expression of
+/***
+ * It is possible for constant folding to change an array expression of
  * unknown length, into one where the length is known.
  * If the expression 'arr' is a literal, set lengthVar to be its length.
+ * Params:
+ *    lengthVar = variable declaration for the `.length` property
+ *    arr = String, ArrayLiteral, or of TypeSArray
  */
 package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr)
 {
@@ -217,37 +220,39 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr)
         return;
     if (lengthVar._init && !lengthVar._init.isVoidInitializer())
         return; // we have previously calculated the length
-    size_t len;
-    if (arr.op == TOK.string_)
-        len = (cast(StringExp)arr).len;
-    else if (arr.op == TOK.arrayLiteral)
-        len = (cast(ArrayLiteralExp)arr).elements.dim;
+    d_uns64 len;
+    if (auto se = arr.isStringExp())
+        len = se.len;
+    else if (auto ale = arr.isArrayLiteralExp())
+        len = ale.elements.dim;
     else
     {
-        Type t = arr.type.toBasetype();
-        if (t.ty == Tsarray)
-            len = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
-        else
+        auto tsa = arr.type.toBasetype().isTypeSArray();
+        if (!tsa)
             return; // we don't know the length yet
+        len = tsa.dim.toInteger();
     }
     Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
     lengthVar._init = new ExpInitializer(Loc.initial, dollar);
     lengthVar.storage_class |= STC.static_ | STC.const_;
 }
 
-/* Same as above, but determines the length from 'type'. */
+/***
+ * Same as above, but determines the length from 'type'.
+ * Params:
+ *    lengthVar = variable declaration for the `.length` property
+ *    type = TypeSArray
+ */
 package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
 {
     if (!lengthVar)
         return;
     if (lengthVar._init && !lengthVar._init.isVoidInitializer())
         return; // we have previously calculated the length
-    size_t len;
-    Type t = type.toBasetype();
-    if (t.ty == Tsarray)
-        len = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
-    else
+    auto tsa = type.toBasetype().isTypeSArray();
+    if (!tsa)
         return; // we don't know the length yet
+    d_uns64 len = tsa.dim.toInteger();
     Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
     lengthVar._init = new ExpInitializer(Loc.initial, dollar);
     lengthVar.storage_class |= STC.static_ | STC.const_;
@@ -265,579 +270,477 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
  */
 Expression Expression_optimize(Expression e, int result, bool keepLvalue)
 {
-    extern (C++) final class OptimizeVisitor : Visitor
-    {
-        alias visit = Visitor.visit;
-
-        Expression ret;
-        private const int result;
-        private const bool keepLvalue;
+    Expression ret = e;
 
-        extern (D) this(Expression e, int result, bool keepLvalue)
-        {
-            this.ret = e;               // default result is original expression
-            this.result = result;
-            this.keepLvalue = keepLvalue;
-        }
+    void error()
+    {
+        ret = ErrorExp.get();
+    }
 
-        void error()
+    /* Returns: true if error
+     */
+    bool expOptimize(ref Expression e, int flags, bool keepLvalue = false)
+    {
+        if (!e)
+            return false;
+        Expression ex = Expression_optimize(e, flags, keepLvalue);
+        if (ex.op == EXP.error)
         {
-            ret = ErrorExp.get();
+            ret = ex; // store error result
+            return true;
         }
-
-        bool expOptimize(ref Expression e, int flags, bool keepLvalue = false)
+        else
         {
-            if (!e)
-                return false;
-            Expression ex = Expression_optimize(e, flags, keepLvalue);
-            if (ex.op == TOK.error)
-            {
-                ret = ex; // store error result
-                return true;
-            }
-            else
-            {
-                e = ex; // modify original
-                return false;
-            }
+            e = ex; // modify original
+            return false;
         }
+    }
 
-        bool unaOptimize(UnaExp e, int flags)
-        {
-            return expOptimize(e.e1, flags);
-        }
+    bool unaOptimize(UnaExp e, int flags)
+    {
+        return expOptimize(e.e1, flags);
+    }
 
-        bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false)
-        {
-            expOptimize(e.e1, flags, keepLhsLvalue);
-            expOptimize(e.e2, flags);
-            return ret.op == TOK.error;
-        }
+    bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false)
+    {
+        return expOptimize(e.e1, flags, keepLhsLvalue) |
+               expOptimize(e.e2, flags);
+    }
 
-        override void visit(Expression e)
-        {
-            //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars());
-        }
+    void visitExp(Expression e)
+    {
+        //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars());
+    }
 
-        override void visit(VarExp e)
-        {
-            VarDeclaration v = e.var.isVarDeclaration();
+    void visitVar(VarExp e)
+    {
+        VarDeclaration v = e.var.isVarDeclaration();
 
-            if (!(keepLvalue && v && !(v.storage_class & STC.manifest)))
-                ret = fromConstInitializer(result, e);
+        if (!(keepLvalue && v && !(v.storage_class & STC.manifest)))
+            ret = fromConstInitializer(result, e);
 
-            // if unoptimized, try to optimize the dtor expression
-            // (e.g., might be a LogicalExp with constant lhs)
-            if (ret == e && v && v.edtor)
+        // if unoptimized, try to optimize the dtor expression
+        // (e.g., might be a LogicalExp with constant lhs)
+        if (ret == e && v && v.edtor)
+        {
+            // prevent infinite recursion (`<var>.~this()`)
+            if (!v.inuse)
             {
-                // prevent infinite recursion (`<var>.~this()`)
-                if (!v.inuse)
-                {
-                    v.inuse++;
-                    expOptimize(v.edtor, WANTvalue);
-                    v.inuse--;
-                }
+                v.inuse++;
+                expOptimize(v.edtor, WANTvalue);
+                v.inuse--;
             }
         }
+    }
 
-        override void visit(TupleExp e)
+    void visitTuple(TupleExp e)
+    {
+        expOptimize(e.e0, WANTvalue);
+        for (size_t i = 0; i < e.exps.dim; i++)
         {
-            expOptimize(e.e0, WANTvalue);
-            for (size_t i = 0; i < e.exps.dim; i++)
-            {
-                expOptimize((*e.exps)[i], WANTvalue);
-            }
+            expOptimize((*e.exps)[i], WANTvalue);
         }
+    }
 
-        override void visit(ArrayLiteralExp e)
+    void visitArrayLiteral(ArrayLiteralExp e)
+    {
+        if (e.elements)
         {
-            if (e.elements)
+            expOptimize(e.basis, result & WANTexpand);
+            for (size_t i = 0; i < e.elements.dim; i++)
             {
-                expOptimize(e.basis, result & WANTexpand);
-                for (size_t i = 0; i < e.elements.dim; i++)
-                {
-                    expOptimize((*e.elements)[i], result & WANTexpand);
-                }
+                expOptimize((*e.elements)[i], result & WANTexpand);
             }
         }
+    }
 
-        override void visit(AssocArrayLiteralExp e)
+    void visitAssocArrayLiteral(AssocArrayLiteralExp e)
+    {
+        assert(e.keys.dim == e.values.dim);
+        for (size_t i = 0; i < e.keys.dim; i++)
         {
-            assert(e.keys.dim == e.values.dim);
-            for (size_t i = 0; i < e.keys.dim; i++)
-            {
-                expOptimize((*e.keys)[i], result & WANTexpand);
-                expOptimize((*e.values)[i], result & WANTexpand);
-            }
+            expOptimize((*e.keys)[i], result & WANTexpand);
+            expOptimize((*e.values)[i], result & WANTexpand);
         }
+    }
 
-        override void visit(StructLiteralExp e)
+    void visitStructLiteral(StructLiteralExp e)
+    {
+        if (e.stageflags & stageOptimize)
+            return;
+        int old = e.stageflags;
+        e.stageflags |= stageOptimize;
+        if (e.elements)
         {
-            if (e.stageflags & stageOptimize)
-                return;
-            int old = e.stageflags;
-            e.stageflags |= stageOptimize;
-            if (e.elements)
+            for (size_t i = 0; i < e.elements.dim; i++)
             {
-                for (size_t i = 0; i < e.elements.dim; i++)
-                {
-                    expOptimize((*e.elements)[i], result & WANTexpand);
-                }
+                expOptimize((*e.elements)[i], result & WANTexpand);
             }
-            e.stageflags = old;
         }
+        e.stageflags = old;
+    }
 
-        override void visit(UnaExp e)
-        {
-            //printf("UnaExp::optimize() %s\n", e.toChars());
-            if (unaOptimize(e, result))
-                return;
-        }
+    void visitUna(UnaExp e)
+    {
+        //printf("UnaExp::optimize() %s\n", e.toChars());
+        if (unaOptimize(e, result))
+            return;
+    }
 
-        override void visit(NegExp e)
+    void visitNeg(NegExp e)
+    {
+        if (unaOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1)
         {
-            if (unaOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1)
-            {
-                ret = Neg(e.type, e.e1).copy();
-            }
+            ret = Neg(e.type, e.e1).copy();
         }
+    }
 
-        override void visit(ComExp e)
+    void visitCom(ComExp e)
+    {
+        if (unaOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1)
         {
-            if (unaOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1)
-            {
-                ret = Com(e.type, e.e1).copy();
-            }
+            ret = Com(e.type, e.e1).copy();
         }
+    }
 
-        override void visit(NotExp e)
+    void visitNop(NotExp e)
+    {
+        if (unaOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1)
         {
-            if (unaOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1)
-            {
-                ret = Not(e.type, e.e1).copy();
-            }
+            ret = Not(e.type, e.e1).copy();
         }
+    }
 
-        override void visit(SymOffExp e)
+    void visitSymOff(SymOffExp e)
+    {
+        assert(e.var);
+    }
+
+    void visitAddr(AddrExp e)
+    {
+        //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
+        /* Rewrite &(a,b) as (a,&b)
+         */
+        if (auto ce = e.e1.isCommaExp())
         {
-            assert(e.var);
+            auto ae = new AddrExp(e.loc, ce.e2, e.type);
+            ret = new CommaExp(ce.loc, ce.e1, ae);
+            ret.type = e.type;
+            return;
         }
-
-        override void visit(AddrExp e)
+        // Keep lvalue-ness
+        if (expOptimize(e.e1, result, true))
+            return;
+        // Convert &*ex to ex
+        if (auto pe = e.e1.isPtrExp())
         {
-            //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
-            /* Rewrite &(a,b) as (a,&b)
-             */
-            if (e.e1.op == TOK.comma)
+            Expression ex = pe.e1;
+            if (e.type.equals(ex.type))
+                ret = ex;
+            else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
             {
-                CommaExp ce = cast(CommaExp)e.e1;
-                auto ae = new AddrExp(e.loc, ce.e2, e.type);
-                ret = new CommaExp(ce.loc, ce.e1, ae);
+                ret = ex.copy();
                 ret.type = e.type;
-                return;
-            }
-            // Keep lvalue-ness
-            if (expOptimize(e.e1, result, true))
-                return;
-            // Convert &*ex to ex
-            if (e.e1.op == TOK.star)
-            {
-                Expression ex = (cast(PtrExp)e.e1).e1;
-                if (e.type.equals(ex.type))
-                    ret = ex;
-                else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
-                {
-                    ret = ex.copy();
-                    ret.type = e.type;
-                }
-                return;
-            }
-            if (e.e1.op == TOK.variable)
-            {
-                VarExp ve = cast(VarExp)e.e1;
-                if (!ve.var.isReference() && !ve.var.isImportedSymbol())
-                {
-                    ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads);
-                    ret.type = e.type;
-                    return;
-                }
-            }
-            if (e.e1.op == TOK.index)
-            {
-                // Convert &array[n] to &array+n
-                IndexExp ae = cast(IndexExp)e.e1;
-                if (ae.e2.op == TOK.int64 && ae.e1.op == TOK.variable)
-                {
-                    sinteger_t index = ae.e2.toInteger();
-                    VarExp ve = cast(VarExp)ae.e1;
-                    if (ve.type.ty == Tsarray && !ve.var.isImportedSymbol())
-                    {
-                        TypeSArray ts = cast(TypeSArray)ve.type;
-                        sinteger_t dim = ts.dim.toInteger();
-                        if (index < 0 || index >= dim)
-                        {
-                            e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
-                            return error();
-                        }
-
-                        import core.checkedint : mulu;
-                        bool overflow;
-                        const offset = mulu(index, ts.nextOf().size(e.loc), overflow);
-                        if (overflow)
-                        {
-                            e.error("array offset overflow");
-                            return error();
-                        }
-
-                        ret = new SymOffExp(e.loc, ve.var, offset);
-                        ret.type = e.type;
-                        return;
-                    }
-                }
             }
+            return;
         }
-
-        override void visit(PtrExp e)
+        if (auto ve = e.e1.isVarExp())
         {
-            //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars());
-            if (expOptimize(e.e1, result))
-                return;
-            // Convert *&ex to ex
-            // But only if there is no type punning involved
-            if (e.e1.op == TOK.address)
+            if (!ve.var.isReference() && !ve.var.isImportedSymbol())
             {
-                Expression ex = (cast(AddrExp)e.e1).e1;
-                if (e.type.equals(ex.type))
-                    ret = ex;
-                else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
-                {
-                    ret = ex.copy();
-                    ret.type = e.type;
-                }
-            }
-            if (keepLvalue)
+                ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads);
+                ret.type = e.type;
                 return;
-            // Constant fold *(&structliteral + offset)
-            if (e.e1.op == TOK.add)
-            {
-                Expression ex = Ptr(e.type, e.e1).copy();
-                if (!CTFEExp.isCantExp(ex))
-                {
-                    ret = ex;
-                    return;
-                }
             }
-            if (e.e1.op == TOK.symbolOffset)
+        }
+        if (auto ae = e.e1.isIndexExp())
+        {
+            // Convert &array[n] to &array+n
+            if (ae.e2.op == EXP.int64 && ae.e1.isVarExp())
             {
-                SymOffExp se = cast(SymOffExp)e.e1;
-                VarDeclaration v = se.var.isVarDeclaration();
-                Expression ex = expandVar(result, v);
-                if (ex && ex.op == TOK.structLiteral)
+                sinteger_t index = ae.e2.toInteger();
+                VarExp ve = ae.e1.isVarExp();
+                if (ve.type.isTypeSArray() && !ve.var.isImportedSymbol())
                 {
-                    StructLiteralExp sle = cast(StructLiteralExp)ex;
-                    ex = sle.getField(e.type, cast(uint)se.offset);
-                    if (ex && !CTFEExp.isCantExp(ex))
+                    TypeSArray ts = ve.type.isTypeSArray();
+                    sinteger_t dim = ts.dim.toInteger();
+                    if (index < 0 || index >= dim)
                     {
-                        ret = ex;
-                        return;
+                        e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+                        return error();
                     }
-                }
-            }
-        }
 
-        override void visit(DotVarExp e)
-        {
-            //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars());
-            if (expOptimize(e.e1, result))
-                return;
-            if (keepLvalue)
-                return;
-            Expression ex = e.e1;
-            if (ex.op == TOK.variable)
-            {
-                VarExp ve = cast(VarExp)ex;
-                VarDeclaration v = ve.var.isVarDeclaration();
-                ex = expandVar(result, v);
-            }
-            if (ex && ex.op == TOK.structLiteral)
-            {
-                StructLiteralExp sle = cast(StructLiteralExp)ex;
-                VarDeclaration vf = e.var.isVarDeclaration();
-                if (vf && !vf.overlapped)
-                {
-                    /* https://issues.dlang.org/show_bug.cgi?id=13021
-                     * Prevent optimization if vf has overlapped fields.
-                     */
-                    ex = sle.getField(e.type, vf.offset);
-                    if (ex && !CTFEExp.isCantExp(ex))
+                    import core.checkedint : mulu;
+                    bool overflow;
+                    const offset = mulu(index, ts.nextOf().size(e.loc), overflow);
+                    if (overflow)
                     {
-                        ret = ex;
-                        return;
+                        e.error("array offset overflow");
+                        return error();
                     }
+
+                    ret = new SymOffExp(e.loc, ve.var, offset);
+                    ret.type = e.type;
+                    return;
                 }
             }
         }
+    }
 
-        override void visit(NewExp e)
+    void visitPtr(PtrExp e)
+    {
+        //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars());
+        if (expOptimize(e.e1, result))
+            return;
+        // Convert *&ex to ex
+        // But only if there is no type punning involved
+        if (auto ey = e.e1.isAddrExp())
         {
-            expOptimize(e.thisexp, WANTvalue);
-            // Optimize parameters
-            if (e.newargs)
+            Expression ex = ey.e1;
+            if (e.type.equals(ex.type))
+                ret = ex;
+            else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
             {
-                for (size_t i = 0; i < e.newargs.dim; i++)
-                {
-                    expOptimize((*e.newargs)[i], WANTvalue);
-                }
+                ret = ex.copy();
+                ret.type = e.type;
             }
-            if (e.arguments)
+        }
+        if (keepLvalue)
+            return;
+        // Constant fold *(&structliteral + offset)
+        if (e.e1.op == EXP.add)
+        {
+            Expression ex = Ptr(e.type, e.e1).copy();
+            if (!CTFEExp.isCantExp(ex))
             {
-                for (size_t i = 0; i < e.arguments.dim; i++)
-                {
-                    expOptimize((*e.arguments)[i], WANTvalue);
-                }
+                ret = ex;
+                return;
             }
         }
-
-        override void visit(CallExp e)
+        if (auto se = e.e1.isSymOffExp())
         {
-            //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars());
-            // Optimize parameters with keeping lvalue-ness
-            if (expOptimize(e.e1, result))
-                return;
-            if (e.arguments)
+            VarDeclaration v = se.var.isVarDeclaration();
+            Expression ex = expandVar(result, v);
+            if (ex && ex.isStructLiteralExp())
             {
-                Type t1 = e.e1.type.toBasetype();
-                if (t1.ty == Tdelegate)
-                    t1 = t1.nextOf();
-                // t1 can apparently be void for __ArrayDtor(T) calls
-                if (auto tf = t1.isTypeFunction())
+                StructLiteralExp sle = ex.isStructLiteralExp();
+                ex = sle.getField(e.type, cast(uint)se.offset);
+                if (ex && !CTFEExp.isCantExp(ex))
                 {
-                    for (size_t i = 0; i < e.arguments.dim; i++)
-                    {
-                        Parameter p = tf.parameterList[i];
-                        bool keep = p && p.isReference();
-                        expOptimize((*e.arguments)[i], WANTvalue, keep);
-                    }
+                    ret = ex;
+                    return;
                 }
             }
         }
+    }
 
-        override void visit(CastExp e)
+    void visitDotVar(DotVarExp e)
+    {
+        //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars());
+        if (expOptimize(e.e1, result))
+            return;
+        if (keepLvalue)
+            return;
+        Expression ex = e.e1;
+        if (auto ve = ex.isVarExp())
         {
-            //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars());
-            //printf("from %s to %s\n", e.type.toChars(), e.to.toChars());
-            //printf("from %s\n", e.type.toChars());
-            //printf("e1.type %s\n", e.e1.type.toChars());
-            //printf("type = %p\n", e.type);
-            assert(e.type);
-            TOK op1 = e.e1.op;
-            Expression e1old = e.e1;
-            if (expOptimize(e.e1, result, keepLvalue))
-                return;
-            if (!keepLvalue)
-                e.e1 = fromConstInitializer(result, e.e1);
-            if (e.e1 == e1old && e.e1.op == TOK.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray)
-            {
-                // Casting this will result in the same expression, and
-                // infinite loop because of Expression::implicitCastTo()
-                return; // no change
-            }
-            if ((e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral) &&
-                (e.type.ty == Tpointer || e.type.ty == Tarray))
+            VarDeclaration v = ve.var.isVarDeclaration();
+            ex = expandVar(result, v);
+        }
+        if (ex && ex.isStructLiteralExp())
+        {
+            StructLiteralExp sle = ex.isStructLiteralExp();
+            VarDeclaration vf = e.var.isVarDeclaration();
+            if (vf && !vf.overlapped)
             {
-                const esz  = e.type.nextOf().size(e.loc);
-                const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc);
-                if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
-                    return error();
-
-                if (e1sz == esz)
+                /* https://issues.dlang.org/show_bug.cgi?id=13021
+                 * Prevent optimization if vf has overlapped fields.
+                 */
+                ex = sle.getField(e.type, vf.offset);
+                if (ex && !CTFEExp.isCantExp(ex))
                 {
-                    // https://issues.dlang.org/show_bug.cgi?id=12937
-                    // If target type is void array, trying to paint
-                    // e.e1 with that type will cause infinite recursive optimization.
-                    if (e.type.nextOf().ty == Tvoid)
-                        return;
-                    ret = e.e1.castTo(null, e.type);
-                    //printf(" returning1 %s\n", ret.toChars());
+                    ret = ex;
                     return;
                 }
             }
+        }
+    }
 
-            if (e.e1.op == TOK.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
-            {
-                //printf(" returning2 %s\n", e.e1.toChars());
-            L1:
-                // Returning e1 with changing its type
-                ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
-                ret.type = e.type;
-                return;
-            }
-            /* The first test here is to prevent infinite loops
-             */
-            if (op1 != TOK.arrayLiteral && e.e1.op == TOK.arrayLiteral)
-            {
-                ret = e.e1.castTo(null, e.to);
-                return;
-            }
-            if (e.e1.op == TOK.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
-            {
-                //printf(" returning3 %s\n", e.e1.toChars());
-                goto L1;
-            }
-            if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
-            {
-                import dmd.astenums : Sizeok;
-
-                // See if we can remove an unnecessary cast
-                ClassDeclaration cdfrom = e.e1.type.isClassHandle();
-                ClassDeclaration cdto = e.type.isClassHandle();
-                if (cdfrom.errors || cdto.errors)
-                    return error();
-                if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
-                    goto L1;    // can always convert a class to Object
-                // Need to determine correct offset before optimizing away the cast.
-                // https://issues.dlang.org/show_bug.cgi?id=16980
-                cdfrom.size(e.loc);
-                assert(cdfrom.sizeok == Sizeok.done);
-                assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null));
-                int offset;
-                if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
-                {
-                    //printf(" returning4 %s\n", e.e1.toChars());
-                    goto L1;
-                }
-            }
-            if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
+    void visitNew(NewExp e)
+    {
+        expOptimize(e.thisexp, WANTvalue);
+        // Optimize parameters
+        if (e.newargs)
+        {
+            for (size_t i = 0; i < e.newargs.dim; i++)
             {
-                //printf(" returning5 %s\n", e.e1.toChars());
-                goto L1;
+                expOptimize((*e.newargs)[i], WANTvalue);
             }
-            if (e.e1.isConst())
+        }
+        if (e.arguments)
+        {
+            for (size_t i = 0; i < e.arguments.dim; i++)
             {
-                if (e.e1.op == TOK.symbolOffset)
-                {
-                    if (e.type.toBasetype().ty != Tsarray)
-                    {
-                        const esz = e.type.size(e.loc);
-                        const e1sz = e.e1.type.size(e.e1.loc);
-                        if (esz == SIZE_INVALID ||
-                            e1sz == SIZE_INVALID)
-                            return error();
-
-                        if (esz == e1sz)
-                            goto L1;
-                    }
-                    return;
-                }
-                if (e.to.toBasetype().ty != Tvoid)
-                {
-                    if (e.e1.type.equals(e.type) && e.type.equals(e.to))
-                        ret = e.e1;
-                    else
-                        ret = Cast(e.loc, e.type, e.to, e.e1).copy();
-                }
+                expOptimize((*e.arguments)[i], WANTvalue);
             }
-            //printf(" returning6 %s\n", ret.toChars());
         }
+    }
 
-        override void visit(BinAssignExp e)
+    void visitCall(CallExp e)
+    {
+        //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars());
+        // Optimize parameters with keeping lvalue-ness
+        if (expOptimize(e.e1, result))
+            return;
+        if (e.arguments)
         {
-            //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars());
-            if (binOptimize(e, result, /*keepLhsLvalue*/ true))
-                return;
-            if (e.op == TOK.leftShiftAssign || e.op == TOK.rightShiftAssign || e.op == TOK.unsignedRightShiftAssign)
+            Type t1 = e.e1.type.toBasetype();
+            if (t1.ty == Tdelegate)
+                t1 = t1.nextOf();
+            // t1 can apparently be void for __ArrayDtor(T) calls
+            if (auto tf = t1.isTypeFunction())
             {
-                if (e.e2.isConst() == 1)
+                for (size_t i = 0; i < e.arguments.dim; i++)
                 {
-                    sinteger_t i2 = e.e2.toInteger();
-                    d_uns64 sz = e.e1.type.size(e.e1.loc);
-                    assert(sz != SIZE_INVALID);
-                    sz *= 8;
-                    if (i2 < 0 || i2 >= sz)
-                    {
-                        e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
-                        return error();
-                    }
+                    Parameter p = tf.parameterList[i];
+                    bool keep = p && p.isReference();
+                    expOptimize((*e.arguments)[i], WANTvalue, keep);
                 }
             }
         }
+    }
 
-        override void visit(BinExp e)
+    void visitCast(CastExp e)
+    {
+        //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars());
+        //printf("from %s to %s\n", e.type.toChars(), e.to.toChars());
+        //printf("from %s\n", e.type.toChars());
+        //printf("e1.type %s\n", e.e1.type.toChars());
+        //printf("type = %p\n", e.type);
+        assert(e.type);
+        const op1 = e.e1.op;
+        Expression e1old = e.e1;
+        if (expOptimize(e.e1, result, keepLvalue))
+            return;
+        if (!keepLvalue)
+            e.e1 = fromConstInitializer(result, e.e1);
+        if (e.e1 == e1old && e.e1.op == EXP.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray)
         {
-            //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
-            const keepLhsLvalue = e.op == TOK.construct || e.op == TOK.blit || e.op == TOK.assign
-                || e.op == TOK.plusPlus || e.op == TOK.minusMinus
-                || e.op == TOK.prePlusPlus || e.op == TOK.preMinusMinus;
-            binOptimize(e, result, keepLhsLvalue);
+            // Casting this will result in the same expression, and
+            // infinite loop because of Expression::implicitCastTo()
+            return; // no change
         }
-
-        override void visit(AddExp e)
+        if ((e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral) &&
+            (e.type.ty == Tpointer || e.type.ty == Tarray))
         {
-            //printf("AddExp::optimize(%s)\n", e.toChars());
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() && e.e2.isConst())
+            const esz  = e.type.nextOf().size(e.loc);
+            const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc);
+            if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
+                return error();
+
+            if (e1sz == esz)
             {
-                if (e.e1.op == TOK.symbolOffset && e.e2.op == TOK.symbolOffset)
+                // https://issues.dlang.org/show_bug.cgi?id=12937
+                // If target type is void array, trying to paint
+                // e.e1 with that type will cause infinite recursive optimization.
+                if (e.type.nextOf().ty == Tvoid)
                     return;
-                ret = Add(e.loc, e.type, e.e1, e.e2).copy();
+                ret = e.e1.castTo(null, e.type);
+                //printf(" returning1 %s\n", ret.toChars());
+                return;
             }
         }
 
-        override void visit(MinExp e)
+        if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
         {
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() && e.e2.isConst())
-            {
-                if (e.e2.op == TOK.symbolOffset)
-                    return;
-                ret = Min(e.loc, e.type, e.e1, e.e2).copy();
-            }
+            //printf(" returning2 %s\n", e.e1.toChars());
+        L1:
+            // Returning e1 with changing its type
+            ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
+            ret.type = e.type;
+            return;
         }
-
-        override void visit(MulExp e)
+        /* The first test here is to prevent infinite loops
+         */
+        if (op1 != EXP.arrayLiteral && e.e1.op == EXP.arrayLiteral)
         {
-            //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars());
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
-            {
-                ret = Mul(e.loc, e.type, e.e1, e.e2).copy();
-            }
+            ret = e.e1.castTo(null, e.to);
+            return;
         }
-
-        override void visit(DivExp e)
+        if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
         {
-            //printf("DivExp::optimize(%s)\n", e.toChars());
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+            //printf(" returning3 %s\n", e.e1.toChars());
+            goto L1;
+        }
+        if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
+        {
+            import dmd.astenums : Sizeok;
+
+            // See if we can remove an unnecessary cast
+            ClassDeclaration cdfrom = e.e1.type.isClassHandle();
+            ClassDeclaration cdto = e.type.isClassHandle();
+            if (cdfrom.errors || cdto.errors)
+                return error();
+            if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
+                goto L1;    // can always convert a class to Object
+            // Need to determine correct offset before optimizing away the cast.
+            // https://issues.dlang.org/show_bug.cgi?id=16980
+            cdfrom.size(e.loc);
+            assert(cdfrom.sizeok == Sizeok.done);
+            assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null));
+            int offset;
+            if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
             {
-                ret = Div(e.loc, e.type, e.e1, e.e2).copy();
+                //printf(" returning4 %s\n", e.e1.toChars());
+                goto L1;
             }
         }
-
-        override void visit(ModExp e)
+        if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
         {
-            if (binOptimize(e, result))
+            //printf(" returning5 %s\n", e.e1.toChars());
+            goto L1;
+        }
+        if (e.e1.isConst())
+        {
+            if (e.e1.op == EXP.symbolOffset)
+            {
+                if (e.type.toBasetype().ty != Tsarray)
+                {
+                    const esz = e.type.size(e.loc);
+                    const e1sz = e.e1.type.size(e.e1.loc);
+                    if (esz == SIZE_INVALID ||
+                        e1sz == SIZE_INVALID)
+                        return error();
+
+                    if (esz == e1sz)
+                        goto L1;
+                }
                 return;
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+            }
+            if (e.to.toBasetype().ty != Tvoid)
             {
-                ret = Mod(e.loc, e.type, e.e1, e.e2).copy();
+                if (e.e1.type.equals(e.type) && e.type.equals(e.to))
+                    ret = e.e1;
+                else
+                    ret = Cast(e.loc, e.type, e.to, e.e1).copy();
             }
         }
+        //printf(" returning6 %s\n", ret.toChars());
+    }
 
-        extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift)
+    void visitBinAssign(BinAssignExp e)
+    {
+        //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars());
+        if (binOptimize(e, result, /*keepLhsLvalue*/ true))
+            return;
+        if (e.op == EXP.leftShiftAssign || e.op == EXP.rightShiftAssign || e.op == EXP.unsignedRightShiftAssign)
         {
-            if (binOptimize(e, result))
-                return;
             if (e.e2.isConst() == 1)
             {
                 sinteger_t i2 = e.e2.toInteger();
@@ -846,329 +749,410 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                 sz *= 8;
                 if (i2 < 0 || i2 >= sz)
                 {
-                    e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
+                    e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
                     return error();
                 }
-                if (e.e1.isConst() == 1)
-                    ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy();
             }
         }
+    }
 
-        override void visit(ShlExp e)
-        {
-            //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars());
-            shift_optimize(e, &Shl);
-        }
+    void visitBin(BinExp e)
+    {
+        //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
+        const keepLhsLvalue = e.op == EXP.construct || e.op == EXP.blit || e.op == EXP.assign
+            || e.op == EXP.plusPlus || e.op == EXP.minusMinus
+            || e.op == EXP.prePlusPlus || e.op == EXP.preMinusMinus;
+        binOptimize(e, result, keepLhsLvalue);
+    }
 
-        override void visit(ShrExp e)
+    void visitAdd(AddExp e)
+    {
+        //printf("AddExp::optimize(%s)\n", e.toChars());
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() && e.e2.isConst())
         {
-            //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars());
-            shift_optimize(e, &Shr);
+            if (e.e1.op == EXP.symbolOffset && e.e2.op == EXP.symbolOffset)
+                return;
+            ret = Add(e.loc, e.type, e.e1, e.e2).copy();
         }
+    }
 
-        override void visit(UshrExp e)
+    void visitMin(MinExp e)
+    {
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() && e.e2.isConst())
         {
-            //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
-            shift_optimize(e, &Ushr);
+            if (e.e2.op == EXP.symbolOffset)
+                return;
+            ret = Min(e.loc, e.type, e.e1, e.e2).copy();
         }
+    }
 
-        override void visit(AndExp e)
+    void visitMul(MulExp e)
+    {
+        //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars());
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
         {
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
-                ret = And(e.loc, e.type, e.e1, e.e2).copy();
+            ret = Mul(e.loc, e.type, e.e1, e.e2).copy();
         }
+    }
 
-        override void visit(OrExp e)
+    void visitDiv(DivExp e)
+    {
+        //printf("DivExp::optimize(%s)\n", e.toChars());
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
         {
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
-                ret = Or(e.loc, e.type, e.e1, e.e2).copy();
+            ret = Div(e.loc, e.type, e.e1, e.e2).copy();
         }
+    }
 
-        override void visit(XorExp e)
+    void visitMod(ModExp e)
+    {
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
         {
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
-                ret = Xor(e.loc, e.type, e.e1, e.e2).copy();
+            ret = Mod(e.loc, e.type, e.e1, e.e2).copy();
         }
+    }
 
-        override void visit(PowExp e)
+    extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift)
+    {
+        if (binOptimize(e, result))
+            return;
+        if (e.e2.isConst() == 1)
         {
-            if (binOptimize(e, result))
-                return;
-            // All negative integral powers are illegal.
-            if (e.e1.type.isintegral() && (e.e2.op == TOK.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
+            sinteger_t i2 = e.e2.toInteger();
+            d_uns64 sz = e.e1.type.size(e.e1.loc);
+            assert(sz != SIZE_INVALID);
+            sz *= 8;
+            if (i2 < 0 || i2 >= sz)
             {
-                e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars());
+                e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
                 return error();
             }
-            // If e2 *could* have been an integer, make it one.
-            if (e.e2.op == TOK.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal()))
-            {
-                // This only applies to floating point, or positive integral powers.
-                if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
-                    e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
-            }
-            if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
-            {
-                Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy();
-                if (!CTFEExp.isCantExp(ex))
-                {
-                    ret = ex;
-                    return;
-                }
-            }
+            if (e.e1.isConst() == 1)
+                ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy();
         }
+    }
+
+    void visitShl(ShlExp e)
+    {
+        //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars());
+        shift_optimize(e, &Shl);
+    }
+
+    void visitShr(ShrExp e)
+    {
+        //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars());
+        shift_optimize(e, &Shr);
+    }
+
+    void visitUshr(UshrExp e)
+    {
+        //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
+        shift_optimize(e, &Ushr);
+    }
 
-        override void visit(CommaExp e)
+    void visitAnd(AndExp e)
+    {
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+            ret = And(e.loc, e.type, e.e1, e.e2).copy();
+    }
+
+    void visitOr(OrExp e)
+    {
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+            ret = Or(e.loc, e.type, e.e1, e.e2).copy();
+    }
+
+    void visitXor(XorExp e)
+    {
+        if (binOptimize(e, result))
+            return;
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+            ret = Xor(e.loc, e.type, e.e1, e.e2).copy();
+    }
+
+    void visitPow(PowExp e)
+    {
+        if (binOptimize(e, result))
+            return;
+        // All negative integral powers are illegal.
+        if (e.e1.type.isintegral() && (e.e2.op == EXP.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
         {
-            //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars());
-            // Comma needs special treatment, because it may
-            // contain compiler-generated declarations. We can interpret them, but
-            // otherwise we must NOT attempt to constant-fold them.
-            // In particular, if the comma returns a temporary variable, it needs
-            // to be an lvalue (this is particularly important for struct constructors)
-            expOptimize(e.e1, WANTvalue);
-            expOptimize(e.e2, result, keepLvalue);
-            if (ret.op == TOK.error)
-                return;
-            if (!e.e1 || e.e1.op == TOK.int64 || e.e1.op == TOK.float64 || !hasSideEffect(e.e1))
-            {
-                ret = e.e2;
-                if (ret)
-                    ret.type = e.type;
-            }
-            //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars());
+            e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars());
+            return error();
         }
-
-        override void visit(ArrayLengthExp e)
+        // If e2 *could* have been an integer, make it one.
+        if (e.e2.op == EXP.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal()))
         {
-            //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars());
-            if (unaOptimize(e, WANTexpand))
-                return;
-            // CTFE interpret static immutable arrays (to get better diagnostics)
-            if (e.e1.op == TOK.variable)
-            {
-                VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
-                if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init)
-                {
-                    if (Expression ci = v.getConstInitializer())
-                        e.e1 = ci;
-                }
-            }
-            if (e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral || e.e1.op == TOK.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray)
-            {
-                ret = ArrayLength(e.type, e.e1).copy();
-            }
+            // This only applies to floating point, or positive integral powers.
+            if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
+                e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
         }
-
-        override void visit(EqualExp e)
+        if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
         {
-            //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars());
-            if (binOptimize(e, WANTvalue))
-                return;
-            Expression e1 = fromConstInitializer(result, e.e1);
-            Expression e2 = fromConstInitializer(result, e.e2);
-            if (e1.op == TOK.error)
+            Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy();
+            if (!CTFEExp.isCantExp(ex))
             {
-                ret = e1;
+                ret = ex;
                 return;
             }
-            if (e2.op == TOK.error)
-            {
-                ret = e2;
-                return;
-            }
-            ret = Equal(e.op, e.loc, e.type, e1, e2).copy();
-            if (CTFEExp.isCantExp(ret))
-                ret = e;
         }
+    }
 
-        override void visit(IdentityExp e)
+    void visitComma(CommaExp e)
+    {
+        //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars());
+        // Comma needs special treatment, because it may
+        // contain compiler-generated declarations. We can interpret them, but
+        // otherwise we must NOT attempt to constant-fold them.
+        // In particular, if the comma returns a temporary variable, it needs
+        // to be an lvalue (this is particularly important for struct constructors)
+        expOptimize(e.e1, WANTvalue);
+        expOptimize(e.e2, result, keepLvalue);
+        if (ret.op == EXP.error)
+            return;
+        if (!e.e1 || e.e1.op == EXP.int64 || e.e1.op == EXP.float64 || !hasSideEffect(e.e1))
         {
-            //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars());
-            if (binOptimize(e, WANTvalue))
-                return;
-            if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == TOK.null_ && e.e2.op == TOK.null_))
+            ret = e.e2;
+            if (ret)
+                ret.type = e.type;
+        }
+        //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars());
+    }
+
+    void visitArrayLength(ArrayLengthExp e)
+    {
+        //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars());
+        if (unaOptimize(e, WANTexpand))
+            return;
+        // CTFE interpret static immutable arrays (to get better diagnostics)
+        if (auto ve = e.e1.isVarExp())
+        {
+            VarDeclaration v = ve.var.isVarDeclaration();
+            if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init)
             {
-                ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy();
-                if (CTFEExp.isCantExp(ret))
-                    ret = e;
+                if (Expression ci = v.getConstInitializer())
+                    e.e1 = ci;
             }
         }
+        if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray)
+        {
+            ret = ArrayLength(e.type, e.e1).copy();
+        }
+    }
 
-        override void visit(IndexExp e)
+    void visitEqual(EqualExp e)
+    {
+        //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars());
+        if (binOptimize(e, WANTvalue))
+            return;
+        Expression e1 = fromConstInitializer(result, e.e1);
+        Expression e2 = fromConstInitializer(result, e.e2);
+        if (e1.op == EXP.error)
         {
-            //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars());
-            if (expOptimize(e.e1, result & WANTexpand))
-                return;
-            Expression ex = fromConstInitializer(result, e.e1);
-            // We might know $ now
-            setLengthVarIfKnown(e.lengthVar, ex);
-            if (expOptimize(e.e2, WANTvalue))
-                return;
-            // Don't optimize to an array literal element directly in case an lvalue is requested
-            if (keepLvalue && ex.op == TOK.arrayLiteral)
-                return;
-            ret = Index(e.type, ex, e.e2).copy();
-            if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
-                ret = e;
+            ret = e1;
+            return;
+        }
+        if (e2.op == EXP.error)
+        {
+            ret = e2;
+            return;
         }
+        ret = Equal(e.op, e.loc, e.type, e1, e2).copy();
+        if (CTFEExp.isCantExp(ret))
+            ret = e;
+    }
 
-        override void visit(SliceExp e)
+    void visitIdentity(IdentityExp e)
+    {
+        //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars());
+        if (binOptimize(e, WANTvalue))
+            return;
+        if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == EXP.null_ && e.e2.op == EXP.null_))
         {
-            //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars());
-            if (expOptimize(e.e1, result & WANTexpand))
-                return;
-            if (!e.lwr)
-            {
-                if (e.e1.op == TOK.string_)
-                {
-                    // Convert slice of string literal into dynamic array
-                    Type t = e.e1.type.toBasetype();
-                    if (Type tn = t.nextOf())
-                        ret = e.e1.castTo(null, tn.arrayOf());
-                }
-            }
-            else
-            {
-                e.e1 = fromConstInitializer(result, e.e1);
-                // We might know $ now
-                setLengthVarIfKnown(e.lengthVar, e.e1);
-                expOptimize(e.lwr, WANTvalue);
-                expOptimize(e.upr, WANTvalue);
-                if (ret.op == TOK.error)
-                    return;
-                ret = Slice(e.type, e.e1, e.lwr, e.upr).copy();
-                if (CTFEExp.isCantExp(ret))
-                    ret = e;
-            }
-            // https://issues.dlang.org/show_bug.cgi?id=14649
-            // Leave the slice form so it might be
-            // a part of array operation.
-            // Assume that the backend codegen will handle the form `e[]`
-            // as an equal to `e` itself.
-            if (ret.op == TOK.string_)
-            {
-                e.e1 = ret;
-                e.lwr = null;
-                e.upr = null;
+            ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy();
+            if (CTFEExp.isCantExp(ret))
                 ret = e;
-            }
-            //printf("-SliceExp::optimize() %s\n", ret.toChars());
         }
+    }
+
+    void visitIndex(IndexExp e)
+    {
+        //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars());
+        if (expOptimize(e.e1, result & WANTexpand))
+            return;
+        Expression ex = fromConstInitializer(result, e.e1);
+        // We might know $ now
+        setLengthVarIfKnown(e.lengthVar, ex);
+        if (expOptimize(e.e2, WANTvalue))
+            return;
+        // Don't optimize to an array literal element directly in case an lvalue is requested
+        if (keepLvalue && ex.op == EXP.arrayLiteral)
+            return;
+        ret = Index(e.type, ex, e.e2).copy();
+        if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
+            ret = e;
+    }
 
-        override void visit(LogicalExp e)
+    void visitSlice(SliceExp e)
+    {
+        //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars());
+        if (expOptimize(e.e1, result & WANTexpand))
+            return;
+        if (!e.lwr)
         {
-            //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars());
-            if (expOptimize(e.e1, WANTvalue))
-                return;
-            const oror = e.op == TOK.orOr;
-            if (e.e1.isBool(oror))
-            {
-                // Replace with (e1, oror)
-                ret = IntegerExp.createBool(oror);
-                ret = Expression.combine(e.e1, ret);
-                if (e.type.toBasetype().ty == Tvoid)
-                {
-                    ret = new CastExp(e.loc, ret, Type.tvoid);
-                    ret.type = e.type;
-                }
-                ret = Expression_optimize(ret, result, false);
-                return;
-            }
-            expOptimize(e.e2, WANTvalue);
-            if (e.e1.isConst())
+            if (e.e1.op == EXP.string_)
             {
-                if (e.e2.isConst())
-                {
-                    bool n1 = e.e1.isBool(true);
-                    bool n2 = e.e2.isBool(true);
-                    ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type);
-                }
-                else if (e.e1.isBool(!oror))
-                {
-                    if (e.type.toBasetype().ty == Tvoid)
-                        ret = e.e2;
-                    else
-                    {
-                        ret = new CastExp(e.loc, e.e2, e.type);
-                        ret.type = e.type;
-                    }
-                }
+                // Convert slice of string literal into dynamic array
+                Type t = e.e1.type.toBasetype();
+                if (Type tn = t.nextOf())
+                    ret = e.e1.castTo(null, tn.arrayOf());
             }
         }
-
-        override void visit(CmpExp e)
+        else
         {
-            //printf("CmpExp::optimize() %s\n", e.toChars());
-            if (binOptimize(e, WANTvalue))
+            e.e1 = fromConstInitializer(result, e.e1);
+            // We might know $ now
+            setLengthVarIfKnown(e.lengthVar, e.e1);
+            expOptimize(e.lwr, WANTvalue);
+            expOptimize(e.upr, WANTvalue);
+            if (ret.op == EXP.error)
                 return;
-            Expression e1 = fromConstInitializer(result, e.e1);
-            Expression e2 = fromConstInitializer(result, e.e2);
-            ret = Cmp(e.op, e.loc, e.type, e1, e2).copy();
+            ret = Slice(e.type, e.e1, e.lwr, e.upr).copy();
             if (CTFEExp.isCantExp(ret))
                 ret = e;
         }
+        // https://issues.dlang.org/show_bug.cgi?id=14649
+        // Leave the slice form so it might be
+        // a part of array operation.
+        // Assume that the backend codegen will handle the form `e[]`
+        // as an equal to `e` itself.
+        if (ret.op == EXP.string_)
+        {
+            e.e1 = ret;
+            e.lwr = null;
+            e.upr = null;
+            ret = e;
+        }
+        //printf("-SliceExp::optimize() %s\n", ret.toChars());
+    }
 
-        override void visit(CatExp e)
+    void visitLogical(LogicalExp e)
+    {
+        //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars());
+        if (expOptimize(e.e1, WANTvalue))
+            return;
+        const oror = e.op == EXP.orOr;
+        if (e.e1.toBool().hasValue(oror))
         {
-            //printf("CatExp::optimize(%d) %s\n", result, e.toChars());
-            if (binOptimize(e, result))
-                return;
-            if (e.e1.op == TOK.concatenate)
+            // Replace with (e1, oror)
+            ret = IntegerExp.createBool(oror);
+            ret = Expression.combine(e.e1, ret);
+            if (e.type.toBasetype().ty == Tvoid)
             {
-                // https://issues.dlang.org/show_bug.cgi?id=12798
-                // optimize ((expr ~ str1) ~ str2)
-                CatExp ce1 = cast(CatExp)e.e1;
-                scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2);
-                cex.type = e.type;
-                Expression ex = Expression_optimize(cex, result, false);
-                if (ex != cex)
-                {
-                    e.e1 = ce1.e1;
-                    e.e2 = ex;
-                }
+                ret = new CastExp(e.loc, ret, Type.tvoid);
+                ret.type = e.type;
             }
-            // optimize "str"[] -> "str"
-            if (e.e1.op == TOK.slice)
+            ret = Expression_optimize(ret, result, false);
+            return;
+        }
+        expOptimize(e.e2, WANTvalue);
+        if (e.e1.isConst())
+        {
+            const e1Opt = e.e1.toBool();
+            if (e.e2.isConst())
             {
-                SliceExp se1 = cast(SliceExp)e.e1;
-                if (se1.e1.op == TOK.string_ && !se1.lwr)
-                    e.e1 = se1.e1;
+                bool n1 = e1Opt.hasValue(true);
+                bool n2 = e.e2.toBool().hasValue(true);
+                ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type);
             }
-            if (e.e2.op == TOK.slice)
+            else if (e1Opt.hasValue(!oror))
             {
-                SliceExp se2 = cast(SliceExp)e.e2;
-                if (se2.e1.op == TOK.string_ && !se2.lwr)
-                    e.e2 = se2.e1;
+                if (e.type.toBasetype().ty == Tvoid)
+                    ret = e.e2;
+                else
+                {
+                    ret = new CastExp(e.loc, e.e2, e.type);
+                    ret.type = e.type;
+                }
             }
-            ret = Cat(e.loc, e.type, e.e1, e.e2).copy();
-            if (CTFEExp.isCantExp(ret))
-                ret = e;
         }
+    }
 
-        override void visit(CondExp e)
+    void visitCmp(CmpExp e)
+    {
+        //printf("CmpExp::optimize() %s\n", e.toChars());
+        if (binOptimize(e, WANTvalue))
+            return;
+        Expression e1 = fromConstInitializer(result, e.e1);
+        Expression e2 = fromConstInitializer(result, e.e2);
+        ret = Cmp(e.op, e.loc, e.type, e1, e2).copy();
+        if (CTFEExp.isCantExp(ret))
+            ret = e;
+    }
+
+    void visitCat(CatExp e)
+    {
+        //printf("CatExp::optimize(%d) %s\n", result, e.toChars());
+        if (binOptimize(e, result))
+            return;
+        if (auto ce1 = e.e1.isCatExp())
         {
-            if (expOptimize(e.econd, WANTvalue))
-                return;
-            if (e.econd.isBool(true))
-                ret = Expression_optimize(e.e1, result, keepLvalue);
-            else if (e.econd.isBool(false))
-                ret = Expression_optimize(e.e2, result, keepLvalue);
-            else
+            // https://issues.dlang.org/show_bug.cgi?id=12798
+            // optimize ((expr ~ str1) ~ str2)
+            scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2);
+            cex.type = e.type;
+            Expression ex = Expression_optimize(cex, result, false);
+            if (ex != cex)
             {
-                expOptimize(e.e1, result, keepLvalue);
-                expOptimize(e.e2, result, keepLvalue);
+                e.e1 = ce1.e1;
+                e.e2 = ex;
             }
         }
+        // optimize "str"[] -> "str"
+        if (auto se1 = e.e1.isSliceExp())
+        {
+            if (se1.e1.op == EXP.string_ && !se1.lwr)
+                e.e1 = se1.e1;
+        }
+        if (auto se2 = e.e2.isSliceExp())
+        {
+            if (se2.e1.op == EXP.string_ && !se2.lwr)
+                e.e2 = se2.e1;
+        }
+        ret = Cat(e.loc, e.type, e.e1, e.e2).copy();
+        if (CTFEExp.isCantExp(ret))
+            ret = e;
     }
 
-    scope OptimizeVisitor v = new OptimizeVisitor(e, result, keepLvalue);
+    void visitCond(CondExp e)
+    {
+        if (expOptimize(e.econd, WANTvalue))
+            return;
+        const opt = e.econd.toBool();
+        if (opt.hasValue(true))
+            ret = Expression_optimize(e.e1, result, keepLvalue);
+        else if (opt.hasValue(false))
+            ret = Expression_optimize(e.e2, result, keepLvalue);
+        else
+        {
+            expOptimize(e.e1, result, keepLvalue);
+            expOptimize(e.e2, result, keepLvalue);
+        }
+    }
 
     // Optimize the expression until it can no longer be simplified.
     size_t b;
@@ -1179,10 +1163,103 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
             e.error("infinite loop while optimizing expression");
             fatal();
         }
-        auto ex = v.ret;
-        ex.accept(v);
-        if (ex == v.ret)
+
+        auto ex = ret;
+        switch (ex.op)
+        {
+            case EXP.variable:          visitVar(ex.isVarExp()); break;
+            case EXP.tuple:             visitTuple(ex.isTupleExp()); break;
+            case EXP.arrayLiteral:      visitArrayLiteral(ex.isArrayLiteralExp()); break;
+            case EXP.assocArrayLiteral: visitAssocArrayLiteral(ex.isAssocArrayLiteralExp()); break;
+            case EXP.structLiteral:     visitStructLiteral(ex.isStructLiteralExp()); break;
+
+            case EXP.import_:
+            case EXP.assert_:
+            case EXP.dotIdentifier:
+            case EXP.dotTemplateDeclaration:
+            case EXP.dotTemplateInstance:
+            case EXP.delegate_:
+            case EXP.dotType:
+            case EXP.uadd:
+            case EXP.delete_:
+            case EXP.vector:
+            case EXP.vectorArray:
+            case EXP.array:
+            case EXP.delegatePointer:
+            case EXP.delegateFunctionPointer:
+            case EXP.preMinusMinus:
+            case EXP.prePlusPlus:       visitUna(cast(UnaExp)ex); break;
+
+            case EXP.negate:            visitNeg(ex.isNegExp()); break;
+            case EXP.tilde:             visitCom(ex.isComExp()); break;
+            case EXP.not:               visitNop(ex.isNotExp()); break;
+            case EXP.symbolOffset:      visitSymOff(ex.isSymOffExp()); break;
+            case EXP.address:           visitAddr(ex.isAddrExp()); break;
+            case EXP.star:              visitPtr(ex.isPtrExp()); break;
+            case EXP.dotVariable:       visitDotVar(ex.isDotVarExp()); break;
+            case EXP.new_:              visitNew(ex.isNewExp()); break;
+            case EXP.call:              visitCall(ex.isCallExp()); break;
+            case EXP.cast_:             visitCast(ex.isCastExp()); break;
+
+            case EXP.addAssign:
+            case EXP.minAssign:
+            case EXP.mulAssign:
+            case EXP.divAssign:
+            case EXP.modAssign:
+            case EXP.andAssign:
+            case EXP.orAssign:
+            case EXP.xorAssign:
+            case EXP.powAssign:
+            case EXP.leftShiftAssign:
+            case EXP.rightShiftAssign:
+            case EXP.unsignedRightShiftAssign:
+            case EXP.concatenateElemAssign:
+            case EXP.concatenateDcharAssign:
+            case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break;
+
+            case EXP.minusMinus:
+            case EXP.plusPlus:
+            case EXP.assign:
+            case EXP.construct:
+            case EXP.blit:
+            case EXP.in_:
+            case EXP.remove:
+            case EXP.dot:                       visitBin(cast(BinExp)ex); break;
+
+            case EXP.add:                       visitAdd(ex.isAddExp()); break;
+            case EXP.min:                       visitMin(ex.isMinExp()); break;
+            case EXP.mul:                       visitMul(ex.isMulExp()); break;
+            case EXP.div:                       visitDiv(ex.isDivExp()); break;
+            case EXP.mod:                       visitMod(ex.isModExp()); break;
+            case EXP.leftShift:                 visitShl(ex.isShlExp()); break;
+            case EXP.rightShift:                visitShr(ex.isShrExp()); break;
+            case EXP.unsignedRightShift:        visitUshr(ex.isUshrExp()); break;
+            case EXP.and:                       visitAnd(ex.isAndExp()); break;
+            case EXP.or:                        visitOr(ex.isOrExp()); break;
+            case EXP.xor:                       visitXor(ex.isXorExp()); break;
+            case EXP.pow:                       visitPow(ex.isPowExp()); break;
+            case EXP.comma:                     visitComma(ex.isCommaExp()); break;
+            case EXP.arrayLength:               visitArrayLength(ex.isArrayLengthExp()); break;
+            case EXP.notEqual:
+            case EXP.equal:                     visitEqual(ex.isEqualExp()); break;
+            case EXP.notIdentity:
+            case EXP.identity:                  visitIdentity(ex.isIdentityExp()); break;
+            case EXP.index:                     visitIndex(ex.isIndexExp()); break;
+            case EXP.slice:                     visitSlice(ex.isSliceExp()); break;
+            case EXP.andAnd:
+            case EXP.orOr:                      visitLogical(ex.isLogicalExp()); break;
+            case EXP.lessThan:
+            case EXP.lessOrEqual:
+            case EXP.greaterThan:
+            case EXP.greaterOrEqual:            visitCmp(cast(CmpExp)ex); break;
+            case EXP.concatenate:               visitCat(ex.isCatExp()); break;
+            case EXP.question:                  visitCond(ex.isCondExp()); break;
+
+            default:                            visitExp(ex); break;
+        }
+
+        if (ex == ret)
             break;
     }
-    return v.ret;
+    return ret;
 }
index f00ceb6cc937f806f4ad87cbdb0d2f92a1190646..2229e7853db3861f428d3aa838cbf624a82208f3 100644 (file)
@@ -50,146 +50,146 @@ private enum CARRAYDECL = 1;
  *
  * Used by hdrgen
  */
-immutable PREC[TOK.max + 1] precedence =
+immutable PREC[EXP.max + 1] precedence =
 [
-    TOK.type : PREC.expr,
-    TOK.error : PREC.expr,
-    TOK.objcClassReference : PREC.expr, // Objective-C class reference, same as TOK.type
-
-    TOK.typeof_ : PREC.primary,
-    TOK.mixin_ : PREC.primary,
-
-    TOK.import_ : PREC.primary,
-    TOK.dotVariable : PREC.primary,
-    TOK.scope_ : PREC.primary,
-    TOK.identifier : PREC.primary,
-    TOK.this_ : PREC.primary,
-    TOK.super_ : PREC.primary,
-    TOK.int64 : PREC.primary,
-    TOK.float64 : PREC.primary,
-    TOK.complex80 : PREC.primary,
-    TOK.null_ : PREC.primary,
-    TOK.string_ : PREC.primary,
-    TOK.arrayLiteral : PREC.primary,
-    TOK.assocArrayLiteral : PREC.primary,
-    TOK.classReference : PREC.primary,
-    TOK.file : PREC.primary,
-    TOK.fileFullPath : PREC.primary,
-    TOK.line : PREC.primary,
-    TOK.moduleString : PREC.primary,
-    TOK.functionString : PREC.primary,
-    TOK.prettyFunction : PREC.primary,
-    TOK.typeid_ : PREC.primary,
-    TOK.is_ : PREC.primary,
-    TOK.assert_ : PREC.primary,
-    TOK.halt : PREC.primary,
-    TOK.template_ : PREC.primary,
-    TOK.dSymbol : PREC.primary,
-    TOK.function_ : PREC.primary,
-    TOK.variable : PREC.primary,
-    TOK.symbolOffset : PREC.primary,
-    TOK.structLiteral : PREC.primary,
-    TOK.compoundLiteral : PREC.primary,
-    TOK.arrayLength : PREC.primary,
-    TOK.delegatePointer : PREC.primary,
-    TOK.delegateFunctionPointer : PREC.primary,
-    TOK.remove : PREC.primary,
-    TOK.tuple : PREC.primary,
-    TOK.traits : PREC.primary,
-    TOK.default_ : PREC.primary,
-    TOK.overloadSet : PREC.primary,
-    TOK.void_ : PREC.primary,
-    TOK.vectorArray : PREC.primary,
-    TOK._Generic : PREC.primary,
+    EXP.type : PREC.expr,
+    EXP.error : PREC.expr,
+    EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
+
+    EXP.typeof_ : PREC.primary,
+    EXP.mixin_ : PREC.primary,
+
+    EXP.import_ : PREC.primary,
+    EXP.dotVariable : PREC.primary,
+    EXP.scope_ : PREC.primary,
+    EXP.identifier : PREC.primary,
+    EXP.this_ : PREC.primary,
+    EXP.super_ : PREC.primary,
+    EXP.int64 : PREC.primary,
+    EXP.float64 : PREC.primary,
+    EXP.complex80 : PREC.primary,
+    EXP.null_ : PREC.primary,
+    EXP.string_ : PREC.primary,
+    EXP.arrayLiteral : PREC.primary,
+    EXP.assocArrayLiteral : PREC.primary,
+    EXP.classReference : PREC.primary,
+    EXP.file : PREC.primary,
+    EXP.fileFullPath : PREC.primary,
+    EXP.line : PREC.primary,
+    EXP.moduleString : PREC.primary,
+    EXP.functionString : PREC.primary,
+    EXP.prettyFunction : PREC.primary,
+    EXP.typeid_ : PREC.primary,
+    EXP.is_ : PREC.primary,
+    EXP.assert_ : PREC.primary,
+    EXP.halt : PREC.primary,
+    EXP.template_ : PREC.primary,
+    EXP.dSymbol : PREC.primary,
+    EXP.function_ : PREC.primary,
+    EXP.variable : PREC.primary,
+    EXP.symbolOffset : PREC.primary,
+    EXP.structLiteral : PREC.primary,
+    EXP.compoundLiteral : PREC.primary,
+    EXP.arrayLength : PREC.primary,
+    EXP.delegatePointer : PREC.primary,
+    EXP.delegateFunctionPointer : PREC.primary,
+    EXP.remove : PREC.primary,
+    EXP.tuple : PREC.primary,
+    EXP.traits : PREC.primary,
+    EXP.default_ : PREC.primary,
+    EXP.overloadSet : PREC.primary,
+    EXP.void_ : PREC.primary,
+    EXP.vectorArray : PREC.primary,
+    EXP._Generic : PREC.primary,
 
     // post
-    TOK.dotTemplateInstance : PREC.primary,
-    TOK.dotIdentifier : PREC.primary,
-    TOK.dotTemplateDeclaration : PREC.primary,
-    TOK.dot : PREC.primary,
-    TOK.dotType : PREC.primary,
-    TOK.plusPlus : PREC.primary,
-    TOK.minusMinus : PREC.primary,
-    TOK.prePlusPlus : PREC.primary,
-    TOK.preMinusMinus : PREC.primary,
-    TOK.call : PREC.primary,
-    TOK.slice : PREC.primary,
-    TOK.array : PREC.primary,
-    TOK.index : PREC.primary,
-
-    TOK.delegate_ : PREC.unary,
-    TOK.address : PREC.unary,
-    TOK.star : PREC.unary,
-    TOK.negate : PREC.unary,
-    TOK.uadd : PREC.unary,
-    TOK.not : PREC.unary,
-    TOK.tilde : PREC.unary,
-    TOK.delete_ : PREC.unary,
-    TOK.new_ : PREC.unary,
-    TOK.newAnonymousClass : PREC.unary,
-    TOK.cast_ : PREC.unary,
-
-    TOK.vector : PREC.unary,
-    TOK.pow : PREC.pow,
-
-    TOK.mul : PREC.mul,
-    TOK.div : PREC.mul,
-    TOK.mod : PREC.mul,
-
-    TOK.add : PREC.add,
-    TOK.min : PREC.add,
-    TOK.concatenate : PREC.add,
-
-    TOK.leftShift : PREC.shift,
-    TOK.rightShift : PREC.shift,
-    TOK.unsignedRightShift : PREC.shift,
-
-    TOK.lessThan : PREC.rel,
-    TOK.lessOrEqual : PREC.rel,
-    TOK.greaterThan : PREC.rel,
-    TOK.greaterOrEqual : PREC.rel,
-    TOK.in_ : PREC.rel,
+    EXP.dotTemplateInstance : PREC.primary,
+    EXP.dotIdentifier : PREC.primary,
+    EXP.dotTemplateDeclaration : PREC.primary,
+    EXP.dot : PREC.primary,
+    EXP.dotType : PREC.primary,
+    EXP.plusPlus : PREC.primary,
+    EXP.minusMinus : PREC.primary,
+    EXP.prePlusPlus : PREC.primary,
+    EXP.preMinusMinus : PREC.primary,
+    EXP.call : PREC.primary,
+    EXP.slice : PREC.primary,
+    EXP.array : PREC.primary,
+    EXP.index : PREC.primary,
+
+    EXP.delegate_ : PREC.unary,
+    EXP.address : PREC.unary,
+    EXP.star : PREC.unary,
+    EXP.negate : PREC.unary,
+    EXP.uadd : PREC.unary,
+    EXP.not : PREC.unary,
+    EXP.tilde : PREC.unary,
+    EXP.delete_ : PREC.unary,
+    EXP.new_ : PREC.unary,
+    EXP.newAnonymousClass : PREC.unary,
+    EXP.cast_ : PREC.unary,
+
+    EXP.vector : PREC.unary,
+    EXP.pow : PREC.pow,
+
+    EXP.mul : PREC.mul,
+    EXP.div : PREC.mul,
+    EXP.mod : PREC.mul,
+
+    EXP.add : PREC.add,
+    EXP.min : PREC.add,
+    EXP.concatenate : PREC.add,
+
+    EXP.leftShift : PREC.shift,
+    EXP.rightShift : PREC.shift,
+    EXP.unsignedRightShift : PREC.shift,
+
+    EXP.lessThan : PREC.rel,
+    EXP.lessOrEqual : PREC.rel,
+    EXP.greaterThan : PREC.rel,
+    EXP.greaterOrEqual : PREC.rel,
+    EXP.in_ : PREC.rel,
 
     /* Note that we changed precedence, so that < and != have the same
      * precedence. This change is in the parser, too.
      */
-    TOK.equal : PREC.rel,
-    TOK.notEqual : PREC.rel,
-    TOK.identity : PREC.rel,
-    TOK.notIdentity : PREC.rel,
-
-    TOK.and : PREC.and,
-    TOK.xor : PREC.xor,
-    TOK.or : PREC.or,
-
-    TOK.andAnd : PREC.andand,
-    TOK.orOr : PREC.oror,
-
-    TOK.question : PREC.cond,
-
-    TOK.assign : PREC.assign,
-    TOK.construct : PREC.assign,
-    TOK.blit : PREC.assign,
-    TOK.addAssign : PREC.assign,
-    TOK.minAssign : PREC.assign,
-    TOK.concatenateAssign : PREC.assign,
-    TOK.concatenateElemAssign : PREC.assign,
-    TOK.concatenateDcharAssign : PREC.assign,
-    TOK.mulAssign : PREC.assign,
-    TOK.divAssign : PREC.assign,
-    TOK.modAssign : PREC.assign,
-    TOK.powAssign : PREC.assign,
-    TOK.leftShiftAssign : PREC.assign,
-    TOK.rightShiftAssign : PREC.assign,
-    TOK.unsignedRightShiftAssign : PREC.assign,
-    TOK.andAssign : PREC.assign,
-    TOK.orAssign : PREC.assign,
-    TOK.xorAssign : PREC.assign,
-
-    TOK.comma : PREC.expr,
-    TOK.declaration : PREC.expr,
-
-    TOK.interval : PREC.assign,
+    EXP.equal : PREC.rel,
+    EXP.notEqual : PREC.rel,
+    EXP.identity : PREC.rel,
+    EXP.notIdentity : PREC.rel,
+
+    EXP.and : PREC.and,
+    EXP.xor : PREC.xor,
+    EXP.or : PREC.or,
+
+    EXP.andAnd : PREC.andand,
+    EXP.orOr : PREC.oror,
+
+    EXP.question : PREC.cond,
+
+    EXP.assign : PREC.assign,
+    EXP.construct : PREC.assign,
+    EXP.blit : PREC.assign,
+    EXP.addAssign : PREC.assign,
+    EXP.minAssign : PREC.assign,
+    EXP.concatenateAssign : PREC.assign,
+    EXP.concatenateElemAssign : PREC.assign,
+    EXP.concatenateDcharAssign : PREC.assign,
+    EXP.mulAssign : PREC.assign,
+    EXP.divAssign : PREC.assign,
+    EXP.modAssign : PREC.assign,
+    EXP.powAssign : PREC.assign,
+    EXP.leftShiftAssign : PREC.assign,
+    EXP.rightShiftAssign : PREC.assign,
+    EXP.unsignedRightShiftAssign : PREC.assign,
+    EXP.andAssign : PREC.assign,
+    EXP.orAssign : PREC.assign,
+    EXP.xorAssign : PREC.assign,
+
+    EXP.comma : PREC.expr,
+    EXP.declaration : PREC.expr,
+
+    EXP.interval : PREC.assign,
 ];
 
 enum ParseStatementFlags : int
@@ -4079,7 +4079,7 @@ class Parser(AST) : Lexer
                     // Handle delegate declaration:
                     //      t delegate(parameter list) nothrow pure
                     //      t function(parameter list) nothrow pure
-                    TOK save = token.value;
+                    const save = token.value;
                     nextToken();
 
                     auto parameterList = parseParameterList(null);
@@ -5752,7 +5752,7 @@ LagainStc:
                  * Error: found 'foo' when expecting ';' following statement
                  * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
                  */
-                if (token.value == TOK.identifier && exp.op == TOK.identifier)
+                if (token.value == TOK.identifier && exp.op == EXP.identifier)
                 {
                     error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
                     nextToken();
@@ -5911,7 +5911,7 @@ LagainStc:
                     // mixin(string)
                     AST.Expression e = parseAssignExp();
                     check(TOK.semicolon);
-                    if (e.op == TOK.mixin_)
+                    if (e.op == EXP.mixin_)
                     {
                         AST.MixinExp cpe = cast(AST.MixinExp)e;
                         s = new AST.CompileStatement(loc, cpe.exps);
@@ -6816,8 +6816,8 @@ LagainStc:
         {
             switch (token.value)
             {
-            case TOK.file:           e = new AST.FileInitExp(token.loc, TOK.file); break;
-            case TOK.fileFullPath:   e = new AST.FileInitExp(token.loc, TOK.fileFullPath); break;
+            case TOK.file:           e = new AST.FileInitExp(token.loc, EXP.file); break;
+            case TOK.fileFullPath:   e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break;
             case TOK.line:           e = new AST.LineInitExp(token.loc); break;
             case TOK.moduleString:   e = new AST.ModuleInitExp(token.loc); break;
             case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
@@ -8470,14 +8470,14 @@ LagainStc:
             nextToken();
             e = parseUnaryExp();
             //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
-            e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+            e = new AST.PreExp(EXP.prePlusPlus, loc, e);
             break;
 
         case TOK.minusMinus:
             nextToken();
             e = parseUnaryExp();
             //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
-            e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+            e = new AST.PreExp(EXP.preMinusMinus, loc, e);
             break;
 
         case TOK.mul:
@@ -8785,11 +8785,11 @@ LagainStc:
                 break;
 
             case TOK.plusPlus:
-                e = new AST.PostExp(TOK.plusPlus, loc, e);
+                e = new AST.PostExp(EXP.plusPlus, loc, e);
                 break;
 
             case TOK.minusMinus:
-                e = new AST.PostExp(TOK.minusMinus, loc, e);
+                e = new AST.PostExp(EXP.minusMinus, loc, e);
                 break;
 
             case TOK.leftParenthesis:
@@ -8946,21 +8946,18 @@ LagainStc:
         const loc = token.loc;
 
         auto e = parseShiftExp();
-        TOK op = token.value;
+        EXP op = EXP.reserved;
 
-        switch (op)
+        switch (token.value)
         {
-        case TOK.equal:
-        case TOK.notEqual:
+        case TOK.equal:         op = EXP.equal; goto Lequal;
+        case TOK.notEqual:      op = EXP.notEqual; goto Lequal;
+        Lequal:
             nextToken();
             auto e2 = parseShiftExp();
             e = new AST.EqualExp(op, loc, e, e2);
             break;
 
-        case TOK.is_:
-            op = TOK.identity;
-            goto L1;
-
         case TOK.not:
         {
             // Attempt to identify '!is'
@@ -8977,19 +8974,21 @@ LagainStc:
             if (tv != TOK.is_)
                 break;
             nextToken();
-            op = TOK.notIdentity;
-            goto L1;
+            op = EXP.notIdentity;
+            goto Lidentity;
         }
-        L1:
+        case TOK.is_:           op = EXP.identity; goto Lidentity;
+        Lidentity:
             nextToken();
             auto e2 = parseShiftExp();
             e = new AST.IdentityExp(op, loc, e, e2);
             break;
 
-        case TOK.lessThan:
-        case TOK.lessOrEqual:
-        case TOK.greaterThan:
-        case TOK.greaterOrEqual:
+        case TOK.lessThan:       op = EXP.lessThan;       goto Lcmp;
+        case TOK.lessOrEqual:    op = EXP.lessOrEqual;    goto Lcmp;
+        case TOK.greaterThan:    op = EXP.greaterThan;    goto Lcmp;
+        case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
+        Lcmp:
             nextToken();
             auto e2 = parseShiftExp();
             e = new AST.CmpExp(op, loc, e, e2);
@@ -9064,7 +9063,7 @@ LagainStc:
         {
             nextToken();
             auto e2 = parseOrExp();
-            e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+            e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
         }
         return e;
     }
@@ -9078,7 +9077,7 @@ LagainStc:
         {
             nextToken();
             auto e2 = parseAndAndExp();
-            e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+            e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
         }
         return e;
     }
@@ -9107,92 +9106,109 @@ LagainStc:
             return e;
 
         // require parens for e.g. `t ? a = 1 : b = 2`
-        if (e.op == TOK.question && !e.parens && precedence[token.value] == PREC.assign)
-            dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
-                e.toChars(), Token.toChars(token.value));
+        void checkRequiredParens()
+        {
+            if (e.op == EXP.question && !e.parens)
+                dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
+                    e.toChars(), Token.toChars(token.value));
+        }
 
         const loc = token.loc;
         switch (token.value)
         {
         case TOK.assign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.AssignExp(loc, e, e2);
             break;
 
         case TOK.addAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.AddAssignExp(loc, e, e2);
             break;
 
         case TOK.minAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.MinAssignExp(loc, e, e2);
             break;
 
         case TOK.mulAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.MulAssignExp(loc, e, e2);
             break;
 
         case TOK.divAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.DivAssignExp(loc, e, e2);
             break;
 
         case TOK.modAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.ModAssignExp(loc, e, e2);
             break;
 
         case TOK.powAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.PowAssignExp(loc, e, e2);
             break;
 
         case TOK.andAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.AndAssignExp(loc, e, e2);
             break;
 
         case TOK.orAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.OrAssignExp(loc, e, e2);
             break;
 
         case TOK.xorAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.XorAssignExp(loc, e, e2);
             break;
 
         case TOK.leftShiftAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.ShlAssignExp(loc, e, e2);
             break;
 
         case TOK.rightShiftAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.ShrAssignExp(loc, e, e2);
             break;
 
         case TOK.unsignedRightShiftAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.UshrAssignExp(loc, e, e2);
             break;
 
         case TOK.concatenateAssign:
+            checkRequiredParens();
             nextToken();
             auto e2 = parseAssignExp();
             e = new AST.CatAssignExp(loc, e, e2);
index 414d6f665f53f8fd8094bb16cfd1865714e14d73..b9f0c5e2eb8d247bd3bee1ae292240b120f33eac 100644 (file)
@@ -16,6 +16,7 @@ import core.stdc.stdio;
 import dmd.expression;
 import dmd.tokens;
 import dmd.visitor;
+import dmd.hdrgen;
 
 /********************
  * Print AST data structure in a nice format.
@@ -45,7 +46,8 @@ extern (C++) final class PrintASTVisitor : Visitor
     override void visit(Expression e)
     {
         printIndent(indent);
-        printf("%s %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "");
+        auto s = EXPtoString(e.op);
+        printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "");
     }
 
     override void visit(IntegerExp e)
@@ -68,7 +70,8 @@ extern (C++) final class PrintASTVisitor : Visitor
     override void visit(StructLiteralExp e)
     {
         printIndent(indent);
-        printf("%s %s, %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "", e.toChars());
+        auto s = EXPtoString(e.op);
+        printf("%.*s %s, %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "", e.toChars());
     }
 
     override void visit(SymbolExp e)
index 88f20952cc9ef88bdb889398da8d631a23ac8a4f..8b0bcf26049d87d1c3c0bbcbd231553592d33871 100644 (file)
@@ -43,6 +43,9 @@ typedef unsigned d_size_t;
         __APPLE__ && __SIZEOF_SIZE_T__ == 8
 // DMD versions between 2.079 and 2.081 mapped D ulong to uint64_t on OS X.
 typedef uint64_t d_size_t;
+#elif defined(__OpenBSD__) && !defined(__LP64__)
+// size_t is 'unsigned long', which makes it mangle differently than D's 'uint'
+typedef unsigned d_size_t;
 #else
 typedef size_t d_size_t;
 #endif
index 64e9571632282a4d502d9d261598960aee251214..2722529bbac9cf715088cc29b9a143934b19ce94 100644 (file)
@@ -120,11 +120,10 @@ nothrow:
                 perror("\tclose error");
                 goto err;
             }
-            // Always store a wchar ^Z past end of buffer so scanner has a sentinel
-            buffer[size] = 0; // ^Z is obsolete, use 0
-            buffer[size + 1] = 0;
-            buffer[size + 2] = 0; //add two more so lexer doesnt read pass the buffer
-            buffer[size + 3] = 0;
+            // Always store a wchar ^Z past end of buffer so scanner has a
+            // sentinel, although ^Z got obselete, so fill with two 0s and add
+            // two more so lexer doesn't read pass the buffer.
+            buffer[size .. size + 4] = 0;
 
             result.success = true;
             result.buffer.data = buffer[0 .. size];
@@ -160,11 +159,10 @@ nothrow:
                 goto err2;
             if (!CloseHandle(h))
                 goto err;
-            // Always store a wchar ^Z past end of buffer so scanner has a sentinel
-            buffer[size] = 0; // ^Z is obsolete, use 0
-            buffer[size + 1] = 0;
-            buffer[size + 2] = 0; //add two more so lexer doesnt read pass the buffer
-            buffer[size + 3] = 0;
+            // Always store a wchar ^Z past end of buffer so scanner has a
+            // sentinel, although ^Z got obselete, so fill with two 0s and add
+            // two more so lexer doesn't read pass the buffer.
+            buffer[size .. size + 4] = 0;
             result.success = true;
             result.buffer.data = buffer[0 .. size];
             return result;
diff --git a/gcc/d/dmd/root/optional.d b/gcc/d/dmd/root/optional.d
new file mode 100644 (file)
index 0000000..a593ddd
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * Optional implementation.
+ *
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d, root/_optional.d)
+ * Documentation:  https://dlang.org/phobos/dmd_root_optional.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.d
+ */
+module dmd.root.optional;
+
+///
+unittest
+{
+    import core.exception : AssertError;
+
+    Optional!int opt;
+    assert( opt.isEmpty());
+    assert(!opt.isPresent());
+    assert(!opt.hasValue(1));
+    assert(!opt.hasValue(2));
+
+    bool caught;
+    try
+        cast(void) opt.get();
+    catch (AssertError)
+        caught = true;
+    assert(caught);
+
+    opt = Optional!int(1);
+    assert(!opt.isEmpty());
+    assert( opt.isPresent());
+    assert( opt.get() == 1);
+    assert( opt.hasValue(1));
+    assert(!opt.hasValue(2));
+}
+
+/// Optional type that is either `empty` or contains a value of type `T`
+extern (C++) struct Optional(T)
+{
+    /// the value (if present)
+    private T value;
+
+    /// whether `value` is set
+    private bool present;
+
+    /// Creates an `Optional` with the given value
+    this(T value)
+    {
+        this.value = value;
+        this.present = true;
+    }
+
+    // Ctor wrapper for the C++ interface (required by older host compilers)
+    /// ditto
+    static Optional!T create(T val)
+    {
+        return Optional!T(val);
+    }
+
+    /// Returns: Whether this `Optional` contains a value
+    bool isPresent() const
+    {
+        return this.present;
+    }
+
+    /// Returns: Whether this `Optional` does not contain a value
+    bool isEmpty() const
+    {
+        return !this.present;
+    }
+
+    /// Returns: The value if present
+    inout(T) get() inout
+    {
+        assert(present);
+        return value;
+    }
+
+    /// Returns: Whether this `Optional` contains the supplied value
+    bool hasValue(const T exp) const
+    {
+        return present && value == exp;
+    }
+}
diff --git a/gcc/d/dmd/root/optional.h b/gcc/d/dmd/root/optional.h
new file mode 100644 (file)
index 0000000..fa52b58
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+/**
+ * Optional implementation.
+ *
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.h, root/_optional.h)
+ * Documentation:  https://dlang.org/phobos/dmd_root_optional.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.h
+ */
+
+/// Optional type that is either `empty` or contains a value of type `T`
+template<typename T>
+struct Optional final
+{
+private:
+    /** the value (if present) **/
+    T value;
+
+    /** whether `value` is set **/
+    bool present;
+
+public:
+    /** Creates an `Optional` with the given value **/
+    Optional(T);
+
+    /** Creates an `Optional` with the given value **/
+    static Optional<T> create(T);
+
+    /** Checks whether this `Optional` contains a value **/
+    bool isPresent() const;
+
+    /** Checks whether this `Optional` does not contain a value **/
+    bool isEmpty() const;
+
+    /** Returns: The value if present **/
+    T get();
+
+    bool hasValue(const T) const;
+};
index 89049599dacdfd1988372c202af2016948c2f639..7eb3e235e41f0aa861d1efa561184f871eeba7c2 100644 (file)
@@ -46,7 +46,7 @@ import dmd.tokens;
 bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
 {
     //printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg);
-    if (e.op != TOK.dotVariable)
+    if (e.op != EXP.dotVariable)
         return false;
     DotVarExp dve = cast(DotVarExp)e;
     if (VarDeclaration v = dve.var.isVarDeclaration())
@@ -170,7 +170,7 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
          */
         if (tfromn.ty == Tvoid && ttobn.isMutable())
         {
-            if (ttob.ty == Tarray && e.op == TOK.arrayLiteral)
+            if (ttob.ty == Tarray && e.op == EXP.arrayLiteral)
                 return true;
             return false;
         }
index 993db90552343247efb504908ae2e3cbe06fb629..c3fe7520175d14063ccc325c022a66a98c2c2009 100644 (file)
@@ -278,15 +278,15 @@ private extern(C++) final class Semantic2Visitor : Visitor
                         return false;
                     }
 
-                    if (e.op == TOK.classReference)
+                    if (e.op == EXP.classReference)
                         return true;
-                    if (e.op == TOK.address && (cast(AddrExp)e).e1.op == TOK.structLiteral)
+                    if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral)
                         return true;
-                    if (e.op == TOK.arrayLiteral)
+                    if (e.op == EXP.arrayLiteral)
                         return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements);
-                    if (e.op == TOK.structLiteral)
+                    if (e.op == EXP.structLiteral)
                         return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
-                    if (e.op == TOK.assocArrayLiteral)
+                    if (e.op == EXP.assocArrayLiteral)
                     {
                         AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
                         return arrayHasInvalidEnumInitializer(ae.values) ||
@@ -306,13 +306,13 @@ private extern(C++) final class Semantic2Visitor : Visitor
             if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
             {
                 ExpInitializer ei = vd._init.isExpInitializer();
-                if (ei && ei.exp.op == TOK.classReference)
+                if (ei && ei.exp.op == EXP.classReference)
                     vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.");
             }
             else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared())
             {
                 ExpInitializer ei = vd._init.isExpInitializer();
-                if (ei && ei.exp.op == TOK.address && (cast(AddrExp)ei.exp).e1.op == TOK.structLiteral)
+                if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral)
                     vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.");
             }
         }
@@ -569,7 +569,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
                 e = e.expressionSemantic(sc);
                 if (definitelyValueParameter(e))
                     e = e.ctfeInterpret();
-                if (e.op == TOK.tuple)
+                if (e.op == EXP.tuple)
                 {
                     TupleExp te = cast(TupleExp)e;
                     eval(sc, te.exps, lastTag);
@@ -697,7 +697,7 @@ private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
     import dmd.dmangle;
 
     // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
-    if (e.op == TOK.type)
+    if (e.op == EXP.type)
     {
         e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
         return;
index 3852d0b26934e90584475ef6b1b35e011bc9df52..893f96b4ea9ff90abf419131c4712e29a2c5f5a1 100644 (file)
@@ -611,7 +611,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                     for (size_t i = 0; i < funcdecl.returns.dim;)
                     {
                         Expression exp = (*funcdecl.returns)[i].exp;
-                        if (exp.op == TOK.variable && (cast(VarExp)exp).var == funcdecl.vresult)
+                        if (exp.op == EXP.variable && (cast(VarExp)exp).var == funcdecl.vresult)
                         {
                             if (addReturn0())
                                 exp.type = Type.tint32;
@@ -817,7 +817,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                     {
                         ReturnStatement rs = (*funcdecl.returns)[i];
                         Expression exp = rs.exp;
-                        if (exp.op == TOK.error)
+                        if (exp.op == EXP.error)
                             continue;
                         if (tret.ty == Terror)
                         {
index d238150e75ecfdb3e4e79a31fb1886661a75f9a2..99833b55a329b3ecee443ef6e8f13ba3235cd165 100644 (file)
@@ -47,7 +47,7 @@ extern (C++) bool isTrivialExp(Expression e)
              * CallExp is always non trivial expression,
              * especially for inlining.
              */
-            if (e.op == TOK.call)
+            if (e.op == EXP.call)
             {
                 stop = true;
                 return;
@@ -153,36 +153,36 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false)
     switch (e.op)
     {
     // Sort the cases by most frequently used first
-    case TOK.assign:
-    case TOK.plusPlus:
-    case TOK.minusMinus:
-    case TOK.declaration:
-    case TOK.construct:
-    case TOK.blit:
-    case TOK.addAssign:
-    case TOK.minAssign:
-    case TOK.concatenateAssign:
-    case TOK.concatenateElemAssign:
-    case TOK.concatenateDcharAssign:
-    case TOK.mulAssign:
-    case TOK.divAssign:
-    case TOK.modAssign:
-    case TOK.leftShiftAssign:
-    case TOK.rightShiftAssign:
-    case TOK.unsignedRightShiftAssign:
-    case TOK.andAssign:
-    case TOK.orAssign:
-    case TOK.xorAssign:
-    case TOK.powAssign:
-    case TOK.in_:
-    case TOK.remove:
-    case TOK.assert_:
-    case TOK.halt:
-    case TOK.delete_:
-    case TOK.new_:
-    case TOK.newAnonymousClass:
+    case EXP.assign:
+    case EXP.plusPlus:
+    case EXP.minusMinus:
+    case EXP.declaration:
+    case EXP.construct:
+    case EXP.blit:
+    case EXP.addAssign:
+    case EXP.minAssign:
+    case EXP.concatenateAssign:
+    case EXP.concatenateElemAssign:
+    case EXP.concatenateDcharAssign:
+    case EXP.mulAssign:
+    case EXP.divAssign:
+    case EXP.modAssign:
+    case EXP.leftShiftAssign:
+    case EXP.rightShiftAssign:
+    case EXP.unsignedRightShiftAssign:
+    case EXP.andAssign:
+    case EXP.orAssign:
+    case EXP.xorAssign:
+    case EXP.powAssign:
+    case EXP.in_:
+    case EXP.remove:
+    case EXP.assert_:
+    case EXP.halt:
+    case EXP.delete_:
+    case EXP.new_:
+    case EXP.newAnonymousClass:
         return true;
-    case TOK.call:
+    case EXP.call:
         {
             if (assumeImpureCalls)
                 return true;
@@ -207,13 +207,13 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false)
             }
             break;
         }
-    case TOK.cast_:
+    case EXP.cast_:
         {
             CastExp ce = cast(CastExp)e;
             /* if:
              *  cast(classtype)func()  // because it may throw
              */
-            if (ce.to.ty == Tclass && ce.e1.op == TOK.call && ce.e1.type.ty == Tclass)
+            if (ce.to.ty == Tclass && ce.e1.op == EXP.call && ce.e1.type.ty == Tclass)
                 return true;
             break;
         }
@@ -235,7 +235,7 @@ bool discardValue(Expression e)
         return false;
     switch (e.op)
     {
-    case TOK.cast_:
+    case EXP.cast_:
         {
             CastExp ce = cast(CastExp)e;
             if (ce.to.equals(Type.tvoid))
@@ -247,9 +247,9 @@ bool discardValue(Expression e)
             }
             break; // complain
         }
-    case TOK.error:
+    case EXP.error:
         return false;
-    case TOK.variable:
+    case EXP.variable:
         {
             VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
             if (v && (v.storage_class & STC.temp))
@@ -260,7 +260,7 @@ bool discardValue(Expression e)
             }
             break;
         }
-    case TOK.call:
+    case EXP.call:
         /* Issue 3882: */
         if (global.params.warnings != DiagnosticReporting.off && !global.gag)
         {
@@ -285,7 +285,7 @@ bool discardValue(Expression e)
                     const(char)* s;
                     if (ce.f)
                         s = ce.f.toPrettyChars();
-                    else if (ce.e1.op == TOK.star)
+                    else if (ce.e1.op == EXP.star)
                     {
                         // print 'fp' if ce.e1 is (*fp)
                         s = (cast(PtrExp)ce.e1).e1.toChars();
@@ -297,13 +297,13 @@ bool discardValue(Expression e)
             }
         }
         return false;
-    case TOK.andAnd:
-    case TOK.orOr:
+    case EXP.andAnd:
+    case EXP.orOr:
         {
             LogicalExp aae = cast(LogicalExp)e;
             return discardValue(aae.e2);
         }
-    case TOK.question:
+    case EXP.question:
         {
             CondExp ce = cast(CondExp)e;
             /* https://issues.dlang.org/show_bug.cgi?id=6178
@@ -333,7 +333,7 @@ bool discardValue(Expression e)
             }
             return false;
         }
-    case TOK.comma:
+    case EXP.comma:
         {
             CommaExp ce = cast(CommaExp)e;
             // Don't complain about compiler-generated comma expressions
@@ -344,7 +344,7 @@ bool discardValue(Expression e)
             // This is concretely done in expressionSemantic, if a CommaExp has Tvoid as type
             return discardValue(ce.e2);
         }
-    case TOK.tuple:
+    case EXP.tuple:
         /* Pass without complaint if any of the tuple elements have side effects.
          * Ideally any tuple elements with no side effects should raise an error,
          * this needs more investigation as to what is the right thing to do.
index 9eba2ffaed206a32151e90a122440af9303d8f20..6979cdf7977c083bbdb5ced9e4e8733720e69504 100644 (file)
@@ -125,7 +125,7 @@ private LabelStatement checkLabeledLoop(Scope* sc, Statement statement)
 private Expression checkAssignmentAsCondition(Expression e)
 {
     auto ec = lastComma(e);
-    if (ec.op == TOK.assign)
+    if (ec.op == EXP.assign)
     {
         ec.error("assignment cannot be used as a condition, perhaps `==` was meant?");
         return ErrorExp.get();
@@ -213,7 +213,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         s.exp = s.exp.optimize(WANTvalue);
         s.exp = checkGC(sc, s.exp);
-        if (s.exp.op == TOK.error)
+        if (s.exp.op == EXP.error)
             return setError();
         result = s;
     }
@@ -546,7 +546,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             ds._body = ds._body.semanticScope(sc, ds, ds, null);
         sc.inLoop = inLoopSave;
 
-        if (ds.condition.op == TOK.dotIdentifier)
+        if (ds.condition.op == EXP.dotIdentifier)
             (cast(DotIdExp)ds.condition).noderef = true;
 
         // check in syntax level
@@ -561,7 +561,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         ds.condition = ds.condition.toBoolean(sc);
 
-        if (ds.condition.op == TOK.error)
+        if (ds.condition.op == EXP.error)
             return setError();
         if (ds._body && ds._body.isErrorStatement())
         {
@@ -619,7 +619,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         if (fs.condition)
         {
-            if (fs.condition.op == TOK.dotIdentifier)
+            if (fs.condition.op == EXP.dotIdentifier)
                 (cast(DotIdExp)fs.condition).noderef = true;
 
             // check in syntax level
@@ -652,406 +652,13 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         sc.pop();
 
-        if (fs.condition && fs.condition.op == TOK.error ||
-            fs.increment && fs.increment.op == TOK.error ||
+        if (fs.condition && fs.condition.op == EXP.error ||
+            fs.increment && fs.increment.op == EXP.error ||
             fs._body && fs._body.isErrorStatement())
             return setError();
         result = fs;
     }
 
-
-    /*******************
-     * Type check and unroll `foreach` over an expression tuple as well
-     * as `static foreach` statements and `static foreach`
-     * declarations. For `static foreach` statements and `static
-     * foreach` declarations, the visitor interface is used (and the
-     * result is written into the `result` field.) For `static
-     * foreach` declarations, the resulting Dsymbols* are returned
-     * directly.
-     *
-     * The unrolled body is wrapped into a
-     *  - UnrolledLoopStatement, for `foreach` over an expression tuple.
-     *  - ForwardingStatement, for `static foreach` statements.
-     *  - ForwardingAttribDeclaration, for `static foreach` declarations.
-     *
-     * `static foreach` variables are declared as `STC.local`, such
-     * that they are inserted into the local symbol tables of the
-     * forwarding constructs instead of forwarded. For `static
-     * foreach` with multiple foreach loop variables whose aggregate
-     * has been lowered into a sequence of tuples, this function
-     * expands the tuples into multiple `STC.local` `static foreach`
-     * variables.
-     */
-    auto makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
-    {
-        // Voldemort return type
-        union U
-        {
-            Statement statement;
-            Dsymbols* decl;
-        }
-
-        U result;
-
-        auto returnEarly()
-        {
-            if (isDecl)
-                result.decl = null;
-            else
-                result.statement = new ErrorStatement();
-            return result;
-        }
-
-        auto loc = fs.loc;
-        size_t dim = fs.parameters.dim;
-        static if(isStatic) bool skipCheck = needExpansion;
-        else enum skipCheck = false;
-        if (!skipCheck && (dim < 1 || dim > 2))
-        {
-            fs.error("only one (value) or two (key,value) arguments for tuple `foreach`");
-            setError();
-            return returnEarly();
-        }
-
-        Type paramtype = (*fs.parameters)[dim - 1].type;
-        if (paramtype)
-        {
-            paramtype = paramtype.typeSemantic(loc, sc);
-            if (paramtype.ty == Terror)
-            {
-                setError();
-                return returnEarly();
-            }
-        }
-
-        Type tab = fs.aggr.type.toBasetype();
-        TypeTuple tuple = cast(TypeTuple)tab;
-        static if(!isDecl)
-        {
-            auto statements = new Statements();
-        }
-        else
-        {
-            auto declarations = new Dsymbols();
-        }
-        //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars());
-        size_t n;
-        TupleExp te = null;
-        if (fs.aggr.op == TOK.tuple) // expression tuple
-        {
-            te = cast(TupleExp)fs.aggr;
-            n = te.exps.dim;
-        }
-        else if (fs.aggr.op == TOK.type) // type tuple
-        {
-            n = Parameter.dim(tuple.arguments);
-        }
-        else
-            assert(0);
-        foreach (j; 0 .. n)
-        {
-            size_t k = (fs.op == TOK.foreach_) ? j : n - 1 - j;
-            Expression e = null;
-            Type t = null;
-            if (te)
-                e = (*te.exps)[k];
-            else
-                t = Parameter.getNth(tuple.arguments, k).type;
-            Parameter p = (*fs.parameters)[0];
-            static if(!isDecl)
-            {
-                auto st = new Statements();
-            }
-            else
-            {
-                auto st = new Dsymbols();
-            }
-
-            static if(isStatic) bool skip = needExpansion;
-            else enum skip = false;
-            if (!skip && dim == 2)
-            {
-                // Declare key
-                if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
-                {
-                    fs.error("no storage class for key `%s`", p.ident.toChars());
-                    setError();
-                    return returnEarly();
-                }
-                static if(isStatic)
-                {
-                    if(!p.type)
-                    {
-                        p.type = Type.tsize_t;
-                    }
-                }
-                p.type = p.type.typeSemantic(loc, sc);
-
-                if (!p.type.isintegral())
-                {
-                    fs.error("foreach: key cannot be of non-integral type `%s`",
-                             p.type.toChars());
-                    setError();
-                    return returnEarly();
-                }
-
-                const length = te ? te.exps.length : tuple.arguments.length;
-                IntRange dimrange = IntRange(SignExtendedNumber(length))._cast(Type.tsize_t);
-                // https://issues.dlang.org/show_bug.cgi?id=12504
-                dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
-                if (!IntRange.fromType(p.type).contains(dimrange))
-                {
-                    fs.error("index type `%s` cannot cover index range 0..%llu",
-                             p.type.toChars(), cast(ulong)length);
-                    setError();
-                    return returnEarly();
-                }
-                Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
-                auto var = new VarDeclaration(loc, p.type, p.ident, ie);
-                var.storage_class |= STC.foreach_ | STC.manifest;
-                static if(isStatic) var.storage_class |= STC.local;
-                static if(!isDecl)
-                {
-                    st.push(new ExpStatement(loc, var));
-                }
-                else
-                {
-                    st.push(var);
-                }
-                p = (*fs.parameters)[1]; // value
-            }
-            /***********************
-             * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
-             *
-             * Params:
-             *     storageClass = The storage class of the variable.
-             *     type = The declared type of the variable.
-             *     ident = The name of the variable.
-             *     e = The initializer of the variable (i.e. the current element of the looped over aggregate).
-             *     t = The type of the initializer.
-             * Returns:
-             *     `true` iff the declaration was successful.
-             */
-            bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t)
-            {
-                if (storageClass & (STC.out_ | STC.lazy_) ||
-                    storageClass & STC.ref_ && !te)
-                {
-                    fs.error("no storage class for value `%s`", ident.toChars());
-                    setError();
-                    return false;
-                }
-                Declaration var;
-                if (e)
-                {
-                    Type tb = e.type.toBasetype();
-                    Dsymbol ds = null;
-                    if (!(storageClass & STC.manifest))
-                    {
-                        if ((isStatic || tb.ty == Tfunction || storageClass&STC.alias_) && e.op == TOK.variable)
-                            ds = (cast(VarExp)e).var;
-                        else if (e.op == TOK.template_)
-                            ds = (cast(TemplateExp)e).td;
-                        else if (e.op == TOK.scope_)
-                            ds = (cast(ScopeExp)e).sds;
-                        else if (e.op == TOK.function_)
-                        {
-                            auto fe = cast(FuncExp)e;
-                            ds = fe.td ? cast(Dsymbol)fe.td : fe.fd;
-                        }
-                        else if (e.op == TOK.overloadSet)
-                            ds = (cast(OverExp)e).vars;
-                    }
-                    else if (storageClass & STC.alias_)
-                    {
-                        fs.error("`foreach` loop variable cannot be both `enum` and `alias`");
-                        setError();
-                        return false;
-                    }
-
-                    if (ds)
-                    {
-                        var = new AliasDeclaration(loc, ident, ds);
-                        if (storageClass & STC.ref_)
-                        {
-                            fs.error("symbol `%s` cannot be `ref`", ds.toChars());
-                            setError();
-                            return false;
-                        }
-                        if (paramtype)
-                        {
-                            fs.error("cannot specify element type for symbol `%s`", ds.toChars());
-                            setError();
-                            return false;
-                        }
-                    }
-                    else if (e.op == TOK.type)
-                    {
-                        var = new AliasDeclaration(loc, ident, e.type);
-                        if (paramtype)
-                        {
-                            fs.error("cannot specify element type for type `%s`", e.type.toChars());
-                            setError();
-                            return false;
-                        }
-                    }
-                    else
-                    {
-                        e = resolveProperties(sc, e);
-                        Initializer ie = new ExpInitializer(Loc.initial, e);
-                        auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
-                        v.storage_class |= STC.foreach_;
-                        if (storageClass & STC.ref_)
-                            v.storage_class |= STC.ref_;
-                        if (isStatic || storageClass&STC.manifest || e.isConst() ||
-                            e.op == TOK.string_ ||
-                            e.op == TOK.structLiteral ||
-                            e.op == TOK.arrayLiteral)
-                        {
-                            if (v.storage_class & STC.ref_)
-                            {
-                                static if (!isStatic)
-                                {
-                                    fs.error("constant value `%s` cannot be `ref`", ie.toChars());
-                                }
-                                else
-                                {
-                                    if (!needExpansion)
-                                    {
-                                        fs.error("constant value `%s` cannot be `ref`", ie.toChars());
-                                    }
-                                    else
-                                    {
-                                        fs.error("constant value `%s` cannot be `ref`", ident.toChars());
-                                    }
-                                }
-                                setError();
-                                return false;
-                            }
-                            else
-                                v.storage_class |= STC.manifest;
-                        }
-                        var = v;
-                    }
-                }
-                else
-                {
-                    var = new AliasDeclaration(loc, ident, t);
-                    if (paramtype)
-                    {
-                        fs.error("cannot specify element type for symbol `%s`", fs.toChars());
-                        setError();
-                        return false;
-                    }
-                }
-                static if (isStatic)
-                {
-                    var.storage_class |= STC.local;
-                }
-                static if (!isDecl)
-                {
-                    st.push(new ExpStatement(loc, var));
-                }
-                else
-                {
-                    st.push(var);
-                }
-                return true;
-            }
-            static if (!isStatic)
-            {
-                // Declare value
-                if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
-                {
-                    return returnEarly();
-                }
-            }
-            else
-            {
-                if (!needExpansion)
-                {
-                    // Declare value
-                    if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
-                    {
-                        return returnEarly();
-                    }
-                }
-                else
-                { // expand tuples into multiple `static foreach` variables.
-                    assert(e && !t);
-                    auto ident = Identifier.generateId("__value");
-                    declareVariable(0, e.type, ident, e, null);
-                    import dmd.cond: StaticForeach;
-                    auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length);
-                    Expression access = new DotIdExp(loc, e, field);
-                    access = expressionSemantic(access, sc);
-                    if (!tuple) return returnEarly();
-                    //printf("%s\n",tuple.toChars());
-                    foreach (l; 0 .. dim)
-                    {
-                        auto cp = (*fs.parameters)[l];
-                        Expression init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type.tsize_t));
-                        init_ = init_.expressionSemantic(sc);
-                        assert(init_.type);
-                        declareVariable(p.storageClass, init_.type, cp.ident, init_, null);
-                    }
-                }
-            }
-
-            static if (!isDecl)
-            {
-                if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646
-                    st.push(fs._body.syntaxCopy());
-                Statement res = new CompoundStatement(loc, st);
-            }
-            else
-            {
-                st.append(Dsymbol.arraySyntaxCopy(dbody));
-            }
-            static if (!isStatic)
-            {
-                res = new ScopeStatement(loc, res, fs.endloc);
-            }
-            else static if (!isDecl)
-            {
-                auto fwd = new ForwardingStatement(loc, res);
-                res = fwd;
-            }
-            else
-            {
-                import dmd.attrib: ForwardingAttribDeclaration;
-                auto res = new ForwardingAttribDeclaration(st);
-            }
-            static if (!isDecl)
-            {
-                statements.push(res);
-            }
-            else
-            {
-                declarations.push(res);
-            }
-        }
-
-        static if (!isStatic)
-        {
-            Statement res = new UnrolledLoopStatement(loc, statements);
-            if (LabelStatement ls = checkLabeledLoop(sc, fs))
-                ls.gotoTarget = res;
-            if (te && te.e0)
-                res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
-            result.statement = res;
-        }
-        else static if (!isDecl)
-        {
-            result.statement = new CompoundStatement(loc, statements);
-        }
-        else
-        {
-            result.decl = declarations;
-        }
-        return result;
-    }
-
     override void visit(ForeachStatement fs)
     {
         /* https://dlang.org/spec/statement.html#foreach-statement
@@ -1090,12 +697,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         fs.aggr = fs.aggr.expressionSemantic(sc);
         fs.aggr = resolveProperties(sc, fs.aggr);
         fs.aggr = fs.aggr.optimize(WANTvalue);
-        if (fs.aggr.op == TOK.error)
+        if (fs.aggr.op == EXP.error)
             return setError();
         Expression oaggr = fs.aggr;     // remember original for error messages
         if (fs.aggr.type && fs.aggr.type.toBasetype().ty == Tstruct &&
             (cast(TypeStruct)(fs.aggr.type.toBasetype())).sym.dtor &&
-            fs.aggr.op != TOK.type && !fs.aggr.isLvalue())
+            !fs.aggr.isTypeExp() && !fs.aggr.isLvalue())
         {
             // https://issues.dlang.org/show_bug.cgi?id=14653
             // Extend the life of rvalue aggregate till the end of foreach.
@@ -1178,7 +785,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         if (tab.ty == Ttuple) // don't generate new scope for tuple loops
         {
-            Statement s = makeTupleForeach!(false,false)(fs, null, false).statement;
+            Statement s = makeTupleForeach(sc, false, false, fs, null, false).statement;
             if (vinit)
                 s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
             result = s.statementSemantic(sc);
@@ -1283,7 +890,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             {
                 e = new DeclarationExp(loc, vinit);
                 e = e.expressionSemantic(sc2);
-                if (e.op == TOK.error)
+                if (e.op == EXP.error)
                     return null;
             }
 
@@ -1421,7 +1028,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                     if (var.storage_class & STC.ref_)
                     {
                         if (fs.aggr.checkModifiable(sc2, ModifyFlags.noError) == Modifiable.initialization)
-                            var.storage_class |= STC.ctorinit;
+                            var.setInCtorOnly = true;
 
                         Type t = tab.nextOf();
                         if (t.constConv(p.type) == MATCH.nomatch)
@@ -1446,7 +1053,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                 auto ie = new ExpInitializer(loc, new SliceExp(loc, fs.aggr, null, null));
                 const valueIsRef = cast(bool) ((*fs.parameters)[dim - 1].storageClass & STC.ref_);
                 VarDeclaration tmp;
-                if (fs.aggr.op == TOK.arrayLiteral && !valueIsRef)
+                if (fs.aggr.op == EXP.arrayLiteral && !valueIsRef)
                 {
                     auto ale = cast(ArrayLiteralExp)fs.aggr;
                     size_t edim = ale.elements ? ale.elements.dim : 0;
@@ -1456,7 +1063,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                     // if telem has been specified explicitly,
                     // converting array literal elements to telem might make it @nogc.
                     fs.aggr = fs.aggr.implicitCastTo(sc, telem.sarrayOf(edim));
-                    if (fs.aggr.op == TOK.error)
+                    if (fs.aggr.op == EXP.error)
                         return retError();
 
                     // for (T[edim] tmp = a, ...)
@@ -1498,12 +1105,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                 if (fs.op == TOK.foreach_reverse_)
                 {
                     // key--
-                    cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key));
+                    cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key));
                 }
                 else
                 {
                     // key < tmp.length
-                    cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), tmp_length);
+                    cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), tmp_length);
                 }
 
                 Expression increment = null;
@@ -1603,7 +1210,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                  */
                 VarDeclaration r;
                 Statement _init;
-                if (vinit && fs.aggr.op == TOK.variable && (cast(VarExp)fs.aggr).var == vinit)
+                if (vinit && fs.aggr.op == EXP.variable && (cast(VarExp)fs.aggr).var == vinit)
                 {
                     r = vinit;
                     _init = new ExpStatement(loc, vinit);
@@ -1788,7 +1395,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident);
         ec = new CallExp(fs.loc, ec, flde);
         ec = ec.expressionSemantic(sc2);
-        if (ec.op == TOK.error)
+        if (ec.op == EXP.error)
             return null;
         if (ec.type != Type.tint32)
         {
@@ -1805,7 +1412,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         /* Call:
          *      aggr(flde)
          */
-        if (fs.aggr.op == TOK.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
+        if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
             !(cast(DelegateExp)fs.aggr).func.needThis())
         {
             // https://issues.dlang.org/show_bug.cgi?id=3560
@@ -1813,7 +1420,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         }
         ec = new CallExp(fs.loc, fs.aggr, flde);
         ec = ec.expressionSemantic(sc2);
-        if (ec.op == TOK.error)
+        if (ec.op == EXP.error)
             return null;
         if (ec.type != Type.tint32)
         {
@@ -2063,7 +1670,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         Expression flde = new FuncExp(fs.loc, fld);
         flde = flde.expressionSemantic(sc);
         fld.tookAddressOf = 0;
-        if (flde.op == TOK.error)
+        if (flde.op == EXP.error)
             return null;
         return cast(FuncExp)flde;
     }
@@ -2143,7 +1750,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             }
             fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
         }
-        if (fs.prm.type.ty == Terror || fs.lwr.op == TOK.error || fs.upr.op == TOK.error)
+        if (fs.prm.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error)
         {
             return setError();
         }
@@ -2187,16 +1794,16 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         Expression cond;
         if (fs.op == TOK.foreach_reverse_)
         {
-            cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key));
+            cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key));
             if (fs.prm.type.isscalar())
             {
                 // key-- > tmp
-                cond = new CmpExp(TOK.greaterThan, loc, cond, new VarExp(loc, tmp));
+                cond = new CmpExp(EXP.greaterThan, loc, cond, new VarExp(loc, tmp));
             }
             else
             {
                 // key-- != tmp
-                cond = new EqualExp(TOK.notEqual, loc, cond, new VarExp(loc, tmp));
+                cond = new EqualExp(EXP.notEqual, loc, cond, new VarExp(loc, tmp));
             }
         }
         else
@@ -2204,12 +1811,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             if (fs.prm.type.isscalar())
             {
                 // key < tmp
-                cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
+                cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
             }
             else
             {
                 // key != tmp
-                cond = new EqualExp(TOK.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
+                cond = new EqualExp(EXP.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
             }
         }
 
@@ -2218,7 +1825,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         {
             // key += 1
             //increment = new AddAssignExp(loc, new VarExp(loc, fs.key), IntegerExp.literal!1);
-            increment = new PreExp(TOK.prePlusPlus, loc, new VarExp(loc, fs.key));
+            increment = new PreExp(EXP.prePlusPlus, loc, new VarExp(loc, fs.key));
         }
         if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type))
         {
@@ -2300,7 +1907,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         }
         else
         {
-            if (ifs.condition.op == TOK.dotIdentifier)
+            if (ifs.condition.op == EXP.dotIdentifier)
                 (cast(DotIdExp)ifs.condition).noderef = true;
 
             ifs.condition = ifs.condition.expressionSemantic(scd);
@@ -2337,7 +1944,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         ctorflow_then.freeFieldinit();          // free extra copy of the data
 
-        if (ifs.condition.op == TOK.error ||
+        if (ifs.condition.op == EXP.error ||
             (ifs.ifbody && ifs.ifbody.isErrorStatement()) ||
             (ifs.elsebody && ifs.elsebody.isErrorStatement()))
         {
@@ -2396,7 +2003,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
                     // pragma(msg) is allowed to contain types as well as expressions
                     e = ctfeInterpretForPragmaMsg(e);
-                    if (e.op == TOK.error)
+                    if (e.op == EXP.error)
                     {
                         errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
                         return setError();
@@ -2506,9 +2113,10 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                     return setError();
                 }
 
-                if (e.isBool(true))
+                const opt = e.toBool();
+                if (opt.hasValue(true))
                     inlining = PINLINE.always;
-                else if (e.isBool(false))
+                else if (opt.hasValue(false))
                     inlining = PINLINE.never;
 
                     FuncDeclaration fd = sc.func;
@@ -2565,7 +2173,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
         Type att = null;
         TypeEnum te = null;
-        while (ss.condition.op != TOK.error)
+        while (!ss.condition.isErrorExp())
         {
             // preserve enum type for final switches
             if (ss.condition.type.ty == Tenum)
@@ -2581,7 +2189,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                 break;
             }
             ss.condition = integralPromotions(ss.condition, sc);
-            if (ss.condition.op != TOK.error && ss.condition.type.isintegral())
+            if (!ss.condition.isErrorExp() && ss.condition.type.isintegral())
                 break;
 
             auto ad = isAggregate(ss.condition.type);
@@ -2594,7 +2202,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                 }
             }
 
-            if (ss.condition.op != TOK.error)
+            if (!ss.condition.isErrorExp())
             {
                 ss.error("`%s` must be of integral or string type, it is a `%s`",
                     ss.condition.toChars(), ss.condition.type.toChars());
@@ -2606,7 +2214,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             ss.condition = ErrorExp.get();
         ss.condition = ss.condition.optimize(WANTvalue);
         ss.condition = checkGC(sc, ss.condition);
-        if (ss.condition.op == TOK.error)
+        if (ss.condition.op == EXP.error)
             conditionError = true;
 
         bool needswitcherror = false;
@@ -2869,12 +2477,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             Expression e = cs.exp;
             // Remove all the casts the user and/or implicitCastTo may introduce
             // otherwise we'd sometimes fail the check below.
-            while (e.op == TOK.cast_)
+            while (e.op == EXP.cast_)
                 e = (cast(CastExp)e).e1;
 
             /* This is where variables are allowed as case expressions.
              */
-            if (e.op == TOK.variable)
+            if (e.op == EXP.variable)
             {
                 VarExp ve = cast(VarExp)e;
                 VarDeclaration v = ve.var.isVarDeclaration();
@@ -2924,7 +2532,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
             if (StringExp se = cs.exp.toStringExp())
                 cs.exp = se;
-            else if (cs.exp.op != TOK.int64 && cs.exp.op != TOK.error)
+            else if (!cs.exp.isIntegerExp() && !cs.exp.isErrorExp())
             {
                 cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars());
                 errors = true;
@@ -2982,7 +2590,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             result = cs.statement;
             return;
         }
-        if (errors || cs.exp.op == TOK.error)
+        if (errors || cs.exp.op == EXP.error)
             return setError();
 
         cs.lastVar = sc.lastVar;
@@ -3020,7 +2628,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         crs.last = crs.last.implicitCastTo(sc, sw.condition.type);
         crs.last = crs.last.ctfeInterpret();
 
-        if (crs.first.op == TOK.error || crs.last.op == TOK.error || errors)
+        if (crs.first.op == EXP.error || crs.last.op == EXP.error || errors)
         {
             if (crs.statement)
                 crs.statement.statementSemantic(sc);
@@ -3151,7 +2759,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             gcs.exp = gcs.exp.expressionSemantic(sc);
             gcs.exp = gcs.exp.implicitCastTo(sc, sc.sw.condition.type);
             gcs.exp = gcs.exp.optimize(WANTvalue);
-            if (gcs.exp.op == TOK.error)
+            if (gcs.exp.op == EXP.error)
                 return setError();
         }
 
@@ -3173,7 +2781,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             TypeFunction tf = cast(TypeFunction)fd.type;
         assert(tf.ty == Tfunction);
 
-        if (rs.exp && rs.exp.op == TOK.variable && (cast(VarExp)rs.exp).var == fd.vresult)
+        if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult)
         {
             // return vresult;
             if (sc.fes)
@@ -3250,7 +2858,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             rs.exp.checkSharedAccess(sc, returnSharedRef);
 
             // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-            if (rs.exp.op == TOK.type)
+            if (rs.exp.op == EXP.type)
                 rs.exp = resolveAliasThis(sc, rs.exp);
 
             rs.exp = resolveProperties(sc, rs.exp);
@@ -3266,7 +2874,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
 
             // Extract side-effect part
             rs.exp = Expression.extractLast(rs.exp, e0);
-            if (rs.exp.op == TOK.call)
+            if (rs.exp.op == EXP.call)
                 rs.exp = valueNoDtor(rs.exp);
 
             if (e0)
@@ -3322,7 +2930,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                     else if (m1 && !m2)
                     {
                     }
-                    else if (rs.exp.op != TOK.error)
+                    else if (!rs.exp.isErrorExp())
                     {
                         rs.error("expected return type of `%s`, not `%s`:",
                                  tret.toChars(),
@@ -3508,7 +3116,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         }
         if (e0)
         {
-            if (e0.op == TOK.declaration || e0.op == TOK.comma)
+            if (e0.op == EXP.declaration || e0.op == EXP.comma)
             {
                 rs.exp = Expression.combine(e0, rs.exp);
             }
@@ -3702,7 +3310,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             ss.exp = resolveProperties(sc, ss.exp);
             ss.exp = ss.exp.optimize(WANTvalue);
             ss.exp = checkGC(sc, ss.exp);
-            if (ss.exp.op == TOK.error)
+            if (ss.exp.op == EXP.error)
             {
                 if (ss._body)
                     ss._body = ss._body.statementSemantic(sc);
@@ -3826,15 +3434,15 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         ws.exp = resolveProperties(sc, ws.exp);
         ws.exp = ws.exp.optimize(WANTvalue);
         ws.exp = checkGC(sc, ws.exp);
-        if (ws.exp.op == TOK.error)
+        if (ws.exp.op == EXP.error)
             return setError();
-        if (ws.exp.op == TOK.scope_)
+        if (ws.exp.op == EXP.scope_)
         {
             sym = new WithScopeSymbol(ws);
             sym.parent = sc.scopesym;
             sym.endlinnum = ws.endloc.linnum;
         }
-        else if (ws.exp.op == TOK.type)
+        else if (ws.exp.op == EXP.type)
         {
             Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc);
             if (!s || !s.isScopeDsymbol())
@@ -4133,7 +3741,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         FuncDeclaration fd = sc.parent.isFuncDeclaration();
         fd.hasReturnExp |= 2;
 
-        if (ts.exp.op == TOK.new_)
+        if (ts.exp.op == EXP.new_)
         {
             NewExp ne = cast(NewExp)ts.exp;
             ne.thrownew = true;
@@ -4142,7 +3750,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         ts.exp = ts.exp.expressionSemantic(sc);
         ts.exp = resolveProperties(sc, ts.exp);
         ts.exp = checkGC(sc, ts.exp);
-        if (ts.exp.op == TOK.error)
+        if (ts.exp.op == EXP.error)
             return setError();
 
         checkThrowEscape(sc, ts.exp, false);
@@ -4499,7 +4107,7 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St
 {
     if (auto es = statement.isExpStatement())
     {
-        if (es.exp && es.exp.op == TOK.declaration)
+        if (es.exp && es.exp.op == EXP.declaration)
         {
             auto de = cast(DeclarationExp)es.exp;
             auto v = de.declaration.isVarDeclaration();
@@ -4565,15 +4173,373 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St
     return statement;
 }
 
-
 /*******************
- * See StatementSemanticVisitor.makeTupleForeach.  This is a simple
- * wrapper that returns the generated statements/declarations.
+ * Type check and unroll `foreach` over an expression tuple as well
+ * as `static foreach` statements and `static foreach`
+ * declarations. For `static foreach` statements and `static
+ * foreach` declarations, the visitor interface is used (and the
+ * result is written into the `result` field.) For `static
+ * foreach` declarations, the resulting Dsymbols* are returned
+ * directly.
+ *
+ * The unrolled body is wrapped into a
+ *  - UnrolledLoopStatement, for `foreach` over an expression tuple.
+ *  - ForwardingStatement, for `static foreach` statements.
+ *  - ForwardingAttribDeclaration, for `static foreach` declarations.
+ *
+ * `static foreach` variables are declared as `STC.local`, such
+ * that they are inserted into the local symbol tables of the
+ * forwarding constructs instead of forwarded. For `static
+ * foreach` with multiple foreach loop variables whose aggregate
+ * has been lowered into a sequence of tuples, this function
+ * expands the tuples into multiple `STC.local` `static foreach`
+ * variables.
  */
-auto makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
+public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
 {
-    scope v = new StatementSemanticVisitor(sc);
-    return v.makeTupleForeach!(isStatic, isDecl)(fs, dbody, needExpansion);
+    // Voldemort return type
+    union U
+    {
+        Statement statement;
+        Dsymbols* decl;
+    }
+
+    U result;
+
+    auto returnEarly()
+    {
+        if (isDecl)
+            result.decl = null;
+        else
+            result.statement = new ErrorStatement();
+        return result;
+    }
+
+    auto loc = fs.loc;
+    size_t dim = fs.parameters.dim;
+    const bool skipCheck = isStatic && needExpansion;
+    if (!skipCheck && (dim < 1 || dim > 2))
+    {
+        fs.error("only one (value) or two (key,value) arguments for tuple `foreach`");
+        return returnEarly();
+    }
+
+    Type paramtype = (*fs.parameters)[dim - 1].type;
+    if (paramtype)
+    {
+        paramtype = paramtype.typeSemantic(loc, sc);
+        if (paramtype.ty == Terror)
+        {
+            return returnEarly();
+        }
+    }
+
+    Type tab = fs.aggr.type.toBasetype();
+    TypeTuple tuple = cast(TypeTuple)tab;
+
+    Statements* statements;
+    Dsymbols* declarations;
+    if (isDecl)
+        declarations = new Dsymbols();
+    else
+        statements = new Statements();
+
+    //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars());
+    size_t n;
+    TupleExp te = null;
+    if (fs.aggr.op == EXP.tuple) // expression tuple
+    {
+        te = cast(TupleExp)fs.aggr;
+        n = te.exps.dim;
+    }
+    else if (fs.aggr.op == EXP.type) // type tuple
+    {
+        n = Parameter.dim(tuple.arguments);
+    }
+    else
+        assert(0);
+    foreach (j; 0 .. n)
+    {
+        size_t k = (fs.op == TOK.foreach_) ? j : n - 1 - j;
+        Expression e = null;
+        Type t = null;
+        if (te)
+            e = (*te.exps)[k];
+        else
+            t = Parameter.getNth(tuple.arguments, k).type;
+        Parameter p = (*fs.parameters)[0];
+
+        Statements* stmts;
+        Dsymbols* decls;
+        if (isDecl)
+            decls = new Dsymbols();
+        else
+            stmts = new Statements();
+
+        const bool skip = isStatic && needExpansion;
+        if (!skip && dim == 2)
+        {
+            // Declare key
+            if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
+            {
+                fs.error("no storage class for key `%s`", p.ident.toChars());
+                return returnEarly();
+            }
+
+            if (isStatic)
+            {
+                if (!p.type)
+                {
+                    p.type = Type.tsize_t;
+                }
+            }
+            p.type = p.type.typeSemantic(loc, sc);
+
+            if (!p.type.isintegral())
+            {
+                fs.error("foreach: key cannot be of non-integral type `%s`",
+                         p.type.toChars());
+                return returnEarly();
+            }
+
+            const length = te ? te.exps.length : tuple.arguments.length;
+            IntRange dimrange = IntRange(SignExtendedNumber(length))._cast(Type.tsize_t);
+            // https://issues.dlang.org/show_bug.cgi?id=12504
+            dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
+            if (!IntRange.fromType(p.type).contains(dimrange))
+            {
+                fs.error("index type `%s` cannot cover index range 0..%llu",
+                         p.type.toChars(), cast(ulong)length);
+                return returnEarly();
+            }
+            Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
+            auto var = new VarDeclaration(loc, p.type, p.ident, ie);
+            var.storage_class |= STC.foreach_ | STC.manifest;
+            if (isStatic)
+                var.storage_class |= STC.local;
+
+            if (isDecl)
+                decls.push(var);
+            else
+                stmts.push(new ExpStatement(loc, var));
+
+            p = (*fs.parameters)[1]; // value
+        }
+        /***********************
+         * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
+         *
+         * Params:
+         *     storageClass = The storage class of the variable.
+         *     type = The declared type of the variable.
+         *     ident = The name of the variable.
+         *     e = The initializer of the variable (i.e. the current element of the looped over aggregate).
+         *     t = The type of the initializer.
+         * Returns:
+         *     `true` iff the declaration was successful.
+         */
+        bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t)
+        {
+            if (storageClass & (STC.out_ | STC.lazy_) ||
+                storageClass & STC.ref_ && !te)
+            {
+                fs.error("no storage class for value `%s`", ident.toChars());
+                return false;
+            }
+            Declaration var;
+            if (e)
+            {
+                Type tb = e.type.toBasetype();
+                Dsymbol ds = null;
+                if (!(storageClass & STC.manifest))
+                {
+                    if ((isStatic || tb.ty == Tfunction || storageClass&STC.alias_) && e.op == EXP.variable)
+                        ds = (cast(VarExp)e).var;
+                    else if (e.op == EXP.template_)
+                        ds = (cast(TemplateExp)e).td;
+                    else if (e.op == EXP.scope_)
+                        ds = (cast(ScopeExp)e).sds;
+                    else if (e.op == EXP.function_)
+                    {
+                        auto fe = cast(FuncExp)e;
+                        ds = fe.td ? cast(Dsymbol)fe.td : fe.fd;
+                    }
+                    else if (e.op == EXP.overloadSet)
+                        ds = (cast(OverExp)e).vars;
+                }
+                else if (storageClass & STC.alias_)
+                {
+                    fs.error("`foreach` loop variable cannot be both `enum` and `alias`");
+                    return false;
+                }
+
+                if (ds)
+                {
+                    var = new AliasDeclaration(loc, ident, ds);
+                    if (storageClass & STC.ref_)
+                    {
+                        fs.error("symbol `%s` cannot be `ref`", ds.toChars());
+                        return false;
+                    }
+                    if (paramtype)
+                    {
+                        fs.error("cannot specify element type for symbol `%s`", ds.toChars());
+                        return false;
+                    }
+                }
+                else if (e.op == EXP.type)
+                {
+                    var = new AliasDeclaration(loc, ident, e.type);
+                    if (paramtype)
+                    {
+                        fs.error("cannot specify element type for type `%s`", e.type.toChars());
+                        return false;
+                    }
+                }
+                else
+                {
+                    e = resolveProperties(sc, e);
+                    Initializer ie = new ExpInitializer(Loc.initial, e);
+                    auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
+                    v.storage_class |= STC.foreach_;
+                    if (storageClass & STC.ref_)
+                        v.storage_class |= STC.ref_;
+                    if (isStatic || storageClass&STC.manifest || e.isConst() ||
+                        e.op == EXP.string_ ||
+                        e.op == EXP.structLiteral ||
+                        e.op == EXP.arrayLiteral)
+                    {
+                        if (v.storage_class & STC.ref_)
+                        {
+                            if (!isStatic)
+                            {
+                                fs.error("constant value `%s` cannot be `ref`", ie.toChars());
+                            }
+                            else
+                            {
+                                if (!needExpansion)
+                                {
+                                    fs.error("constant value `%s` cannot be `ref`", ie.toChars());
+                                }
+                                else
+                                {
+                                    fs.error("constant value `%s` cannot be `ref`", ident.toChars());
+                                }
+                            }
+                            return false;
+                        }
+                        else
+                            v.storage_class |= STC.manifest;
+                    }
+                    var = v;
+                }
+            }
+            else
+            {
+                var = new AliasDeclaration(loc, ident, t);
+                if (paramtype)
+                {
+                    fs.error("cannot specify element type for symbol `%s`", fs.toChars());
+                    return false;
+                }
+            }
+            if (isStatic)
+            {
+                var.storage_class |= STC.local;
+            }
+
+            if (isDecl)
+                decls.push(var);
+            else
+                stmts.push(new ExpStatement(loc, var));
+            return true;
+        }
+
+        if (!isStatic)
+        {
+            // Declare value
+            if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
+            {
+                return returnEarly();
+            }
+        }
+        else
+        {
+            if (!needExpansion)
+            {
+                // Declare value
+                if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
+                {
+                    return returnEarly();
+                }
+            }
+            else
+            {   // expand tuples into multiple `static foreach` variables.
+                assert(e && !t);
+                auto ident = Identifier.generateId("__value");
+                declareVariable(0, e.type, ident, e, null);
+                import dmd.cond: StaticForeach;
+                auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length);
+                Expression access = new DotIdExp(loc, e, field);
+                access = expressionSemantic(access, sc);
+                if (!tuple) return returnEarly();
+                //printf("%s\n",tuple.toChars());
+                foreach (l; 0 .. dim)
+                {
+                    auto cp = (*fs.parameters)[l];
+                    Expression init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type.tsize_t));
+                    init_ = init_.expressionSemantic(sc);
+                    assert(init_.type);
+                    declareVariable(p.storageClass, init_.type, cp.ident, init_, null);
+                }
+            }
+        }
+
+        Statement s;
+        Dsymbol d;
+        if (isDecl)
+            decls.append(Dsymbol.arraySyntaxCopy(dbody));
+        else
+        {
+            if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646
+                stmts.push(fs._body.syntaxCopy());
+            s = new CompoundStatement(loc, stmts);
+        }
+
+        if (!isStatic)
+        {
+            s = new ScopeStatement(loc, s, fs.endloc);
+        }
+        else if (isDecl)
+        {
+            import dmd.attrib: ForwardingAttribDeclaration;
+            d = new ForwardingAttribDeclaration(decls);
+        }
+        else
+        {
+            s = new ForwardingStatement(loc, s);
+        }
+
+        if (isDecl)
+            declarations.push(d);
+        else
+            statements.push(s);
+    }
+
+    if (!isStatic)
+    {
+        Statement res = new UnrolledLoopStatement(loc, statements);
+        if (LabelStatement ls = checkLabeledLoop(sc, fs))
+            ls.gotoTarget = res;
+        if (te && te.e0)
+            res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
+        result.statement = res;
+    }
+    else if (isDecl)
+        result.decl = declarations;
+    else
+        result.statement = new CompoundStatement(loc, statements);
+
+    return result;
 }
 
 /*********************************
@@ -4611,16 +4577,16 @@ private Statements* flatten(Statement statement, Scope* sc)
              * expand template mixin in statement scope
              * to handle variable destructors.
              */
-            if (!es.exp || es.exp.op != TOK.declaration)
+            if (!es.exp || !es.exp.isDeclarationExp())
                 return null;
 
-            Dsymbol d = (cast(DeclarationExp)es.exp).declaration;
+            Dsymbol d = es.exp.isDeclarationExp().declaration;
             auto tm = d.isTemplateMixin();
             if (!tm)
                 return null;
 
             Expression e = es.exp.expressionSemantic(sc);
-            if (e.op == TOK.error || tm.errors)
+            if (e.op == EXP.error || tm.errors)
                 return errorStatements();
             assert(tm.members);
 
@@ -4697,7 +4663,7 @@ private Statements* flatten(Statement statement, Scope* sc)
             sfs.sfe.prepare(sc);
             if (sfs.sfe.ready())
             {
-                Statement s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement;
+                Statement s = makeTupleForeach(sc, true, false, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement;
                 auto result = s.flatten(sc);
                 if (result)
                 {
index d1578ec3a121d67452441d30e313dc57b016e53f..6d74ad29a5a471d279e37544b944155bb6ef8e09 100644 (file)
@@ -48,19 +48,19 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
 
     bool impl(Expression e)
     {
-        if (e.op == TOK.not)
+        if (e.isNotExp())
         {
             NotExp ne = cast(NotExp)e;
             return !impl(ne.e1);
         }
 
-        if (e.op == TOK.andAnd || e.op == TOK.orOr)
+        if (e.op == EXP.andAnd || e.op == EXP.orOr)
         {
             LogicalExp aae = cast(LogicalExp)e;
             bool result = impl(aae.e1);
             if (errors)
                 return false;
-            if (e.op == TOK.andAnd)
+            if (e.op == EXP.andAnd)
             {
                 if (!result)
                     return false;
@@ -74,7 +74,7 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
             return !errors && result;
         }
 
-        if (e.op == TOK.question)
+        if (e.op == EXP.question)
         {
             CondExp ce = cast(CondExp)e;
             bool result = impl(ce.econd);
@@ -99,7 +99,7 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
         e = e.optimize(WANTvalue);
 
         if (nerrors != global.errors ||
-            e.op == TOK.error ||
+            e.isErrorExp() ||
             e.type.toBasetype() == Type.terror)
         {
             errors = true;
@@ -108,9 +108,10 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
 
         e = e.ctfeInterpret();
 
-        if (e.isBool(true))
+        const opt = e.toBool();
+        if (opt.hasValue(true))
             return true;
-        else if (e.isBool(false))
+        else if (opt.hasValue(false))
         {
             if (negatives)
                 negatives.push(before);
@@ -171,27 +172,27 @@ private uint visualizeFull(Expression original, Expression instantiated,
     // returns true if satisfied
     bool impl(Expression orig, Expression e, bool inverted, bool orOperand, bool unreached)
     {
-        TOK op = orig.op;
+        EXP op = orig.op;
 
         // lower all 'not' to the bottom
         // !(A && B) -> !A || !B
         // !(A || B) -> !A && !B
         if (inverted)
         {
-            if (op == TOK.andAnd)
-                op = TOK.orOr;
-            else if (op == TOK.orOr)
-                op = TOK.andAnd;
+            if (op == EXP.andAnd)
+                op = EXP.orOr;
+            else if (op == EXP.orOr)
+                op = EXP.andAnd;
         }
 
-        if (op == TOK.not)
+        if (op == EXP.not)
         {
             NotExp no = cast(NotExp)orig;
             NotExp ne = cast(NotExp)e;
             assert(ne);
             return impl(no.e1, ne.e1, !inverted, orOperand, unreached);
         }
-        else if (op == TOK.andAnd)
+        else if (op == EXP.andAnd)
         {
             BinExp bo = cast(BinExp)orig;
             BinExp be = cast(BinExp)e;
@@ -200,7 +201,7 @@ private uint visualizeFull(Expression original, Expression instantiated,
             const r2 = impl(bo.e2, be.e2, inverted, false, unreached || !r1);
             return r1 && r2;
         }
-        else if (op == TOK.orOr)
+        else if (op == EXP.orOr)
         {
             if (!orOperand) // do not indent A || B || C twice
                 indent++;
@@ -214,7 +215,7 @@ private uint visualizeFull(Expression original, Expression instantiated,
                 indent--;
             return r1 || r2;
         }
-        else if (op == TOK.question)
+        else if (op == EXP.question)
         {
             CondExp co = cast(CondExp)orig;
             CondExp ce = cast(CondExp)e;
@@ -308,24 +309,24 @@ private uint visualizeShort(Expression original, Expression instantiated,
 
     bool impl(Expression orig, Expression e, bool inverted)
     {
-        TOK op = orig.op;
+        EXP op = orig.op;
 
         if (inverted)
         {
-            if (op == TOK.andAnd)
-                op = TOK.orOr;
-            else if (op == TOK.orOr)
-                op = TOK.andAnd;
+            if (op == EXP.andAnd)
+                op = EXP.orOr;
+            else if (op == EXP.orOr)
+                op = EXP.andAnd;
         }
 
-        if (op == TOK.not)
+        if (op == EXP.not)
         {
             NotExp no = cast(NotExp)orig;
             NotExp ne = cast(NotExp)e;
             assert(ne);
             return impl(no.e1, ne.e1, !inverted);
         }
-        else if (op == TOK.andAnd)
+        else if (op == EXP.andAnd)
         {
             BinExp bo = cast(BinExp)orig;
             BinExp be = cast(BinExp)e;
@@ -334,7 +335,7 @@ private uint visualizeShort(Expression original, Expression instantiated,
             r = r && impl(bo.e2, be.e2, inverted);
             return r;
         }
-        else if (op == TOK.orOr)
+        else if (op == EXP.orOr)
         {
             BinExp bo = cast(BinExp)orig;
             BinExp be = cast(BinExp)e;
@@ -346,7 +347,7 @@ private uint visualizeShort(Expression original, Expression instantiated,
                 stack.setDim(lbefore); // purge added positive items
             return r;
         }
-        else if (op == TOK.question)
+        else if (op == EXP.question)
         {
             CondExp co = cast(CondExp)orig;
             CondExp ce = cast(CondExp)e;
index 16739addf57355b2a5b70f52f2638bd4040bae27..7a875a5d66315b6daeb73a9fa31337f8ec143ac0 100644 (file)
@@ -27,7 +27,7 @@ module dmd.target;
 
 import dmd.globals : Param;
 
-enum CPU
+enum CPU : ubyte
 {
     x87,
     mmx,
@@ -66,6 +66,7 @@ extern (C++) struct Target
     import dmd.mtype : Type, TypeFunction, TypeTuple;
     import dmd.root.ctfloat : real_t;
     import dmd.statement : Statement;
+    import dmd.tokens : EXP;
 
     /// Bit decoding of the Target.OS
     enum OS : ubyte
@@ -213,7 +214,7 @@ extern (C++) struct Target
      * Returns:
      *      true if the operation is supported or type is not a vector
      */
-    extern (C++) bool isVectorOpSupported(Type type, uint op, Type t2 = null);
+    extern (C++) bool isVectorOpSupported(Type type, EXP op, Type t2 = null);
 
     /**
      * Default system linkage for the target.
index 6a75ccc5ebd8d60d98c4f4476954f8f8c16d4978..13636932078191179d64020a8eb7e4142b44ab7a 100644 (file)
@@ -26,7 +26,7 @@ class Type;
 class TypeTuple;
 class TypeFunction;
 
-enum class CPU
+enum class CPU : unsigned char
 {
     x87,
     mmx,
@@ -194,7 +194,7 @@ public:
     unsigned fieldalign(Type *type);
     Type *va_listType(const Loc &loc, Scope *sc);  // get type of va_list
     int isVectorTypeSupported(int sz, Type *type);
-    bool isVectorOpSupported(Type *type, unsigned op, Type *t2 = NULL);
+    bool isVectorOpSupported(Type *type, EXP op, Type *t2 = NULL);
     // ABI and backend.
     LINK systemLinkage();
     TypeTuple *toArgTypes(Type *t);
index 620492fc0c7161a2ead0e98565e7901a9f85fa47..b462742485675a8b556c3d4a8227a5cd726b5b44 100644 (file)
@@ -87,8 +87,8 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor
                 sc = sc.endCTFE();
                 e = e.implicitCastTo(sc, tvp.valType);
                 e = e.ctfeInterpret();
-                if (e.op == TOK.int64 || e.op == TOK.float64 ||
-                    e.op == TOK.complex80 || e.op == TOK.null_ || e.op == TOK.string_)
+                if (e.op == EXP.int64 || e.op == EXP.float64 ||
+                    e.op == EXP.complex80 || e.op == EXP.null_ || e.op == EXP.string_)
                     tvp.specValue = e;
             }
 
@@ -100,7 +100,7 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor
                 sc = sc.endCTFE();
                 e = e.implicitCastTo(sc, tvp.valType);
                 e = e.ctfeInterpret();
-                if (e.op == TOK.int64)
+                if (e.op == EXP.int64)
                     tvp.defaultValue = e;
             }
         }
index 1ea51a89bff7a9634bc49d14390f20a000ffc8fa..2609af56ac0082430cde77cba4d803ba14b4dea9 100644 (file)
@@ -318,6 +318,157 @@ enum TOK : ushort
     __attribute__,
 }
 
+/// Expression nodes
+enum EXP : ubyte
+{
+    reserved,
+
+    // Other
+    negate,
+    cast_,
+    null_,
+    assert_,
+    true_,
+    false_,
+    array,
+    call,
+    address,
+    type,
+    throw_,
+    new_,
+    delete_,
+    star,
+    symbolOffset,
+    variable,
+    dotVariable,
+    dotIdentifier,
+    dotTemplateInstance,
+    dotType,
+    slice,
+    arrayLength,
+    version_,
+    dollar,
+    template_,
+    dotTemplateDeclaration,
+    declaration,
+    typeof_,
+    pragma_,
+    dSymbol,
+    typeid_,
+    uadd,
+    remove,
+    newAnonymousClass,
+    arrayLiteral,
+    assocArrayLiteral,
+    structLiteral,
+    classReference,
+    thrownException,
+    delegatePointer,
+    delegateFunctionPointer,
+
+    // Operators
+    lessThan,
+    greaterThan,
+    lessOrEqual,
+    greaterOrEqual,
+    equal,
+    notEqual,
+    identity,
+    notIdentity,
+    index,
+    is_,
+
+    leftShift,
+    rightShift,
+    leftShiftAssign,
+    rightShiftAssign,
+    unsignedRightShift,
+    unsignedRightShiftAssign,
+    concatenate,
+    concatenateAssign, // ~=
+    concatenateElemAssign,
+    concatenateDcharAssign,
+    add,
+    min,
+    addAssign,
+    minAssign,
+    mul,
+    div,
+    mod,
+    mulAssign,
+    divAssign,
+    modAssign,
+    and,
+    or,
+    xor,
+    andAssign,
+    orAssign,
+    xorAssign,
+    assign,
+    not,
+    tilde,
+    plusPlus,
+    minusMinus,
+    construct,
+    blit,
+    dot,
+    comma,
+    question,
+    andAnd,
+    orOr,
+    prePlusPlus,
+    preMinusMinus,
+
+    // Leaf operators
+    identifier,
+    string_,
+    this_,
+    super_,
+    halt,
+    tuple,
+    error,
+
+    // Basic types
+    void_,
+    int64,
+    float64,
+    complex80,
+    char_,
+    import_,
+    delegate_,
+    function_,
+    mixin_,
+    in_,
+    default_,
+    break_,
+    continue_,
+    goto_,
+    scope_,
+
+    traits,
+    overloadSet,
+    line,
+    file,
+    fileFullPath,
+    moduleString,   // __MODULE__
+    functionString, // __FUNCTION__
+    prettyFunction, // __PRETTY_FUNCTION__
+    shared_,
+    pow,
+    powAssign,
+    vector,
+
+    voidExpression,
+    cantExpression,
+    showCtfeContext,
+    objcClassReference,
+    vectorArray,
+    arrow,      // ->
+    compoundLiteral, // ( type-name ) { initializer-list }
+    _Generic,
+    interval,
+}
+
 enum FirstCKeyword = TOK.inline;
 
 // Assert that all token enum members have consecutive values and
@@ -1009,12 +1160,17 @@ nothrow:
         return p;
     }
 
-    static const(char)* toChars(uint value)
+    static const(char)* toChars(TOK value)
     {
         return toString(value).ptr;
     }
 
-    extern (D) static string toString(uint value) pure nothrow @nogc @safe
+    static const(char)* toChars(ushort value)
+    {
+        return toString(cast(TOK)value).ptr;
+    }
+
+    extern (D) static string toString(TOK value) pure nothrow @nogc @safe
     {
         return tochars[value];
     }
index d14d0aab5939ea46337906b210ad58cca29a8af8..f3e4411217e626926ba8b8a78149909e4586ca3e 100644 (file)
@@ -32,187 +32,453 @@ class Identifier;
         ?       &&      ||
  */
 
-typedef unsigned short TOK;
-enum
+enum class TOK : unsigned short
 {
-        TOKreserved,
-
-        // Other
-        TOKlparen,      TOKrparen,
-        TOKlbracket,    TOKrbracket,
-        TOKlcurly,      TOKrcurly,
-        TOKcolon,       TOKneg,
-        TOKsemicolon,   TOKdotdotdot,
-        TOKeof,         TOKcast,
-        TOKnull,        TOKassert,
-        TOKtrue,        TOKfalse,
-        TOKarray,       TOKcall,
-        TOKaddress,
-        TOKtype,        TOKthrow,
-        TOKnew,         TOKdelete,
-        TOKstar,        TOKsymoff,
-        TOKvar,         TOKdotvar,
-        TOKdotid,       TOKdotti,
-        TOKdottype,     TOKslice,
-        TOKarraylength, TOKversion,
-        TOKmodule,      TOKdollar,
-        TOKtemplate,    TOKdottd,
-        TOKdeclaration, TOKtypeof,
-        TOKpragma,      TOKdsymbol,
-        TOKtypeid,      TOKuadd,
-        TOKremove,
-        TOKnewanonclass, TOKcomment,
-        TOKarrayliteral, TOKassocarrayliteral,
-        TOKstructliteral,
-        TOKclassreference,
-        TOKthrownexception,
-        TOKdelegateptr,
-        TOKdelegatefuncptr,
-
-// 54
-        // Operators
-        TOKlt,          TOKgt,
-        TOKle,          TOKge,
-        TOKequal,       TOKnotequal,
-        TOKidentity,    TOKnotidentity,
-        TOKindex,       TOKis,
-
-// 64
-        TOKshl,         TOKshr,
-        TOKshlass,      TOKshrass,
-        TOKushr,        TOKushrass,
-        TOKcat,         TOKcatass,      TOKcatelemass,  TOKcatdcharass,     // ~ ~=
-        TOKadd,         TOKmin,         TOKaddass,      TOKminass,
-        TOKmul,         TOKdiv,         TOKmod,
-        TOKmulass,      TOKdivass,      TOKmodass,
-        TOKand,         TOKor,          TOKxor,
-        TOKandass,      TOKorass,       TOKxorass,
-        TOKassign,      TOKnot,         TOKtilde,
-        TOKplusplus,    TOKminusminus,  TOKconstruct,   TOKblit,
-        TOKdot,         TOKcomma,
-        TOKquestion,    TOKandand,      TOKoror,
-        TOKpreplusplus, TOKpreminusminus,
-
-// 105
-        // Numeric literals
-        TOKint32v, TOKuns32v,
-        TOKint64v, TOKuns64v,
-        TOKint128v, TOKuns128v,
-        TOKfloat32v, TOKfloat64v, TOKfloat80v,
-        TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
-
-        // Char constants
-        TOKcharv, TOKwcharv, TOKdcharv,
-
-        // Leaf operators
-        TOKidentifier,  TOKstring, TOKxstring,
-        TOKthis,        TOKsuper,
-        TOKhalt,        TOKtuple,
-        TOKerror,
-
-        // Basic types
-        TOKvoid,
-        TOKint8, TOKuns8,
-        TOKint16, TOKuns16,
-        TOKint32, TOKuns32,
-        TOKint64, TOKuns64,
-        TOKint128, TOKuns128,
-        TOKfloat32, TOKfloat64, TOKfloat80,
-        TOKimaginary32, TOKimaginary64, TOKimaginary80,
-        TOKcomplex32, TOKcomplex64, TOKcomplex80,
-        TOKchar, TOKwchar, TOKdchar, TOKbool,
-
-// 152
-        // Aggregates
-        TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
-        TOKalias, TOKoverride, TOKdelegate, TOKfunction,
-        TOKmixin,
-
-        TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
-        TOKstatic, TOKfinal, TOKconst, TOKabstract,
-        TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
-        TOKauto, TOKpackage, TOKimmutable,
-
-// 182
-        // Statements
-        TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
-        TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
-        TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
-        TOKasm, TOKforeach, TOKforeach_reverse,
-        TOKscope,
-        TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
-
-// 206
-        // Contracts
-        TOKinvariant,
-
-        // Testing
-        TOKunittest,
-
-        // Added after 1.0
-        TOKargTypes,
-        TOKref,
-        TOKmacro,
-
-// 211
-        TOKparameters,
-        TOKtraits,
-        TOKoverloadset,
-        TOKpure,
-        TOKnothrow,
-        TOKgshared,
-        TOKline,
-        TOKfile,
-        TOKfilefullpath,
-        TOKmodulestring,
-        TOKfuncstring,
-        TOKprettyfunc,
-        TOKshared,
-        TOKat,
-        TOKpow,
-        TOKpowass,
-        TOKgoesto,
-        TOKvector,
-        TOKpound,
-
-// 230
-        TOKinterval,
-        TOKvoidexp,
-        TOKcantexp,
-        TOKshowctfecontext,
-
-        TOKobjc_class_reference,
-        TOKvectorarray,
-
-        TOKarrow,
-        TOKcolonColon,
-        TOKwchar_tLiteral,
-        TOKcompoundLiteral,
-
-        TOKinline,
-        TOKregister,
-        TOKrestrict,
-        TOKsigned,
-        TOKsizeof_,
-        TOKtypedef_,
-        TOKunsigned,
-        TOKvolatile,
-        TOK_Alignas,
-        TOK_Alignof,
-        TOK_Atomic,
-        TOK_Bool,
-        TOK_Complex,
-        TOK_Generic,
-        TOK_Imaginary,
-        TOK_Noreturn,
-        TOK_Static_assert,
-        TOK_Thread_local,
-
-        TOK__cdecl,
-        TOK__declspec,
-        TOK__attribute__,
-
-        TOKMAX
+    reserved,
+
+    // Other
+    leftParenthesis,
+    rightParenthesis,
+    leftBracket,
+    rightBracket,
+    leftCurly,
+    rightCurly,
+    colon,
+    negate,
+    semicolon,
+    dotDotDot,
+    endOfFile,
+    cast_,
+    null_,
+    assert_,
+    true_,
+    false_,
+    array,
+    call,
+    address,
+    type,
+    throw_,
+    new_,
+    delete_,
+    star,
+    symbolOffset,
+    variable,
+    dotVariable,
+    dotIdentifier,
+    dotTemplateInstance,
+    dotType,
+    slice,
+    arrayLength,
+    version_,
+    module_,
+    dollar,
+    template_,
+    dotTemplateDeclaration,
+    declaration,
+    typeof_,
+    pragma_,
+    dSymbol,
+    typeid_,
+    uadd,
+    remove,
+    newAnonymousClass,
+    comment,
+    arrayLiteral,
+    assocArrayLiteral,
+    structLiteral,
+    classReference,
+    thrownException,
+    delegatePointer,
+    delegateFunctionPointer,
+
+    // Operators
+    lessThan,       // 54
+    greaterThan,
+    lessOrEqual,
+    greaterOrEqual,
+    equal,
+    notEqual,
+    identity,
+    notIdentity,
+    index,
+    is_,
+
+    leftShift,      // 64
+    rightShift,
+    leftShiftAssign,
+    rightShiftAssign,
+    unsignedRightShift,
+    unsignedRightShiftAssign,
+    concatenate,
+    concatenateAssign, // ~=
+    concatenateElemAssign,
+    concatenateDcharAssign,
+    add,
+    min,
+    addAssign,
+    minAssign,
+    mul,
+    div,
+    mod,
+    mulAssign,
+    divAssign,
+    modAssign,
+    and_,
+    or_,
+    xor_,
+    andAssign,
+    orAssign,
+    xorAssign,
+    assign,
+    not_,
+    tilde,
+    plusPlus,
+    minusMinus,
+    construct,
+    blit,
+    dot,
+    comma,
+    question,
+    andAnd,
+    orOr,
+    prePlusPlus,
+    preMinusMinus,
+
+    // Numeric literals
+    int32Literal,   // 104,
+    uns32Literal,
+    int64Literal,
+    uns64Literal,
+    int128Literal,
+    uns128Literal,
+    float32Literal,
+    float64Literal,
+    float80Literal,
+    imaginary32Literal,
+    imaginary64Literal,
+    imaginary80Literal,
+
+    // Char constants
+    charLiteral,    // 116,
+    wcharLiteral,
+    dcharLiteral,
+
+    // Leaf operators
+    identifier,     // 119,
+    string_,
+    hexadecimalString,
+    this_,
+    super_,
+    halt,
+    tuple,
+    error,
+
+    // Basic types
+    void_,          // 127
+    int8,
+    uns8,
+    int16,
+    uns16,
+    int32,
+    uns32,
+    int64,
+    uns64,
+    int128,
+    uns128,
+    float32,
+    float64,
+    float80,
+    imaginary32,
+    imaginary64,
+    imaginary80,
+    complex32,
+    complex64,
+    complex80,
+    char_,
+    wchar_,
+    dchar_,
+    bool_,
+
+    // Aggregates
+    struct_,        // 151
+    class_,
+    interface_,
+    union_,
+    enum_,
+    import_,
+    alias_,
+    override_,
+    delegate_,
+    function_,
+    mixin_,
+    align_,
+    extern_,
+    private_,
+    protected_,
+    public_,
+    export_,
+    static_,
+    final_,
+    const_,
+    abstract_,
+    debug_,
+    deprecated_,
+    in_,
+    out_,
+    inout_,
+    lazy_,
+    auto_,
+    package_,
+    immutable_,
+
+    // Statements
+    if_,            // 181
+    else_,
+    while_,
+    for_,
+    do_,
+    switch_,
+    case_,
+    default_,
+    break_,
+    continue_,
+    with_,
+    synchronized_,
+    return_,
+    goto_,
+    try_,
+    catch_,
+    finally_,
+    asm_,
+    foreach_,
+    foreach_reverse_,
+    scope_,
+    onScopeExit,
+    onScopeFailure,
+    onScopeSuccess,
+
+    // Contracts
+    invariant_,     // 205
+
+    // Testing
+    unittest_,
+
+    // Added after 1.0
+    argumentTypes,
+    ref_,
+    macro_,
+
+    parameters,     // 210
+    traits,
+    overloadSet,
+    pure_,
+    nothrow_,
+    gshared,
+    line,
+    file,
+    fileFullPath,
+    moduleString,   // __MODULE__
+    functionString, // __FUNCTION__
+    prettyFunction, // __PRETTY_FUNCTION__
+    shared_,
+    at,
+    pow,
+    powAssign,
+    goesTo,
+    vector,
+    pound,
+
+    interval,       // 229
+    voidExpression,
+    cantExpression,
+    showCtfeContext,
+
+    objcClassReference,
+    vectorArray,
+
+    arrow,      // ->
+    colonColon, // ::
+    wchar_tLiteral,
+    compoundLiteral, // ( type-name ) { initializer-list }
+
+    // C only keywords
+    inline_,
+    register_,
+    restrict_,
+    signed_,
+    sizeof_,
+    typedef_,
+    unsigned_,
+    volatile_,
+    _Alignas_,
+    _Alignof_,
+    _Atomic_,
+    _Bool_,
+    _Complex_,
+    _Generic_,
+    _Imaginary_,
+    _Noreturn_,
+    _Static_assert_,
+    _Thread_local_,
+
+    // C only extended keywords
+    cdecl,
+    declspec,
+    attribute__,
+
+    MAX,
+};
+
+enum class EXP : unsigned char
+{
+    reserved,
+
+    // Other
+    negate,
+    cast_,
+    null_,
+    assert_,
+    true_,
+    false_,
+    array,
+    call,
+    address,
+    type,
+    throw_,
+    new_,
+    delete_,
+    star,
+    symbolOffset,
+    variable,
+    dotVariable,
+    dotIdentifier,
+    dotTemplateInstance,
+    dotType,
+    slice,
+    arrayLength,
+    version_,
+    dollar,
+    template_,
+    dotTemplateDeclaration,
+    declaration,
+    typeof_,
+    pragma_,
+    dSymbol,
+    typeid_,
+    uadd,
+    remove,
+    newAnonymousClass,
+    arrayLiteral,
+    assocArrayLiteral,
+    structLiteral,
+    classReference,
+    thrownException,
+    delegatePointer,
+    delegateFunctionPointer,
+
+    // Operators
+    lessThan,
+    greaterThan,
+    lessOrEqual,
+    greaterOrEqual,
+    equal,
+    notEqual,
+    identity,
+    notIdentity,
+    index,
+    is_,
+
+    leftShift,
+    rightShift,
+    leftShiftAssign,
+    rightShiftAssign,
+    unsignedRightShift,
+    unsignedRightShiftAssign,
+    concatenate,
+    concatenateAssign, // ~=
+    concatenateElemAssign,
+    concatenateDcharAssign,
+    add,
+    min,
+    addAssign,
+    minAssign,
+    mul,
+    div,
+    mod,
+    mulAssign,
+    divAssign,
+    modAssign,
+    and_,
+    or_,
+    xor_,
+    andAssign,
+    orAssign,
+    xorAssign,
+    assign,
+    not_,
+    tilde,
+    plusPlus,
+    minusMinus,
+    construct,
+    blit,
+    dot,
+    comma,
+    question,
+    andAnd,
+    orOr,
+    prePlusPlus,
+    preMinusMinus,
+
+    // Leaf operators
+    identifier,
+    string_,
+    this_,
+    super_,
+    halt,
+    tuple,
+    error,
+
+    // Basic types
+    void_,
+    int64,
+    float64,
+    complex80,
+    char_,
+    import_,
+    delegate_,
+    function_,
+    mixin_,
+    in_,
+    default_,
+    break_,
+    continue_,
+    goto_,
+    scope_,
+
+    traits,
+    overloadSet,
+    line,
+    file,
+    fileFullPath,
+    moduleString,   // __MODULE__
+    functionString, // __FUNCTION__
+    prettyFunction, // __PRETTY_FUNCTION__
+    shared_,
+    pow,
+    powAssign,
+    vector,
+
+    voidExpression,
+    cantExpression,
+    showCtfeContext,
+    objcClassReference,
+    vectorArray,
+    arrow,      // ->
+    compoundLiteral, // ( type-name ) { initializer-list }
+    _Generic_,
+    interval,
+
+    MAX
 };
 
 #define TOKwild TOKinout
@@ -255,7 +521,7 @@ struct Token
     int isKeyword();
     const char *toChars() const;
 
-    static const char *toChars(unsigned value);
+    static const char *toChars(TOK value);
 };
 
 #if defined(__GNUC__)
index cc1d2e351e634cfef1b9753aa1d654d658d6d9c9..7b9a8c8fdff24bd198fa75118943ca1c1c5b347f 100644 (file)
@@ -80,9 +80,9 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
 {
     if (auto e = isExpression(oarg))
     {
-        if (e.op == TOK.dotVariable)
+        if (e.op == EXP.dotVariable)
             return (cast(DotVarExp)e).var;
-        if (e.op == TOK.dotTemplateDeclaration)
+        if (e.op == EXP.dotTemplateDeclaration)
             return (cast(DotTemplateExp)e).td;
     }
     return getDsymbol(oarg);
@@ -569,7 +569,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
     {
         if (global.params.vcomplex)
         {
-            if (isTypeX(t => t.iscomplex() || t.isimaginary()).isBool(true))
+            if (isTypeX(t => t.iscomplex() || t.isimaginary()).toBool().hasValue(true))
                 return True();
         }
         return isDsymX(t => t.isDeprecated());
@@ -998,7 +998,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
                 e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars());
                 return ErrorExp.get();
             }
-            includeTemplates = b.isBool(true);
+            includeTemplates = b.toBool().hasValue(true);
         }
 
         StringExp se = ex.toStringExp();
@@ -1055,7 +1055,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
         }
         else if (e.ident == Id.getMember)
         {
-            if (ex.op == TOK.dotIdentifier)
+            if (ex.op == EXP.dotIdentifier)
                 // Prevent semantic() from replacing Symbol with its initializer
                 (cast(DotIdExp)ex).wantsym = true;
             ex = ex.expressionSemantic(scx);
@@ -1085,7 +1085,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
             {
                 if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration())
                     f = dve.var;
-                if (dve.e1.op == TOK.dotType || dve.e1.op == TOK.this_)
+                if (dve.e1.op == EXP.dotType || dve.e1.op == EXP.this_)
                     ex = null;
                 else
                     ex = dve.e1;
@@ -1105,7 +1105,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
                 if (td && td.funcroot)
                     f = td.funcroot;
                 ex = null;
-                if (dte.e1.op != TOK.dotType && dte.e1.op != TOK.this_)
+                if (dte.e1.op != EXP.dotType && dte.e1.op != EXP.this_)
                     ex = dte.e1;
             }
             bool[string] funcTypeHash;
@@ -1290,7 +1290,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
                 Expression x = isExpression(o);
                 Type t = isType(o);
                 if (x)
-                    printf("e = %s %s\n", Token.toChars(x.op), x.toChars());
+                    printf("e = %s %s\n", EXPtoString(x.op).ptr, x.toChars());
                 if (t)
                     printf("t = %d %s\n", t.ty, t.toChars());
             }
@@ -1792,7 +1792,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
                         err |= tf.isnothrow && canThrow(ex, sc2.func, false);
                     }
                     ex = checkGC(sc2, ex);
-                    if (ex.op == TOK.error)
+                    if (ex.op == EXP.error)
                         err = true;
                 }
             }
@@ -1919,6 +1919,27 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
     {
         return pointerBitmap(e);
     }
+    if (e.ident == Id.initSymbol)
+    {
+        if (dim != 1)
+            return dimError(1);
+
+        auto o = (*e.args)[0];
+        Type t = isType(o);
+        AggregateDeclaration ad = t ? isAggregate(t) : null;
+
+        // Interfaces don't have an init symbol and hence cause linker errors
+        if (!ad || ad.isInterfaceDeclaration())
+        {
+            e.error("struct / class type expected as argument to __traits(initSymbol) instead of `%s`", o.toChars());
+            return ErrorExp.get();
+        }
+
+        Declaration d = new SymbolDeclaration(ad.loc, ad);
+        d.type = Type.tvoid.arrayOf().constOf();
+        d.storage_class |= STC.rvalue;
+        return new VarExp(e.loc, d);
+    }
     if (e.ident == Id.isZeroInit)
     {
         if (dim != 1)
@@ -2105,7 +2126,7 @@ private bool isSame(RootObject o1, RootObject o2, Scope* sc)
         }
         else if (auto ea = isExpression(oarg))
         {
-            if (ea.op == TOK.function_)
+            if (ea.op == EXP.function_)
             {
                 if (auto fe = cast(FuncExp)ea)
                     return fe.fd;
index f75ae0e0b5af9ab203f4f8afe0424e1b746c15b1..417d2c11af4900d2588e7f5dc8dd0674d91234ec 100644 (file)
@@ -153,7 +153,7 @@ private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expr
 
     eindex = semanticLength(sc, tup, eindex);
     eindex = eindex.ctfeInterpret();
-    if (eindex.op == TOK.error)
+    if (eindex.op == EXP.error)
     {
         pt = Type.terror;
         return;
@@ -386,7 +386,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
          *  enum a = 1; alias b = a;
          *  template X(alias e){ alias v = e; }  alias x = X!(1);
          *  struct S { int v; alias w = v; }
-         *      // TypeIdentifier 'a', 'e', and 'v' should be TOK.variable,
+         *      // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
          *      // because getDsymbol() need to work in AliasDeclaration::semantic().
          */
         if (!v.type ||
@@ -602,7 +602,7 @@ Expression typeToExpression(Type t)
  */
 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
 {
-    //printf("toExpressionHelper(e = %s %s)\n", Token.toChars(e.op), e.toChars());
+    //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
     foreach (id; t.idents[i .. t.idents.dim])
     {
         //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
@@ -722,7 +722,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         {
             mtype.dim = semanticLength(sc, tup, mtype.dim);
             mtype.dim = mtype.dim.ctfeInterpret();
-            if (mtype.dim.op == TOK.error)
+            if (mtype.dim.op == EXP.error)
                 return error();
 
             uinteger_t d = mtype.dim.toUInteger();
@@ -758,7 +758,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
 
             mtype.dim = mtype.dim.optimize(WANTvalue);
             mtype.dim = mtype.dim.ctfeInterpret();
-            if (mtype.dim.op == TOK.error)
+            if (mtype.dim.op == EXP.error)
                 return error();
 
             errors = global.errors;
@@ -768,7 +768,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
 
             mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
             mtype.dim = mtype.dim.optimize(WANTvalue);
-            if (mtype.dim.op == TOK.error)
+            if (mtype.dim.op == EXP.error)
                 return error();
 
             errors = global.errors;
@@ -776,7 +776,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             if (errors != global.errors)
                 return error();
 
-            if (mtype.dim.op == TOK.error)
+            if (mtype.dim.op == EXP.error)
                 return error();
 
             Type overflowError()
@@ -1273,7 +1273,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                 iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
                 e = iz.initializerToExpression();
             }
-            if (e.op == TOK.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
+            if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
             {
                 FuncExp fe = cast(FuncExp)e;
                 // Replace function literal with a function symbol,
@@ -1299,7 +1299,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                 e = e.toLvalue(sc, e);
 
             fparam.defaultArg = e;
-            return (e.op != TOK.error);
+            return (e.op != EXP.error);
         }
 
         ubyte wildparams = 0;
@@ -1707,7 +1707,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                     .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
                 //assert(0);
             }
-            else if (e.op == TOK.variable) // special case: variable is used as a type
+            else if (e.op == EXP.variable) // special case: variable is used as a type
             {
                 Dsymbol varDecl = mtype.toDsymbol(sc);
                 const(Loc) varDeclLoc = varDecl.getLoc();
@@ -1814,29 +1814,29 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         {
             switch (e.op)
             {
-            case TOK.dotVariable:
+            case EXP.dotVariable:
                 mtype.sym = (cast(DotVarExp)e).var;
                 break;
-            case TOK.variable:
+            case EXP.variable:
                 mtype.sym = (cast(VarExp)e).var;
                 break;
-            case TOK.function_:
+            case EXP.function_:
                 auto fe = cast(FuncExp)e;
                 mtype.sym = fe.td ? fe.td : fe.fd;
                 break;
-            case TOK.dotTemplateDeclaration:
+            case EXP.dotTemplateDeclaration:
                 mtype.sym = (cast(DotTemplateExp)e).td;
                 break;
-            case TOK.dSymbol:
+            case EXP.dSymbol:
                 mtype.sym = (cast(DsymbolExp)e).s;
                 break;
-            case TOK.template_:
+            case EXP.template_:
                 mtype.sym = (cast(TemplateExp)e).td;
                 break;
-            case TOK.scope_:
+            case EXP.scope_:
                 mtype.sym = (cast(ScopeExp)e).sds;
                 break;
-            case TOK.tuple:
+            case EXP.tuple:
                 TupleExp te = e.toTupleExp();
                 Objects* elems = new Objects(te.exps.dim);
                 foreach (i; 0 .. elems.dim)
@@ -1844,13 +1844,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                     auto src = (*te.exps)[i];
                     switch (src.op)
                     {
-                    case TOK.type:
+                    case EXP.type:
                         (*elems)[i] = (cast(TypeExp)src).type;
                         break;
-                    case TOK.dotType:
+                    case EXP.dotType:
                         (*elems)[i] = (cast(DotTypeExp)src).sym.isType();
                         break;
-                    case TOK.overloadSet:
+                    case EXP.overloadSet:
                         (*elems)[i] = (cast(OverExp)src).type;
                         break;
                     default:
@@ -1863,13 +1863,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
                 mtype.sym = td;
                 break;
-            case TOK.dotType:
+            case EXP.dotType:
                 result = (cast(DotTypeExp)e).sym.isType();
                 break;
-            case TOK.type:
+            case EXP.type:
                 result = (cast(TypeExp)e).type;
                 break;
-            case TOK.overloadSet:
+            case EXP.overloadSet:
                 result = (cast(OverExp)e).type;
                 break;
             default:
@@ -1979,7 +1979,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         mtype.upr = semanticLength(sc, tbn, mtype.upr);
         mtype.lwr = mtype.lwr.ctfeInterpret();
         mtype.upr = mtype.upr.ctfeInterpret();
-        if (mtype.lwr.op == TOK.error || mtype.upr.op == TOK.error)
+        if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
             return error();
 
         uinteger_t i1 = mtype.lwr.toUInteger();
@@ -2861,7 +2861,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
             {
                 mt.dim = semanticLength(sc, tup, mt.dim);
                 mt.dim = mt.dim.ctfeInterpret();
-                if (mt.dim.op == TOK.error)
+                if (mt.dim.op == EXP.error)
                     return returnError();
 
                 const d = mt.dim.toUInteger();
@@ -2879,7 +2879,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
                 if (o.dyncast() == DYNCAST.expression)
                 {
                     Expression e = cast(Expression)o;
-                    if (e.op == TOK.dSymbol)
+                    if (e.op == EXP.dSymbol)
                         return returnSymbol((cast(DsymbolExp)e).s);
                     else
                         return returnExp(e);
@@ -3124,7 +3124,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
         exp2 = resolvePropertiesOnly(sc2, exp2);
         sc2.pop();
 
-        if (exp2.op == TOK.error)
+        if (exp2.op == EXP.error)
         {
             if (!global.gag)
                 mt.exp = exp2;
@@ -3132,8 +3132,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
         }
         mt.exp = exp2;
 
-        if (mt.exp.op == TOK.type ||
-            mt.exp.op == TOK.scope_)
+        if (mt.exp.op == EXP.type ||
+            mt.exp.op == EXP.scope_)
         {
             if (mt.exp.checkType())
                 goto Lerr;
@@ -3145,8 +3145,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
              * template functions.
              */
         }
-        if (auto f = mt.exp.op == TOK.variable    ? (cast(   VarExp)mt.exp).var.isFuncDeclaration()
-                   : mt.exp.op == TOK.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null)
+        if (auto f = mt.exp.op == EXP.variable    ? (cast(   VarExp)mt.exp).var.isFuncDeclaration()
+                   : mt.exp.op == EXP.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null)
         {
             // f might be a unittest declaration which is incomplete when compiled
             // without -unittest. That causes a segfault in checkForwardRef, see
@@ -3377,12 +3377,12 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
         }
         Expression ex = e.lastComma();
-        if (ex.op == TOK.dotVariable)
+        if (ex.op == EXP.dotVariable)
         {
             DotVarExp dv = cast(DotVarExp)ex;
             v = dv.var.isVarDeclaration();
         }
-        else if (ex.op == TOK.variable)
+        else if (ex.op == EXP.variable)
         {
             VarExp ve = cast(VarExp)ex;
             v = ve.var.isVarDeclaration();
@@ -3552,9 +3552,9 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         {
             printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
         }
-        if (ident == Id.ptr && e.op == TOK.call)
+        if (ident == Id.ptr && e.op == EXP.call)
         {
-            /* The trouble with TOK.call is the return ABI for float[4] is different from
+            /* The trouble with EXP.call is the return ABI for float[4] is different from
              * __vector(float[4]), and a type paint won't do.
              */
             e = new AddrExp(e.loc, e);
@@ -3618,7 +3618,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         }
         else if (ident == Id.ptr)
         {
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
             {
                 e.error("`%s` is not an expression", e.toChars());
                 return ErrorExp.get();
@@ -3644,19 +3644,19 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         {
             printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
         }
-        if (e.op == TOK.type && (ident == Id.length || ident == Id.ptr))
+        if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
         {
             e.error("`%s` is not an expression", e.toChars());
             return ErrorExp.get();
         }
         if (ident == Id.length)
         {
-            if (e.op == TOK.string_)
+            if (e.op == EXP.string_)
             {
                 StringExp se = cast(StringExp)e;
                 return new IntegerExp(se.loc, se.len, Type.tsize_t);
             }
-            if (e.op == TOK.null_)
+            if (e.op == EXP.null_)
             {
                 return new IntegerExp(e.loc, 0, Type.tsize_t);
             }
@@ -3864,7 +3864,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                 if (!gagError)
                 {
                     global.endGagging(errors);
-                    if (exp && exp.op == TOK.error)
+                    if (exp && exp.op == EXP.error)
                         exp = null;
                 }
 
@@ -3886,7 +3886,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         {
             printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
         }
-        assert(e.op != TOK.dot);
+        assert(e.op != EXP.dot);
 
         // https://issues.dlang.org/show_bug.cgi?id=14010
         if (ident == Id._mangleof)
@@ -3909,7 +3909,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             }
 
             Expression e0;
-            Expression ev = e.op == TOK.type ? null : e;
+            Expression ev = e.op == EXP.type ? null : e;
             if (ev)
                 ev = extractSideEffect(sc, "__tup", e0, ev);
 
@@ -4003,7 +4003,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         TemplateDeclaration td = s.isTemplateDeclaration();
         if (td)
         {
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
                 e = new TemplateExp(e.loc, td);
             else
                 e = new DotTemplateExp(e.loc, e, td);
@@ -4024,7 +4024,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             s = ti.inst.toAlias();
             if (!s.isTemplateInstance())
                 goto L1;
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
                 e = new ScopeExp(e.loc, ti);
             else
                 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
@@ -4040,7 +4040,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         if (o)
         {
             auto oe = new OverExp(e.loc, o);
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
             {
                 return oe;
             }
@@ -4054,7 +4054,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             return ErrorExp.get();
         }
 
-        if (e.op == TOK.type)
+        if (e.op == EXP.type)
         {
             /* It's:
              *    Struct.d
@@ -4084,7 +4084,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             return ve;
         }
 
-        bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField();
+        bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
         if (d.isDataseg() || unreal && d.isField())
         {
             // (e, d)
@@ -4146,7 +4146,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         {
             printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
         }
-        assert(e.op != TOK.dot);
+        assert(e.op != EXP.dot);
 
         // https://issues.dlang.org/show_bug.cgi?id=12543
         if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
@@ -4167,7 +4167,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             mt.sym.size(e.loc); // do semantic of type
 
             Expression e0;
-            Expression ev = e.op == TOK.type ? null : e;
+            Expression ev = e.op == EXP.type ? null : e;
             if (ev)
                 ev = extractSideEffect(sc, "__tup", e0, ev);
 
@@ -4207,7 +4207,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             // See if it's a 'this' class or a base class
             if (mt.sym.ident == ident)
             {
-                if (e.op == TOK.type)
+                if (e.op == EXP.type)
                 {
                     return mt.Type.getProperty(sc, e.loc, ident, 0);
                 }
@@ -4217,7 +4217,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             }
             if (auto cbase = mt.sym.searchBase(ident))
             {
-                if (e.op == TOK.type)
+                if (e.op == EXP.type)
                 {
                     return mt.Type.getProperty(sc, e.loc, ident, 0);
                 }
@@ -4238,7 +4238,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                 }
 
                 Type t = Type.typeinfoclass.type;
-                if (e.op == TOK.type || e.op == TOK.dotType)
+                if (e.op == EXP.type || e.op == EXP.dotType)
                 {
                     /* For type.classinfo, we know the classinfo
                      * at compile time.
@@ -4412,7 +4412,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
 
         Expression toTemplateExp(TemplateDeclaration td)
         {
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
                 e = new TemplateExp(e.loc, td);
             else
                 e = new DotTemplateExp(e.loc, e, td);
@@ -4439,7 +4439,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             s = ti.inst.toAlias();
             if (!s.isTemplateInstance())
                 goto L1;
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
                 e = new ScopeExp(e.loc, ti);
             else
                 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
@@ -4456,7 +4456,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         if (o)
         {
             auto oe = new OverExp(e.loc, o);
-            if (e.op == TOK.type)
+            if (e.op == EXP.type)
             {
                 return oe;
             }
@@ -4470,7 +4470,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
             return ErrorExp.get();
         }
 
-        if (e.op == TOK.type)
+        if (e.op == EXP.type)
         {
             /* It's:
              *    Class.d
@@ -4589,7 +4589,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                 assert(0);
         }
 
-        bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField();
+        bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
         if (d.isDataseg() || unreal && d.isField())
         {
             // (e, d)
@@ -4750,7 +4750,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc)
             Parameter p = (*mt.arguments)[i];
             assert(p.type);
             Expression e = p.type.defaultInitLiteral(loc);
-            if (e.op == TOK.error)
+            if (e.op == EXP.error)
             {
                 return e;
             }
@@ -4818,7 +4818,7 @@ private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identif
 
     static Expression pvalToResult(Expression e, const ref Loc loc)
     {
-        if (e.op != TOK.error)
+        if (e.op != EXP.error)
         {
             e = e.copy();
             e.loc = loc;
@@ -4902,12 +4902,12 @@ private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identif
              *      maxval = e;
              */
             Expression e = em.value;
-            Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval);
+            Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
             ed.inuse++;
             ec = ec.expressionSemantic(em._scope);
             ed.inuse--;
             ec = ec.ctfeInterpret();
-            if (ec.op == TOK.error)
+            if (ec.op == EXP.error)
             {
                 ed.errors = true;
                 continue;
index 8e1d43e2b8f80a06a72e9b6cd93232579f74e3be..f1c014dbc168861021220116892e75e6b0692c44 100644 (file)
@@ -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;
index b14b0ca5111e06d1256f0624e57c0dcd86ae4a67..dec2bd47265b04f1e5c764c109ae8e29c8ae778b 100644 (file)
@@ -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);
     }
 
index d0a5e2f685966c22981c37fa35b4b40a80372ceb..893bc238631a77fdb3b430f346e07745d531c733 100644 (file)
@@ -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.
index fdff6db06260bef21a87097d3644d051890bef90..3961a1d9bed37354593fc6083163c63d3b2f2196 100644 (file)
@@ -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),
index 55d63f89cb7915783fc942d75b34fb722faff3e2..17b63ba8a7d7597b4a2585927f4c5f031994c89b 100644 (file)
@@ -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))
          {
index b39b92eb822668ce08657ba1194d58b060dbca22..1d551e5249bd2015a97ba33c2eea56ee9f11f9d8 100644 (file)
@@ -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);
diff --git a/gcc/testsuite/gdc.test/compilable/covariant_override.d b/gcc/testsuite/gdc.test/compilable/covariant_override.d
new file mode 100644 (file)
index 0000000..1afe0a2
--- /dev/null
@@ -0,0 +1,34 @@
+// https://issues.dlang.org/show_bug.cgi?id=21538
+// REQUIRED_ARGS: -preview=dip1000
+
+interface I
+{
+    void f(void delegate() @safe dg) @safe;
+}
+
+class CI : I
+{
+    override void f(void delegate() @system dg) @safe { }
+}
+
+abstract class A
+{
+    void f(void delegate() @safe dg) @safe;
+}
+
+class CA : A
+{
+    override void f(void delegate() @system dg) @safe { }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20904
+auto blah(void delegate())
+{
+}
+
+void delegate()[string] r;
+void main()
+{
+    void delegate() nothrow a;
+    r["v"] = a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/emptygenmain.d b/gcc/testsuite/gdc.test/compilable/emptygenmain.d
new file mode 100644 (file)
index 0000000..be7bee8
--- /dev/null
@@ -0,0 +1,3 @@
+// REQUIRED_ARGS: -main -c
+
+void foo() { }
index b041e072e9c2cb0833f904423768ec00a4fb5410..22734cf48b3c13bdf36ef2fd21ee00f826e602e7 100644 (file)
@@ -111,3 +111,15 @@ void* useTls()
     void* a3 = &globalNoreturn;
     return a1 < a2 ? a2 : a3;
 }
+
+/***************************************************/
+
+noreturn testfn(noreturn function() fn)
+{
+    fn();
+}
+
+noreturn testdg(noreturn delegate() dg)
+{
+    dg();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17870.d b/gcc/testsuite/gdc.test/compilable/test17870.d
new file mode 100644 (file)
index 0000000..2329b60
--- /dev/null
@@ -0,0 +1,26 @@
+alias AliasSeq(T...) = T;
+
+class A
+{
+    int z = 3;
+}
+
+class B : A
+{
+    int a = 1;
+}
+
+class C : B
+{
+    int b = 2;
+    alias tup = AliasSeq!(b, a, z);
+}
+
+void main()
+{
+    static const ins = new C;
+    static assert(&ins.tup[0] == &ins.b);
+    static assert(&ins.tup[1] == &ins.a);
+    static assert(&ins.tup[2] == &ins.z);
+    static assert(ins.tup == AliasSeq!(2,1,3));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19873.d b/gcc/testsuite/gdc.test/compilable/test19873.d
new file mode 100644 (file)
index 0000000..7252edd
--- /dev/null
@@ -0,0 +1,37 @@
+// PERMUTE_ARGS -preview=dip1000
+// https://issues.dlang.org/show_bug.cgi?id=19873
+int* ed(scope int* x)
+{
+    auto y = x;
+    return y;
+}
+
+int* et(scope int* x) @trusted
+{
+    auto y = x;
+    return y;
+}
+
+int* es(scope int* x) @system
+{
+    auto y = x;
+    return y;
+}
+
+auto ad(scope int* x)
+{
+    auto y = x;
+    return y;
+}
+
+auto at(scope int* x) @trusted
+{
+    auto y = x;
+    return y;
+}
+
+auto as(scope int* x) @system
+{
+    auto y = x;
+    return y;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21719.d b/gcc/testsuite/gdc.test/compilable/test21719.d
new file mode 100644 (file)
index 0000000..9d444e1
--- /dev/null
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=21719
+
+struct S
+{
+    auto f()
+    {
+    } // inferred to be @safe @nogc pure nothrow
+}
+
+class C
+{
+    auto f() // should also infer the same attributes
+    {
+    }
+}
+
+pure @nogc nothrow @safe void test(S s, C c)
+{
+    s.f;
+    c.f;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22254.d b/gcc/testsuite/gdc.test/compilable/test22254.d
new file mode 100644 (file)
index 0000000..94f6596
--- /dev/null
@@ -0,0 +1,19 @@
+// https://issues.dlang.org/show_bug.cgi?id=22254
+
+struct Template(T) { T t; }
+
+Template!Bar a;
+Template!Bar b;
+
+immutable struct Bar { }
+
+static assert(is(typeof(a) == typeof(b)));
+static assert(is(typeof(a) == Template!(immutable Bar)));
+
+Template!C c1;
+Template!C c2;
+
+immutable class C { }
+
+static assert(is(typeof(c1) == typeof(c2)));
+static assert(is(typeof(c1) == Template!(immutable C)));
diff --git a/gcc/testsuite/gdc.test/compilable/test22510.d b/gcc/testsuite/gdc.test/compilable/test22510.d
new file mode 100644 (file)
index 0000000..af5d0a4
--- /dev/null
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=22510
+
+struct S
+{
+       int b;
+
+    @disable this(this);
+    this (scope ref inout S) inout
+    {
+       this.b = b;
+    }
+}
+
+void main()
+{
+       auto scoped_s = S(4);
+       auto heap_s = new S(42);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/covariant_override.d b/gcc/testsuite/gdc.test/fail_compilation/covariant_override.d
new file mode 100644 (file)
index 0000000..7738770
--- /dev/null
@@ -0,0 +1,35 @@
+/++
+https://issues.dlang.org/show_bug.cgi?id=21538
+
+TEST_OUTPUT:
+---
+fail_compilation/covariant_override.d(23): Error: function `@safe void covariant_override.CI.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.I.f(void delegate() @system dg)`?
+fail_compilation/covariant_override.d(34): Error: function `@safe void covariant_override.CA.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.A.f(void delegate() @system dg)`?
+fail_compilation/covariant_override.d(20): Error: class `covariant_override.CI` interface function `void f(void delegate() @system dg) @safe` is not implemented
+---
+++/
+
+static assert(!is(void delegate() @system : void delegate() @safe));
+static assert( is(void delegate() @safe : void delegate() @system));
+
+interface I
+{
+    void f(void delegate() @system dg) @safe;
+}
+
+class CI : I
+{
+    // this overrride should not be legal
+    override void f(void delegate() @safe dg) @safe { }
+}
+
+abstract class A
+{
+    void f(void delegate() @system dg) @safe;
+}
+
+class CA : A
+{
+    // this overrride should not be legal
+    override void f(void delegate() @safe dg) @safe { }
+}
index de3673f7860de589119d005b02fc0f046019489d..4b31a92f9ab3480f824c853287418d33d311efa4 100644 (file)
@@ -5,8 +5,8 @@ fail_compilation/fail10964.d(28): Error: function `fail10964.S.__postblit` is no
 fail_compilation/fail10964.d(29): Error: function `fail10964.S.__postblit` is not `nothrow`
 fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is not `nothrow`
 fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not `nothrow`
-fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not `nothrow`
-fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(34): Error: function `core.internal.array.construction._d_arraysetctor!(S[], S)._d_arraysetctor` is not `nothrow`
+fail_compilation/fail10964.d(35): Error: function `core.internal.array.construction._d_arrayctor!(S[], S)._d_arrayctor` is not `nothrow`
 fail_compilation/fail10964.d(22): Error: `nothrow` function `fail10964.foo` may throw
 ---
 */
index 06e0687ce39e7babf6a51d38957530d43b9b4aab..d9f554a4b78b1c5d2eef7133640ea7d3f5997d64 100644 (file)
@@ -1,24 +1,26 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail10968.d(39): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(39): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27):        `fail10968.SA.__postblit` is declared here
-fail_compilation/fail10968.d(40): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(40): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27):        `fail10968.SA.__postblit` is declared here
 fail_compilation/fail10968.d(41): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
 fail_compilation/fail10968.d(41): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27):        `fail10968.SA.__postblit` is declared here
-fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27):        `fail10968.SA.__postblit` is declared here
-fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(29):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(42): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(42): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(43): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(43): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29):        `fail10968.SA.__postblit` is declared here
 fail_compilation/fail10968.d(46): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
 fail_compilation/fail10968.d(46): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(29):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(47): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor`
+fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29):        `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor`
 ---
 */
 
@@ -49,12 +51,12 @@ void bar() pure @safe
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail10968.d(72): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
-fail_compilation/fail10968.d(73): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
 fail_compilation/fail10968.d(74): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
-fail_compilation/fail10968.d(77): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
-fail_compilation/fail10968.d(78): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(75): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(76): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
 fail_compilation/fail10968.d(79): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(80): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(81): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
 ---
 */
 
index a8f3ae453dbad617fcd96a9997ae12370ba0e2e3..279d9da6dfc2141eae26f56367525487687745d7 100644 (file)
@@ -1,25 +1,25 @@
 /*
-REQUIRED_ARGS: -de
+REQUIRED_ARGS: -de -revert=intpromote
 TEST_OUTPUT:
 ---
-fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, use '-preview=intpromote' switch or `~cast(int)(c)`
-fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, use '-preview=intpromote' switch or `-cast(int)(c)`
-fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, use '-preview=intpromote' switch or `+cast(int)(c)`
-fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, use '-preview=intpromote' switch or `~cast(int)(w)`
-fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, use '-preview=intpromote' switch or `-cast(int)(w)`
-fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, use '-preview=intpromote' switch or `+cast(int)(w)`
-fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, use '-preview=intpromote' switch or `~cast(int)(sb)`
-fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, use '-preview=intpromote' switch or `-cast(int)(sb)`
-fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, use '-preview=intpromote' switch or `+cast(int)(sb)`
-fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, use '-preview=intpromote' switch or `~cast(int)(ub)`
-fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, use '-preview=intpromote' switch or `-cast(int)(ub)`
-fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, use '-preview=intpromote' switch or `+cast(int)(ub)`
-fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, use '-preview=intpromote' switch or `~cast(int)(s)`
-fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, use '-preview=intpromote' switch or `-cast(int)(s)`
-fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, use '-preview=intpromote' switch or `+cast(int)(s)`
-fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, use '-preview=intpromote' switch or `~cast(int)(us)`
-fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, use '-preview=intpromote' switch or `-cast(int)(us)`
-fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, use '-preview=intpromote' switch or `+cast(int)(us)`
+fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, remove '-revert=intpromote' switch or `~cast(int)(c)`
+fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, remove '-revert=intpromote' switch or `-cast(int)(c)`
+fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, remove '-revert=intpromote' switch or `+cast(int)(c)`
+fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, remove '-revert=intpromote' switch or `~cast(int)(w)`
+fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, remove '-revert=intpromote' switch or `-cast(int)(w)`
+fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, remove '-revert=intpromote' switch or `+cast(int)(w)`
+fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, remove '-revert=intpromote' switch or `~cast(int)(sb)`
+fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, remove '-revert=intpromote' switch or `-cast(int)(sb)`
+fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, remove '-revert=intpromote' switch or `+cast(int)(sb)`
+fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, remove '-revert=intpromote' switch or `~cast(int)(ub)`
+fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, remove '-revert=intpromote' switch or `-cast(int)(ub)`
+fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, remove '-revert=intpromote' switch or `+cast(int)(ub)`
+fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, remove '-revert=intpromote' switch or `~cast(int)(s)`
+fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, remove '-revert=intpromote' switch or `-cast(int)(s)`
+fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, remove '-revert=intpromote' switch or `+cast(int)(s)`
+fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, remove '-revert=intpromote' switch or `~cast(int)(us)`
+fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, remove '-revert=intpromote' switch or `-cast(int)(us)`
+fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, remove '-revert=intpromote' switch or `+cast(int)(us)`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail809.d b/gcc/testsuite/gdc.test/fail_compilation/fail809.d
deleted file mode 100644 (file)
index b83639b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// REQUIRED_ARGS: -preview=dip1000
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail809.d(11): Error: scope variable `dg_` may not be returned
----
-*/
-int delegate() test(lazy int dg)
-{
-    int delegate() dg_ = &dg;
-    return dg_;
-}
index dbe8ea2f883d2d870cefbdb62993b09413d4f922..175ade3cafcac39c597744ab570f986a346da792 100644 (file)
@@ -120,7 +120,7 @@ fail_compilation/fob2.d(515): Error: variable `fob2.test52.p` has undefined stat
 }
 
 
-@live void test52()
+@live void test52() @safe
 {
     int x = 5;
     auto p = &x;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d
new file mode 100644 (file)
index 0000000..c3e8a78
--- /dev/null
@@ -0,0 +1,10 @@
+module imports.test20023b;
+
+auto threw()() @safe
+{
+    try
+        throw new Exception("Hello");
+    catch (Exception e)
+        return e;
+    assert(0);
+}
index 58f0430f5ad5dd30042d2ac545344b81b4222fe1..64db4c811962eeb83834d2820f0a5a7a26cc743a 100644 (file)
@@ -14,14 +14,14 @@ fail_compilation/retscope.d(49): Error: address of struct temporary returned by
 
 
 
-int* foo1(return scope int* p) { return p; } // ok
+int* foo1(return scope int* p) @safe { return p; } // ok
 
-int* foo2()(scope int* p) { return p; }  // ok, 'return' is inferred
+int* foo2()(scope int* p) @safe { return p; }  // ok, 'return' is inferred
 alias foo2a = foo2!();
 
-int* foo3(scope int* p) { return p; }   // error
+int* foo3(scope int* p) @safe { return p; }   // error
 
-int* foo4(bool b)
+int* foo4(bool b) @safe
 {
     int i;
     int j;
index 173473a6675d4467537dd589e4e6f075be636019..1b3078ff05194902a6e23c3c2c08079ff4d69b79 100644 (file)
@@ -1,18 +1,52 @@
 /* TEST_OUTPUT:
+PERMUTE_ARGS -dip1000
 ---
-fail_compilation/test15191.d(17): Error: cannot take address of `ref return` of `foo()` in `@safe` function `bar`
+fail_compilation/test15191.d(31): Error: returning `&identity(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(37): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(43): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive`
+fail_compilation/test15191.d(43): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
 ---
 */
 
-
 // https://issues.dlang.org/show_bug.cgi?id=15191
+// https://issues.dlang.org/show_bug.cgi?id=22519
 
-ref int foo(return ref int s)@safe
+@safe:
+ref int foo(return ref int s)
 {
     return s;
 }
 
-int* bar(return ref int s) @safe
+int* bar(return ref int s)
 {
     return &foo(s);
 }
+
+ref int identity(ref return int x) {return x;}
+ref int* identityPtr(ref return int* x) {return x;}
+
+int* addrOfRefEscape()
+{
+       int x;
+       return &identity(x);
+}
+
+int** addrOfRefSystem() @system
+{
+       int* x;
+       return &identityPtr(x);
+}
+
+int** addrOfRefTransitive()
+{
+       int* x;
+       return &identityPtr(x);
+}
+
+int gInt;
+ref int getGlobalInt() {return gInt;}
+
+int* addrOfRefGlobal()
+{
+       return &getGlobalInt();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17977.d b/gcc/testsuite/gdc.test/fail_compilation/test17977.d
new file mode 100644 (file)
index 0000000..ff6bc1c
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=15399
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test17977.d(19): Error: address of variable `__slList3` assigned to `elem` with longer lifetime
+---
+*/
+
+@safe:
+struct List {
+    int* data;
+    ~this();
+    int* front() return;
+}
+
+void test()
+{
+    auto elem = List().front;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20023.d b/gcc/testsuite/gdc.test/fail_compilation/test20023.d
new file mode 100644 (file)
index 0000000..909e699
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRED_ARGS: -preview=dip1000 -preview=dip1008 -Ifail_compilation/extra-files
+// https://issues.dlang.org/show_bug.cgi?id=20023
+/*
+TEST_OUTPUT:
+---
+fail_compilation/imports/test20023b.d(8): Error: scope variable `e` may not be returned
+fail_compilation/test20023.d(15): Error: template instance `imports.test20023b.threw!()` error instantiating
+---
+*/
+import imports.test20023b;
+
+@safe:
+void main()
+{
+    threw!()();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d b/gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d
new file mode 100644 (file)
index 0000000..94ff80a
--- /dev/null
@@ -0,0 +1,63 @@
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(105): Error: struct / class type expected as argument to __traits(initSymbol) instead of `int`
+fail_compilation/traits_initSymbol.d(106): Error: struct / class type expected as argument to __traits(initSymbol) instead of `S[2]`
+fail_compilation/traits_initSymbol.d(107): Error: struct / class type expected as argument to __traits(initSymbol) instead of `123`
+---
+*/
+#line 100
+
+struct S { int i = 4; }
+
+void test1()
+{
+    const void[] initInt   = __traits(initSymbol, int);
+    const void[] initArray = __traits(initSymbol, S[2]);
+    const void[] initValue = __traits(initSymbol, 123);
+}
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(203): Error: cannot determine the address of the initializer symbol during CTFE
+fail_compilation/traits_initSymbol.d(203):        called from here: `(*function () pure nothrow @nogc @safe => S)()`
+---
+*/
+#line 200
+
+void test2()
+{
+    enum initLen = (() => __traits(initSymbol, S))();
+}
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(305): Error: struct / class type expected as argument to __traits(initSymbol) instead of `traits_initSymbol.Interface`
+---
+*/
+#line 300
+
+interface Interface {}
+
+void test3()
+{
+    const void[] initInterface = __traits(initSymbol, Interface);
+}
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(404): Error: expected 1 arguments for `initSymbol` but had 0
+fail_compilation/traits_initSymbol.d(405): Error: expected 1 arguments for `initSymbol` but had 2
+---
+*/
+#line 400
+
+
+void test4()
+{
+    const void[] tmp = __traits(initSymbol);
+    const void[] tmo = __traits(initSymbol, Interface, S);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b19294.d b/gcc/testsuite/gdc.test/runnable/b19294.d
new file mode 100644 (file)
index 0000000..5700195
--- /dev/null
@@ -0,0 +1,163 @@
+alias T = MyStruct!float;
+
+struct MyStruct(U)
+{
+    U x;
+    U y;
+
+    this(U xx, U yy)
+    {
+        x = xx;
+        y = yy;
+    }
+
+    MyStruct!U opBinary(string op)(MyStruct!U z) const
+    {
+        alias C = typeof(return);
+        auto w = C(this.x, this.y);
+        return w.opOpAssign!(op)(z);
+    }
+
+    MyStruct!U opBinaryRight(string op)(MyStruct!U z) const
+    {
+        return opBinary!(op)(z);
+    }
+
+    ref MyStruct opOpAssign(string op, U)(const MyStruct!U z)
+    {
+        mixin ("x "~op~"= z.x;");
+        mixin ("y "~op~"= z.y;");
+        return this;
+    }
+
+    MyStruct!U opBinary(string op, R)(R z) const
+        if (is(R == int) || is(R == float))
+    {
+        alias C = typeof(return);
+        auto w = C(this.x, this.y);
+        return w.opOpAssign!(op)(z);
+    }
+
+    MyStruct!U opBinaryRight(string op, R)(R z) const
+        if (is(R == int) || is(R == float))
+    {
+        return opBinary!(op)(z);
+    }
+
+    ref MyStruct opOpAssign(string op, R)(const R z)
+        if (is(R == int) || is(R == float))
+    {
+        mixin ("x "~op~"= z;");
+        return this;
+    }
+}
+
+void main()
+{
+    T c = MyStruct!float(1.0f, 1.0f);
+    T[] arr = [T(1,1), T(2,2), T(3,3), T(4,4), T(5,5), T(6,6)];
+    T[] result = new T[arr.length];
+
+    // part 2
+
+    result[0] = c * c;
+    assert(result[0] == T(1, 1));
+
+    result[0] = arr[1] * arr[2];
+    assert(result[0] == T(6, 6));
+
+    int[] intarr = [6, 5, 4, 3, 2, 1];
+
+    result[] = arr[] * arr[];
+    assert(result[] == [T(1, 1), T(4, 4), T(9, 9), T(16, 16), T(25, 25), T(36, 36)]);
+
+    result[] = arr[] * 3;
+    assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+    result[] = 3 * arr[];
+    assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+    result[] = arr[];
+    result[1..3] = arr[1..3] * 2.0f;
+    assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(4, 4), T(5, 5), T(6, 6)]);
+    result[1..3] = 2.0f * arr[1..3];
+    assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(4, 4), T(5, 5), T(6, 6)]);
+
+    result[] = arr[];
+    result[1..$] = arr[1..$] * 2.0f;
+    assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(8, 4), T(10, 5), T(12, 6)]);
+    result[1..$] = 2.0f * arr[1..$];
+    assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(8, 4), T(10, 5), T(12, 6)]);
+
+    result[] = intarr[] * arr[];
+    assert(result[] == [T(6, 1), T(10, 2), T(12, 3), T(12, 4), T(10, 5), T(6, 6)]);
+    result[] = arr[] * intarr[];
+    assert(result[] == [T(6, 1), T(10, 2), T(12, 3), T(12, 4), T(10, 5), T(6, 6)]);
+
+    result[] = intarr[] * T(2,3);
+    assert(result[] == [T(12, 3), T(10, 3), T(8, 3), T(6, 3), T(4, 3), T(2, 3)]);
+    result[] = T(2,3) * intarr[];
+    assert(result[] == [T(12, 3), T(10, 3), T(8, 3), T(6, 3), T(4, 3), T(2, 3)]);
+
+    result[] = intarr[] * c;
+    assert(result[] == [T(6, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+    result[] = c * intarr[];
+    assert(result[] == [T(6, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+
+    result[] = arr[];
+    result[1..3] = intarr[1..3] * c;
+    assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(4, 4), T(5, 5), T(6, 6)]);
+    result[1..3] = c * intarr[1..3];
+    assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(4, 4), T(5, 5), T(6, 6)]);
+
+    result[1..$] = intarr[1..$] * c;
+    assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+    result[1..$] = c * intarr[1..$];
+    assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+
+    result[] = arr[];
+    result[1..3] = intarr[1..3] * arr[1..3];
+    assert(result[] == [T(1, 1), T(10, 2), T(12, 3), T(4, 4), T(5, 5), T(6, 6)]);
+    result[1..3] = arr[1..3] * intarr[1..3];
+    assert(result[] == [T(1, 1), T(10, 2), T(12, 3), T(4, 4), T(5, 5), T(6, 6)]);
+
+    result[] = [1,2,3,4,5,6] * c;
+    assert(result[] == [T(1, 1), T(2, 1), T(3, 1), T(4, 1), T(5, 1), T(6, 1)]);
+    result[] = c * [1,2,3,4,5,6];
+    assert(result[] == [T(1, 1), T(2, 1), T(3, 1), T(4, 1), T(5, 1), T(6, 1)]);
+
+    result[] = arr[] * [1,2,3,4,5,6];
+    assert(result[] == [T(1, 1), T(4, 2), T(9, 3), T(16, 4), T(25, 5), T(36, 6)]);
+    result[] = [1,2,3,4,5,6] *  arr[];
+    assert(result[] == [T(1, 1), T(4, 2), T(9, 3), T(16, 4), T(25, 5), T(36, 6)]);
+
+    result[] = [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c] * [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c];
+    assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]);
+
+    result[] = [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c] * [1,2,3,4,5,6];
+    assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]);
+    result[] = [1,2,3,4,5,6] * [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c];
+    assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]);
+
+    result[] = arr[] * c;
+    assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]);
+    result[] = c * arr[];
+    assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]);
+
+    result[] = c * 3.0f * arr[];
+    assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+    result[] = 3.0f * c * arr[];
+    assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+    result[] = arr[] * 3.0f * c;
+    assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+    // result[] = arr[] * c * 3.0f; //not ok
+    // assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+    result[] = 3.0f * arr[] * c;
+    assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+    // result[] = c * arr[] * 3.0f; //not ok
+    // assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+    result[] = c * arr[] * c;
+    assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]);
+}
index 4f38f4d33229ec87ede1443f7fa744ad52b74dc4..30aa9503b09caa8732dc7f18fa62934208c96854 100644 (file)
@@ -1,5 +1,5 @@
 /*
-REQUIRED_ARGS: -mcpu=native -preview=intpromote
+REQUIRED_ARGS: -mcpu=native
 PERMUTE_ARGS: -O -inline -release
 */
 
diff --git a/gcc/testsuite/gdc.test/runnable/test15862.d b/gcc/testsuite/gdc.test/runnable/test15862.d
new file mode 100644 (file)
index 0000000..87e2560
--- /dev/null
@@ -0,0 +1,39 @@
+// https://issues.dlang.org/show_bug.cgi?id=15862
+
+/*
+PERMUTE_ARGS:
+REQUIRED_ARGS: -O -release
+*/
+
+
+int* p() pure nothrow {return new int;}
+int[] a() pure nothrow {return [0];}
+Object o() pure nothrow {return new Object;}
+
+auto pa() pure nothrow {return new int;}
+
+void main()
+{
+    {
+        int* p1 = p();
+        int* p2 = p();
+
+        if (p1 is p2) assert(0);
+
+        int[] a1 = a();
+        int[] a2 = a();
+
+        if (a1 is a2) assert(0);
+
+        Object o1 = o();
+        Object o2 = o();
+
+        if (o1 is o2) assert(0);
+    }
+    {
+        auto p1 = pa();
+        auto p2 = pa();
+
+        if (p1 is p2) assert(0);
+    }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21367.d b/gcc/testsuite/gdc.test/runnable/test21367.d
new file mode 100644 (file)
index 0000000..96e8d6c
--- /dev/null
@@ -0,0 +1,47 @@
+// https://issues.dlang.org/show_bug.cgi?id=21367
+
+string result = "";
+
+struct RCArray(T)
+{
+    T* data;
+    this(this)
+    {
+        result ~= "A";
+    }
+    ~this()
+    {
+        result ~= "B";
+    }
+}
+
+struct Variant(T...)
+{
+    union
+    {
+        T payload;
+    }
+    this(this)
+    {
+        result ~= "C";
+    }
+
+    ~this()
+    {
+        result ~= "D";
+    }
+}
+
+alias Ft = Variant!(RCArray!double, RCArray!int);
+
+void fun(Ft a) {}
+void main()
+{
+    Ft a;
+    Ft b = a;
+}
+
+static ~this()
+{
+    assert(result == "CDD");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test22227.d b/gcc/testsuite/gdc.test/runnable/test22227.d
new file mode 100644 (file)
index 0000000..7ef53c3
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRED_ARGS: -debug -O -release
+// https://issues.dlang.org/show_bug.cgi?id=22277
+
+bool secret = false;
+
+void free(immutable void* x) pure nothrow
+{
+    debug secret = true;
+}
+
+void main()
+{
+    free(null);
+    if (!secret)
+        assert(0);
+}
index 7b884e5857cde1767f6bf7167dfc2725582e1ea6..285365eea82e36b53254a724e6a9a63f49dccbd3 100644 (file)
@@ -1,4 +1,4 @@
-/* PERMUTE_ARGS:
+/* PERMUTE_ARGS: -preview=dip1000
  */
 
 // https://issues.dlang.org/show_bug.cgi?id=15624
@@ -140,3 +140,32 @@ void testInverseAttributes()
     }
     safe();
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=20907
+Lockstep!() lockstep()
+{
+    return Lockstep!()();
+}
+
+struct Lockstep()
+{
+    int opApply(int delegate(int) callback) @system
+    {
+        return 0;
+    }
+
+    int opApply(int delegate(int) pure nothrow @nogc @safe callback) pure nothrow @nogc @safe
+    {
+        return 0;
+    }
+}
+
+void foo0()
+{
+    foreach (x; lockstep()) {}
+}
+
+void foo1()
+{
+    foreach (x; lockstep()) {}
+}
index b5c7f7d1855fc6ad079b64bac86bb6312b1513c7..617e3fb11cc058aff7b4180d5664e5a076d7fdc3 100644 (file)
@@ -1,5 +1,5 @@
 /*
-REQUIRED_ARGS: -mcpu=native -preview=intpromote
+REQUIRED_ARGS: -mcpu=native
 PERMUTE_ARGS: -O -inline -release
 */
 
index 5c0e75de60f0749d9ab7d00cc1ada8de128477b6..764bb1b045e6e86fc546d40a042ca6b2c9b5a2b3 100644 (file)
@@ -2860,9 +2860,11 @@ static assert(is(S7038b == shared));
 immutable struct S7038c{ int x; }
 static assert(is(S7038c == immutable));
 
-static assert(!is(C7038 == const));
+// https://issues.dlang.org/show_bug.cgi?id=22515
+// Classes fixed for consistency with structs
+static assert(is(C7038 == const));
 const class C7038{ int x; }
-static assert(!is(C7038 == const));
+static assert(is(C7038 == const));
 
 void test7038()
 {
@@ -2871,7 +2873,7 @@ void test7038()
     static assert(is(typeof(s.x) == const int));
 
     C7038 c;
-    static assert(!is(typeof(c) == const));
+    static assert(is(typeof(c) == const));
     static assert(is(typeof(c.x) == const int));
 }
 
diff --git a/gcc/testsuite/gdc.test/runnable/traits_initSymbol.d b/gcc/testsuite/gdc.test/runnable/traits_initSymbol.d
new file mode 100644 (file)
index 0000000..0385d98
--- /dev/null
@@ -0,0 +1,119 @@
+struct Zero
+{
+    int x;
+}
+
+void testZero()
+{
+    auto zeroInit = __traits(initSymbol, Zero);
+    static assert(is(typeof(zeroInit) == const(void[])));
+
+    assert(zeroInit.ptr is null);
+    assert(zeroInit.length == Zero.sizeof);
+}
+
+struct NonZero
+{
+    long x = 1;
+}
+
+void testNonZero()
+{
+    auto nonZeroInit = __traits(initSymbol, NonZero);
+    static assert(is(typeof(nonZeroInit) == const(void[])));
+
+    assert(nonZeroInit.ptr);
+    assert(nonZeroInit.length == NonZero.sizeof);
+    assert(cast(const(long[])) nonZeroInit == [1L]);
+}
+
+class C
+{
+    short x = 123;
+}
+
+void testClass()
+{
+    auto cInit = __traits(initSymbol, C);
+    static assert(is(typeof(cInit) == const(void[])));
+
+    assert(cInit.ptr);
+    assert(cInit.length == __traits(classInstanceSize, C));
+
+    scope c = new C;
+    assert((cast(void*) c)[0 .. cInit.length] == cInit);
+}
+
+struct AlignedStruct
+{
+    short s = 5;
+    // 2 byte padding
+    align(4) char c = 'c';
+    // 3 byte padding
+    int i = 4;
+    // reduced alignment
+    align(1) long l = 0xDEADBEEF;
+}
+
+void testAlignedStruct()
+{
+    auto init = __traits(initSymbol, AlignedStruct);
+
+    assert(init.ptr);
+    assert(init.length == AlignedStruct.sizeof);
+
+    version (GNU)
+        AlignedStruct exp = AlignedStruct();
+    else
+        AlignedStruct exp;
+    assert(init == (cast(void*) &exp)[0 .. AlignedStruct.sizeof]);
+
+}
+
+class AlignedClass : C
+{
+    short s = 5;
+    // 2 byte padding
+    align(4) char c = 'c';
+    // 3 byte padding
+    int i = 4;
+    // reduced alignment
+    align(1) long l = 0xDEADBEEF;
+}
+
+void testAlignedClass()
+{
+    auto init = __traits(initSymbol, AlignedClass);
+
+    assert(init.ptr);
+    assert(init.length == __traits(classInstanceSize, AlignedClass));
+
+    scope ac = new AlignedClass();
+    assert(init == (cast(void*) ac)[0 .. init.length]);
+}
+
+extern (C++) class ExternCppClass
+{
+    int i = 4;
+}
+
+void testExternCppClass()
+{
+    auto init = __traits(initSymbol, ExternCppClass);
+
+    assert(init.ptr);
+    assert(init.length == __traits(classInstanceSize, ExternCppClass));
+
+    scope ac = new ExternCppClass();
+    assert(init == (cast(void*) ac)[0 .. init.length]);
+}
+
+void main()
+{
+    testZero();
+    testNonZero();
+    testClass();
+    testAlignedStruct();
+    testAlignedClass();
+    testExternCppClass();
+}
index 20cc225759a09b366df821c1f25c89e8e4edfa55..4fe6b00eba72360f5b7f0e8922feac16b3384112 100644 (file)
@@ -4903,7 +4903,7 @@ static assert(is(typeof(S5933d.x) == FuncType5933));
 
 
 class C5933a { auto x() { return 0; } }
-static assert(is(typeof(&(new C5933b()).x) == int delegate()));
+static assert(is(typeof(&(new C5933b()).x) == int delegate() pure nothrow @nogc @safe));
 
 class C5933b { auto x() { return 0; } }
 //static assert(is(typeof((new C5933b()).x) == FuncType5933));
@@ -7923,8 +7923,9 @@ void test17349()
 {
     static struct S
     {
-        int bar(void delegate(ref int*)) { return 1; }
-        int bar(void delegate(ref const int*)) const { return 2; }
+        // Specify attribute inferred for dg1/dg2
+        int bar(void delegate(ref int*) pure nothrow @nogc @safe) { return 1; }
+        int bar(void delegate(ref const int*) pure nothrow @nogc @safe) const { return 2; }
     }
 
     void dg1(ref int*) { }
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp
new file mode 100644 (file)
index 0000000..f3a9a85
--- /dev/null
@@ -0,0 +1,103 @@
+#include <stdarg.h>
+#include <assert.h>
+
+class C1
+{
+public:
+    virtual ~C1();
+
+    int i;
+
+    int f0();
+    int f1(int a);
+    int f2(int a, int b);
+    virtual int f3(int a, int b);
+    int f4(int a, ...);
+};
+
+C1::~C1()
+{
+}
+
+int C1::f0()
+{
+    return i;
+}
+
+int C1::f1(int a)
+{
+    return i + a;
+}
+
+int C1::f2(int a, int b)
+{
+    return i + a + b;
+}
+
+int C1::f3(int a, int b)
+{
+    return i + a + b;
+}
+
+int C1::f4(int a, ...)
+{
+    int r = i + a;
+    int last = a;
+
+    va_list argp;
+    va_start(argp, a);
+    while (last)
+    {
+        last = va_arg(argp, int);
+        r += last;
+    }
+    va_end(argp);
+    return r;
+}
+
+C1 *createC1()
+{
+    return new C1();
+}
+
+class C2
+{
+public:
+    virtual ~C2();
+
+    int i;
+
+    int f0();
+    int f1(int a);
+    int f2(int a, int b);
+    virtual int f3(int a, int b);
+    int f4(int a, ...);
+};
+
+C2 *createC2();
+
+void runCPPTests()
+{
+    C2 *c2 = createC2();
+    c2->i = 100;
+    assert(c2->f0() == 100);
+    assert(c2->f1(1) == 101);
+    assert(c2->f2(20, 3) == 123);
+    assert(c2->f3(20, 3) == 123);
+    assert(c2->f4(20, 3, 0) == 123);
+
+    int (C2::*fp0)() = &C2::f0;
+    int (C2::*fp1)(int) = &C2::f1;
+    int (C2::*fp2)(int, int) = &C2::f2;
+    int (C2::*fp3)(int, int) = &C2::f3;
+#ifndef __DMC__
+    int (C2::*fp4)(int, ...) = &C2::f4;
+#endif
+    assert((c2->*(fp0))() == 100);
+    assert((c2->*(fp1))(1) == 101);
+    assert((c2->*(fp2))(20, 3) == 123);
+    assert((c2->*(fp3))(20, 3) == 123);
+#ifndef __DMC__
+    assert((c2->*(fp4))(20, 3, 0) == 123);
+#endif
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test7925.d b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d
new file mode 100644 (file)
index 0000000..2f52826
--- /dev/null
@@ -0,0 +1,151 @@
+// EXTRA_CPP_SOURCES: cpp7925.cpp
+
+/*
+Exclude -O due to a codegen bug on OSX:
+https://issues.dlang.org/show_bug.cgi?id=22556
+
+PERMUTE_ARGS(osx): -inline -release -g
+*/
+
+import core.vararg;
+
+extern(C++) class C1
+{
+public:
+    ~this();
+
+    int i;
+
+    final int f0();
+    final int f1(int a);
+    final int f2(int a, int b);
+    int f3(int a, int b);
+    final int f4(int a, ...);
+};
+
+extern(C++) C1 createC1();
+
+extern(C++) class C2
+{
+public:
+    ~this()
+    {
+    }
+
+    int i;
+
+    final int f0()
+    {
+        return i;
+    }
+
+    final int f1(int a)
+    {
+        return i + a;
+    }
+
+    final int f2(int a, int b)
+    {
+        return i + a + b;
+    }
+
+    int f3(int a, int b)
+    {
+        return i + a + b;
+    }
+
+    final int f4(int a, ...)
+    {
+        int r = i + a;
+        int last = a;
+
+        va_list argp;
+        va_start(argp, a);
+        while (last)
+        {
+            last = va_arg!int(argp);
+            r += last;
+        }
+        va_end(argp);
+        return r;
+    }
+};
+
+extern(C++) C2 createC2()
+{
+    return new C2;
+}
+
+auto callMember(alias F, Params...)(__traits(parent, F) obj, Params params)
+{
+    static if(__traits(getFunctionVariadicStyle, F) == "stdarg")
+        enum varargSuffix = ", ...";
+    else
+        enum varargSuffix = "";
+
+    static if(is(typeof(&F) R == return) && is(typeof(F) P == __parameters))
+        mixin("extern(" ~ __traits(getLinkage, F) ~ ") R delegate(P" ~ varargSuffix ~ ") dg;");
+    dg.funcptr = &F;
+    dg.ptr = cast(void*)obj;
+    return dg(params);
+}
+
+extern(C++) void runCPPTests();
+
+void main()
+{
+    C1 c1 = createC1();
+    c1.i = 100;
+    assert(c1.f0() == 100);
+    assert(c1.f1(1) == 101);
+    assert(c1.f2(20, 3) == 123);
+    assert(c1.f3(20, 3) == 123);
+    assert(c1.f4(20, 3, 0) == 123);
+
+    auto dg0 = &c1.f0;
+    auto dg1 = &c1.f1;
+    auto dg2 = &c1.f2;
+    auto dg3 = &c1.f3;
+    auto dg4 = &c1.f4;
+    assert(dg0() == 100);
+    assert(dg1(1) == 101);
+    assert(dg2(20, 3) == 123);
+    assert(dg3(20, 3) == 123);
+    assert(dg4(20, 3, 0) == 123);
+
+    assert(callMember!(C1.f0)(c1) == 100);
+    assert(callMember!(C1.f1)(c1, 1) == 101);
+    assert(callMember!(C1.f2)(c1, 20, 3) == 123);
+    assert(callMember!(C1.f3)(c1, 20, 3) == 123);
+    assert(callMember!(C1.f4)(c1, 20, 3, 0) == 123);
+
+    int i;
+    extern(C++) void delegate() lamdba1 = () {
+        i = 5;
+    };
+    lamdba1();
+    assert(i == 5);
+
+    extern(C++) int function(int, int) lamdba2 = (int a, int b) {
+        return a + b;
+    };
+    assert(lamdba2(3, 4) == 7);
+
+    extern(C++) void delegate(int, ...) lamdba3 = (int a, ...) {
+        i = a;
+        int last = a;
+
+        va_list argp;
+        va_start(argp, a);
+        while (last)
+        {
+            last = va_arg!int(argp);
+            i += last;
+        }
+        va_end(argp);
+    };
+    lamdba3(1000, 200, 30, 4, 0);
+    assert(i == 1234);
+
+    runCPPTests();
+}
index d0d3a25ad1e85b133404ea99ad3cbbff14cc6b58..edb101758b8d373a81aac6c718ec2f3c300c500d 100644 (file)
@@ -1,4 +1,4 @@
-178c44ff362902af589603767055cfac89215652
+bc58b1e9ea68051af9094651a26313371297b79f
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
index 44d4fe16be0cbe0e21824cc169240079badfac6b..224d06e78ca7905bf349c3bd6f41994a7f8609a8 100644 (file)
@@ -280,9 +280,8 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
        core/sys/linux/sys/procfs.d core/sys/linux/sys/signalfd.d \
        core/sys/linux/sys/socket.d core/sys/linux/sys/sysinfo.d \
        core/sys/linux/sys/time.d core/sys/linux/sys/xattr.d \
-       core/sys/linux/syscalls.d core/sys/linux/termios.d \
-       core/sys/linux/time.d core/sys/linux/timerfd.d core/sys/linux/tipc.d \
-       core/sys/linux/unistd.d
+       core/sys/linux/termios.d core/sys/linux/time.d \
+       core/sys/linux/timerfd.d core/sys/linux/tipc.d core/sys/linux/unistd.d
 
 DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
        core/sys/netbsd/err.d core/sys/netbsd/execinfo.d \
index 84be8082f7a4c7644aa8b2b2e3fa0424a9695ef9..bb936ddc1fff25aeb9ff107f1a8fac6f6f421ab1 100644 (file)
@@ -367,9 +367,9 @@ am__objects_18 = core/sys/linux/config.lo core/sys/linux/dlfcn.lo \
        core/sys/linux/sys/procfs.lo core/sys/linux/sys/signalfd.lo \
        core/sys/linux/sys/socket.lo core/sys/linux/sys/sysinfo.lo \
        core/sys/linux/sys/time.lo core/sys/linux/sys/xattr.lo \
-       core/sys/linux/syscalls.lo core/sys/linux/termios.lo \
-       core/sys/linux/time.lo core/sys/linux/timerfd.lo \
-       core/sys/linux/tipc.lo core/sys/linux/unistd.lo
+       core/sys/linux/termios.lo core/sys/linux/time.lo \
+       core/sys/linux/timerfd.lo core/sys/linux/tipc.lo \
+       core/sys/linux/unistd.lo
 @DRUNTIME_OS_LINUX_TRUE@am__objects_19 = $(am__objects_18)
 am__objects_20 = core/sys/windows/accctrl.lo \
        core/sys/windows/aclapi.lo core/sys/windows/aclui.lo \
@@ -944,9 +944,8 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
        core/sys/linux/sys/procfs.d core/sys/linux/sys/signalfd.d \
        core/sys/linux/sys/socket.d core/sys/linux/sys/sysinfo.d \
        core/sys/linux/sys/time.d core/sys/linux/sys/xattr.d \
-       core/sys/linux/syscalls.d core/sys/linux/termios.d \
-       core/sys/linux/time.d core/sys/linux/timerfd.d core/sys/linux/tipc.d \
-       core/sys/linux/unistd.d
+       core/sys/linux/termios.d core/sys/linux/time.d \
+       core/sys/linux/timerfd.d core/sys/linux/tipc.d core/sys/linux/unistd.d
 
 DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
        core/sys/netbsd/err.d core/sys/netbsd/execinfo.d \
@@ -1675,7 +1674,6 @@ core/sys/linux/sys/socket.lo: core/sys/linux/sys/$(am__dirstamp)
 core/sys/linux/sys/sysinfo.lo: core/sys/linux/sys/$(am__dirstamp)
 core/sys/linux/sys/time.lo: core/sys/linux/sys/$(am__dirstamp)
 core/sys/linux/sys/xattr.lo: core/sys/linux/sys/$(am__dirstamp)
-core/sys/linux/syscalls.lo: core/sys/linux/$(am__dirstamp)
 core/sys/linux/termios.lo: core/sys/linux/$(am__dirstamp)
 core/sys/linux/time.lo: core/sys/linux/$(am__dirstamp)
 core/sys/linux/timerfd.lo: core/sys/linux/$(am__dirstamp)
index 33ca0ddc7bd64fff667d54974389adbf48d5567b..1915fb0844ad5d619bb304147e47a41559d6eec3 100644 (file)
@@ -54,13 +54,13 @@ pure @safe:
     enum AddType { no, yes }
 
 
-    this( return const(char)[] buf_, return char[] dst_ = null )
+    this( return scope const(char)[] buf_, return scope char[] dst_ = null )
     {
         this( buf_, AddType.yes, dst_ );
     }
 
 
-    this( return const(char)[] buf_, AddType addType_, return char[] dst_ = null )
+    this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null )
     {
         buf     = buf_;
         addType = addType_;
@@ -105,7 +105,7 @@ pure @safe:
         //throw new ParseException( msg );
         debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
         throw __ctfe ? new ParseException(msg)
-                     : cast(ParseException) cast(void*) typeid(ParseException).initializer;
+                     : cast(ParseException) __traits(initSymbol, ParseException).ptr;
 
     }
 
@@ -116,7 +116,7 @@ pure @safe:
 
         //throw new OverflowException( msg );
         debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
-        throw cast(OverflowException) cast(void*) typeid(OverflowException).initializer;
+        throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
     }
 
 
index 9c8223767e1cef77e543ffbaff3458d512d573c4..ae71f513129ddc8c9ba027e0427c121f16b56fbb 100644 (file)
@@ -14,16 +14,27 @@ import core.internal.traits : Unqual;
 /**
  * Does array initialization (not assignment) from another array of the same element type.
  * Params:
+ *  to = what array to initialize
  *  from = what data the array should be initialized with
+ *  makeWeaklyPure = unused; its purpose is to prevent the function from becoming
+ *      strongly pure and risk being optimised out
  * Returns:
  *  The created and initialized array `to`
  * Bugs:
  *  This function template was ported from a much older runtime hook that bypassed safety,
  *  purity, and throwabilty checks. To prevent breaking existing code, this function template
  *  is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations.
+ *
+ *  The third parameter is never used, but is necessary in order for the
+ *  function be treated as weakly pure, instead of strongly pure.
+ *  This is needed because constructions such as the one below can be ignored by
+ *  the compiler if `_d_arrayctor` is believed to be pure, because purity would
+ *  mean the call to `_d_arrayctor` has no effects (no side effects and the
+ *  return value is ignored), despite it actually modifying the contents of `a`.
+ *      const S[2] b;
+ *      const S[2] a = b;  // this would get lowered to _d_arrayctor(a, b)
  */
-Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @trusted
-    if (is(Unqual!T1 == Unqual!T2))
+Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* makeWeaklyPure = null) @trusted
 {
     pragma(inline, false);
     import core.internal.traits : hasElaborateCopyConstructor;
@@ -32,14 +43,12 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
     import core.stdc.stdint : uintptr_t;
     debug(PRINTF) import core.stdc.stdio : printf;
 
-    debug(PRINTF) printf("_d_arrayctor(to = %p,%d, from = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, T1.tsize);
+    debug(PRINTF) printf("_d_arrayctor(from = %p,%d) size = %d\n", from.ptr, from.length, T.sizeof);
 
-    Tarr1 to = void;
+    void[] vFrom = (cast(void*) from.ptr)[0..from.length];
+    void[] vTo = (cast(void*) to.ptr)[0..to.length];
 
-    void[] vFrom = (cast(void*)from.ptr)[0..from.length];
-    void[] vTo = (cast(void*)to.ptr)[0..to.length];
-
-    // Force `enforceRawArraysConformable` to be `pure`
+    // Force `enforceRawArraysConformable` to remain weakly `pure`
     void enforceRawArraysConformable(const char[] action, const size_t elementSize,
         const void[] a1, const void[] a2) @trusted
     {
@@ -50,9 +59,9 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
         (cast(Type)&enforceRawArraysConformableNogc)(action, elementSize, a1, a2, false);
     }
 
-    enforceRawArraysConformable("initialization", T1.sizeof, vFrom, vTo);
+    enforceRawArraysConformable("initialization", T.sizeof, vFrom, vTo);
 
-    static if (hasElaborateCopyConstructor!T1)
+    static if (hasElaborateCopyConstructor!T)
     {
         size_t i;
         try
@@ -66,7 +75,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
             */
             while (i--)
             {
-                auto elem = cast(Unqual!T1*)&to[i];
+                auto elem = cast(Unqual!T*) &to[i];
                 destroy(*elem);
             }
 
@@ -76,7 +85,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
     else
     {
         // blit all elements at once
-        memcpy(cast(void*) to.ptr, from.ptr, to.length * T1.sizeof);
+        memcpy(cast(void*) to.ptr, from.ptr, to.length * T.sizeof);
     }
 
     return to;
@@ -94,7 +103,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
 
     S[4] arr1;
     S[4] arr2 = [S(0), S(1), S(2), S(3)];
-    arr1 = _d_arrayctor!(typeof(arr1))(arr2[]);
+    _d_arrayctor(arr1[], arr2[]);
 
     assert(counter == 4);
     assert(arr1 == arr2);
@@ -117,7 +126,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
 
     S[4] arr1;
     S[4] arr2 = [S(0), S(1), S(2), S(3)];
-    arr1 = _d_arrayctor!(typeof(arr1))(arr2[]);
+    _d_arrayctor(arr1[], arr2[]);
 
     assert(counter == 4);
     assert(arr1 == arr2);
@@ -143,7 +152,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
     {
         Throw[4] a;
         Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];
-        a = _d_arrayctor!(typeof(a))(b[]);
+        _d_arrayctor(a[], b[]);
     }
     catch (Exception)
     {
@@ -168,7 +177,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste
     {
         NoThrow[4] a;
         NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
-        a = _d_arrayctor!(typeof(a))(b[]);
+        _d_arrayctor(a[], b[]);
     }
     catch (Exception)
     {
@@ -274,7 +283,7 @@ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted
     {
         Throw[4] a;
         Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];
-        a = _d_arrayctor!(typeof(a))(b[]);
+        _d_arrayctor(a[], b[]);
     }
     catch (Exception)
     {
index 2789d2913a7e15d17eaecc9a85018c40a55bd592..a876fcc537f8b740ab01cb572375792262d02dbf 100644 (file)
@@ -801,7 +801,7 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == delegate) || is(T : V*, V
 }
 
 @trusted pure nothrow @nogc
-const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == struct) || is(T == union))
+const(ubyte)[] toUbyte(T)(const return ref scope T val) if (is(T == struct) || is(T == union))
 {
     if (__ctfe)
     {
@@ -826,7 +826,11 @@ const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == struct) || i
     }
     else
     {
-        return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
+        // We're escaping a reference to `val` here because we cannot express
+        // ref return + scope, it's currently seen as ref + return scope
+        // https://issues.dlang.org/show_bug.cgi?id=22541
+        // Once fixed, the @system lambda should be removed
+        return (() @system => (cast(const(ubyte)*)&val)[0 .. T.sizeof])();
     }
 }
 
index 7e9b5f2ad48d574128c0795b9c7268b97d62b54c..a7446debae656495e63369bd5240832750a6da95 100644 (file)
@@ -89,44 +89,35 @@ Emplaces T.init.
 In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
 constructors etc.
 +/
-template emplaceInitializer(T)
+void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted
 if (!is(T == const) && !is(T == immutable) && !is(T == inout))
 {
-    import core.internal.traits : hasElaborateAssign, Unqual;
+    import core.internal.traits : hasElaborateAssign;
 
-    // Avoid stack allocation by hacking to get to the struct/union init symbol.
-    static if (is(T == struct) || is(T == union))
+    static if (__traits(isZeroInit, T))
     {
-        pragma(mangle, "_D" ~ Unqual!T.mangleof[1..$] ~ "6__initZ")
-        __gshared extern immutable T initializer;
+        import core.stdc.string : memset;
+        memset(cast(void*) &chunk, 0, T.sizeof);
     }
-
-    void emplaceInitializer(scope ref T chunk) nothrow pure @trusted
+    else static if (__traits(isScalar, T) ||
+                    T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; }))
     {
-        static if (__traits(isZeroInit, T))
-        {
-            import core.stdc.string : memset;
-            memset(cast(void*) &chunk, 0, T.sizeof);
-        }
-        else static if (__traits(isScalar, T) ||
-                        T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; }))
-        {
-            chunk = T.init;
-        }
-        else static if (__traits(isStaticArray, T))
-        {
-            // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one.
-            foreach (i; 0 .. T.length)
-            {
-                emplaceInitializer(chunk[i]);
-            }
-        }
-        else
+        chunk = T.init;
+    }
+    else static if (__traits(isStaticArray, T))
+    {
+        // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one.
+        foreach (i; 0 .. T.length)
         {
-            import core.stdc.string : memcpy;
-            memcpy(cast(void*)&chunk, &initializer, T.sizeof);
+            emplaceInitializer(chunk[i]);
         }
     }
+    else
+    {
+        import core.stdc.string : memcpy;
+        const initializer = __traits(initSymbol, T);
+        memcpy(cast(void*)&chunk, initializer.ptr, initializer.length);
+    }
 }
 
 @safe unittest
index 529fee49436dd27aaa041eeab1f9eeae42f861d8..64a9cc92ffba8b70776bc8c5fb19dcda6be0a96c 100644 (file)
@@ -119,7 +119,7 @@ char[] signedToTempString(uint radix = 10)(long value, return scope char[] buf)
     if (neg)
     {
         // about to do a slice without a bounds check
-        auto trustedSlice(return char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; }
+        auto trustedSlice(return scope char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; }
         r = trustedSlice(r);
         r[0] = '-';
     }
index ca0f7f599a66ec595fa93a4cefd7de5f7c48c17a..27bf7f2b90552ca1eb28e12314b8d105c0c703a7 100644 (file)
@@ -583,7 +583,7 @@ void validate(S)(const scope S s)
 /* =================== Conversion to UTF8 ======================= */
 
 @safe pure nothrow @nogc
-char[] toUTF8(return char[] buf, dchar c)
+char[] toUTF8(return scope char[] buf, dchar c)
     in
     {
         assert(isValidDchar(c));
@@ -623,7 +623,7 @@ char[] toUTF8(return char[] buf, dchar c)
  * Encodes string s into UTF-8 and returns the encoded string.
  */
 @safe pure nothrow
-string toUTF8(return string s)
+string toUTF8(return scope string s)
     in
     {
         validate(s);
@@ -692,7 +692,7 @@ string toUTF8(const scope dchar[] s)
 /* =================== Conversion to UTF16 ======================= */
 
 @safe pure nothrow @nogc
-wchar[] toUTF16(return wchar[] buf, dchar c)
+wchar[] toUTF16(return scope wchar[] buf, dchar c)
     in
     {
         assert(isValidDchar(c));
@@ -784,7 +784,7 @@ wptr toUTF16z(const scope char[] s)
 
 /** ditto */
 @safe pure nothrow
-wstring toUTF16(return wstring s)
+wstring toUTF16(return scope wstring s)
     in
     {
         validate(s);
@@ -864,7 +864,7 @@ dstring toUTF32(const scope wchar[] s)
 
 /** ditto */
 @safe pure nothrow
-dstring toUTF32(return dstring s)
+dstring toUTF32(return scope dstring s)
     in
     {
         validate(s);
index d93b891226ce0b403ebb85dba57b3589f7c42143..b45e95f4226e9a09d1fed262cbbded556d9e53ee 100644 (file)
@@ -103,8 +103,8 @@ T emplace(T, Args...)(T chunk, auto ref Args args)
         " is abstract and it can't be emplaced");
 
     // Initialize the object in its pre-ctor state
-    enum classSize = __traits(classInstanceSize, T);
-    (() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])();
+    const initializer = __traits(initSymbol, T);
+    (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })();
 
     static if (isInnerClass!T)
     {
@@ -224,6 +224,31 @@ T emplace(T, Args...)(void[] chunk, auto ref Args args)
     assert(c.i == 5);
 }
 
+///
+@betterC
+@nogc pure nothrow @system unittest
+{
+    // works with -betterC too:
+
+    static extern (C++) class C
+    {
+        @nogc pure nothrow @safe:
+        int i = 3;
+        this(int i)
+        {
+            assert(this.i == 3);
+            this.i = i;
+        }
+        int virtualGetI() { return i; }
+    }
+
+    import core.internal.traits : classInstanceAlignment;
+
+    align(classInstanceAlignment!C) byte[__traits(classInstanceSize, C)] buffer;
+    C c = emplace!C(buffer[], 42);
+    assert(c.virtualGetI() == 42);
+}
+
 @system unittest
 {
     class Outer
@@ -1921,7 +1946,7 @@ private void moveImpl(T)(scope ref T target, return scope ref T source)
 
     static if (is(T == struct))
     {
-        //  Unsafe when compiling without -dip1000
+        //  Unsafe when compiling without -preview=dip1000
         if ((() @trusted => &source == &target)()) return;
         // Destroy target before overwriting it
         static if (hasElaborateDestructor!T) target.__xdtor();
@@ -2099,7 +2124,7 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source)
 
     static if (is(T == struct))
     {
-        //  Unsafe when compiling without -dip1000
+        //  Unsafe when compiling without -preview=dip1000
         assert((() @trusted => &source !is &target)(), "source and target must not be identical");
 
         static if (hasElaborateAssign!T || !isAssignable!T)
@@ -2123,12 +2148,7 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source)
             static if (__traits(isZeroInit, T))
                 () @trusted { memset(&source, 0, sz); }();
             else
-            {
-                import core.internal.lifetime : emplaceInitializer;
-                ubyte[T.sizeof] init = void;
-                emplaceInitializer(*(() @trusted { return cast(T*)init.ptr; }()));
-                () @trusted { memcpy(&source, init.ptr, sz); }();
-            }
+                () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }();
         }
     }
     else static if (__traits(isStaticArray, T))
@@ -2201,3 +2221,74 @@ pure nothrow @nogc @system unittest
     static assert(!__traits(compiles, f(ncarray)));
     f(move(ncarray));
 }
+
+/**
+ * This is called for a delete statement where the value
+ * being deleted is a pointer to a struct with a destructor
+ * but doesn't have an overloaded delete operator.
+ *
+ * Params:
+ *   p = pointer to the value to be deleted
+ */
+void _d_delstruct(T)(ref T *p)
+{
+    if (p)
+    {
+        debug(PRINTF) printf("_d_delstruct(%p)\n", p);
+
+        import core.memory : GC;
+
+        destroy(*p);
+        GC.free(p);
+        p = null;
+    }
+}
+
+@system unittest
+{
+    int dtors = 0;
+    struct S { ~this() { ++dtors; } }
+
+    S *s = new S();
+    _d_delstruct(s);
+
+    assert(s == null);
+    assert(dtors == 1);
+}
+
+@system unittest
+{
+    int innerDtors = 0;
+    int outerDtors = 0;
+
+    struct Inner { ~this() { ++innerDtors; } }
+    struct Outer
+    {
+        Inner *i1;
+        Inner *i2;
+
+        this(int x)
+        {
+            i1 = new Inner();
+            i2 = new Inner();
+        }
+
+        ~this()
+        {
+            ++outerDtors;
+
+            _d_delstruct(i1);
+            assert(i1 == null);
+
+            _d_delstruct(i2);
+            assert(i2 == null);
+        }
+    }
+
+    Outer *o = new Outer(0);
+    _d_delstruct(o);
+
+    assert(o == null);
+    assert(innerDtors == 2);
+    assert(outerDtors == 1);
+}
index 3770c13337ca36c53d58f1fefde4b63106c179ae..c4df0f2d0dd0b822d013704c513dc5fd3c3069ce 100644 (file)
@@ -270,7 +270,7 @@ extern(C):
      * reentrant, and must be called once for every call to disable before
      * automatic collections are enabled.
      */
-    pragma(mangle, "gc_enable") static void enable() nothrow; /* FIXME pure */
+    pragma(mangle, "gc_enable") static void enable() nothrow pure;
 
 
     /**
@@ -280,7 +280,7 @@ extern(C):
      * such as during an out of memory condition.  This function is reentrant,
      * but enable must be called once for each call to disable.
      */
-    pragma(mangle, "gc_disable") static void disable() nothrow; /* FIXME pure */
+    pragma(mangle, "gc_disable") static void disable() nothrow pure;
 
 
     /**
@@ -290,14 +290,14 @@ extern(C):
      * and then to reclaim free space.  This action may need to suspend all
      * running threads for at least part of the collection process.
      */
-    pragma(mangle, "gc_collect") static void collect() nothrow; /* FIXME pure */
+    pragma(mangle, "gc_collect") static void collect() nothrow pure;
 
     /**
      * Indicates that the managed memory space be minimized by returning free
      * physical memory to the operating system.  The amount of free memory
      * returned depends on the allocator design and on program behavior.
      */
-    pragma(mangle, "gc_minimize") static void minimize() nothrow; /* FIXME pure */
+    pragma(mangle, "gc_minimize") static void minimize() nothrow pure;
 
 extern(D):
 
@@ -551,7 +551,7 @@ extern(C):
      * Throws:
      *  `OutOfMemoryError` on allocation failure.
      */
-    pragma(mangle, "gc_realloc") static void* realloc(return void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
+    pragma(mangle, "gc_realloc") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
 
     // https://issues.dlang.org/show_bug.cgi?id=13111
     ///
@@ -635,7 +635,7 @@ extern(C):
      * Returns:
      *  The actual number of bytes reserved or zero on error.
      */
-    pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow; /* FIXME pure */
+    pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow pure;
 
 
     /**
@@ -807,7 +807,7 @@ extern(C):
      * }
      * ---
      */
-    pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc; /* FIXME pure */
+    pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc pure;
 
 
     /**
@@ -818,7 +818,7 @@ extern(C):
      * Params:
      *  p = A pointer into a GC-managed memory block or null.
      */
-    pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc; /* FIXME pure */
+    pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc pure;
 
 
     /**
@@ -849,7 +849,8 @@ extern(C):
      * // rawMemory will be recognized on collection.
      * ---
      */
-    pragma(mangle, "gc_addRange") static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow; /* FIXME pure */
+    pragma(mangle, "gc_addRange")
+    static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow pure;
 
 
     /**
@@ -861,7 +862,7 @@ extern(C):
      * Params:
      *  p  = A pointer to a valid memory address or to null.
      */
-    pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc; /* FIXME pure */
+    pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc pure;
 
 
     /**
index 2f11a663eb540edbf3d974d54d7d5bb9191441a9..92f8f705540878fbfad4bf2997c74c303dcb3d0c 100644 (file)
@@ -26,6 +26,10 @@ else version (TVOS)
 else version (WatchOS)
     version = Darwin;
 
+version (CRuntime_Glibc)
+    version = AlignedAllocSupported;
+else {}
+
 extern (C):
 @system:
 
@@ -166,6 +170,12 @@ void*   realloc(void* ptr, size_t size);
 ///
 void    free(void* ptr);
 
+/// since C11
+version (AlignedAllocSupported)
+{
+    void* aligned_alloc(size_t alignment, size_t size);
+}
+
 ///
 noreturn abort() @safe;
 ///
index a26811ca6236c02f098e3287c10ba84d6fbfa3d7..f15ef851909a3015ae8d39541c3d1f28a1501e97 100644 (file)
@@ -35,31 +35,31 @@ nothrow:
 @nogc:
 
 ///
-inout(void)* memchr(return inout void* s, int c, size_t n) pure;
+inout(void)* memchr(return scope inout void* s, int c, size_t n) pure;
 ///
 int   memcmp(scope const void* s1, scope const void* s2, size_t n) pure;
 ///
-void* memcpy(return void* s1, scope const void* s2, size_t n) pure;
+void* memcpy(return scope void* s1, scope const void* s2, size_t n) pure;
 version (Windows)
 {
     ///
     int memicmp(scope const char* s1, scope const char* s2, size_t n);
 }
 ///
-void* memmove(return void* s1, scope const void* s2, size_t n) pure;
+void* memmove(return scope void* s1, scope const void* s2, size_t n) pure;
 ///
-void* memset(return void* s, int c, size_t n) pure;
+void* memset(return scope void* s, int c, size_t n) pure;
 
 ///
-char*  strcat(return char* s1, scope const char* s2) pure;
+char*  strcat(return scope char* s1, scope const char* s2) pure;
 ///
-inout(char)*  strchr(return inout(char)* s, int c) pure;
+inout(char)*  strchr(return scope inout(char)* s, int c) pure;
 ///
 int    strcmp(scope const char* s1, scope const char* s2) pure;
 ///
 int    strcoll(scope const char* s1, scope const char* s2);
 ///
-char*  strcpy(return char* s1, scope const char* s2) pure;
+char*  strcpy(return scope char* s1, scope const char* s2) pure;
 ///
 size_t strcspn(scope const char* s1, scope const char* s2) pure;
 ///
@@ -70,7 +70,7 @@ char*  strerror(int errnum);
 version (ReturnStrerrorR)
 {
     ///
-    const(char)* strerror_r(int errnum, return char* buf, size_t buflen);
+    const(char)* strerror_r(int errnum, return scope char* buf, size_t buflen);
 }
 // This one is
 else
@@ -80,20 +80,20 @@ else
 ///
 size_t strlen(scope const char* s) pure;
 ///
-char*  strncat(return char* s1, scope const char* s2, size_t n) pure;
+char*  strncat(return scope char* s1, scope const char* s2, size_t n) pure;
 ///
 int    strncmp(scope const char* s1, scope const char* s2, size_t n) pure;
 ///
-char*  strncpy(return char* s1, scope const char* s2, size_t n) pure;
+char*  strncpy(return scope char* s1, scope const char* s2, size_t n) pure;
 ///
-inout(char)*  strpbrk(return inout(char)* s1, scope const char* s2) pure;
+inout(char)*  strpbrk(return scope inout(char)* s1, scope const char* s2) pure;
 ///
-inout(char)*  strrchr(return inout(char)* s, int c) pure;
+inout(char)*  strrchr(return scope inout(char)* s, int c) pure;
 ///
 size_t strspn(scope const char* s1, scope const char* s2) pure;
 ///
-inout(char)*  strstr(return inout(char)* s1, scope const char* s2) pure;
+inout(char)*  strstr(return scope inout(char)* s1, scope const char* s2) pure;
 ///
-char*  strtok(return char* s1, scope const char* s2);
+char*  strtok(return scope char* s1, scope const char* s2);
 ///
 size_t strxfrm(scope char* s1, scope const char* s2, size_t n);
index 6da5618ada652c89be4e44b0bdb4b6207301ef73..e8fb94b11e6607fe94e5c1c97fff5afbbc535d7f 100644 (file)
@@ -213,13 +213,13 @@ c_ulong wcstoul(const scope wchar_t* nptr, wchar_t** endptr, int base);
 ulong   wcstoull(const scope wchar_t* nptr, wchar_t** endptr, int base);
 
 ///
-pure wchar_t* wcscpy(return wchar_t* s1, scope const wchar_t* s2);
+pure wchar_t* wcscpy(return scope wchar_t* s1, scope const wchar_t* s2);
 ///
-pure wchar_t* wcsncpy(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wcsncpy(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
-pure wchar_t* wcscat(return wchar_t* s1, scope const wchar_t* s2);
+pure wchar_t* wcscat(return scope wchar_t* s1, scope const wchar_t* s2);
 ///
-pure wchar_t* wcsncat(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wcsncat(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
 pure int wcscmp(scope const wchar_t* s1, scope const wchar_t* s2);
 ///
@@ -229,32 +229,32 @@ pure int wcsncmp(scope const wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
 size_t   wcsxfrm(scope wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
-pure inout(wchar_t)* wcschr(return inout(wchar_t)* s, wchar_t c);
+pure inout(wchar_t)* wcschr(return scope inout(wchar_t)* s, wchar_t c);
 ///
 pure size_t wcscspn(scope const wchar_t* s1, scope const wchar_t* s2);
 ///
-pure inout(wchar_t)* wcspbrk(return inout(wchar_t)* s1, scope const wchar_t* s2);
+pure inout(wchar_t)* wcspbrk(return scope inout(wchar_t)* s1, scope const wchar_t* s2);
 ///
-pure inout(wchar_t)* wcsrchr(return inout(wchar_t)* s, wchar_t c);
+pure inout(wchar_t)* wcsrchr(return scope inout(wchar_t)* s, wchar_t c);
 ///
 pure size_t wcsspn(scope const wchar_t* s1, scope const wchar_t* s2);
 ///
-pure inout(wchar_t)* wcsstr(return inout(wchar_t)* s1, scope const wchar_t* s2);
+pure inout(wchar_t)* wcsstr(return scope inout(wchar_t)* s1, scope const wchar_t* s2);
 ///
-wchar_t* wcstok(return wchar_t* s1, scope const wchar_t* s2, wchar_t** ptr);
+wchar_t* wcstok(return scope wchar_t* s1, scope const wchar_t* s2, wchar_t** ptr);
 ///
 pure size_t wcslen(scope const wchar_t* s);
 
 ///
-pure inout(wchar_t)* wmemchr(return inout wchar_t* s, wchar_t c, size_t n);
+pure inout(wchar_t)* wmemchr(return scope inout wchar_t* s, wchar_t c, size_t n);
 ///
 pure int      wmemcmp(scope const wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
-pure wchar_t* wmemcpy(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wmemcpy(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
-pure wchar_t* wmemmove(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wmemmove(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
 ///
-pure wchar_t* wmemset(return wchar_t* s, wchar_t c, size_t n);
+pure wchar_t* wmemset(return scope wchar_t* s, wchar_t c, size_t n);
 
 ///
 size_t wcsftime(wchar_t* s, size_t maxsize, const scope wchar_t* format, const scope tm* timeptr);
index f920057cd06a77b966c4341dcf86d4cd1014a386..d65cd8d1832fa687f41b860cf8eedf1771b5749d 100644 (file)
@@ -19,6 +19,8 @@ version (CppRuntime_Gcc)
     version = GenericBaseException;
 version (CppRuntime_Clang)
     version = GenericBaseException;
+version (CppRuntime_Sun)
+    version = GenericBaseException;
 
 extern (C++, "std"):
 @nogc:
index b153ab9aef00beb0fe48537b396363c03d071a91..b848a1474601e376548ec60695f88c60e3892fba 100644 (file)
@@ -189,7 +189,7 @@ class Mutex :
             if (pthread_mutex_lock(&m_hndl) == 0)
                 return;
 
-            SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer;
+            SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr;
             syncErr.msg = "Unable to lock mutex.";
             throw syncErr;
         }
@@ -227,7 +227,7 @@ class Mutex :
             if (pthread_mutex_unlock(&m_hndl) == 0)
                 return;
 
-            SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer;
+            SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr;
             syncErr.msg = "Unable to unlock mutex.";
             throw syncErr;
         }
index cbee06c4efeb733e9a950bd7bb24df2bd3acca4c..10a5610ac449ba467b70d846073eb43a6d8841c0 100644 (file)
@@ -14,4 +14,4 @@ extern (C):
 nothrow:
 @nogc:
 
-pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
index 11e5ced26b76072381bce2fddd2b796fb1bcad9e..4d400f207c7cf1cf996b40bc2b61aff8a65d83fe 100644 (file)
@@ -222,7 +222,7 @@ enum
  */
 ubyte GET_LIBRARY_ORDINAL(uint n_desc) @safe { return ((n_desc) >> 8) & 0xff; }
 /// Ditto
-ref ushort SET_LIBRARY_ORDINAL(return scope ref ushort n_desc, uint ordinal) @safe
+ref ushort SET_LIBRARY_ORDINAL(return ref ushort n_desc, uint ordinal) @safe
 {
     return n_desc = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8));
 }
index bd65fde27bcb76c58ae108df2b94b420e475c231..ac988b58f0d40e860194fc22a89ae066a2b289de 100644 (file)
@@ -27,5 +27,5 @@ nothrow:
 static if (__DARWIN_C_LEVEL >= __DARWIN_C_FULL)
 {
     // ^ __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
-    pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+    pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
 }
index b64178f65622d2ba9c022e74670b188779f17c21..4b8422748b60ee2eae5bda9c42b39cd424880028 100644 (file)
@@ -17,6 +17,6 @@ nothrow:
 
 static if (__BSD_VISIBLE)
 {
-    pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+    pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
 }
 
index 3602ea8e86bd1ecc9bf04f56c7c664bbcf2d9ce0..459e9115878e2983d883f23ed9c58b6fa30f2a07 100644 (file)
@@ -17,5 +17,5 @@ nothrow:
 
 static if (__BSD_VISIBLE)
 {
-    pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+    pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
 }
index 1b2c8d86a4ab4e01200dc72f56c03cb0910d2c17..e3c94cf6a8ac655b2ed5bf7340d4a32c437ede65 100644 (file)
@@ -18,5 +18,5 @@ nothrow:
 
 static if (__USE_GNU)
 {
-    pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+    pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
 }
diff --git a/libphobos/libdruntime/core/sys/linux/syscalls.d b/libphobos/libdruntime/core/sys/linux/syscalls.d
deleted file mode 100644 (file)
index 8c65371..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-module core.sys.linux.syscalls;
-
-version (linux):
-extern (C):
-@system:
-nothrow:
-@nogc:
-
-import core.stdc.config : c_long;
-
-version (CoreDdoc)
-{
-    /// Linux system call number from Linux's asm/unistd.h
-    enum SystemCall : c_long;
-}
-else version (X86_64)
-{
-    // https://github.com/torvalds/linux/blob/v4.14/arch/sh/include/uapi/asm/unistd_64.h
-    // https://github.com/torvalds/linux/blob/v4.14/arch/x86/entry/syscalls/syscall_64.tbl
-    enum SystemCall : c_long
-    {
-        read = 0,
-        write = 1,
-        open = 2,
-        close = 3,
-        stat = 4,
-        fstat = 5,
-        lstat = 6,
-        poll = 7,
-        lseek = 8,
-        mmap = 9,
-        mprotect = 10,
-        munmap = 11,
-        brk = 12,
-        rt_sigaction = 13,
-        rt_sigprocmask = 14,
-        rt_sigreturn = 15,
-        ioctl = 16,
-        pread64 = 17,
-        pwrite64 = 18,
-        readv = 19,
-        writev = 20,
-        access = 21,
-        pipe = 22,
-        select = 23,
-        sched_yield = 24,
-        mremap = 25,
-        msync = 26,
-        mincore = 27,
-        madvise = 28,
-        shmget = 29,
-        shmat = 30,
-        shmctl = 31,
-        dup = 32,
-        dup2 = 33,
-        pause = 34,
-        nanosleep = 35,
-        getitimer = 36,
-        alarm = 37,
-        setitimer = 38,
-        getpid = 39,
-        sendfile = 40,
-        socket = 41,
-        connect = 42,
-        accept = 43,
-        sendto = 44,
-        recvfrom = 45,
-        sendmsg = 46,
-        recvmsg = 47,
-        shutdown = 48,
-        bind = 49,
-        listen = 50,
-        getsockname = 51,
-        getpeername = 52,
-        socketpair = 53,
-        setsockopt = 54,
-        getsockopt = 55,
-        clone = 56,
-        fork = 57,
-        vfork = 58,
-        execve = 59,
-        exit = 60,
-        wait4 = 61,
-        kill = 62,
-        uname = 63,
-        semget = 64,
-        semop = 65,
-        semctl = 66,
-        shmdt = 67,
-        msgget = 68,
-        msgsnd = 69,
-        msgrcv = 70,
-        msgctl = 71,
-        fcntl = 72,
-        flock = 73,
-        fsync = 74,
-        fdatasync = 75,
-        truncate = 76,
-        ftruncate = 77,
-        getdents = 78,
-        getcwd = 79,
-        chdir = 80,
-        fchdir = 81,
-        rename = 82,
-        mkdir = 83,
-        rmdir = 84,
-        creat = 85,
-        link = 86,
-        unlink = 87,
-        symlink = 88,
-        readlink = 89,
-        chmod = 90,
-        fchmod = 91,
-        chown = 92,
-        fchown = 93,
-        lchown = 94,
-        umask = 95,
-        gettimeofday = 96,
-        getrlimit = 97,
-        getrusage = 98,
-        sysinfo = 99,
-        times = 100,
-        ptrace = 101,
-        getuid = 102,
-        syslog = 103,
-        getgid = 104,
-        setuid = 105,
-        setgid = 106,
-        geteuid = 107,
-        getegid = 108,
-        setpgid = 109,
-        getppid = 110,
-        getpgrp = 111,
-        setsid = 112,
-        setreuid = 113,
-        setregid = 114,
-        getgroups = 115,
-        setgroups = 116,
-        setresuid = 117,
-        getresuid = 118,
-        setresgid = 119,
-        getresgid = 120,
-        getpgid = 121,
-        setfsuid = 122,
-        setfsgid = 123,
-        getsid = 124,
-        capget = 125,
-        capset = 126,
-        rt_sigpending = 127,
-        rt_sigtimedwait = 128,
-        rt_sigqueueinfo = 129,
-        rt_sigsuspend = 130,
-        sigaltstack = 131,
-        utime = 132,
-        mknod = 133,
-        uselib = 134,
-        personality = 135,
-        ustat = 136,
-        statfs = 137,
-        fstatfs = 138,
-        sysfs = 139,
-        getpriority = 140,
-        setpriority = 141,
-        sched_setparam = 142,
-        sched_getparam = 143,
-        sched_setscheduler = 144,
-        sched_getscheduler = 145,
-        sched_get_priority_max = 146,
-        sched_get_priority_min = 147,
-        sched_rr_get_interval = 148,
-        mlock = 149,
-        munlock = 150,
-        mlockall = 151,
-        munlockall = 152,
-        vhangup = 153,
-        modify_ldt = 154,
-        pivot_root = 155,
-        _sysctl = 156,
-        prctl = 157,
-        arch_prctl = 158,
-        adjtimex = 159,
-        setrlimit = 160,
-        chroot = 161,
-        sync = 162,
-        acct = 163,
-        settimeofday = 164,
-        mount = 165,
-        umount2 = 166,
-        swapon = 167,
-        swapoff = 168,
-        reboot = 169,
-        sethostname = 170,
-        setdomainname = 171,
-        iopl = 172,
-        ioperm = 173,
-        create_module = 174,
-        init_module = 175,
-        delete_module = 176,
-        get_kernel_syms = 177,
-        query_module = 178,
-        quotactl = 179,
-        nfsservctl = 180,
-        getpmsg = 181,
-        putpmsg = 182,
-        afs_syscall = 183,
-        tuxcall = 184,
-        security = 185,
-        gettid = 186,
-        readahead = 187,
-        setxattr = 188,
-        lsetxattr = 189,
-        fsetxattr = 190,
-        getxattr = 191,
-        lgetxattr = 192,
-        fgetxattr = 193,
-        listxattr = 194,
-        llistxattr = 195,
-        flistxattr = 196,
-        removexattr = 197,
-        lremovexattr = 198,
-        fremovexattr = 199,
-        tkill = 200,
-        time = 201,
-        futex = 202,
-        sched_setaffinity = 203,
-        sched_getaffinity = 204,
-        set_thread_area = 205,
-        io_setup = 206,
-        io_destroy = 207,
-        io_getevents = 208,
-        io_submit = 209,
-        io_cancel = 210,
-        get_thread_area = 211,
-        lookup_dcookie = 212,
-        epoll_create = 213,
-        epoll_ctl_old = 214,
-        epoll_wait_old = 215,
-        remap_file_pages = 216,
-        getdents64 = 217,
-        set_tid_address = 218,
-        restart_syscall = 219,
-        semtimedop = 220,
-        fadvise64 = 221,
-        timer_create = 222,
-        timer_settime = 223,
-        timer_gettime = 224,
-        timer_getoverrun = 225,
-        timer_delete = 226,
-        clock_settime = 227,
-        clock_gettime = 228,
-        clock_getres = 229,
-        clock_nanosleep = 230,
-        exit_group = 231,
-        epoll_wait = 232,
-        epoll_ctl = 233,
-        tgkill = 234,
-        utimes = 235,
-        vserver = 236,
-        mbind = 237,
-        set_mempolicy = 238,
-        get_mempolicy = 239,
-        mq_open = 240,
-        mq_unlink = 241,
-        mq_timedsend = 242,
-        mq_timedreceive = 243,
-        mq_notify = 244,
-        mq_getsetattr = 245,
-        kexec_load = 246,
-        waitid = 247,
-        add_key = 248,
-        request_key = 249,
-        keyctl = 250,
-        ioprio_set = 251,
-        ioprio_get = 252,
-        inotify_init = 253,
-        inotify_add_watch = 254,
-        inotify_rm_watch = 255,
-        migrate_pages = 256,
-        openat = 257,
-        mkdirat = 258,
-        mknodat = 259,
-        fchownat = 260,
-        futimesat = 261,
-        newfstatat = 262,
-        unlinkat = 263,
-        renameat = 264,
-        linkat = 265,
-        symlinkat = 266,
-        readlinkat = 267,
-        fchmodat = 268,
-        faccessat = 269,
-        pselect6 = 270,
-        ppoll = 271,
-        unshare = 272,
-        set_robust_list = 273,
-        get_robust_list = 274,
-        splice = 275,
-        tee = 276,
-        sync_file_range = 277,
-        vmsplice = 278,
-        move_pages = 279,
-        utimensat = 280,
-        epoll_pwait = 281,
-        signalfd = 282,
-        timerfd_create = 283,
-        eventfd = 284,
-        fallocate = 285,
-        timerfd_settime = 286,
-        timerfd_gettime = 287,
-        accept4 = 288,
-        signalfd4 = 289,
-        eventfd2 = 290,
-        epoll_create1 = 291,
-        dup3 = 292,
-        pipe2 = 293,
-        inotify_init1 = 294,
-        preadv = 295,
-        pwritev = 296,
-        rt_tgsigqueueinfo = 297,
-        perf_event_open = 298,
-        recvmmsg = 299,
-        fanotify_init = 300,
-        fanotify_mark = 301,
-        prlimit64 = 302,
-        name_to_handle_at = 303,
-        open_by_handle_at = 304,
-        clock_adjtime = 305,
-        syncfs = 306,
-        sendmmsg = 307,
-        setns = 308,
-        getcpu = 309,
-        process_vm_readv = 310,
-        process_vm_writev = 311,
-        kcmp = 312,
-        finit_module = 313,
-        sched_setattr = 314,
-        sched_getattr = 315,
-        renameat2 = 316,
-        seccomp = 317,
-        getrandom = 318,
-        memfd_create = 319,
-        kexec_file_load = 320,
-        bpf = 321,
-        execveat = 322,
-        userfaultfd = 323,
-        membarrier = 324,
-        mlock2 = 325,
-        copy_file_range = 326,
-        preadv2 = 327,
-        pwritev2 = 328,
-        pkey_mprotect = 329,
-        pkey_alloc = 330,
-        pkey_free = 331,
-        statx = 332,
-    }
-}
-else version (X86)
-{
-    // https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl
-    // https://github.com/torvalds/linux/blob/v4.14/arch/sh/include/uapi/asm/unistd_32.h
-    enum SystemCall : c_long
-    {
-        restart_syscall = 0,
-        exit = 1,
-        fork = 2,
-        read = 3,
-        write = 4,
-        open = 5,
-        close = 6,
-        waitpid = 7,
-        creat = 8,
-        link = 9,
-        unlink = 10,
-        execve = 11,
-        chdir = 12,
-        time = 13,
-        mknod = 14,
-        chmod = 15,
-        lchown = 16,
-        break_ = 17,
-        oldstat = 18,
-        lseek = 19,
-        getpid = 20,
-        mount = 21,
-        umount = 22,
-        setuid = 23,
-        getuid = 24,
-        stime = 25,
-        ptrace = 26,
-        alarm = 27,
-        oldfstat = 28,
-        pause = 29,
-        utime = 30,
-        stty = 31,
-        gtty = 32,
-        access = 33,
-        nice = 34,
-        ftime = 35,
-        sync = 36,
-        kill = 37,
-        rename = 38,
-        mkdir = 39,
-        rmdir = 40,
-        dup = 41,
-        pipe = 42,
-        times = 43,
-        prof = 44,
-        brk = 45,
-        setgid = 46,
-        getgid = 47,
-        signal = 48,
-        geteuid = 49,
-        getegid = 50,
-        acct = 51,
-        umount2 = 52,
-        lock = 53,
-        ioctl = 54,
-        fcntl = 55,
-        mpx = 56,
-        setpgid = 57,
-        ulimit = 58,
-        oldolduname = 59,
-        umask = 60,
-        chroot = 61,
-        ustat = 62,
-        dup2 = 63,
-        getppid = 64,
-        getpgrp = 65,
-        setsid = 66,
-        sigaction = 67,
-        sgetmask = 68,
-        ssetmask = 69,
-        setreuid = 70,
-        setregid = 71,
-        sigsuspend = 72,
-        sigpending = 73,
-        sethostname = 74,
-        setrlimit = 75,
-        getrlimit = 76,
-        getrusage = 77,
-        gettimeofday = 78,
-        settimeofday = 79,
-        getgroups = 80,
-        setgroups = 81,
-        select = 82,
-        symlink = 83,
-        oldlstat = 84,
-        readlink = 85,
-        uselib = 86,
-        swapon = 87,
-        reboot = 88,
-        readdir = 89,
-        mmap = 90,
-        munmap = 91,
-        truncate = 92,
-        ftruncate = 93,
-        fchmod = 94,
-        fchown = 95,
-        getpriority = 96,
-        setpriority = 97,
-        profil = 98,
-        statfs = 99,
-        fstatfs = 100,
-        ioperm = 101,
-        socketcall = 102,
-        syslog = 103,
-        setitimer = 104,
-        getitimer = 105,
-        stat = 106,
-        lstat = 107,
-        fstat = 108,
-        olduname = 109,
-        iopl = 110,
-        vhangup = 111,
-        idle = 112,
-        vm86old = 113,
-        wait4 = 114,
-        swapoff = 115,
-        sysinfo = 116,
-        ipc = 117,
-        fsync = 118,
-        sigreturn = 119,
-        clone = 120,
-        setdomainname = 121,
-        uname = 122,
-        modify_ldt = 123,
-        adjtimex = 124,
-        mprotect = 125,
-        sigprocmask = 126,
-        create_module = 127,
-        init_module = 128,
-        delete_module = 129,
-        get_kernel_syms = 130,
-        quotactl = 131,
-        getpgid = 132,
-        fchdir = 133,
-        bdflush = 134,
-        sysfs = 135,
-        personality = 136,
-        afs_syscall = 137,
-        setfsuid = 138,
-        setfsgid = 139,
-        _llseek = 140,
-        getdents = 141,
-        _newselect = 142,
-        flock = 143,
-        msync = 144,
-        readv = 145,
-        writev = 146,
-        getsid = 147,
-        fdatasync = 148,
-        _sysctl = 149,
-        mlock = 150,
-        munlock = 151,
-        mlockall = 152,
-        munlockall = 153,
-        sched_setparam = 154,
-        sched_getparam = 155,
-        sched_setscheduler = 156,
-        sched_getscheduler = 157,
-        sched_yield = 158,
-        sched_get_priority_max = 159,
-        sched_get_priority_min = 160,
-        sched_rr_get_interval = 161,
-        nanosleep = 162,
-        mremap = 163,
-        setresuid = 164,
-        getresuid = 165,
-        vm86 = 166,
-        query_module = 167,
-        poll = 168,
-        nfsservctl = 169,
-        setresgid = 170,
-        getresgid = 171,
-        prctl = 172,
-        rt_sigreturn = 173,
-        rt_sigaction = 174,
-        rt_sigprocmask = 175,
-        rt_sigpending = 176,
-        rt_sigtimedwait = 177,
-        rt_sigqueueinfo = 178,
-        rt_sigsuspend = 179,
-        pread64 = 180,
-        pwrite64 = 181,
-        chown = 182,
-        getcwd = 183,
-        capget = 184,
-        capset = 185,
-        sigaltstack = 186,
-        sendfile = 187,
-        getpmsg = 188,
-        putpmsg = 189,
-        vfork = 190,
-        ugetrlimit = 191,
-        mmap2 = 192,
-        truncate64 = 193,
-        ftruncate64 = 194,
-        stat64 = 195,
-        lstat64 = 196,
-        fstat64 = 197,
-        lchown32 = 198,
-        getuid32 = 199,
-        getgid32 = 200,
-        geteuid32 = 201,
-        getegid32 = 202,
-        setreuid32 = 203,
-        setregid32 = 204,
-        getgroups32 = 205,
-        setgroups32 = 206,
-        fchown32 = 207,
-        setresuid32 = 208,
-        getresuid32 = 209,
-        setresgid32 = 210,
-        getresgid32 = 211,
-        chown32 = 212,
-        setuid32 = 213,
-        setgid32 = 214,
-        setfsuid32 = 215,
-        setfsgid32 = 216,
-        pivot_root = 217,
-        mincore = 218,
-        madvise = 219,
-        getdents64 = 220,
-        fcntl64 = 221,
-        gettid = 224,
-        readahead = 225,
-        setxattr = 226,
-        lsetxattr = 227,
-        fsetxattr = 228,
-        getxattr = 229,
-        lgetxattr = 230,
-        fgetxattr = 231,
-        listxattr = 232,
-        llistxattr = 233,
-        flistxattr = 234,
-        removexattr = 235,
-        lremovexattr = 236,
-        fremovexattr = 237,
-        tkill = 238,
-        sendfile64 = 239,
-        futex = 240,
-        sched_setaffinity = 241,
-        sched_getaffinity = 242,
-        set_thread_area = 243,
-        get_thread_area = 244,
-        io_setup = 245,
-        io_destroy = 246,
-        io_getevents = 247,
-        io_submit = 248,
-        io_cancel = 249,
-        fadvise64 = 250,
-        exit_group = 252,
-        lookup_dcookie = 253,
-        epoll_create = 254,
-        epoll_ctl = 255,
-        epoll_wait = 256,
-        remap_file_pages = 257,
-        set_tid_address = 258,
-        timer_create = 259,
-        timer_settime = 260,
-        timer_gettime = 261,
-        timer_getoverrun = 262,
-        timer_delete = 263,
-        clock_settime = 264,
-        clock_gettime = 265,
-        clock_getres = 266,
-        clock_nanosleep = 267,
-        statfs64 = 268,
-        fstatfs64 = 269,
-        tgkill = 270,
-        utimes = 271,
-        fadvise64_64 = 272,
-        vserver = 273,
-        mbind = 274,
-        get_mempolicy = 275,
-        set_mempolicy = 276,
-        mq_open = 277,
-        mq_unlink = 278,
-        mq_timedsend = 279,
-        mq_timedreceive = 280,
-        mq_notify = 281,
-        mq_getsetattr = 282,
-        kexec_load = 283,
-        waitid = 284,
-        add_key = 286,
-        request_key = 287,
-        keyctl = 288,
-        ioprio_set = 289,
-        ioprio_get = 290,
-        inotify_init = 291,
-        inotify_add_watch = 292,
-        inotify_rm_watch = 293,
-        migrate_pages = 294,
-        openat = 295,
-        mkdirat = 296,
-        mknodat = 297,
-        fchownat = 298,
-        futimesat = 299,
-        fstatat64 = 300,
-        unlinkat = 301,
-        renameat = 302,
-        linkat = 303,
-        symlinkat = 304,
-        readlinkat = 305,
-        fchmodat = 306,
-        faccessat = 307,
-        pselect6 = 308,
-        ppoll = 309,
-        unshare = 310,
-        set_robust_list = 311,
-        get_robust_list = 312,
-        splice = 313,
-        sync_file_range = 314,
-        tee = 315,
-        vmsplice = 316,
-        move_pages = 317,
-        getcpu = 318,
-        epoll_pwait = 319,
-        utimensat = 320,
-        signalfd = 321,
-        timerfd_create = 322,
-        eventfd = 323,
-        fallocate = 324,
-        timerfd_settime = 325,
-        timerfd_gettime = 326,
-        signalfd4 = 327,
-        eventfd2 = 328,
-        epoll_create1 = 329,
-        dup3 = 330,
-        pipe2 = 331,
-        inotify_init1 = 332,
-        preadv = 333,
-        pwritev = 334,
-        rt_tgsigqueueinfo = 335,
-        perf_event_open = 336,
-        recvmmsg = 337,
-        fanotify_init = 338,
-        fanotify_mark = 339,
-        prlimit64 = 340,
-        name_to_handle_at = 341,
-        open_by_handle_at = 342,
-        clock_adjtime = 343,
-        syncfs = 344,
-        sendmmsg = 345,
-        setns = 346,
-        process_vm_readv = 347,
-        process_vm_writev = 348,
-        kcmp = 349,
-        finit_module = 350,
-        sched_setattr = 351,
-        sched_getattr = 352,
-        renameat2 = 353,
-        seccomp = 354,
-        getrandom = 355,
-        memfd_create = 356,
-        bpf = 357,
-        execveat = 358,
-        socket = 359,
-        socketpair = 360,
-        bind = 361,
-        connect = 362,
-        listen = 363,
-        accept4 = 364,
-        getsockopt = 365,
-        setsockopt = 366,
-        getsockname = 367,
-        getpeername = 368,
-        sendto = 369,
-        sendmsg = 370,
-        recvfrom = 371,
-        recvmsg = 372,
-        shutdown = 373,
-        userfaultfd = 374,
-        membarrier = 375,
-        mlock2 = 376,
-        copy_file_range = 377,
-        preadv2 = 378,
-        pwritev2 = 379,
-        pkey_mprotect = 380,
-        pkey_alloc = 381,
-        pkey_free = 382,
-        statx = 383,
-        arch_prctl = 384,
-    }
-}
index 1ef16c12689c151935a41a7dd02341befe0d52d4..4845746700558f904eda7cbeff7b93f9687966cb 100644 (file)
@@ -1,20 +1,16 @@
 module core.sys.linux.unistd;
 
+public import core.sys.posix.unistd;
+
 version (linux):
-extern (C):
+extern(C):
 nothrow:
 @system:
-@nogc:
-
-public import core.sys.posix.unistd;
-public import core.sys.linux.syscalls : SystemCall;
-import core.stdc.config : c_long;
 
 // Additional seek constants for sparse file handling
 // from Linux's unistd.h, stdio.h, and linux/fs.h
 // (see http://man7.org/linux/man-pages/man2/lseek.2.html)
-enum
-{
+enum {
     /// Offset is relative to the next location containing data
     SEEK_DATA = 3,
     /// Offset is relative to the next hole (or EOF if file is not sparse)
@@ -26,17 +22,3 @@ char* getpass(const(char)* prompt);
 
 // Exit all threads in a process
 void exit_group(int status);
-
-/**
-Invoke system call specified by number, passing it the remaining arguments.
-This is completely system-dependent, and not often useful.
-
-In Unix, `syscall' sets `errno' for all errors and most calls return -1
-for errors; in many systems you cannot pass arguments or get return
-values for all system calls (`pipe', `fork', and `getppid' typically
-among them).
-
-In Mach, all system calls take normal arguments and always return an
-error code (zero for success).
-*/
-c_long syscall(SystemCall number, ...) @nogc nothrow;
index ab9ced80cf14259ac29b5c4bcea48e6feaecb379..f1281da275b7ea00678e88594931bebc0f7b90ff 100644 (file)
@@ -17,5 +17,5 @@ nothrow:
 
 static if (_NETBSD_SOURCE)
 {
-    pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+    pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
 }
index 131e67727e8de37fa6c389ee4f92946662d1a96f..4480c94ac37b66d4b057a9059a82c10531dced7a 100644 (file)
@@ -18,7 +18,7 @@ nothrow:
 static if (__BSD_VISIBLE)
 {
     void explicit_bzero(void*, size_t);
-    pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+    pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
     void* memrchr(scope const void*, int, size_t);
     size_t strlcat(char*, scope const char*, size_t);
     size_t strlcpy(char*, scope const char*, size_t);
index 0dce8c53f31e416421e554b69d61ca3d5c44ff86..32e51561562acd1108a6414dc5a80e7b07077c1f 100644 (file)
@@ -513,15 +513,21 @@ else version (DragonFlyBSD)
 }
 else version (Solaris)
 {
+    //SIGABRT (defined in core.stdc.signal)
     enum SIGALRM = 14;
     enum SIGBUS = 10;
     enum SIGCHLD = 18;
     enum SIGCONT = 25;
+    //SIGFPE (defined in core.stdc.signal)
     enum SIGHUP = 1;
+    //SIGILL (defined in core.stdc.signal)
+    //SIGINT (defined in core.stdc.signal)
     enum SIGKILL = 9;
     enum SIGPIPE = 13;
     enum SIGQUIT = 3;
+    //SIGSEGV (defined in core.stdc.signal)
     enum SIGSTOP = 23;
+    //SIGTERM (defined in core.stdc.signal)
     enum SIGTSTP = 24;
     enum SIGTTIN = 26;
     enum SIGTTOU = 27;
@@ -1339,6 +1345,10 @@ else version (Solaris)
         uint[4] __bits;
     }
 
+    enum SIG_BLOCK = 1;
+    enum SIG_UNBLOCK = 2;
+    enum SIG_SETMASK = 3;
+
     struct siginfo_t
     {
         int si_signo;
@@ -1427,6 +1437,18 @@ else version (Solaris)
         ___data __data;
     }
 
+    enum SI_NOINFO  = 32767;
+    enum SI_DTRACE  = 2050;
+    enum SI_RCTL    = 2049;
+    enum SI_USER    = 0;
+    enum SI_LWP     = -1;
+    enum SI_QUEUE   = -2;
+    enum SI_TIMER   = -3;
+    enum SI_ASYNCIO = -4;
+    enum SI_MESGQ   = -5;
+
+    enum SIGIO = SIGPOLL;
+
     int kill(pid_t, int);
     int sigaction(int, const scope sigaction_t*, sigaction_t*);
     int sigaddset(sigset_t*, int);
@@ -2833,9 +2855,9 @@ else version (Solaris)
     enum SIGPROF = 29;
     enum SIGSYS = 12;
     enum SIGTRAP = 5;
-    enum SIGVTALRM = 31;
+    enum SIGVTALRM = 28;
     enum SIGXCPU = 30;
-    enum SIGXFSZ = 25;
+    enum SIGXFSZ = 31;
 
     enum
     {
index b9e1c1c88c27569dce996364bb5bbc416d2a5a77..79d25624e2afb3bf15f47a789a08c3ae45352baa 100644 (file)
@@ -31,11 +31,11 @@ public import core.sys.posix.locale : locale_t;
 public import core.stdc.string;
 
 /// Copy string until character found
-void*  memccpy(return void* dst, scope const void* src, int c, size_t n) pure;
+void*  memccpy(return scope void* dst, scope const void* src, int c, size_t n) pure;
 /// Copy string (including terminating '\0')
-char*  stpcpy(return char* dst, scope const char* src) pure;
+char*  stpcpy(return scope char* dst, scope const char* src) pure;
 /// Ditto
-char*  stpncpy(return char* dst, const char* src, size_t len) pure;
+char*  stpncpy(return scope char* dst, const char* src, size_t len) pure;
 /// Compare strings according to current collation
 int    strcoll_l(scope const char* s1, scope const char* s2, locale_t locale);
 ///
@@ -47,6 +47,6 @@ size_t strnlen(scope const char* str, size_t maxlen) pure;
 /// System signal messages
 const(char)*  strsignal(int);
 /// Isolate sequential tokens in a null-terminated string
-char*  strtok_r(return char* str, scope const char* sep, char** context) pure;
+char*  strtok_r(return scope char* str, scope const char* sep, char** context) pure;
 /// Transform a string under locale
 size_t strxfrm_l(char* s1, scope const char* s2, size_t n, locale_t locale);
index de51c6a474671f4ae5fb4a34532073aeaabaf41c..6e0cfd3ac3d8eb91355affc9a182451275e296b5 100644 (file)
@@ -217,7 +217,7 @@ version (CRuntime_Glibc)
     }
     else
     {
-        extern (D) inout(ubyte)*   CMSG_DATA( return inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
+        extern (D) inout(ubyte)*   CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
     }
 
     private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc;
index 7da26317d356f52766c84cc1e6cbeb9049d87f69..7a46d520cc3852261e6c1559a22b38a0de68ed3e 100644 (file)
@@ -393,7 +393,7 @@ enum SHF_LINK_ORDER       = 0x80;
 enum SHF_OS_NONCONFORMING = 0x100;
 enum SHF_GROUP            = 0x200;
 enum SHF_TLS              = 0x400;
-
+enum SHF_COMPRESSED       = 0x800;
 enum SHF_MASKOS = 0x0ff00000;
 
 enum SHF_MASKPROC = 0xf0000000;
@@ -656,3 +656,6 @@ enum NT_ZONENAME   = 21;
 enum NT_FDINFO     = 22;
 enum NT_SPYMASTER  = 23;
 enum NT_NUM        = 23;
+
+enum SHF_ORDERED = 0x40000000;
+enum SHF_EXCLUDE = 0x80000000;
index 0c8198513d0b84e5fda7fd7264ef921e8bf52725..9927b64aec9de4edcdc67c4402a5a9f295f712c1 100644 (file)
@@ -52,9 +52,6 @@ enum R_386_NUM          = 39;
 
 enum ELF_386_MAXPGSZ = 0x10000;
 
-enum SHF_ORDERED = 0x40000000;
-enum SHF_EXCLUDE = 0x80000000;
-
 enum SHN_BEFORE = 0xff00;
 enum SHN_AFTER  = 0xff01;
 
index 81d02347598e1fd63f1268cb7134dfa107f4685f..e43bd405b8ad1da7812b58154d3192d139332137 100644 (file)
@@ -118,9 +118,6 @@ enum ELF_SPARCV9_MAXPGSZ = 0x100000;
 
 enum SHT_SPARC_GOTDATA = 0x70000000;
 
-enum SHF_ORDERED = 0x40000000;
-enum SHF_EXCLUDE = 0x80000000;
-
 enum SHN_BEFORE = 0xff00;
 enum SHN_AFTER  =  0xff01;
 
index 9848fb99115ba9e5ab1629199d84e10a61bd3a12..96698e8f0f9217e9da4ddced8aae3e4711edb2a4 100644 (file)
@@ -39,7 +39,8 @@ extern(Windows)
     alias BOOL         function(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, IMAGEHLP_SYMBOLA64 *Symbol) SymGetSymFromAddr64Func;
     alias DWORD        function(PCSTR DecoratedName, PSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) UnDecorateSymbolNameFunc;
     alias DWORD64      function(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) SymLoadModule64Func;
-    alias BOOL         function(HANDLE HProcess, PTSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc;
+    alias BOOL         function(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc;
+    alias BOOL         function(HANDLE hProcess, PCSTR SearchPath) SymSetSearchPathFunc;
     alias BOOL         function(HANDLE hProcess, DWORD64 Address) SymUnloadModule64Func;
     alias BOOL         function(HANDLE hProcess, ULONG ActionCode, ulong CallbackContext, ulong UserContext) PSYMBOL_REGISTERED_CALLBACK64;
     alias BOOL         function(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ulong UserContext) SymRegisterCallback64Func;
@@ -61,6 +62,7 @@ struct DbgHelp
     UnDecorateSymbolNameFunc UnDecorateSymbolName;
     SymLoadModule64Func      SymLoadModule64;
     SymGetSearchPathFunc     SymGetSearchPath;
+    SymSetSearchPathFunc     SymSetSearchPath;
     SymUnloadModule64Func    SymUnloadModule64;
     SymRegisterCallback64Func SymRegisterCallback64;
     ImagehlpApiVersionFunc   ImagehlpApiVersion;
@@ -84,6 +86,7 @@ struct DbgHelp
             sm_inst.UnDecorateSymbolName     = cast(UnDecorateSymbolNameFunc) GetProcAddress(sm_hndl,"UnDecorateSymbolName");
             sm_inst.SymLoadModule64          = cast(SymLoadModule64Func) GetProcAddress(sm_hndl,"SymLoadModule64");
             sm_inst.SymGetSearchPath         = cast(SymGetSearchPathFunc) GetProcAddress(sm_hndl,"SymGetSearchPath");
+            sm_inst.SymSetSearchPath         = cast(SymSetSearchPathFunc) GetProcAddress(sm_hndl,"SymSetSearchPath");
             sm_inst.SymUnloadModule64        = cast(SymUnloadModule64Func) GetProcAddress(sm_hndl,"SymUnloadModule64");
             sm_inst.SymRegisterCallback64    = cast(SymRegisterCallback64Func) GetProcAddress(sm_hndl, "SymRegisterCallback64");
             sm_inst.ImagehlpApiVersion       = cast(ImagehlpApiVersionFunc) GetProcAddress(sm_hndl, "ImagehlpApiVersion");
@@ -91,7 +94,8 @@ struct DbgHelp
                     sm_inst.SymSetOptions && sm_inst.SymFunctionTableAccess64 && sm_inst.SymGetLineFromAddr64 &&
                     sm_inst.SymGetModuleBase64 && sm_inst.SymGetModuleInfo64 && sm_inst.SymGetSymFromAddr64 &&
                     sm_inst.UnDecorateSymbolName && sm_inst.SymLoadModule64 && sm_inst.SymGetSearchPath &&
-                    sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 && sm_inst.ImagehlpApiVersion);
+                    sm_inst.SymSetSearchPath && sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 &&
+                    sm_inst.ImagehlpApiVersion);
 
             return &sm_inst;
         }
index b7dde9387afd44844782b53d1b6081de9bdf679c..fe4d24fafce5f82a886180b974cc3333f0bf58e2 100644 (file)
@@ -719,7 +719,7 @@ class Thread : ThreadBase
                     // the effective maximum.
 
                     // maxupri
-                    result.PRIORITY_MIN = -clinfo[0];
+                    result.PRIORITY_MIN = -cast(int)(clinfo[0]);
                     // by definition
                     result.PRIORITY_DEFAULT = 0;
                 }
@@ -2196,8 +2196,7 @@ extern (C) void thread_init() @nogc
         status = sem_init( &suspendCount, 0, 0 );
         assert( status == 0 );
     }
-    if (typeid(Thread).initializer.ptr)
-        _mainThreadStore[] = typeid(Thread).initializer[];
+    _mainThreadStore[] = __traits(initSymbol, Thread)[];
     Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor());
 }
 
index 4592bf1d9757c98c900efea7dac0261d50cbbdde..9cee4d8d77d270520011a851f4c5210ef54879c6 100644 (file)
@@ -771,10 +771,7 @@ package void thread_term_tpl(ThreadT, MainThreadStore)(ref MainThreadStore _main
     // destruct manually as object.destroy is not @nogc
     (cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor();
     _d_monitordelete_nogc(ThreadBase.sm_main);
-    if (typeid(ThreadT).initializer.ptr)
-        _mainThreadStore[] = typeid(ThreadT).initializer[];
-    else
-        (cast(ubyte[])_mainThreadStore)[] = 0;
+    _mainThreadStore[] = __traits(initSymbol, ThreadT)[];
     ThreadBase.sm_main = null;
 
     assert(ThreadBase.sm_tbeg && ThreadBase.sm_tlen == 1);
index a079e0e73e998cb5a844bba00a0f72a4ed37d1e3..fee19ae65f0b7e9ac42c296f620432233ba7db8e 100644 (file)
@@ -3485,7 +3485,7 @@ enum immutable(void)* rtinfoHasPointers = cast(void*)1;
 
 // Helper functions
 
-private inout(TypeInfo) getElement(return inout TypeInfo value) @trusted pure nothrow
+private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow
 {
     TypeInfo element = cast() value;
     for (;;)
@@ -4215,8 +4215,8 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == class))
 
         static if (initialize)
         {
-            enum classSize = __traits(classInstanceSize, T);
-            (cast(void*)obj)[0 .. classSize] = typeid(T).initializer[];
+            const initializer = __traits(initSymbol, T);
+            (cast(void*)obj)[0 .. initializer.length] = initializer[];
         }
     }
     else
@@ -4651,6 +4651,8 @@ public import core.internal.array.construction : _d_arrayctor;
 public import core.internal.array.construction : _d_arraysetctor;
 public import core.internal.array.capacity: _d_arraysetlengthTImpl;
 
+public import core.lifetime : _d_delstruct;
+
 public import core.internal.dassert: _d_assert_fail;
 
 public import core.internal.destruction: __ArrayDtor;
index 6ff93f76da432dfbd16b6c2338924170d03ba351..0c38622a8790980d0d6641e0fafc96efd159733f 100644 (file)
@@ -287,7 +287,7 @@ TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo va
     void* p = GC.malloc(sizeti + (2 + rtisize) * (void*).sizeof);
     import core.stdc.string : memcpy;
 
-    memcpy(p, typeid(TypeInfo_Struct).initializer().ptr, sizeti);
+    memcpy(p, __traits(initSymbol, TypeInfo_Struct).ptr, sizeti);
 
     auto ti = cast(TypeInfo_Struct) p;
     auto extra = cast(TypeInfo*)(p + sizeti);
@@ -853,7 +853,7 @@ struct Range
 
 extern (C) pure nothrow @nogc @safe
 {
-    Range _aaRange(return AA aa)
+    Range _aaRange(return scope AA aa)
     {
         if (!aa)
             return Range();
index dcb4438c700693d47e3b459afa88ffe733e958ca..1604510b4277ebf2211f879d0206a279e90f4522 100644 (file)
@@ -36,7 +36,7 @@ extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const
  *      If it is null, return null.
  *      Else, undefined crash
  */
-Object _d_toObject(return void* p)
+Object _d_toObject(return scope void* p)
 {
     if (!p)
         return null;
index f7682f31b633ee1d24c60196101b7a047fa4f8b1..a6605f4d60374e411e0bf5e8092069f9a287b66a 100644 (file)
@@ -101,6 +101,9 @@ string rt_cmdlineOption(string opt, scope rt_configCallBack dg) @nogc nothrow
     {
         foreach (a; rt_args)
         {
+            if (a == "--")
+                break;
+
             if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" &&
                 a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=')
             {
index f1a9d87386030c08de218951d769f965a0041b72..1f7a81de80faf3e62d69d0fe7c8de049c71b47d2 100644 (file)
@@ -181,7 +181,7 @@ extern (C) void _d_delstruct(void** p, TypeInfo_Struct inf) @weak
 }
 
 // strip const/immutable/shared/inout from type info
-inout(TypeInfo) unqualify(return inout(TypeInfo) cti) pure nothrow @nogc
+inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc
 {
     TypeInfo ti = cast() cti;
     while (ti)
@@ -381,7 +381,7 @@ size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow
 /**
   get the start of the array for the given block
   */
-void *__arrayStart(return BlkInfo info) nothrow pure
+void *__arrayStart(return scope BlkInfo info) nothrow pure
 {
     return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0);
 }
index 6bfce635c72a885296a635b2d74e7d12ff30115a..763f439282253d6f12034b9c7da21845ff85e705 100644 (file)
@@ -264,7 +264,7 @@ struct Monitor
 
 private:
 
-@property ref shared(Monitor*) monitor(return Object h) pure nothrow @nogc
+@property ref shared(Monitor*) monitor(return scope Object h) pure nothrow @nogc
 {
     return *cast(shared Monitor**)&h.__monitor;
 }
index 29bcf33c01f2713945edf739aca96c9619fbfc30..68fefcb1ae4f5b682ad85ab8639ee188ea79fabe 100644 (file)
@@ -1,4 +1,4 @@
-574bf883b790340fb753d6542ec48a3ba3e6cb82
+12329adb67fb43891d6e4e543e7257bc34db0aa7
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
index 9e728e4622f4f9d52653be62fde9fe3752e1619f..af665c41197d5fe2199ce0ccded267f33dd7be4c 100644 (file)
@@ -3595,7 +3595,6 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
     assert(res.equal("cba"));
 }
 
-
 /// Ditto
 auto joiner(RoR)(RoR r)
 if (isInputRange!RoR && isInputRange!(ElementType!RoR))
@@ -3621,14 +3620,32 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
                 _currentBack = typeof(_currentBack).init;
         }
 
+        void replaceCurrent(typeof(_current) current) @trusted
+        {
+            import core.lifetime : move;
+
+            current.move(_current);
+        }
+
+        static if (isBidirectional)
+        {
+            void replaceCurrentBack(typeof(_currentBack) currentBack) @trusted
+            {
+                import core.lifetime : move;
+
+                currentBack.move(_currentBack);
+            }
+        }
+
     public:
         this(RoR r)
         {
             _items = r;
+            // field _current must be initialized in constructor, because it is nested struct
+            _current = typeof(_current).init;
 
             static if (isBidirectional && hasNested!Result)
                 _currentBack = typeof(_currentBack).init;
-            // field _current must be initialized in constructor, because it is nested struct
             mixin(popFrontEmptyElements);
             static if (isBidirectional)
                 mixin(popBackEmptyElements);
@@ -3673,13 +3690,13 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
                 // consumed when a .save'd copy of ourselves is iterated over. So
                 // we need to .save each subrange we traverse.
                 static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
-                    _current = _items.front.save;
+                    replaceCurrent(_items.front.save);
                 else
-                    _current = _items.front;
+                    replaceCurrent(_items.front);
             }
             else
             {
-                _current = typeof(_current).init;
+                replaceCurrent(typeof(_current).init);
             }
         };
 
@@ -3696,9 +3713,9 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
                 static if (isBidirectional)
                 {
                     static if (is(typeof(null) : typeof(_currentBack)))
-                        r._currentBack = _currentBack is null ? null : _currentBack.save;
+                        r.replaceCurrentBack(_currentBack is null ? null : _currentBack.save);
                     else
-                        r._currentBack = _currentBack.save;
+                        r.replaceCurrentBack(_currentBack.save);
                     r.reachedFinalElement = reachedFinalElement;
                 }
                 return r;
@@ -3784,22 +3801,22 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
                     static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
                     {
                         if (reachedFinalElement)
-                            _current = _items.back.save;
+                            replaceCurrent(_items.back.save);
                         else
-                            _currentBack = _items.back.save;
+                            replaceCurrentBack(_items.back.save);
                     }
                     else
                     {
                         if (reachedFinalElement)
-                            _current = _items.back;
+                            replaceCurrent(_items.back);
                         else
-                            _currentBack = _items.back;
+                            replaceCurrentBack(_items.back);
                     }
                 }
                 else
                 {
-                    _current = typeof(_current).init;
-                    _currentBack = typeof(_currentBack).init;
+                    replaceCurrent(typeof(_current).init);
+                    replaceCurrentBack(typeof(_currentBack).init);
                 }
             };
 
@@ -4232,6 +4249,15 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
     assert([[0]].joiner.save.back == 0);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22561
+@safe pure unittest
+{
+    import std.range : only;
+
+    static immutable struct S { int[] array; }
+    assert([only(S(null))].joiner.front == S(null));
+}
+
 /++
 Implements the homonym function (also known as `accumulate`, $(D
 compress), `inject`, or `foldl`) present in various programming
index 07cbb9b98238dc8b8b3af3038f8a30dbe955a3eb..22b7b98c229e112858f4dc41cc7c96d27d89630c 100644 (file)
@@ -886,31 +886,13 @@ if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range
     static if (hasElaborateAssign!T)
     {
         import std.algorithm.internal : addressOf;
-        //Elaborate opAssign. Must go the memcpy road.
-        //We avoid calling emplace here, because our goal is to initialize to
-        //the static state of T.init,
-        //So we want to avoid any un-necassarilly CC'ing of T.init
+        //Elaborate opAssign. Must go the memcpy/memset road.
         static if (!__traits(isZeroInit, T))
         {
-            auto p = typeid(T).initializer();
             for ( ; !range.empty ; range.popFront() )
             {
-                static if (__traits(isStaticArray, T))
-                {
-                    // static array initializer only contains initialization
-                    // for one element of the static array.
-                    auto elemp = cast(void *) addressOf(range.front);
-                    auto endp = elemp + T.sizeof;
-                    while (elemp < endp)
-                    {
-                        memcpy(elemp, p.ptr, p.length);
-                        elemp += p.length;
-                    }
-                }
-                else
-                {
-                    memcpy(addressOf(range.front), p.ptr, T.sizeof);
-                }
+                import core.internal.lifetime : emplaceInitializer;
+                emplaceInitializer(range.front);
             }
         }
         else
@@ -1456,10 +1438,7 @@ private void moveEmplaceImpl(T)(ref scope T target, ref return scope T source)
             static if (__traits(isZeroInit, T))
                 () @trusted { memset(&source, 0, sz); }();
             else
-            {
-                auto init = typeid(T).initializer();
-                () @trusted { memcpy(&source, init.ptr, sz); }();
-            }
+                () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }();
         }
     }
     else static if (isStaticArray!T)
index f2877ccbdf43d1f006fbaca7dc84ca6a56ddfe99..ee68b234b1510a426da714520559e85046733740 100644 (file)
@@ -3121,14 +3121,14 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R &&
     else
         static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof);
 
-    static trustedMalloc(size_t len) @trusted
+    static trustedMalloc()(size_t len) @trusted
     {
         import core.checkedint : mulu;
-        import core.stdc.stdlib : malloc;
+        import core.memory : pureMalloc;
         bool overflow;
         const nbytes = mulu(len, T.sizeof, overflow);
         if (overflow) assert(false, "multiplication overflowed");
-        T[] result = (cast(T*) malloc(nbytes))[0 .. len];
+        T[] result = (cast(T*) pureMalloc(nbytes))[0 .. len];
         static if (hasIndirections!T)
         {
             import core.memory : GC;
@@ -3145,15 +3145,15 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R &&
         {
             foreach (i; 0 .. length) collectException(destroy(xform1[i]));
         }
-        static void trustedFree(T[] p) @trusted
+        static void trustedFree()(T[] p) @trusted
         {
-            import core.stdc.stdlib : free;
+            import core.memory : pureFree;
             static if (hasIndirections!T)
             {
                 import core.memory : GC;
                 GC.removeRange(p.ptr);
             }
-            free(p.ptr);
+            pureFree(p.ptr);
         }
         trustedFree(xform1);
     }
@@ -3186,7 +3186,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
 }
 
 ///
-@safe unittest
+@safe pure unittest
 {
     import std.algorithm.iteration : map;
     import std.numeric : entropy;
@@ -3207,7 +3207,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
     assert(isSorted!("a > b")(map!(entropy)(arr)));
 }
 
-@safe unittest
+@safe pure unittest
 {
     import std.algorithm.iteration : map;
     import std.numeric : entropy;
@@ -3228,7 +3228,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
     assert(isSorted!("a < b")(map!(entropy)(arr)));
 }
 
-@safe unittest
+@safe pure unittest
 {
     // binary transform function
     string[] strings = [ "one", "two", "three" ];
@@ -3237,7 +3237,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=4909
-@safe unittest
+@safe pure unittest
 {
     import std.typecons : Tuple;
     Tuple!(char)[] chars;
@@ -3245,7 +3245,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=5924
-@safe unittest
+@safe pure unittest
 {
     import std.typecons : Tuple;
     Tuple!(char)[] chars;
@@ -3253,7 +3253,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=13965
-@safe unittest
+@safe pure unittest
 {
     import std.typecons : Tuple;
     Tuple!(char)[] chars;
@@ -3261,7 +3261,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=13965
-@safe unittest
+@safe pure unittest
 {
     import std.algorithm.iteration : map;
     import std.numeric : entropy;
index a9830af61a27741f2bd329aa7a341608aa5b5f45..fb383ae3f2e239d654d181828101d2011b245599 100644 (file)
@@ -2149,14 +2149,16 @@ private
 
                     if (msg.convertsTo!(Args))
                     {
-                        static if (is(ReturnType!(t) == bool))
+                        alias RT = ReturnType!(t);
+                        static if (is(RT == bool))
                         {
                             return msg.map(op);
                         }
                         else
                         {
                             msg.map(op);
-                            return true;
+                            static if (!is(immutable RT == immutable noreturn))
+                                return true;
                         }
                     }
                 }
@@ -2745,7 +2747,8 @@ auto ref initOnce(alias var)(lazy typeof(var) init, shared Mutex mutex)
             if (!atomicLoad!(MemoryOrder.raw)(flag))
             {
                 var = init;
-                atomicStore!(MemoryOrder.rel)(flag, true);
+                static if (!is(immutable typeof(var) == immutable noreturn))
+                    atomicStore!(MemoryOrder.rel)(flag, true);
             }
         }
     }
@@ -2827,3 +2830,26 @@ auto ref initOnce(alias var)(lazy typeof(var) init, Mutex mutex)
     immutable expected = Aggregate(42, [1, 2, 3, 4, 5]);
     assert(result1 == expected);
 }
+
+// Noreturn support
+@system unittest
+{
+    static noreturn foo(int) { throw new Exception(""); }
+
+    if (false) spawn(&foo, 1);
+    if (false) spawnLinked(&foo, 1);
+
+    if (false) receive(&foo);
+    if (false) receiveTimeout(Duration.init, &foo);
+
+    // Wrapped in __traits(compiles) to skip codegen which crashes dmd's backend
+    static assert(__traits(compiles, receiveOnly!noreturn()                 ));
+    static assert(__traits(compiles, send(Tid.init, noreturn.init)          ));
+    static assert(__traits(compiles, prioritySend(Tid.init, noreturn.init)  ));
+    static assert(__traits(compiles, yield(noreturn.init)                   ));
+
+    static assert(__traits(compiles, {
+        __gshared noreturn n;
+        initOnce!n(noreturn.init);
+    }));
+}
index cc3e2e85dbcc56647a9feb3cc4b4cac15c8c18ea..32d56ecc73396b972d4292e5a05376cfa744ae51 100644 (file)
@@ -196,6 +196,12 @@ struct DList(T)
 
         T _payload = T.init;
 
+        this (BaseNode _base, T _payload)
+        {
+            this._base = _base;
+            this._payload = _payload;
+        }
+
         inout(BaseNode)* asBaseNode() inout @trusted
         {
             return &_base;
index f8e70fc08825a005ffbac093ae5fe58857c32dd0..0b0a0b2f59f5248d658f0278756fa21255fe46bd 100644 (file)
@@ -887,7 +887,7 @@ if (is(typeof(binaryFun!less(T.init, T.init))))
      * Returns:
      *   true if node was added
      */
-    private bool _add(return Elem n)
+    private bool _add(return scope Elem n)
     {
         Node result;
         static if (!allowDuplicates)
index 741088a72dcd40112c7d612d85490ef30ce4962a..ba2a21056c74b4e41359187070cf4b2f53b73480 100644 (file)
@@ -8349,7 +8349,7 @@ private:
     }
 
     {
-        SysTime stFunc(scope const SysTime st) { return cast(SysTime) st; }
+        SysTime stFunc(scope const SysTime st) { return SysTime.init; }
         auto interval = Interval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)),
                                          SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
         auto ir = IntervalRange!(SysTime, Direction.fwd)(interval, &stFunc);
@@ -8794,7 +8794,7 @@ private:
     }
 
     {
-        SysTime stFunc(scope const SysTime st) { return cast(SysTime) st; }
+        SysTime stFunc(scope const SysTime st) { return SysTime.init; }
         auto posInfInterval = PosInfInterval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)));
         auto ir = PosInfIntervalRange!SysTime(posInfInterval, &stFunc);
     }
@@ -9076,7 +9076,7 @@ private:
     }
 
     {
-        SysTime stFunc(scope const SysTime st) { return cast(SysTime)(st); }
+        SysTime stFunc(scope const SysTime st) { return SysTime.init; }
         auto negInfInterval = NegInfInterval!SysTime(SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
         auto ir = NegInfIntervalRange!(SysTime)(negInfInterval, &stFunc);
     }
index 4da1281f98a0faec05f1bb9aa738e5bcc2865341..9b2a8443fddac427479f1cc7a2e644c2a730861c 100644 (file)
@@ -503,7 +503,7 @@ public:
                        given $(REF DateTime,std,datetime,date) is assumed to
                        be in the given time zone.
       +/
-    this(DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
+    this(DateTime dateTime, return scope immutable TimeZone tz = null) return scope @safe nothrow
     {
         try
             this(dateTime, Duration.zero, tz);
@@ -554,7 +554,7 @@ public:
             $(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's
             greater than or equal to one second.
       +/
-    this(DateTime dateTime, Duration fracSecs, immutable TimeZone tz = null) @safe
+    this(DateTime dateTime, Duration fracSecs, return scope immutable TimeZone tz = null) return scope @safe
     {
         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
@@ -611,7 +611,7 @@ public:
                    given $(REF Date,std,datetime,date) is assumed to be in the
                    given time zone.
       +/
-    this(Date date, immutable TimeZone tz = null) @safe nothrow
+    this(Date date, return scope immutable TimeZone tz = null) return scope @safe nothrow
     {
         _timezone = tz is null ? LocalTime() : tz;
 
@@ -664,7 +664,7 @@ public:
                       $(LREF SysTime). If null,
                       $(REF LocalTime,std,datetime,timezone) will be used.
       +/
-    this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
+    this(long stdTime, return scope immutable TimeZone tz = null) return scope @safe pure nothrow
     {
         _stdTime = stdTime;
         _timezone = tz is null ? LocalTime() : tz;
@@ -693,7 +693,7 @@ public:
 
         Returns: The `this` of this `SysTime`.
       +/
-    ref SysTime opAssign()(auto ref const(SysTime) rhs) return @safe pure nothrow scope
+    ref SysTime opAssign()(auto ref const(SysTime) rhs) return scope @safe pure nothrow
     {
         _stdTime = rhs._stdTime;
         _timezone = rhs._timezone;
@@ -710,6 +710,7 @@ public:
         st = other;
         assert(st == other);
 
+        version (none) // https://issues.dlang.org/show_bug.cgi?id=21175
         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
         {
             left = right;
@@ -2184,7 +2185,7 @@ public:
         hours - adjust the time to this $(LREF SysTime)'s time zone before
         returning.
       +/
-    @property immutable(TimeZone) timezone() @safe const pure nothrow scope
+    @property immutable(TimeZone) timezone() @safe const pure nothrow return scope
     {
         return _timezone;
     }
@@ -2238,7 +2239,7 @@ public:
     /++
         Returns whether DST is in effect for this $(LREF SysTime).
       +/
-    @property bool dstInEffect() @safe const nothrow scope
+    @property bool dstInEffect() @safe const nothrow return scope
     {
         return _timezone.dstInEffect(_stdTime);
     }
@@ -2261,7 +2262,7 @@ public:
         Returns what the offset from UTC is for this $(LREF SysTime).
         It includes the DST offset in effect at that time (if any).
       +/
-    @property Duration utcOffset() @safe const nothrow scope
+    @property Duration utcOffset() @safe const nothrow return scope
     {
         return _timezone.utcOffsetAt(_stdTime);
     }
@@ -9586,13 +9587,13 @@ private:
 
         @property override bool hasDST() @safe const nothrow @nogc { return false; }
 
-        override bool dstInEffect(long stdTime) @safe const nothrow @nogc { return false; }
+        override bool dstInEffect(long stdTime) @safe const scope nothrow @nogc { return false; }
 
-        override long utcToTZ(long stdTime) @safe const nothrow @nogc { return 0; }
+        override long utcToTZ(long stdTime) @safe const scope nothrow @nogc { return 0; }
 
-        override long tzToUTC(long adjTime) @safe const nothrow @nogc { return 0; }
+        override long tzToUTC(long adjTime) @safe const scope nothrow @nogc { return 0; }
 
-        override Duration utcOffsetAt(long stdTime) @safe const nothrow @nogc { return Duration.zero; }
+        override Duration utcOffsetAt(long stdTime) @safe const scope nothrow @nogc { return Duration.zero; }
 
     private:
 
@@ -9628,7 +9629,7 @@ private:
         return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
     }
 
-    pragma(inline, true) @property void _timezone(immutable TimeZone tz) @safe pure nothrow @nogc scope
+    pragma(inline, true) @property void _timezone(return scope immutable TimeZone tz) @safe pure nothrow @nogc scope
     {
         _timezoneStorage = tz;
     }
index 052758097a92b621caff6d4606f0b0fe657b74dd..a55411b02d5765943bb72feb847707c4af0e9894 100644 (file)
@@ -100,7 +100,7 @@ public:
         However, on Windows, it may be the unabbreviated name (e.g. Pacific
         Standard Time). Regardless, it is not the same as name.
       +/
-    @property string stdName() @safe const nothrow
+    @property string stdName() @safe const scope nothrow
     {
         return _stdName;
     }
@@ -113,7 +113,7 @@ public:
         However, on Windows, it may be the unabbreviated name (e.g. Pacific
         Daylight Time). Regardless, it is not the same as name.
       +/
-    @property string dstName() @safe const nothrow
+    @property string dstName() @safe const scope nothrow
     {
         return _dstName;
     }
@@ -137,7 +137,7 @@ public:
             stdTime = The UTC time that needs to be checked for DST in this time
                       zone.
       +/
-    abstract bool dstInEffect(long stdTime) @safe const nothrow;
+    abstract bool dstInEffect(long stdTime) @safe const scope nothrow;
 
 
     /++
@@ -148,7 +148,7 @@ public:
             stdTime = The UTC time that needs to be adjusted to this time zone's
                       time.
       +/
-    abstract long utcToTZ(long stdTime) @safe const nothrow;
+    abstract long utcToTZ(long stdTime) @safe const scope nothrow;
 
 
     /++
@@ -159,7 +159,7 @@ public:
             adjTime = The time in this time zone that needs to be adjusted to
                       UTC time.
       +/
-    abstract long tzToUTC(long adjTime) @safe const nothrow;
+    abstract long tzToUTC(long adjTime) @safe const scope nothrow;
 
 
     /++
@@ -170,7 +170,7 @@ public:
             stdTime = The UTC time for which to get the offset from UTC for this
                       time zone.
       +/
-    Duration utcOffsetAt(long stdTime) @safe const nothrow
+    Duration utcOffsetAt(long stdTime) @safe const scope nothrow
     {
         return dur!"hnsecs"(utcToTZ(stdTime) - stdTime);
     }
@@ -580,7 +580,7 @@ public:
         dynamically rather than it being fixed like it would be with most time
         zones.
       +/
-    @property override string stdName() @trusted const nothrow
+    @property override string stdName() @trusted const scope nothrow
     {
         version (Posix)
         {
@@ -665,7 +665,7 @@ public:
         dynamically rather than it being fixed like it would be with most time
         zones.
       +/
-    @property override string dstName() @trusted const nothrow
+    @property override string dstName() @trusted const scope nothrow
     {
         version (Posix)
         {
@@ -809,7 +809,7 @@ public:
             stdTime = The UTC time that needs to be checked for DST in this time
                       zone.
       +/
-    override bool dstInEffect(long stdTime) @trusted const nothrow
+    override bool dstInEffect(long stdTime) @trusted const scope nothrow
     {
         import core.stdc.time : tm;
 
@@ -863,7 +863,7 @@ public:
         See_Also:
             `TimeZone.utcToTZ`
       +/
-    override long utcToTZ(long stdTime) @trusted const nothrow
+    override long utcToTZ(long stdTime) @trusted const scope nothrow
     {
         version (Solaris)
             return stdTime + convert!("seconds", "hnsecs")(tm_gmtoff(stdTime));
@@ -904,7 +904,7 @@ public:
             adjTime = The time in this time zone that needs to be adjusted to
                       UTC time.
       +/
-    override long tzToUTC(long adjTime) @trusted const nothrow
+    override long tzToUTC(long adjTime) @trusted const scope nothrow
     {
         version (Posix)
         {
@@ -1159,7 +1159,7 @@ public:
     /++
         Always returns false.
       +/
-    override bool dstInEffect(long stdTime) @safe const nothrow
+    override bool dstInEffect(long stdTime) @safe const scope nothrow
     {
         return false;
     }
@@ -1175,7 +1175,7 @@ public:
         See_Also:
             `TimeZone.utcToTZ`
       +/
-    override long utcToTZ(long stdTime) @safe const nothrow
+    override long utcToTZ(long stdTime) @safe const scope nothrow
     {
         return stdTime;
     }
@@ -1208,7 +1208,7 @@ public:
             adjTime = The time in this time zone that needs to be adjusted to
                       UTC time.
       +/
-    override long tzToUTC(long adjTime) @safe const nothrow
+    override long tzToUTC(long adjTime) @safe const scope nothrow
     {
         return adjTime;
     }
@@ -1238,7 +1238,7 @@ public:
             stdTime = The UTC time for which to get the offset from UTC for this
                       time zone.
       +/
-    override Duration utcOffsetAt(long stdTime) @safe const nothrow
+    override Duration utcOffsetAt(long stdTime) @safe const scope nothrow
     {
         return dur!"hnsecs"(0);
     }
@@ -1285,7 +1285,7 @@ public:
     /++
         Always returns false.
       +/
-    override bool dstInEffect(long stdTime) @safe const nothrow
+    override bool dstInEffect(long stdTime) @safe const scope nothrow
     {
         return false;
     }
@@ -1299,7 +1299,7 @@ public:
             stdTime = The UTC time that needs to be adjusted to this time zone's
                       time.
       +/
-    override long utcToTZ(long stdTime) @safe const nothrow
+    override long utcToTZ(long stdTime) @safe const scope nothrow
     {
         return stdTime + _utcOffset.total!"hnsecs";
     }
@@ -1326,7 +1326,7 @@ public:
             adjTime = The time in this time zone that needs to be adjusted to
                       UTC time.
       +/
-    override long tzToUTC(long adjTime) @safe const nothrow
+    override long tzToUTC(long adjTime) @safe const scope nothrow
     {
         return adjTime - _utcOffset.total!"hnsecs";
     }
@@ -1352,7 +1352,7 @@ public:
             stdTime = The UTC time for which to get the offset from UTC for this
                       time zone.
       +/
-    override Duration utcOffsetAt(long stdTime) @safe const nothrow
+    override Duration utcOffsetAt(long stdTime) @safe const scope nothrow
     {
         return _utcOffset;
     }
@@ -1919,7 +1919,7 @@ public:
             stdTime = The UTC time that needs to be checked for DST in this time
                       zone.
       +/
-    override bool dstInEffect(long stdTime) @safe const nothrow
+    override bool dstInEffect(long stdTime) @safe const scope nothrow
     {
         assert(!_transitions.empty);
 
@@ -1943,7 +1943,7 @@ public:
             stdTime = The UTC time that needs to be adjusted to this time zone's
                       time.
       +/
-    override long utcToTZ(long stdTime) @safe const nothrow
+    override long utcToTZ(long stdTime) @safe const scope nothrow
     {
         assert(!_transitions.empty);
 
@@ -1968,7 +1968,7 @@ public:
             adjTime = The time in this time zone that needs to be adjusted to
                       UTC time.
       +/
-    override long tzToUTC(long adjTime) @safe const nothrow
+    override long tzToUTC(long adjTime) @safe const scope nothrow
     {
         assert(!_transitions.empty, "UTC offset's not available");
 
@@ -2691,7 +2691,7 @@ private:
     }
 
 
-    int calculateLeapSeconds(long stdTime) @safe const pure nothrow
+    int calculateLeapSeconds(long stdTime) @safe const scope pure nothrow
     {
         if (_leapSeconds.empty)
             return 0;
@@ -2864,7 +2864,7 @@ version (StdDdoc)
             current dates but will still return true for `hasDST` because the
             time zone did at some point have DST.
           +/
-        @property override bool hasDST() @safe const nothrow;
+        @property override bool hasDST() @safe const scope nothrow;
 
 
         /++
@@ -2876,7 +2876,7 @@ version (StdDdoc)
                 stdTime = The UTC time that needs to be checked for DST in this
                           time zone.
           +/
-        override bool dstInEffect(long stdTime) @safe const nothrow;
+        override bool dstInEffect(long stdTime) @safe const scope nothrow;
 
 
         /++
@@ -2888,7 +2888,7 @@ version (StdDdoc)
                 stdTime = The UTC time that needs to be adjusted to this time
                           zone's time.
           +/
-        override long utcToTZ(long stdTime) @safe const nothrow;
+        override long utcToTZ(long stdTime) @safe const scope nothrow;
 
 
         /++
@@ -2900,7 +2900,7 @@ version (StdDdoc)
                 adjTime = The time in this time zone that needs to be adjusted
                           to UTC time.
           +/
-        override long tzToUTC(long adjTime) @safe const nothrow;
+        override long tzToUTC(long adjTime) @safe const scope nothrow;
 
 
         /++
@@ -2945,9 +2945,9 @@ version (StdDdoc)
         else
             alias TIME_ZONE_INFORMATION = void*;
 
-        static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow;
-        static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow;
-        static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow;
+        static bool _dstInEffect(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow;
+        static long _utcToTZ(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow;
+        static long _tzToUTC(const scope TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow;
 
         this() immutable pure
         {
@@ -2967,25 +2967,25 @@ else version (Windows)
 
     public:
 
-        @property override bool hasDST() @safe const nothrow
+        @property override bool hasDST() @safe const scope nothrow
         {
             return _tzInfo.DaylightDate.wMonth != 0;
         }
 
 
-        override bool dstInEffect(long stdTime) @safe const nothrow
+        override bool dstInEffect(long stdTime) @safe const scope nothrow
         {
             return _dstInEffect(&_tzInfo, stdTime);
         }
 
 
-        override long utcToTZ(long stdTime) @safe const nothrow
+        override long utcToTZ(long stdTime) @safe const scope nothrow
         {
             return _utcToTZ(&_tzInfo, stdTime, hasDST);
         }
 
 
-        override long tzToUTC(long adjTime) @safe const nothrow
+        override long tzToUTC(long adjTime) @safe const scope nothrow
         {
             return _tzToUTC(&_tzInfo, adjTime, hasDST);
         }
@@ -3071,7 +3071,7 @@ else version (Windows)
 
     private:
 
-        static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow
+        static bool _dstInEffect(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow
         {
             try
             {
@@ -3155,7 +3155,7 @@ else version (Windows)
         }
 
 
-        static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow
+        static long _utcToTZ(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow
         {
             if (hasDST && WindowsTimeZone._dstInEffect(tzInfo, stdTime))
                 return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias);
@@ -3164,7 +3164,7 @@ else version (Windows)
         }
 
 
-        static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow
+        static long _tzToUTC(const scope TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow
         {
             if (hasDST)
             {
index 1bfed64eae544cf18381113cde449b4593c6298d..315e054cbab1aa6e4c6cf6cd61a2b67ae59ee799 100644 (file)
@@ -1124,7 +1124,7 @@ version (Windows) private ulong makeUlong(DWORD dwLow, DWORD dwHigh) @safe pure
 }
 
 version (Posix) private extern (C) pragma(mangle, stat.mangleof)
-int trustedStat(const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted;
+int trustedStat(scope const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted;
 
 /**
 Get size of file `name` in bytes.
@@ -1928,7 +1928,7 @@ if (isConvertibleToString!R)
     assert(!f.exists);
 }
 
-private bool existsImpl(const(FSChar)* namez) @trusted nothrow @nogc
+private bool existsImpl(scope const(FSChar)* namez) @trusted nothrow @nogc
 {
     version (Windows)
     {
@@ -2010,7 +2010,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     version (Windows)
     {
         auto namez = name.tempCString!FSChar();
-        static auto trustedGetFileAttributesW(const(FSChar)* namez) @trusted
+        static auto trustedGetFileAttributesW(scope const(FSChar)* namez) @trusted
         {
             return GetFileAttributesW(namez);
         }
@@ -2220,7 +2220,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     version (Windows)
     {
         auto namez = name.tempCString!FSChar();
-        static auto trustedSetFileAttributesW(const(FSChar)* namez, uint dwFileAttributes) @trusted
+        static auto trustedSetFileAttributesW(scope const(FSChar)* namez, uint dwFileAttributes) @trusted
         {
             return SetFileAttributesW(namez, dwFileAttributes);
         }
@@ -2233,7 +2233,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     else version (Posix)
     {
         auto namez = name.tempCString!FSChar();
-        static auto trustedChmod(const(FSChar)* namez, mode_t mode) @trusted
+        static auto trustedChmod(scope const(FSChar)* namez, mode_t mode) @trusted
         {
             return chmod(namez, mode);
         }
@@ -2868,14 +2868,14 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
 
     version (Windows)
     {
-        static auto trustedChdir(const(FSChar)* pathz) @trusted
+        static auto trustedChdir(scope const(FSChar)* pathz) @trusted
         {
             return SetCurrentDirectoryW(pathz);
         }
     }
     else version (Posix)
     {
-        static auto trustedChdir(const(FSChar)* pathz) @trusted
+        static auto trustedChdir(scope const(FSChar)* pathz) @trusted
         {
             return core.sys.posix.unistd.chdir(pathz) == 0;
         }
@@ -2939,7 +2939,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
 
     version (Windows)
     {
-        static auto trustedCreateDirectoryW(const(FSChar)* pathz) @trusted
+        static auto trustedCreateDirectoryW(scope const(FSChar)* pathz) @trusted
         {
             return CreateDirectoryW(pathz, null);
         }
@@ -2953,7 +2953,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     {
         import std.conv : octal;
 
-        static auto trustedMkdir(const(FSChar)* pathz, mode_t mode) @trusted
+        static auto trustedMkdir(scope const(FSChar)* pathz, mode_t mode) @trusted
         {
             return core.sys.posix.sys.stat.mkdir(pathz, mode);
         }
@@ -3143,14 +3143,14 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
 
     version (Windows)
     {
-        static auto trustedRmdir(const(FSChar)* pathz) @trusted
+        static auto trustedRmdir(scope const(FSChar)* pathz) @trusted
         {
             return RemoveDirectoryW(pathz);
         }
     }
     else version (Posix)
     {
-        static auto trustedRmdir(const(FSChar)* pathz) @trusted
+        static auto trustedRmdir(scope const(FSChar)* pathz) @trusted
         {
             return core.sys.posix.unistd.rmdir(pathz) == 0;
         }
@@ -3859,17 +3859,17 @@ else version (Windows)
             return _size;
         }
 
-        @property SysTime timeCreated() const pure nothrow scope
+        @property SysTime timeCreated() const pure nothrow return scope
         {
             return cast(SysTime)_timeCreated;
         }
 
-        @property SysTime timeLastAccessed() const pure nothrow scope
+        @property SysTime timeLastAccessed() const pure nothrow return scope
         {
             return cast(SysTime)_timeLastAccessed;
         }
 
-        @property SysTime timeLastModified() const pure nothrow scope
+        @property SysTime timeLastModified() const pure nothrow return scope
         {
             return cast(SysTime)_timeLastModified;
         }
index a61ee81cc450de4b230f05eb31a81ac69c1188ec..b21f58d602e5f268e523b6973fbe59cce6314e34 100644 (file)
@@ -227,7 +227,7 @@ private struct TempCStringBuffer(To = char)
     @disable this(this);
     alias ptr this; /// implicitly covert to raw pointer
 
-    @property inout(To)* buffPtr() inout
+    @property inout(To)* buffPtr() return inout
     {
         return _ptr == useStack ? _buff.ptr : _ptr;
     }
index 79446756fa6c4273b846aadfa959b867432492d4..6a93e0a16b06fd23c105e35e5fd97ee2bee04abe 100644 (file)
@@ -879,7 +879,7 @@ public:
     }
 
     // return x / y
-    static BigUint divInt(T)(scope return BigUint x, T y_) pure nothrow @safe
+    static BigUint divInt(T)(return scope BigUint x, T y_) pure nothrow @safe
     if ( is(immutable T == immutable uint) )
     {
         uint y = y_;
@@ -942,7 +942,7 @@ public:
     }
 
     // return x / y
-    static BigUint div(scope return BigUint x, scope BigUint y) pure nothrow @safe
+    static BigUint div(return scope BigUint x, scope BigUint y) pure nothrow @safe
     {
         if (y.data.length > x.data.length)
             return BigUint(ZERO);
@@ -954,7 +954,7 @@ public:
     }
 
     // return x % y
-    static BigUint mod(scope return BigUint x, scope BigUint y) pure nothrow @safe
+    static BigUint mod(return scope BigUint x, scope BigUint y) pure nothrow @safe
     {
         if (y.data.length > x.data.length) return x;
         if (y.data.length == 1)
@@ -1020,7 +1020,7 @@ public:
      * exponentiation is used.
      * Memory allocation is minimized: at most one temporary BigUint is used.
      */
-    static BigUint pow(scope return BigUint x, ulong y) pure nothrow @safe
+    static BigUint pow(return scope BigUint x, ulong y) pure nothrow @safe
     {
         // Deal with the degenerate cases first.
         if (y == 0) return BigUint(ONE);
@@ -1259,7 +1259,7 @@ public:
 }
 
 // Remove leading zeros from x, to restore the BigUint invariant
-inout(BigDigit) [] removeLeadingZeros(scope return inout(BigDigit) [] x) pure nothrow @safe
+inout(BigDigit) [] removeLeadingZeros(return scope inout(BigDigit) [] x) pure nothrow @safe
 {
     size_t k = x.length;
     while (k>1 && x[k - 1]==0) --k;
@@ -1916,7 +1916,7 @@ pure @safe unittest
 // every 8 digits.
 // buff.length must be data.length*8 if separator is zero,
 // or data.length*9 if separator is non-zero. It will be completely filled.
-char [] biguintToHex(scope return char [] buff, const scope BigDigit [] data, char separator=0,
+char [] biguintToHex(return scope char [] buff, const scope BigDigit [] data, char separator=0,
         LetterCase letterCase = LetterCase.upper) pure nothrow @safe
 {
     int x=0;
index af7aa383d8e4882a20398b60173f0ab169209610..ea22d6357660448f9f767e5566c07dd457d897c1 100644 (file)
@@ -159,7 +159,7 @@ struct JSONValue
         return store.str;
     }
     /// ditto
-    @property string str(return string v) pure nothrow @nogc @trusted return // TODO make @safe
+    @property string str(return scope string v) pure nothrow @nogc @trusted return // TODO make @safe
     {
         assign(v);
         return v;
@@ -282,7 +282,7 @@ struct JSONValue
         return store.object;
     }
     /// ditto
-    @property JSONValue[string] object(return JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe
+    @property JSONValue[string] object(return scope JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe
     {
         assign(v);
         return v;
@@ -321,14 +321,14 @@ struct JSONValue
        (*a)[0] = "world";  // segmentation fault
        ---
      */
-    @property ref inout(JSONValue[]) array() inout pure @system
+    @property ref inout(JSONValue[]) array() return scope inout pure @system
     {
         enforce!JSONException(type == JSONType.array,
                                 "JSONValue is not an array");
         return store.array;
     }
     /// ditto
-    @property JSONValue[] array(return JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe
+    @property JSONValue[] array(return scope JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe
     {
         assign(v);
         return v;
@@ -635,7 +635,7 @@ struct JSONValue
      * Hash syntax for json objects.
      * Throws: `JSONException` if `type` is not `JSONType.object`.
      */
-    ref inout(JSONValue) opIndex(return string k) inout pure @safe
+    ref inout(JSONValue) opIndex(return scope string k) inout pure @safe
     {
         auto o = this.objectNoRef;
         return *enforce!JSONException(k in o,
index f2a8ff3025de9a86c211e10c2eeb4d43da89b1af..12a29fe44c9a111bb5428b6800195e181aad0639 100644 (file)
@@ -1893,7 +1893,7 @@ Note that only the first item of "matchAll" was ever used in practice
 so we can return `const(Char)[]` instead of `const(Char)[][]` using a
 zero-length string to indicate no match.
 +/
-const(Char)[] matchIPSuffix(Char)(return const(Char)[] s) @nogc nothrow pure @safe
+const(Char)[] matchIPSuffix(Char)(return scope const(Char)[] s) @nogc nothrow pure @safe
 {
     size_t end = s.length;
     if (end < 7) return null;
index 98c5b9467485ebcf787609a5496203cc3558f954..958f606ff523d67aefdd2f761894366f764cf853 100644 (file)
@@ -276,7 +276,7 @@ static:
     multi-threaded programs. See e.g.
     $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
     */
-    inout(char)[] opIndexAssign(return inout char[] value, scope const(char)[] name) @trusted
+    inout(char)[] opIndexAssign(return scope inout char[] value, scope const(char)[] name) @trusted
     {
         version (Posix)
         {
@@ -4385,6 +4385,7 @@ else version (Posix)
 
     void browse(scope const(char)[] url) nothrow @nogc @safe
     {
+        const buffer = url.tempCString(); // Retain buffer until end of scope
         const(char)*[3] args;
 
         // Trusted because it's called with a zero-terminated literal
@@ -4408,7 +4409,6 @@ else version (Posix)
             }
         }
 
-        const buffer = url.tempCString(); // Retain buffer until end of scope
         args[1] = buffer;
         args[2] = null;
 
index a3483561134944f75ba6b8f1d096ee782103332e..106e51ceedb193eb62dd9a17e7cc4a5a1edd6a6d 100644 (file)
@@ -166,12 +166,16 @@ version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
     assert(10.iota.randomSample(3, rnd2).equal([7, 8, 9]));
 
     // Cover all elements in an array in random order
-    version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147
-    assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5]));
+    version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147
+        assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5]));
+    else
+        assert(10.iota.randomCover(rnd2).equal([4, 8, 7, 3, 5, 9, 2, 6, 0, 1]));
 
     // Shuffle an array
-    version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147
-    assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1]));
+    version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147
+        assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1]));
+    else
+        assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([4, 2, 5, 0, 1]));
 }
 
 version (StdUnittest)
index d3097d548ce2e1eb183c43591309fc0aa4cb2a1d..f30ea80ae443abb49833eb62302a491e3ac4449d 100644 (file)
@@ -4650,7 +4650,7 @@ if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1)
     auto namez = name.tempCString!FSChar();
     auto modez = mode.tempCString!FSChar();
 
-    static _fopenImpl(const(FSChar)* namez, const(FSChar)* modez) @trusted nothrow @nogc
+    static _fopenImpl(scope const(FSChar)* namez, scope const(FSChar)* modez) @trusted nothrow @nogc
     {
         version (Windows)
         {
index db0e3da304cca29cfacebdf150477ee1c860af54..6dee863521da87ddf20ea0420697a5cbe2767422 100644 (file)
@@ -2239,7 +2239,7 @@ if (is(T == class) || is(T == interface) || isAssociativeArray!T)
         U stripped;
     }
 
-    void opAssign(T another) pure nothrow @nogc
+    void opAssign(return scope T another) pure nothrow @nogc
     {
         // If `T` defines `opCast` we must infer the safety
         static if (hasMember!(T, "opCast"))
@@ -2271,7 +2271,7 @@ if (is(T == class) || is(T == interface) || isAssociativeArray!T)
         opAssign(initializer);
     }
 
-    @property inout(T) get() @trusted pure nothrow @nogc inout
+    @property inout(T) get() @trusted pure nothrow @nogc return scope inout
     {
         return original;
     }
@@ -2792,6 +2792,15 @@ struct Nullable(T)
         }
     }
 
+    this (ref return scope inout Nullable!T rhs) inout
+    {
+        _isNull = rhs._isNull;
+        if (!_isNull)
+            _value.payload = rhs._value.payload;
+        else
+            _value = DontCallDestructorT.init;
+    }
+
     /**
      * If they are both null, then they are equal. If one is null and the other
      * is not, then they are not equal. If they are both non-null, then they are
@@ -3284,11 +3293,11 @@ auto nullable(T)(T t)
     static struct S2 //inspired from 9404
     {
         Nullable!int ni;
-        this(S2 other)
+        this(ref S2 other)
         {
             ni = other.ni;
         }
-        void opAssign(S2 other)
+        void opAssign(ref S2 other)
         {
             ni = other.ni;
         }
@@ -9566,3 +9575,21 @@ unittest
     assert((a ^ true) == Ternary.no);
     assert((a ^ false) == Ternary.yes);
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=22511
+@safe unittest
+{
+    static struct S
+    {
+        int b;
+        @disable this(this);
+        this (ref return scope inout S rhs) inout
+        {
+            this.b = rhs.b + 1;
+        }
+    }
+
+    Nullable!S s1 = S(1);
+    Nullable!S s2 = s1;
+    assert(s2.get().b > s1.get().b);
+}
index 45b7207c1f13ff6fc3c13d0e8a44bb8f9e94b131..a27cbea177b55eb6d3947aa45f7d2a2f203280d9 100644 (file)
@@ -1987,8 +1987,8 @@ pure:
     {
         return this[0] == val[0] && this[1] == val[1];
     }
-    @property ref inout(uint) a() inout { return _tuple[0]; }
-    @property ref inout(uint) b() inout { return _tuple[1]; }
+    @property ref inout(uint) a() return inout { return _tuple[0]; }
+    @property ref inout(uint) b() return inout { return _tuple[1]; }
 }
 
 /**
index be60e7a8f3aa5bd5aacd548b1dca0fafdd70c598..866ec48cbdccf7bb1e5d23f5919ccf4785ba39e7 100644 (file)
@@ -4315,12 +4315,12 @@ if (isSomeChar!C)
             {
                 enum Empty = uint.max;  // range is empty or just constructed
 
-                this(return R r)
+                this(return scope R r)
                 {
                     this.r = r;
                 }
 
-                this(return R r, uint buff)
+                this(return scope R r, uint buff)
                 {
                     this.r = r;
                     this.buff = buff;
@@ -4328,7 +4328,7 @@ if (isSomeChar!C)
 
                 static if (isBidirectionalRange!R)
                 {
-                    this(return R r, uint frontBuff, uint backBuff)
+                    this(return scope R r, uint frontBuff, uint backBuff)
                     {
                         this.r = r;
                         this.buff = frontBuff;
@@ -4436,12 +4436,12 @@ if (isSomeChar!C)
         {
             static struct Result
             {
-                this(return R r)
+                this(return scope R r)
                 {
                     this.r = r;
                 }
 
-                this(return R r, ushort pos, ushort fill, C[4 / C.sizeof] buf)
+                this(return scope R r, ushort pos, ushort fill, C[4 / C.sizeof] buf)
                 {
                     this.r = r;
                     this.pos = pos;
@@ -4451,7 +4451,7 @@ if (isSomeChar!C)
 
                 static if (isBidirectionalRange!R)
                 {
-                    this(return R r, ushort frontPos, ushort frontFill,
+                    this(return scope R r, ushort frontPos, ushort frontFill,
                          ushort backPos, ushort backFill, C[4 / C.sizeof] buf)
                     {
                         this.r = r;
index e8f4d943ff369f7e0e2f311507fe97795e3d95c3..544caa204b3a0f23a55fc53f3b9d57b5f558445d 100644 (file)
@@ -22,6 +22,7 @@ set dg-output-text [list]
 set config_test_list [list \
     { test19433 "--DRT-dont-eat-me" 0 } \
     { test20459 "foo bar -- --DRT-gcopts=profile:1" 0 } \
+    { test22523 "-- --DRT-testmode=run-main" 0 } \
 ]
 
 # Initialize dg.
diff --git a/libphobos/testsuite/libphobos.config/test22523.d b/libphobos/testsuite/libphobos.config/test22523.d
new file mode 100644 (file)
index 0000000..f308696
--- /dev/null
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=22523
+
+import core.stdc.stdio;
+
+int main()
+{
+    puts("Executed main although it should be skipped!");
+    return 1;
+}
+
+unittest {}