From 9c7d5e8846edb28e5421211ee8eaad93e234de2c Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Fri, 10 Dec 2021 03:14:20 +0100 Subject: [PATCH] d: Merge upstream dmd 3982604c5, druntime bc58b1e9, phobos 12329adb6. 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. --- gcc/d/Make-lang.in | 1 + gcc/d/d-attribs.cc | 6 +- gcc/d/d-codegen.cc | 6 +- gcc/d/d-compiler.cc | 4 +- gcc/d/d-lang.cc | 11 +- gcc/d/d-port.cc | 2 + gcc/d/d-target.cc | 30 +- gcc/d/decl.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/access.d | 2 +- gcc/d/dmd/aggregate.d | 14 +- gcc/d/dmd/aliasthis.d | 4 +- gcc/d/dmd/arrayop.d | 79 +- gcc/d/dmd/astenums.d | 4 +- gcc/d/dmd/attrib.d | 11 +- gcc/d/dmd/blockexit.d | 20 +- gcc/d/dmd/builtin.d | 2 - gcc/d/dmd/canthrow.d | 2 +- gcc/d/dmd/clone.d | 8 +- gcc/d/dmd/common/outbuffer.h | 2 +- gcc/d/dmd/cond.d | 2 +- gcc/d/dmd/constfold.d | 166 +- gcc/d/dmd/cparse.d | 45 +- gcc/d/dmd/cppmangle.d | 2 +- gcc/d/dmd/ctfeexpr.d | 394 ++--- gcc/d/dmd/dcast.d | 176 +- gcc/d/dmd/declaration.d | 40 +- gcc/d/dmd/declaration.h | 9 +- gcc/d/dmd/dinterpret.d | 634 +++---- gcc/d/dmd/dmangle.d | 4 +- gcc/d/dmd/dstruct.d | 18 +- gcc/d/dmd/dsymbol.d | 16 +- gcc/d/dmd/dsymbolsem.d | 56 +- gcc/d/dmd/dtemplate.d | 137 +- gcc/d/dmd/dtoh.d | 11 +- gcc/d/dmd/escape.d | 65 +- gcc/d/dmd/expression.d | 784 ++++----- gcc/d/dmd/expression.h | 28 +- gcc/d/dmd/expressionsem.d | 802 +++++---- gcc/d/dmd/foreachvar.d | 2 +- gcc/d/dmd/func.d | 9 +- gcc/d/dmd/globals.d | 2 +- gcc/d/dmd/hdrgen.d | 195 ++- gcc/d/dmd/iasmgcc.d | 4 +- gcc/d/dmd/id.d | 3 + gcc/d/dmd/initsem.d | 56 +- gcc/d/dmd/lambdacomp.d | 5 +- gcc/d/dmd/lexer.d | 22 +- gcc/d/dmd/mtype.d | 16 +- gcc/d/dmd/nogc.d | 6 +- gcc/d/dmd/ob.d | 6 +- gcc/d/dmd/objc.d | 12 +- gcc/d/dmd/opover.d | 323 ++-- gcc/d/dmd/optimize.d | 1535 +++++++++-------- gcc/d/dmd/parse.d | 340 ++-- gcc/d/dmd/printast.d | 7 +- gcc/d/dmd/root/dcompat.h | 3 + gcc/d/dmd/root/file.d | 18 +- gcc/d/dmd/root/optional.d | 86 + gcc/d/dmd/root/optional.h | 42 + gcc/d/dmd/safe.d | 4 +- gcc/d/dmd/semantic2.d | 18 +- gcc/d/dmd/semantic3.d | 4 +- gcc/d/dmd/sideeffect.d | 84 +- gcc/d/dmd/statementsem.d | 882 +++++----- gcc/d/dmd/staticcond.d | 51 +- gcc/d/dmd/target.d | 5 +- gcc/d/dmd/target.h | 4 +- gcc/d/dmd/templateparamsem.d | 6 +- gcc/d/dmd/tokens.d | 160 +- gcc/d/dmd/tokens.h | 628 +++++-- gcc/d/dmd/traits.d | 41 +- gcc/d/dmd/typesem.d | 124 +- gcc/d/expr.cc | 259 +-- gcc/d/intrinsics.cc | 2 +- gcc/d/lang.opt | 8 +- gcc/d/runtime.def | 7 - gcc/d/toir.cc | 3 +- gcc/d/types.cc | 2 +- .../gdc.test/compilable/covariant_override.d | 34 + .../gdc.test/compilable/emptygenmain.d | 3 + gcc/testsuite/gdc.test/compilable/noreturn1.d | 12 + gcc/testsuite/gdc.test/compilable/test17870.d | 26 + gcc/testsuite/gdc.test/compilable/test19873.d | 37 + gcc/testsuite/gdc.test/compilable/test21719.d | 21 + gcc/testsuite/gdc.test/compilable/test22254.d | 19 + gcc/testsuite/gdc.test/compilable/test22510.d | 18 + .../fail_compilation/covariant_override.d | 35 + .../gdc.test/fail_compilation/fail10964.d | 4 +- .../gdc.test/fail_compilation/fail10968.d | 38 +- .../gdc.test/fail_compilation/fail16997.d | 38 +- .../gdc.test/fail_compilation/fail809.d | 12 - .../gdc.test/fail_compilation/fob2.d | 2 +- .../fail_compilation/imports/test20023b.d | 10 + .../gdc.test/fail_compilation/retscope.d | 8 +- .../gdc.test/fail_compilation/test15191.d | 42 +- .../gdc.test/fail_compilation/test17977.d | 20 + .../gdc.test/fail_compilation/test20023.d | 16 + .../fail_compilation/traits_initSymbol.d | 63 + gcc/testsuite/gdc.test/runnable/b19294.d | 163 ++ gcc/testsuite/gdc.test/runnable/mars1.d | 2 +- gcc/testsuite/gdc.test/runnable/test15862.d | 39 + gcc/testsuite/gdc.test/runnable/test21367.d | 47 + gcc/testsuite/gdc.test/runnable/test22227.d | 16 + gcc/testsuite/gdc.test/runnable/testOpApply.d | 31 +- gcc/testsuite/gdc.test/runnable/testcgelem.d | 2 +- gcc/testsuite/gdc.test/runnable/testconst.d | 8 +- .../gdc.test/runnable/traits_initSymbol.d | 119 ++ gcc/testsuite/gdc.test/runnable/xtest46.d | 7 +- .../runnable_cxx/extra-files/cpp7925.cpp | 103 ++ .../gdc.test/runnable_cxx/test7925.d | 151 ++ libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/Makefile.am | 5 +- libphobos/libdruntime/Makefile.in | 12 +- libphobos/libdruntime/core/demangle.d | 8 +- .../core/internal/array/construction.d | 43 +- libphobos/libdruntime/core/internal/convert.d | 8 +- .../libdruntime/core/internal/lifetime.d | 49 +- libphobos/libdruntime/core/internal/string.d | 2 +- libphobos/libdruntime/core/internal/utf.d | 10 +- libphobos/libdruntime/core/lifetime.d | 111 +- libphobos/libdruntime/core/memory.d | 21 +- libphobos/libdruntime/core/stdc/stdlib.d | 10 + libphobos/libdruntime/core/stdc/string.d | 28 +- libphobos/libdruntime/core/stdc/wchar_.d | 26 +- libphobos/libdruntime/core/stdcpp/exception.d | 2 + libphobos/libdruntime/core/sync/mutex.d | 4 +- .../libdruntime/core/sys/bionic/string.d | 2 +- .../libdruntime/core/sys/darwin/mach/nlist.d | 2 +- .../libdruntime/core/sys/darwin/string.d | 2 +- .../core/sys/dragonflybsd/string.d | 2 +- .../libdruntime/core/sys/freebsd/string.d | 2 +- libphobos/libdruntime/core/sys/linux/string.d | 2 +- .../libdruntime/core/sys/linux/syscalls.d | 745 -------- libphobos/libdruntime/core/sys/linux/unistd.d | 26 +- .../libdruntime/core/sys/netbsd/string.d | 2 +- .../libdruntime/core/sys/openbsd/string.d | 2 +- libphobos/libdruntime/core/sys/posix/signal.d | 26 +- libphobos/libdruntime/core/sys/posix/string.d | 8 +- .../libdruntime/core/sys/posix/sys/socket.d | 2 +- .../libdruntime/core/sys/solaris/sys/elf.d | 5 +- .../core/sys/solaris/sys/elf_386.d | 3 - .../core/sys/solaris/sys/elf_SPARC.d | 3 - .../libdruntime/core/sys/windows/dbghelp.d | 8 +- libphobos/libdruntime/core/thread/osthread.d | 5 +- .../libdruntime/core/thread/threadbase.d | 5 +- libphobos/libdruntime/object.d | 8 +- libphobos/libdruntime/rt/aaA.d | 4 +- libphobos/libdruntime/rt/cast_.d | 2 +- libphobos/libdruntime/rt/config.d | 3 + libphobos/libdruntime/rt/lifetime.d | 4 +- libphobos/libdruntime/rt/monitor_.d | 2 +- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/iteration.d | 52 +- libphobos/src/std/algorithm/mutation.d | 29 +- libphobos/src/std/algorithm/sorting.d | 26 +- libphobos/src/std/concurrency.d | 32 +- libphobos/src/std/container/dlist.d | 6 + libphobos/src/std/container/rbtree.d | 2 +- libphobos/src/std/datetime/interval.d | 6 +- libphobos/src/std/datetime/systime.d | 27 +- libphobos/src/std/datetime/timezone.d | 74 +- libphobos/src/std/file.d | 28 +- libphobos/src/std/internal/cstring.d | 2 +- libphobos/src/std/internal/math/biguintcore.d | 12 +- libphobos/src/std/json.d | 10 +- libphobos/src/std/net/isemail.d | 2 +- libphobos/src/std/process.d | 4 +- libphobos/src/std/random.d | 12 +- libphobos/src/std/stdio.d | 2 +- libphobos/src/std/typecons.d | 35 +- libphobos/src/std/uni/package.d | 4 +- libphobos/src/std/utf.d | 12 +- .../testsuite/libphobos.config/config.exp | 1 + .../testsuite/libphobos.config/test22523.d | 11 + 175 files changed, 6436 insertions(+), 4902 deletions(-) create mode 100644 gcc/d/dmd/root/optional.d create mode 100644 gcc/d/dmd/root/optional.h create mode 100644 gcc/testsuite/gdc.test/compilable/covariant_override.d create mode 100644 gcc/testsuite/gdc.test/compilable/emptygenmain.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17870.d create mode 100644 gcc/testsuite/gdc.test/compilable/test19873.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21719.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22254.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22510.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/covariant_override.d delete mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail809.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17977.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test20023.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d create mode 100644 gcc/testsuite/gdc.test/runnable/b19294.d create mode 100644 gcc/testsuite/gdc.test/runnable/test15862.d create mode 100644 gcc/testsuite/gdc.test/runnable/test21367.d create mode 100644 gcc/testsuite/gdc.test/runnable/test22227.d create mode 100644 gcc/testsuite/gdc.test/runnable/traits_initSymbol.d create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/test7925.d delete mode 100644 libphobos/libdruntime/core/sys/linux/syscalls.d create mode 100644 libphobos/testsuite/libphobos.config/test22523.d diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index d7f714760f7a..00169a743a1b 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -162,6 +162,7 @@ D_FRONTEND_OBJS = \ d/root-filename.o \ d/root-hash.o \ d/root-longdouble.o \ + d/root-optional.o \ d/root-port.o \ d/root-region.o \ d/root-rmem.o \ diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 04b9791ab1bf..5c9f569d1c4c 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -337,10 +337,10 @@ build_attributes (Expressions *eattrs) continue; /* Get the result of the attribute if it hasn't already been folded. */ - if (attr->op == TOKcall) + if (attr->op == EXP::call) attr = attr->ctfeInterpret (); - if (attr->op != TOKstructliteral) + if (attr->op != EXP::structLiteral) { warning_at (make_location_t (attr->loc), OPT_Wattributes, "%qE attribute has no effect", @@ -353,7 +353,7 @@ build_attributes (Expressions *eattrs) Expressions *elems = attr->isStructLiteralExp ()->elements; Expression *e0 = (*elems)[0]; - if (e0->op != TOKstring) + if (e0->op != EXP::string_) { warning_at (make_location_t (attr->loc), OPT_Wattributes, "unknown attribute %qs", e0->toChars()); diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index c082ac5ab80f..39c3c6ce987b 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2154,9 +2154,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object, { Lagain: Expression *arg = (*arguments)[i]; - gcc_assert (arg->op != TOKtuple); + gcc_assert (arg->op != EXP::tuple); - if (arg->op == TOKcomma) + if (arg->op == EXP::comma) { CommaExp *ce = arg->isCommaExp (); tree tce = build_expr (ce->e1); @@ -2200,7 +2200,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object, /* Nested structs also have ADDRESSABLE set, but if the type has neither a copy constructor nor a destructor available, then we need to take care of copying its value before passing it. */ - if (arg->op == TOKstructliteral || (!sd->postblit && !sd->dtor)) + if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor)) targ = force_target_expr (targ); targ = convert (build_reference_type (TREE_TYPE (targ)), diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc index 3df40073ac54..c1e78c0a5deb 100644 --- a/gcc/d/d-compiler.cc +++ b/gcc/d/d-compiler.cc @@ -50,7 +50,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type) cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type)); else if (expr->type->isfloating ()) cst = build_float_cst (expr->toReal (), expr->type); - else if (expr->op == TOKarrayliteral) + else if (expr->op == EXP::arrayLiteral) { /* Build array as VECTOR_CST, assumes EXPR is constant. */ Expressions *elements = expr->isArrayLiteralExp ()->elements; @@ -99,7 +99,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type) cst = native_interpret_expr (vectype, buffer, len); Expression *e = d_eval_constant_expression (expr->loc, cst); - gcc_assert (e != NULL && e->op == TOKvector); + gcc_assert (e != NULL && e->op == EXP::vector); return e->isVectorExp ()->e1; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 576eefcc01f2..2c5d206a95fa 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -620,10 +620,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.inclusiveInContracts = value; break; - case OPT_fpreview_intpromote: - global.params.fix16997 = value; - break; - case OPT_fpreview_nosharedaccess: global.params.noSharedAccess = value; break; @@ -642,8 +638,9 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, case OPT_frevert_all: global.params.useDIP25 = FeatureState::disabled; - global.params.markdown = !value; global.params.dtorFields = FeatureState::disabled; + global.params.fix16997 = !value; + global.params.markdown = !value; break; case OPT_frevert_dip25: @@ -654,6 +651,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.dtorFields = FeatureState::disabled; break; + case OPT_frevert_intpromote: + global.params.fix16997 = !value; + break; + case OPT_frevert_markdown: global.params.markdown = !value; break; diff --git a/gcc/d/d-port.cc b/gcc/d/d-port.cc index 58b3fe138b2b..4e867a7db4a5 100644 --- a/gcc/d/d-port.cc +++ b/gcc/d/d-port.cc @@ -145,6 +145,8 @@ Port::readlongBE (const void *buffer) void Port::valcpy (void *buffer, uint64_t value, size_t sz) { + gcc_assert (((size_t) buffer) % sz == 0); + switch (sz) { case 1: diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 21417dddf781..dd244f121198 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -287,7 +287,7 @@ Target::isVectorTypeSupported (int sz, Type *type) Returns true if the operation is supported or type is not a vector. */ bool -Target::isVectorOpSupported (Type *type, unsigned op, Type *) +Target::isVectorOpSupported (Type *type, EXP op, Type *) { if (type->ty != TY::Tvector) return true; @@ -299,31 +299,31 @@ Target::isVectorOpSupported (Type *type, unsigned op, Type *) /* Don't support if expression cannot be represented. */ switch (op) { - case TOKpow: - case TOKpowass: + case EXP::pow: + case EXP::powAssign: /* pow() is lowered as a function call. */ return false; - case TOKmod: - case TOKmodass: + case EXP::mod: + case EXP::modAssign: /* fmod() is lowered as a function call. */ if (type->isfloating ()) return false; break; - case TOKandand: - case TOKoror: + case EXP::andAnd: + case EXP::orOr: /* Logical operators must have a result type of bool. */ return false; - case TOKle: - case TOKlt: - case TOKge: - case TOKgt: - case TOKequal: - case TOKnotequal: - case TOKidentity: - case TOKnotidentity: + case EXP::lessOrEqual: + case EXP::lessThan: + case EXP::greaterOrEqual: + case EXP::greaterThan: + case EXP::equal: + case EXP::notEqual: + case EXP::identity: + case EXP::notIdentity: /* Comparison operators must have a result type of bool. */ return false; diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index c69f5664e8cf..bbde4a669e45 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -2239,7 +2239,7 @@ layout_class_initializer (ClassDeclaration *cd) ne->type = cd->type; Expression *e = ne->ctfeInterpret (); - gcc_assert (e->op == TOKclassreference); + gcc_assert (e->op == EXP::classReference); return build_class_instance (e->isClassReferenceExp ()); } diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index d23e1fedba48..4bae16c86eb9 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -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. diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d index 944c9d3e1245..d8a65179a9e3 100644 --- a/gcc/d/dmd/access.d +++ b/gcc/d/dmd/access.d @@ -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; diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 1fe8e809aa55..dc772e8eeac6 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -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; } diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index e048cdc2e1b4..80db47ded1d9 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -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()) { diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index e2b33194f060..a234501075ce 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -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(); } diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index df88bb97bdf7..f6387651e5f0 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -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 diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 0bf40ef9a728..e8704aabf730 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -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. diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 0ecd6351f7d6..5945644482a2 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -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; } - diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d index c4f84b129686..2f5b6c734a68 100644 --- a/gcc/d/dmd/builtin.d +++ b/gcc/d/dmd/builtin.d @@ -13,8 +13,6 @@ module dmd.builtin; -import core.stdc.math; -import core.stdc.string; import dmd.arraytypes; import dmd.expression; import dmd.func; diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index ed05af6ac7cb..b67a9d14dd4c 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -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. */ diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index da66812b9548..c536d25f0a3b 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -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: diff --git a/gcc/d/dmd/common/outbuffer.h b/gcc/d/dmd/common/outbuffer.h index a5e3f9c541d7..ce23436d782f 100644 --- a/gcc/d/dmd/common/outbuffer.h +++ b/gcc/d/dmd/common/outbuffer.h @@ -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 diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 05bd4bd550d1..abf28144c41b 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -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()) diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 1dada60de3b4..3ca23f24d7e5 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -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(); diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 7d8ab67ee6ac..dfc45e0bc31e 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -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(); diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index df742c0bd8f7..4ad79da02f29 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -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'); diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 7f76d7565e0d..9cd09bab643b 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -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 ""; - case TOK.voidExpression: + case EXP.voidExpression: return "cast(void)0"; - case TOK.showCtfeContext: + case EXP.showCtfeContext: return ""; - case TOK.break_: + case EXP.break_: return ""; - case TOK.continue_: + case EXP.continue_: return ""; - case TOK.goto_: + case EXP.goto_: return ""; 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) diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 87c3adae9e60..2e5a79d0febb 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -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: diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index e3f135a03d8b..18c8ca2da749 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -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; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 4a4c35304177..884146e14166 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -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; } diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a1f36c0c48f9..891adb3c6bdc 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -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); diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index c417f93c353b..065968025a63 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -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 diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 0925e7cd38a2..1f05642d301d 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -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) && diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 9aa435d64638..b1d1b1d8d7c3 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -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; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 047c1eb6f69f..0bf9a80f37d1 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -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(); } diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 9d7957a975d3..5dedcba56277 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -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) { diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index e19adfc4b149..51f53c8402fb 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -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); } } diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index d502f80975b3..62f87e506ab6 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -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); } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 2a6233244547..e6b7e3014f18 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -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) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 691364cb265d..411822cb9d6b 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -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 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 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 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 toBool(); void accept(Visitor *v) { v->visit(this); } }; @@ -336,7 +336,7 @@ public: VarDeclaration *var; ThisExp *syntaxCopy(); - bool isBool(bool result); + Optional 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 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 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 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 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 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 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 toBool(); Expression *addDtorHook(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 8e152d6a1fcc..ec2bce47b471 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -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!() if (tups1.ttEmpty && tups2.te) { - result = IntegerExp.createBool(exp.op != TOK.equal); + result = IntegerExp.createBool(exp.op != EXP.equal); return; } // AliasSeq!() == 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; diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index 9579ac7d6a54..e9a43f921054 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -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 diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 2d6a756178e9..da33587fc88a 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -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 && diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 747a1138905a..7409dcc29027 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -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 diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 4ff07b5de329..a45429867396 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -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)]; +} diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 3ff0e894e2ac..cd3011731f55 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -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; } } diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 1ee51533b531..83c89c05fda1 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -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" }, diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 5828486c6fe4..c5aa0f46dd1f 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -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; } diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index 44a6c0665070..336f8dd80ec5 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -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) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index e2b4199b80a2..d38cce4ca007 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -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 diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index a21924b3aacb..e338a05a524c 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -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() diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 4bb2907c9ba2..31a25a714178 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -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_)) diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 605e9f3bfdd9..156428eb6991 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -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); } diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index eb4ba1db20de..42363818dd81 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -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); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index ff03a6e0d3cc..4d250c04771a 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -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; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 9f116fe85096..6b2176b29112 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -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 (`.~this()`) + if (!v.inuse) { - // prevent infinite recursion (`.~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; } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index f00ceb6cc937..2229e7853db3 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -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); diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index 414d6f665f53..b9f0c5e2eb8d 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -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) diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h index 88f20952cc9e..8b0bcf26049d 100644 --- a/gcc/d/dmd/root/dcompat.h +++ b/gcc/d/dmd/root/dcompat.h @@ -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 diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index 64e957163228..2722529bbac9 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -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 index 000000000000..a593ddd54fdf --- /dev/null +++ b/gcc/d/dmd/root/optional.d @@ -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 index 000000000000..fa52b584f326 --- /dev/null +++ b/gcc/d/dmd/root/optional.h @@ -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 +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 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; +}; diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 89049599dacd..7eb3e235e41f 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -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; } diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 993db9055234..c3fe7520175d 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -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; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 3852d0b26934..893f96b4ea9f 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -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) { diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index d238150e75ec..99833b55a329 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -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. diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 9eba2ffaed20..6979cdf7977c 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -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) { diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d index d1578ec3a121..6d74ad29a5a4 100644 --- a/gcc/d/dmd/staticcond.d +++ b/gcc/d/dmd/staticcond.d @@ -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; diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index 16739addf573..7a875a5d6631 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -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. diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index 6a75ccc5ebd8..136369320781 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -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); diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index 620492fc0c71..b46274248567 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -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; } } diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 1ea51a89bff7..2609af56ac00 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -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]; } diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index d14d0aab5939..f3e4411217e6 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -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__) diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index cc1d2e351e63..7b9a8c8fdff2 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -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; diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index f75ae0e0b5af..417d2c11af49 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -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; diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 8e1d43e2b8f8..f1c014dbc168 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -88,7 +88,7 @@ lvalue_p (Expression *e) if (ce != NULL && ce->e1->isLvalue ()) return true; - return (e->op != TOKslice && e->isLvalue ()); + return (e->op != EXP::slice && e->isLvalue ()); } /* Build an expression of code CODE, data type TYPE, and operands ARG0 and @@ -162,7 +162,7 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2) { /* Skip casts for lhs assignment. */ Expression *e1b = e1; - while (e1b->op == TOKcast) + while (e1b->op == EXP::cast_) { CastExp *ce = e1b->isCastExp (); gcc_assert (same_type_p (ce->type, ce->to)); @@ -264,7 +264,7 @@ public: void visit (IdentityExp *e) { - tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR; + tree_code code = (e->op == EXP::identity) ? EQ_EXPR : NE_EXPR; Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); @@ -331,7 +331,7 @@ public: { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); - tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR; + tree_code code = (e->op == EXP::equal) ? EQ_EXPR : NE_EXPR; if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray) && (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray)) @@ -391,7 +391,7 @@ public: Otherwise for inequality: (e1.length != 0 && memcmp); */ tree tsizecmp = build_boolop (code, t1len, size_zero_node); - if (e->op == TOKequal) + if (e->op == EXP::equal) result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result); else result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result); @@ -404,7 +404,7 @@ public: else { tree tlencmp = build_boolop (code, t1len, t2len); - if (e->op == TOKequal) + if (e->op == EXP::equal) result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result); else result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result); @@ -428,7 +428,7 @@ public: d_array_convert (e->e2), build_typeinfo (e->loc, t1array)); - if (e->op == TOKnotequal) + if (e->op == EXP::notEqual) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); this->result_ = result; @@ -453,7 +453,7 @@ public: build_expr (e->e1), build_expr (e->e2)); - if (e->op == TOKnotequal) + if (e->op == EXP::notEqual) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); this->result_ = result; @@ -499,19 +499,19 @@ public: switch (e->op) { - case TOKle: + case EXP::lessOrEqual: code = LE_EXPR; break; - case TOKlt: + case EXP::lessThan: code = LT_EXPR; break; - case TOKge: + case EXP::greaterOrEqual: code = GE_EXPR; break; - case TOKgt: + case EXP::greaterThan: code = GT_EXPR; break; @@ -540,7 +540,7 @@ public: void visit (LogicalExp *e) { - tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; + tree_code code = (e->op == EXP::andAnd) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; if (e->e2->type->toBasetype ()->ty != TY::Tvoid) { @@ -559,7 +559,7 @@ public: tree t2 = build_expr_dtor (e->e2); /* Invert condition for logical or if expression. */ - if (e->op == TOKoror) + if (e->op == EXP::orOr) t1 = build1 (TRUTH_NOT_EXPR, d_bool_type, t1); this->result_ = build_condition (build_ctype (e->type), @@ -576,8 +576,8 @@ public: switch (e->op) { - case TOKadd: - case TOKmin: + case EXP::add: + case EXP::min: if ((e->e1->type->isreal () && e->e2->type->isimaginary ()) || (e->e1->type->isimaginary () && e->e2->type->isreal ())) { @@ -586,7 +586,7 @@ public: tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); - if (e->op == TOKmin) + if (e->op == EXP::min) t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2); if (e->e1->type->isreal ()) @@ -597,22 +597,22 @@ public: return; } else - code = (e->op == TOKadd) + code = (e->op == EXP::add) ? PLUS_EXPR : MINUS_EXPR; break; - case TOKmul: + case EXP::mul: code = MULT_EXPR; break; - case TOKdiv: + case EXP::div: /* Determine if the div expression is a lowered pointer diff operation. The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'. */ if (MinExp *me = e->e1->isMinExp ()) { if (me->e1->type->ty == TY::Tpointer && me->e2->type->ty == TY::Tpointer - && e->e2->op == TOKint64) + && e->e2->op == EXP::int64) { code = EXACT_DIV_EXPR; break; @@ -623,32 +623,32 @@ public: ? TRUNC_DIV_EXPR : RDIV_EXPR; break; - case TOKmod: + case EXP::mod: code = e->e1->type->isfloating () ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR; break; - case TOKand: + case EXP::and_: code = BIT_AND_EXPR; break; - case TOKor: + case EXP::or_: code = BIT_IOR_EXPR; break; - case TOKxor: + case EXP::xor_: code = BIT_XOR_EXPR; break; - case TOKshl: + case EXP::leftShift: code = LSHIFT_EXPR; break; - case TOKshr: + case EXP::rightShift: code = RSHIFT_EXPR; break; - case TOKushr: + case EXP::unsignedRightShift: code = UNSIGNED_RSHIFT_EXPR; break; @@ -678,15 +678,15 @@ public: tree result; - if (e->e1->op == TOKcat) + if (e->e1->op == EXP::concatenate) { /* Flatten multiple concatenations to an array. So the expression ((a ~ b) ~ c) becomes [a, b, c] */ int ndims = 2; - for (Expression *ex = e->e1; ex->op == TOKcat;) + for (Expression *ex = e->e1; ex->op == EXP::concatenate;) { - if (ex->op == TOKcat) + if (ex->op == EXP::concatenate) { ex = ex->isCatExp ()->e1; ndims++; @@ -703,7 +703,7 @@ public: int dim = ndims - 1; for (Expression *oe = ce->e2; oe != NULL; - (ce->e1->op != TOKcat + (ce->e1->op != EXP::concatenate ? (oe = ce->e1) : (ce = ce->e1->isCatExp (), oe = ce->e2))) { @@ -751,59 +751,59 @@ public: switch (e->op) { - case TOKaddass: + case EXP::addAssign: code = PLUS_EXPR; break; - case TOKminass: + case EXP::minAssign: code = MINUS_EXPR; break; - case TOKmulass: + case EXP::mulAssign: code = MULT_EXPR; break; - case TOKdivass: + case EXP::divAssign: code = e->e1->type->isintegral () ? TRUNC_DIV_EXPR : RDIV_EXPR; break; - case TOKmodass: + case EXP::modAssign: code = e->e1->type->isfloating () ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR; break; - case TOKandass: + case EXP::andAssign: code = BIT_AND_EXPR; break; - case TOKorass: + case EXP::orAssign: code = BIT_IOR_EXPR; break; - case TOKxorass: + case EXP::xorAssign: code = BIT_XOR_EXPR; break; - case TOKpowass: + case EXP::powAssign: gcc_unreachable (); - case TOKshlass: + case EXP::leftShiftAssign: code = LSHIFT_EXPR; break; - case TOKshrass: - case TOKushrass: + case EXP::rightShiftAssign: + case EXP::unsignedRightShiftAssign: /* Use the original lhs type before it was promoted. The left operand of `>>>=' does not undergo integral promotions before shifting. Strip off casts just incase anyway. */ - while (e1b->op == TOKcast) + while (e1b->op == EXP::cast_) { CastExp *ce = e1b->isCastExp (); gcc_assert (same_type_p (ce->type, ce->to)); e1b = ce->e1; } - code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR; + code = (e->op == EXP::rightShiftAssign) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR; break; default: @@ -908,7 +908,7 @@ public: /* First, handle special assignment semantics. */ /* Look for array.length = n; */ - if (e->e1->op == TOKarraylength) + if (e->e1->op == EXP::arrayLength) { /* This case should have been rewritten to `_d_arraysetlengthT` in the semantic phase. */ @@ -916,7 +916,7 @@ public: } /* Look for array[] = n; */ - if (e->e1->op == TOKslice) + if (e->e1->op == EXP::slice) { SliceExp *se = e->e1->isSliceExp (); Type *stype = se->e1->type->toBasetype (); @@ -937,15 +937,18 @@ public: tree init = stabilize_expr (&t1); t1 = d_save_expr (t1); - if ((postblit || destructor) && e->op != TOKblit) + if ((postblit || destructor) && e->op != EXP::blit) { - libcall_fn libcall = (e->op == TOKconstruct) - ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN; + /* Need to call postblit/destructor as part of assignment. + Construction has already been handled by the front-end. */ + gcc_assert (e->op != EXP::construct); + /* So we can call postblits on const/immutable objects. */ Type *tm = etype->unSharedOf ()->mutableOf (); tree ti = build_typeinfo (e->loc, tm); - result = build_libcall (libcall, Type::tvoid, 4, + /* Generate: _d_arraysetassign (t1.ptr, &t2, t1.length, ti); */ + result = build_libcall (LIBCALL_ARRAYSETASSIGN, Type::tvoid, 4, d_array_ptr (t1), build_address (t2), d_array_length (t1), ti); @@ -1011,14 +1014,11 @@ public: this->result_ = compound_expr (result, t1); } - else if ((postblit || destructor) && e->op != TOKblit) + else if ((postblit || destructor) + && e->op != EXP::blit && e->op != EXP::construct) { - /* Generate: _d_arrayassign(ti, from, to) - or: _d_arrayctor(ti, from, to) */ - libcall_fn libcall = (e->op == TOKconstruct) - ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN; - - this->result_ = build_libcall (libcall, e->type, 3, + /* Generate: _d_arrayassign(ti, from, to); */ + this->result_ = build_libcall (LIBCALL_ARRAYASSIGN, e->type, 3, build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1)); @@ -1039,8 +1039,8 @@ public: /* Look for reference initializations. */ if (e->memset == MemorySet::referenceInit) { - gcc_assert (e->op == TOKconstruct || e->op == TOKblit); - gcc_assert (e->e1->op == TOKvar); + gcc_assert (e->op == EXP::construct || e->op == EXP::blit); + gcc_assert (e->e1->op == EXP::variable); Declaration *decl = e->e1->isVarExp ()->var; if (decl->storage_class & (STCout | STCref)) @@ -1060,7 +1060,7 @@ public: /* Other types of assignments that may require post construction. */ Type *tb1 = e->e1->type->toBasetype (); - tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR; + tree_code modifycode = (e->op == EXP::construct) ? INIT_EXPR : MODIFY_EXPR; /* Look for struct assignment. */ if (tb1->ty == TY::Tstruct) @@ -1071,10 +1071,10 @@ public: StructDeclaration *sd = tb1->isTypeStruct ()->sym; /* Look for struct = 0. */ - if (e->e2->op == TOKint64) + if (e->e2->op == EXP::int64) { /* Use memset to fill struct. */ - gcc_assert (e->op == TOKblit); + gcc_assert (e->op == EXP::blit); tree result = build_memset_call (t1); /* Maybe set-up hidden pointer to outer scope context. */ @@ -1095,8 +1095,8 @@ public: tree init = NULL_TREE; /* Fill any alignment holes in the struct using memset. */ - if ((e->op == TOKconstruct - || (e->e2->op == TOKstructliteral && e->op == TOKblit)) + if ((e->op == EXP::construct + || (e->e2->op == EXP::structLiteral && e->op == EXP::blit)) && (sd->isUnionDeclaration () || !identity_compare_p (sd))) { t1 = stabilize_reference (t1); @@ -1120,10 +1120,10 @@ public: if (tb1->ty == TY::Tsarray) { /* Look for array = 0. */ - if (e->e2->op == TOKint64) + if (e->e2->op == EXP::int64) { /* Use memset to fill the array. */ - gcc_assert (e->op == TOKblit); + gcc_assert (e->op == EXP::blit); this->result_ = build_memset_call (build_expr (e->e1)); return; } @@ -1132,17 +1132,17 @@ public: gcc_assert (e->e2->type->toBasetype ()->ty == TY::Tsarray); /* Determine if we need to run postblit. */ - bool postblit = needs_postblit (etype); - bool destructor = needs_dtor (etype); - bool lvalue = lvalue_p (e->e2); + const bool postblit = needs_postblit (etype); + const bool destructor = needs_dtor (etype); + const bool lvalue = lvalue_p (e->e2); /* Optimize static array assignment with array literal. Even if the elements in rhs are all rvalues and don't have to call postblits, this assignment should call dtors on old assigned elements. */ if ((!postblit && !destructor) - || (e->op == TOKconstruct && e->e2->op == TOKarrayliteral) - || (e->op == TOKconstruct && !lvalue && postblit) - || (e->op == TOKblit || e->e1->type->size () == 0)) + || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral) + || (e->op == EXP::construct && !lvalue && postblit) + || (e->op == EXP::blit || e->e1->type->size () == 0)) { tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (build_expr (e->e2), @@ -1152,32 +1152,22 @@ public: return; } + /* All other kinds of lvalue or rvalue static array assignment. + Array construction has already been handled by the front-end. */ + gcc_assert (e->op != EXP::construct); + + /* Generate: _d_arrayassign_l() + or: _d_arrayassign_r() */ + libcall_fn libcall = (lvalue) + ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; + tree elembuf = build_local_temp (build_ctype (etype)); Type *arrtype = (e->type->ty == TY::Tsarray) ? etype->arrayOf () : e->type; - tree result; - - if (e->op == TOKconstruct) - { - /* Generate: _d_arrayctor(ti, from, to) */ - result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3, - build_typeinfo (e->loc, etype), - d_array_convert (e->e2), - d_array_convert (e->e1)); - } - else - { - /* Generate: _d_arrayassign_l() - or: _d_arrayassign_r() */ - libcall_fn libcall = (lvalue) - ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; - tree elembuf = build_local_temp (build_ctype (etype)); - - result = build_libcall (libcall, arrtype, 4, - build_typeinfo (e->loc, etype), - d_array_convert (e->e2), - d_array_convert (e->e1), - build_address (elembuf)); - } + tree result = build_libcall (libcall, arrtype, 4, + build_typeinfo (e->loc, etype), + d_array_convert (e->e2), + d_array_convert (e->e1), + build_address (elembuf)); /* Cast the libcall result back to a static array. */ if (e->type->ty == TY::Tsarray) @@ -1202,12 +1192,12 @@ public: { tree result; - if (e->op == TOKplusplus) + if (e->op == EXP::plusPlus) { result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); } - else if (e->op == TOKminusminus) + else if (e->op == EXP::minusMinus) { result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); @@ -1441,7 +1431,7 @@ public: the destructor is called for the object instance. */ libcall_fn libcall; - if (e->e1->op == TOKvar) + if (e->e1->op == EXP::variable) { VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration (); if (v && v->onstack) @@ -1586,10 +1576,10 @@ public: size_t offset; tree result; - if (e->e1->op == TOKadd) + if (e->e1->op == EXP::add) { AddExp *ae = e->e1->isAddExp (); - if (ae->e1->op == TOKaddress + if (ae->e1->op == EXP::address && ae->e2->isConst () && ae->e2->type->isintegral ()) { Expression *ex = ae->e1->isAddrExp ()->e1; @@ -1598,7 +1588,7 @@ public: offset = ae->e2->toUInteger (); } } - else if (e->e1->op == TOKsymoff) + else if (e->e1->op == EXP::symbolOffset) { SymOffExp *se = e->e1->isSymOffExp (); if (!declaration_reference_p (se->var)) @@ -1650,7 +1640,7 @@ public: /* The frontend optimizer can convert const symbol into a struct literal. Taking the address of a struct literal is otherwise illegal. */ - if (e->e1->op == TOKstructliteral) + if (e->e1->op == EXP::structLiteral) { StructLiteralExp *sle = e->e1->isStructLiteralExp ()->origin; gcc_assert (sle != NULL); @@ -1689,21 +1679,21 @@ public: TypeFunction *tf = NULL; /* Calls to delegates can sometimes look like this. */ - if (e1b->op == TOKcomma) + if (e1b->op == EXP::comma) { e1b = e1b->isCommaExp ()->e2; - gcc_assert (e1b->op == TOKvar); + gcc_assert (e1b->op == EXP::variable); Declaration *var = e1b->isVarExp ()->var; gcc_assert (var->isFuncDeclaration () && !var->needThis ()); } - if (e1b->op == TOKdotvar && tb->ty != TY::Tdelegate) + if (e1b->op == EXP::dotVariable && tb->ty != TY::Tdelegate) { DotVarExp *dve = e1b->isDotVarExp (); /* Don't modify the static initializer for struct literals. */ - if (dve->e1->op == TOKstructliteral) + if (dve->e1->op == EXP::structLiteral) { StructLiteralExp *sle = dve->e1->isStructLiteralExp (); sle->useStaticInit = false; @@ -1775,7 +1765,7 @@ public: { /* This could be a delegate expression (TY == Tdelegate), but not actually a delegate variable. */ - if (e1b->op == TOKdotvar) + if (e1b->op == EXP::dotVariable) { /* This gets the true function type, getting the function type from e1->type can sometimes be incorrect, such as when calling @@ -1795,7 +1785,7 @@ public: object = delegate_object (callee); callee = delegate_method (callee); } - else if (e1b->op == TOKvar) + else if (e1b->op == EXP::variable) { FuncDeclaration *fd = e1b->isVarExp ()->var->isFuncDeclaration (); gcc_assert (fd != NULL); @@ -1877,7 +1867,7 @@ public: if (e->func->isNested () && !e->func->isThis ()) { - if (e->e1->op == TOKnull) + if (e->e1->op == EXP::null_) object = build_expr (e->e1); else object = get_frame_for_symbol (e->func); @@ -1908,7 +1898,7 @@ public: /* Get pointer to function out of the virtual table. */ if (e->func->isVirtual () && !e->func->isFinalFunc () - && e->e1->op != TOKsuper && e->e1->op != TOKdottype) + && e->e1->op != EXP::super_ && e->e1->op != EXP::dotType) { tree fntype = build_pointer_type (TREE_TYPE (fndecl)); object = d_save_expr (object); @@ -2105,9 +2095,9 @@ public: Type *ftype = e->type->toBasetype (); /* This check is for lambda's, remove `vthis' as function isn't nested. */ - if (e->fd->tok == TOKreserved && ftype->ty == TY::Tpointer) + if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer) { - e->fd->tok = TOKfunction; + e->fd->tok = TOK::function_; e->fd->vthis = NULL; } @@ -2196,9 +2186,9 @@ public: FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration (); if (fld != NULL) { - if (fld->tok == TOKreserved) + if (fld->tok == TOK::reserved) { - fld->tok = TOKfunction; + fld->tok = TOK::function_; fld->vthis = NULL; } @@ -2210,7 +2200,7 @@ public: { /* Want the initializer, not the expression. */ VarDeclaration *var = e->var->isVarDeclaration (); - SymbolDeclaration *sd = e->var->isSymbolDeclaration (); + SymbolDeclaration *sdecl = e->var->isSymbolDeclaration (); tree init = NULL_TREE; if (var && (var->isConst () || var->isImmutable ()) @@ -2226,8 +2216,15 @@ public: var->inuse--; } } - else if (sd && sd->dsym) - init = layout_struct_initializer (sd->dsym); + else if (sdecl && sdecl->dsym) + { + if (StructDeclaration *sd = sdecl->dsym->isStructDeclaration ()) + init = layout_struct_initializer (sd); + else if (ClassDeclaration *cd = sdecl->dsym->isClassDeclaration ()) + init = layout_class_initializer (cd); + else + gcc_unreachable (); + } else error_at (make_location_t (e->loc), "non-constant expression %qs", e->toChars ()); @@ -2242,6 +2239,26 @@ public: tree result = get_decl_tree (e->var); TREE_USED (result) = 1; + /* The variable expression generated for `__traits(initSymbol)'. */ + if (SymbolDeclaration *sd = e->var->isSymbolDeclaration ()) + { + if (e->type->isTypeDArray ()) + { + /* Generate a slice for non-zero initialized aggregates, + otherwise create an empty array. */ + gcc_assert (e->type == Type::tvoid->arrayOf ()->constOf ()); + + tree type = build_ctype (e->type); + tree length = size_int (sd->dsym->structsize); + tree ptr = (sd->dsym->isStructDeclaration () + && sd->dsym->type->isZeroInit (e->loc)) + ? null_pointer_node : build_address (result); + + this->result_ = d_array_value (type, length, ptr); + return; + } + } + /* For variables that are references - currently only out/inout arguments; objects don't count - evaluating the variable means we want what it refers to. */ @@ -2954,7 +2971,7 @@ public: tree type = build_ctype (e->type); /* First handle array literal expressions. */ - if (e->e1->op == TOKarrayliteral) + if (e->e1->op == EXP::arrayLiteral) { ArrayLiteralExp *ale = e->e1->isArrayLiteralExp (); vec *elms = NULL; diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc index b14b0ca5111e..dec2bd47265b 100644 --- a/gcc/d/intrinsics.cc +++ b/gcc/d/intrinsics.cc @@ -431,7 +431,7 @@ expand_intrinsic_rotate (intrinsic_code intrinsic, tree callexp) gcc_assert (ti && ti->tiargs && ti->tiargs->length == 2); Expression *e = isExpression ((*ti->tiargs)[0]); - gcc_assert (e && e->op == TOKint64); + gcc_assert (e && e->op == EXP::int64); count = build_expr (e, true); } diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index d0a5e2f68596..893bc238631a 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -380,10 +380,6 @@ fpreview=inclusiveincontracts D RejectNegative Implement 'in' contracts of overridden methods to be a superset of parent contract. -fpreview=intpromote -D RejectNegative -Use C-style integral promotion for unary '+', '-' and '~'. - fpreview=nosharedaccess D RejectNegative Disable access to shared memory objects. @@ -412,6 +408,10 @@ frevert=dtorfields D RejectNegative Don't destruct fields of partially constructed objects. +frevert=intpromote +D RejectNegative +Use C-style integral promotion for unary '+', '-' and '~'. + frevert=markdown D RejectNegative Disable Markdown replacements in Ddoc. diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index fdff6db06260..3961a1d9bed3 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -140,13 +140,6 @@ DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID), DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR), P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) -/* Used for constructing a new array from an existing array. The `set' variant - is for when the constructor value is a single element. */ -DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID), - P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) -DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR), - P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) - /* Used for concatenating two or more arrays together. Then `n' variant is for when there is more than two arrays to handle. */ DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE), diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index 55d63f89cb79..17b63ba8a7d7 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -969,8 +969,7 @@ public: StructLiteralExp *sle = NULL; bool using_rvo_p = false; - if (DotVarExp *dve = (s->exp->op == TOKcall - && s->exp->isCallExp ()->e1->op == TOKdotvar + if (DotVarExp *dve = (s->exp->isCallExp () ? s->exp->isCallExp ()->e1->isDotVarExp () : NULL)) { diff --git a/gcc/d/types.cc b/gcc/d/types.cc index b39b92eb8226..1d551e5249bd 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -338,7 +338,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) RootObject *ro = (*td->objects)[j]; gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION); Expression *e = (Expression *) ro; - gcc_assert (e->op == TOKdsymbol); + gcc_assert (e->op == EXP::dSymbol); DsymbolExp *se = e->isDsymbolExp (); tmembers.push (se->s); diff --git a/gcc/testsuite/gdc.test/compilable/covariant_override.d b/gcc/testsuite/gdc.test/compilable/covariant_override.d new file mode 100644 index 000000000000..1afe0a28cfb5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/covariant_override.d @@ -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 index 000000000000..be7bee83fa0a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/emptygenmain.d @@ -0,0 +1,3 @@ +// REQUIRED_ARGS: -main -c + +void foo() { } diff --git a/gcc/testsuite/gdc.test/compilable/noreturn1.d b/gcc/testsuite/gdc.test/compilable/noreturn1.d index b041e072e9c2..22734cf48b3c 100644 --- a/gcc/testsuite/gdc.test/compilable/noreturn1.d +++ b/gcc/testsuite/gdc.test/compilable/noreturn1.d @@ -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 index 000000000000..2329b609170e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17870.d @@ -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 index 000000000000..7252edd75206 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test19873.d @@ -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 index 000000000000..9d444e16c785 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21719.d @@ -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 index 000000000000..94f6596a19d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22254.d @@ -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 index 000000000000..af5d0a433eb9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22510.d @@ -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 index 000000000000..7738770775d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/covariant_override.d @@ -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 { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d index de3673f7860d..4b31a92f9ab3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d @@ -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 --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d index 06e0687ce39e..d9f554a4b78b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d @@ -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 --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16997.d b/gcc/testsuite/gdc.test/fail_compilation/fail16997.d index a8f3ae453dba..279d9da6dfc2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail16997.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16997.d @@ -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 index b83639b0d08c..000000000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail809.d +++ /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_; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fob2.d b/gcc/testsuite/gdc.test/fail_compilation/fob2.d index dbe8ea2f883d..175ade3cafca 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fob2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fob2.d @@ -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 index 000000000000..c3e8a78e98d7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d @@ -0,0 +1,10 @@ +module imports.test20023b; + +auto threw()() @safe +{ + try + throw new Exception("Hello"); + catch (Exception e) + return e; + assert(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d index 58f0430f5ad5..64db4c811962 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d @@ -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; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d index 173473a6675d..1b3078ff0519 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d @@ -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 index 000000000000..ff6bc1c44f4f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17977.d @@ -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 index 000000000000..909e699d3b5a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test20023.d @@ -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 index 000000000000..94ff80ad5517 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d @@ -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 index 000000000000..5700195ccb8f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/b19294.d @@ -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)]); +} diff --git a/gcc/testsuite/gdc.test/runnable/mars1.d b/gcc/testsuite/gdc.test/runnable/mars1.d index 4f38f4d33229..30aa9503b09c 100644 --- a/gcc/testsuite/gdc.test/runnable/mars1.d +++ b/gcc/testsuite/gdc.test/runnable/mars1.d @@ -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 index 000000000000..87e25600d8b7 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test15862.d @@ -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 index 000000000000..96e8d6c66d1c --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test21367.d @@ -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 index 000000000000..7ef53c37a60e --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test22227.d @@ -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); +} diff --git a/gcc/testsuite/gdc.test/runnable/testOpApply.d b/gcc/testsuite/gdc.test/runnable/testOpApply.d index 7b884e5857cd..285365eea82e 100644 --- a/gcc/testsuite/gdc.test/runnable/testOpApply.d +++ b/gcc/testsuite/gdc.test/runnable/testOpApply.d @@ -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()) {} +} diff --git a/gcc/testsuite/gdc.test/runnable/testcgelem.d b/gcc/testsuite/gdc.test/runnable/testcgelem.d index b5c7f7d1855f..617e3fb11cc0 100644 --- a/gcc/testsuite/gdc.test/runnable/testcgelem.d +++ b/gcc/testsuite/gdc.test/runnable/testcgelem.d @@ -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/testconst.d b/gcc/testsuite/gdc.test/runnable/testconst.d index 5c0e75de60f0..764bb1b045e6 100644 --- a/gcc/testsuite/gdc.test/runnable/testconst.d +++ b/gcc/testsuite/gdc.test/runnable/testconst.d @@ -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 index 000000000000..0385d98c8ffe --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/traits_initSymbol.d @@ -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(); +} diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index 20cc225759a0..4fe6b00eba72 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -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 index 000000000000..f3a9a8552a94 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp @@ -0,0 +1,103 @@ +#include +#include + +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 index 000000000000..2f52826bc4f1 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d @@ -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(); +} diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index d0d3a25ad1e8..edb101758b8d 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -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. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 44d4fe16be0c..224d06e78ca7 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -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 \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 84be8082f7a4..bb936ddc1fff 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -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) diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d index 33ca0ddc7bd6..1915fb0844ad 100644 --- a/libphobos/libdruntime/core/demangle.d +++ b/libphobos/libdruntime/core/demangle.d @@ -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; } diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d index 9c8223767e1c..ae71f513129d 100644 --- a/libphobos/libdruntime/core/internal/array/construction.d +++ b/libphobos/libdruntime/core/internal/array/construction.d @@ -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) { diff --git a/libphobos/libdruntime/core/internal/convert.d b/libphobos/libdruntime/core/internal/convert.d index 2789d2913a7e..a876fcc537f8 100644 --- a/libphobos/libdruntime/core/internal/convert.d +++ b/libphobos/libdruntime/core/internal/convert.d @@ -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])(); } } diff --git a/libphobos/libdruntime/core/internal/lifetime.d b/libphobos/libdruntime/core/internal/lifetime.d index 7e9b5f2ad48d..a7446debae65 100644 --- a/libphobos/libdruntime/core/internal/lifetime.d +++ b/libphobos/libdruntime/core/internal/lifetime.d @@ -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 diff --git a/libphobos/libdruntime/core/internal/string.d b/libphobos/libdruntime/core/internal/string.d index 529fee49436d..64a9cc92ffba 100644 --- a/libphobos/libdruntime/core/internal/string.d +++ b/libphobos/libdruntime/core/internal/string.d @@ -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] = '-'; } diff --git a/libphobos/libdruntime/core/internal/utf.d b/libphobos/libdruntime/core/internal/utf.d index ca0f7f599a66..27bf7f2b9055 100644 --- a/libphobos/libdruntime/core/internal/utf.d +++ b/libphobos/libdruntime/core/internal/utf.d @@ -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); diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index d93b891226ce..b45e95f4226e 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -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); +} diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d index 3770c13337ca..c4df0f2d0dd0 100644 --- a/libphobos/libdruntime/core/memory.d +++ b/libphobos/libdruntime/core/memory.d @@ -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; /** diff --git a/libphobos/libdruntime/core/stdc/stdlib.d b/libphobos/libdruntime/core/stdc/stdlib.d index 2f11a663eb54..92f8f7055408 100644 --- a/libphobos/libdruntime/core/stdc/stdlib.d +++ b/libphobos/libdruntime/core/stdc/stdlib.d @@ -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; /// diff --git a/libphobos/libdruntime/core/stdc/string.d b/libphobos/libdruntime/core/stdc/string.d index a26811ca6236..f15ef851909a 100644 --- a/libphobos/libdruntime/core/stdc/string.d +++ b/libphobos/libdruntime/core/stdc/string.d @@ -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); diff --git a/libphobos/libdruntime/core/stdc/wchar_.d b/libphobos/libdruntime/core/stdc/wchar_.d index 6da5618ada65..e8fb94b11e66 100644 --- a/libphobos/libdruntime/core/stdc/wchar_.d +++ b/libphobos/libdruntime/core/stdc/wchar_.d @@ -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); diff --git a/libphobos/libdruntime/core/stdcpp/exception.d b/libphobos/libdruntime/core/stdcpp/exception.d index f920057cd06a..d65cd8d1832f 100644 --- a/libphobos/libdruntime/core/stdcpp/exception.d +++ b/libphobos/libdruntime/core/stdcpp/exception.d @@ -19,6 +19,8 @@ version (CppRuntime_Gcc) version = GenericBaseException; version (CppRuntime_Clang) version = GenericBaseException; +version (CppRuntime_Sun) + version = GenericBaseException; extern (C++, "std"): @nogc: diff --git a/libphobos/libdruntime/core/sync/mutex.d b/libphobos/libdruntime/core/sync/mutex.d index b153ab9aef00..b848a1474601 100644 --- a/libphobos/libdruntime/core/sync/mutex.d +++ b/libphobos/libdruntime/core/sync/mutex.d @@ -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; } diff --git a/libphobos/libdruntime/core/sys/bionic/string.d b/libphobos/libdruntime/core/sys/bionic/string.d index cbee06c4efeb..10a5610ac449 100644 --- a/libphobos/libdruntime/core/sys/bionic/string.d +++ b/libphobos/libdruntime/core/sys/bionic/string.d @@ -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); diff --git a/libphobos/libdruntime/core/sys/darwin/mach/nlist.d b/libphobos/libdruntime/core/sys/darwin/mach/nlist.d index 11e5ced26b76..4d400f207c7c 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/nlist.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/nlist.d @@ -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)); } diff --git a/libphobos/libdruntime/core/sys/darwin/string.d b/libphobos/libdruntime/core/sys/darwin/string.d index bd65fde27bcb..ac988b58f0d4 100644 --- a/libphobos/libdruntime/core/sys/darwin/string.d +++ b/libphobos/libdruntime/core/sys/darwin/string.d @@ -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); } diff --git a/libphobos/libdruntime/core/sys/dragonflybsd/string.d b/libphobos/libdruntime/core/sys/dragonflybsd/string.d index b64178f65622..4b8422748b60 100644 --- a/libphobos/libdruntime/core/sys/dragonflybsd/string.d +++ b/libphobos/libdruntime/core/sys/dragonflybsd/string.d @@ -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); } diff --git a/libphobos/libdruntime/core/sys/freebsd/string.d b/libphobos/libdruntime/core/sys/freebsd/string.d index 3602ea8e86bd..459e9115878e 100644 --- a/libphobos/libdruntime/core/sys/freebsd/string.d +++ b/libphobos/libdruntime/core/sys/freebsd/string.d @@ -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); } diff --git a/libphobos/libdruntime/core/sys/linux/string.d b/libphobos/libdruntime/core/sys/linux/string.d index 1b2c8d86a4ab..e3c94cf6a8ac 100644 --- a/libphobos/libdruntime/core/sys/linux/string.d +++ b/libphobos/libdruntime/core/sys/linux/string.d @@ -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 index 8c653719317d..000000000000 --- a/libphobos/libdruntime/core/sys/linux/syscalls.d +++ /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, - } -} diff --git a/libphobos/libdruntime/core/sys/linux/unistd.d b/libphobos/libdruntime/core/sys/linux/unistd.d index 1ef16c12689c..484574670055 100644 --- a/libphobos/libdruntime/core/sys/linux/unistd.d +++ b/libphobos/libdruntime/core/sys/linux/unistd.d @@ -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; diff --git a/libphobos/libdruntime/core/sys/netbsd/string.d b/libphobos/libdruntime/core/sys/netbsd/string.d index ab9ced80cf14..f1281da275b7 100644 --- a/libphobos/libdruntime/core/sys/netbsd/string.d +++ b/libphobos/libdruntime/core/sys/netbsd/string.d @@ -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); } diff --git a/libphobos/libdruntime/core/sys/openbsd/string.d b/libphobos/libdruntime/core/sys/openbsd/string.d index 131e67727e8d..4480c94ac37b 100644 --- a/libphobos/libdruntime/core/sys/openbsd/string.d +++ b/libphobos/libdruntime/core/sys/openbsd/string.d @@ -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); diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d index 0dce8c53f31e..32e51561562a 100644 --- a/libphobos/libdruntime/core/sys/posix/signal.d +++ b/libphobos/libdruntime/core/sys/posix/signal.d @@ -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 { diff --git a/libphobos/libdruntime/core/sys/posix/string.d b/libphobos/libdruntime/core/sys/posix/string.d index b9e1c1c88c27..79d25624e2af 100644 --- a/libphobos/libdruntime/core/sys/posix/string.d +++ b/libphobos/libdruntime/core/sys/posix/string.d @@ -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); diff --git a/libphobos/libdruntime/core/sys/posix/sys/socket.d b/libphobos/libdruntime/core/sys/posix/sys/socket.d index de51c6a47467..6e0cfd3ac3d8 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/socket.d +++ b/libphobos/libdruntime/core/sys/posix/sys/socket.d @@ -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; diff --git a/libphobos/libdruntime/core/sys/solaris/sys/elf.d b/libphobos/libdruntime/core/sys/solaris/sys/elf.d index 7da26317d356..7a46d520cc38 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/elf.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/elf.d @@ -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; diff --git a/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d b/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d index 0c8198513d0b..9927b64aec9d 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d @@ -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; diff --git a/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d b/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d index 81d02347598e..e43bd405b8ad 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d @@ -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; diff --git a/libphobos/libdruntime/core/sys/windows/dbghelp.d b/libphobos/libdruntime/core/sys/windows/dbghelp.d index 9848fb99115b..96698e8f0f92 100644 --- a/libphobos/libdruntime/core/sys/windows/dbghelp.d +++ b/libphobos/libdruntime/core/sys/windows/dbghelp.d @@ -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; } diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index b7dde9387afd..fe4d24fafce5 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -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()); } diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d index 4592bf1d9757..9cee4d8d77d2 100644 --- a/libphobos/libdruntime/core/thread/threadbase.d +++ b/libphobos/libdruntime/core/thread/threadbase.d @@ -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); diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index a079e0e73e99..fee19ae65f0b 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -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; diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d index 6ff93f76da43..0c38622a8790 100644 --- a/libphobos/libdruntime/rt/aaA.d +++ b/libphobos/libdruntime/rt/aaA.d @@ -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(); diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d index dcb4438c7006..1604510b4277 100644 --- a/libphobos/libdruntime/rt/cast_.d +++ b/libphobos/libdruntime/rt/cast_.d @@ -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; diff --git a/libphobos/libdruntime/rt/config.d b/libphobos/libdruntime/rt/config.d index f7682f31b633..a6605f4d6037 100644 --- a/libphobos/libdruntime/rt/config.d +++ b/libphobos/libdruntime/rt/config.d @@ -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] == '=') { diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index f1a9d8738603..1f7a81de80fa 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -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); } diff --git a/libphobos/libdruntime/rt/monitor_.d b/libphobos/libdruntime/rt/monitor_.d index 6bfce635c72a..763f43928225 100644 --- a/libphobos/libdruntime/rt/monitor_.d +++ b/libphobos/libdruntime/rt/monitor_.d @@ -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; } diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 29bcf33c01f2..68fefcb1ae4f 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -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. diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index 9e728e4622f4..af665c41197d 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -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 diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d index 07cbb9b98238..22b7b98c229e 100644 --- a/libphobos/src/std/algorithm/mutation.d +++ b/libphobos/src/std/algorithm/mutation.d @@ -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) diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d index f2877ccbdf43..ee68b234b151 100644 --- a/libphobos/src/std/algorithm/sorting.d +++ b/libphobos/src/std/algorithm/sorting.d @@ -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; diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d index a9830af61a27..fb383ae3f2e2 100644 --- a/libphobos/src/std/concurrency.d +++ b/libphobos/src/std/concurrency.d @@ -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); + })); +} diff --git a/libphobos/src/std/container/dlist.d b/libphobos/src/std/container/dlist.d index cc3e2e85dbcc..32d56ecc7339 100644 --- a/libphobos/src/std/container/dlist.d +++ b/libphobos/src/std/container/dlist.d @@ -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; diff --git a/libphobos/src/std/container/rbtree.d b/libphobos/src/std/container/rbtree.d index f8e70fc08825..0b0a0b2f59f5 100644 --- a/libphobos/src/std/container/rbtree.d +++ b/libphobos/src/std/container/rbtree.d @@ -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) diff --git a/libphobos/src/std/datetime/interval.d b/libphobos/src/std/datetime/interval.d index 741088a72dcd..ba2a21056c74 100644 --- a/libphobos/src/std/datetime/interval.d +++ b/libphobos/src/std/datetime/interval.d @@ -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); } diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d index 4da1281f98a0..9b2a8443fdda 100644 --- a/libphobos/src/std/datetime/systime.d +++ b/libphobos/src/std/datetime/systime.d @@ -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; } diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d index 052758097a92..a55411b02d57 100644 --- a/libphobos/src/std/datetime/timezone.d +++ b/libphobos/src/std/datetime/timezone.d @@ -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) { diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index 1bfed64eae54..315e054cbab1 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -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; } diff --git a/libphobos/src/std/internal/cstring.d b/libphobos/src/std/internal/cstring.d index a61ee81cc450..b21f58d602e5 100644 --- a/libphobos/src/std/internal/cstring.d +++ b/libphobos/src/std/internal/cstring.d @@ -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; } diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d index 79446756fa6c..6a93e0a16b06 100644 --- a/libphobos/src/std/internal/math/biguintcore.d +++ b/libphobos/src/std/internal/math/biguintcore.d @@ -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; diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d index af7aa383d8e4..ea22d6357660 100644 --- a/libphobos/src/std/json.d +++ b/libphobos/src/std/json.d @@ -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, diff --git a/libphobos/src/std/net/isemail.d b/libphobos/src/std/net/isemail.d index f2a8ff3025de..12a29fe44c9a 100644 --- a/libphobos/src/std/net/isemail.d +++ b/libphobos/src/std/net/isemail.d @@ -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; diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d index 98c5b9467485..958f606ff523 100644 --- a/libphobos/src/std/process.d +++ b/libphobos/src/std/process.d @@ -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; diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d index a34835611349..106e51ceedb1 100644 --- a/libphobos/src/std/random.d +++ b/libphobos/src/std/random.d @@ -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) diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index d3097d548ce2..f30ea80ae443 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -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) { diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index db0e3da304cc..6dee863521da 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -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); +} diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 45b7207c1f13..a27cbea177b5 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -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]; } } /** diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index be60e7a8f3aa..866ec48cbdcc 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -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; diff --git a/libphobos/testsuite/libphobos.config/config.exp b/libphobos/testsuite/libphobos.config/config.exp index e8f4d943ff36..544caa204b3a 100644 --- a/libphobos/testsuite/libphobos.config/config.exp +++ b/libphobos/testsuite/libphobos.config/config.exp @@ -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 index 000000000000..f3086963f2e9 --- /dev/null +++ b/libphobos/testsuite/libphobos.config/test22523.d @@ -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 {} -- 2.39.5