From 6384eff56dba1fac071c1b525f7e49cf03f2737f Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 20 Feb 2022 20:02:23 +0100 Subject: [PATCH] d: Merge upstream dmd cb49e99f8, druntime 55528bd1, phobos 1a3e80ec2. D front-end changes: - Import dmd v2.099.0-beta.1. - It's now an error to use `alias this' for partial assignment. - The `delete' keyword has been removed from the language. - Using `this' and `super' as types has been removed from the language, the parser no longer specially handles this wrong code with an informative error. D Runtime changes: - Import druntime v2.099.0-beta.1. Phobos changes: - Import phobos v2.099.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd cb49e99f8. * dmd/VERSION: Update version to v2.099.0-beta.1. * decl.cc (layout_class_initializer): Update call to NewExp::create. * expr.cc (ExprVisitor::visit (DeleteExp *)): Remove handling of deleting arrays and pointers. (ExprVisitor::visit (DotVarExp *)): Convert complex types to the front-end library type representing them. (ExprVisitor::visit (StringExp *)): Use getCodeUnit instead of charAt to get the value of each index in a string expression. * runtime.def (DELMEMORY): Remove. (DELARRAYT): Remove. * types.cc (TypeVisitor::visit (TypeEnum *)): Handle anonymous enums. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 55528bd1. * src/MERGE: Merge upstream phobos 1a3e80ec2. * testsuite/libphobos.hash/test_hash.d: Update. * testsuite/libphobos.betterc/test19933.d: New test. --- gcc/d/decl.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/apply.d | 4 +- gcc/d/dmd/canthrow.d | 12 +- gcc/d/dmd/clone.d | 37 +- gcc/d/dmd/constfold.d | 6 +- gcc/d/dmd/cparse.d | 27 +- gcc/d/dmd/ctfeexpr.d | 2 +- gcc/d/dmd/dcast.d | 4267 ++++++++++---------- gcc/d/dmd/declaration.d | 5 +- gcc/d/dmd/declaration.h | 1 - gcc/d/dmd/dinterpret.d | 106 +- gcc/d/dmd/dmangle.d | 3 +- gcc/d/dmd/dmodule.d | 78 +- gcc/d/dmd/dscope.d | 2 +- gcc/d/dmd/dsymbol.d | 11 +- gcc/d/dmd/dsymbol.h | 2 + gcc/d/dmd/dsymbolsem.d | 184 +- gcc/d/dmd/dtemplate.d | 52 +- gcc/d/dmd/dtoh.d | 24 +- gcc/d/dmd/escape.d | 2 +- gcc/d/dmd/expression.d | 115 +- gcc/d/dmd/expression.h | 17 +- gcc/d/dmd/expressionsem.d | 304 +- gcc/d/dmd/func.d | 3 +- gcc/d/dmd/hdrgen.d | 70 +- gcc/d/dmd/iasmgcc.d | 2 +- gcc/d/dmd/id.d | 4 - gcc/d/dmd/importc.d | 47 + gcc/d/dmd/initsem.d | 4 + gcc/d/dmd/lexer.d | 444 +- gcc/d/dmd/mtype.d | 45 +- gcc/d/dmd/nogc.d | 42 +- gcc/d/dmd/opover.d | 342 +- gcc/d/dmd/optimize.d | 7 - gcc/d/dmd/parse.d | 794 ++-- gcc/d/dmd/printast.d | 10 + gcc/d/dmd/semantic2.d | 2 +- gcc/d/dmd/semantic3.d | 22 +- gcc/d/dmd/statementsem.d | 206 +- gcc/d/dmd/staticassert.d | 5 + gcc/d/dmd/staticassert.h | 1 + gcc/d/dmd/tokens.d | 120 +- gcc/d/dmd/tokens.h | 13 +- gcc/d/dmd/transitivevisitor.d | 4 - gcc/d/dmd/typesem.d | 80 +- gcc/d/expr.cc | 46 +- gcc/d/runtime.def | 7 - gcc/d/types.cc | 14 +- gcc/testsuite/gdc.dg/special1.d | 12 + gcc/testsuite/gdc.test/compilable/99bottles.d | 212 +- gcc/testsuite/gdc.test/compilable/b18242.d | 6 +- gcc/testsuite/gdc.test/compilable/b19294.d | 10 +- gcc/testsuite/gdc.test/compilable/b20938.d | 6 +- gcc/testsuite/gdc.test/compilable/b21285.d | 10 +- gcc/testsuite/gdc.test/compilable/commontype.d | 9 +- gcc/testsuite/gdc.test/compilable/ddoc10.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc11.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc14.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc3.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc5.d | 4 +- gcc/testsuite/gdc.test/compilable/ddoc5446.d | 22 +- gcc/testsuite/gdc.test/compilable/ddoc9155.d | 10 +- gcc/testsuite/gdc.test/compilable/debugInference.d | 6 +- gcc/testsuite/gdc.test/compilable/defa.d | 2 +- gcc/testsuite/gdc.test/compilable/dlangui_crash.d | 34 + .../gdc.test/compilable/enumbasearithmetic.d | 20 + gcc/testsuite/gdc.test/compilable/header18364.d | 2 +- gcc/testsuite/gdc.test/compilable/imports/b33a.d | 4 +- .../gdc.test/compilable/imports/imp22734.c | 3 + .../gdc.test/compilable/imports/test22714a.d | 3 + .../gdc.test/compilable/imports/test22714b.d | 12 + gcc/testsuite/gdc.test/compilable/issue16472.d | 42 + gcc/testsuite/gdc.test/compilable/issue21340.d | 4 +- gcc/testsuite/gdc.test/compilable/issue21813b.d | 2 +- gcc/testsuite/gdc.test/compilable/minimal.d | 2 +- gcc/testsuite/gdc.test/compilable/test10993.d | 2 +- gcc/testsuite/gdc.test/compilable/test16107.d | 6 +- gcc/testsuite/gdc.test/compilable/test17545.d | 2 +- gcc/testsuite/gdc.test/compilable/test17906.d | 7 - gcc/testsuite/gdc.test/compilable/test18030.d | 2 +- gcc/testsuite/gdc.test/compilable/test19014.d | 2 +- gcc/testsuite/gdc.test/compilable/test19315.d | 2 +- gcc/testsuite/gdc.test/compilable/test19557.d | 2 +- gcc/testsuite/gdc.test/compilable/test19609.d | 4 +- gcc/testsuite/gdc.test/compilable/test21177.d | 76 + gcc/testsuite/gdc.test/compilable/test21196.d | 71 + gcc/testsuite/gdc.test/compilable/test22224.d | 2 +- gcc/testsuite/gdc.test/compilable/test22632.d | 4 + gcc/testsuite/gdc.test/compilable/test22714.d | 3 + gcc/testsuite/gdc.test/compilable/test22734.d | 6 + gcc/testsuite/gdc.test/compilable/test4375.d | 6 +- gcc/testsuite/gdc.test/compilable/test7172.d | 2 +- gcc/testsuite/gdc.test/compilable/test8296.d | 4 +- gcc/testsuite/gdc.test/compilable/test8513.d | 8 +- gcc/testsuite/gdc.test/compilable/testpostblit.d | 2 +- gcc/testsuite/gdc.test/compilable/testsctreturn.d | 16 + gcc/testsuite/gdc.test/compilable/typeid_name.d | 2 +- gcc/testsuite/gdc.test/compilable/vgc1.d | 17 +- gcc/testsuite/gdc.test/fail_compilation/b20011.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/b3841.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/bug16165.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/bug8150a.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/bug8150b.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ccast.d | 2 +- .../gdc.test/fail_compilation/ctfe14731.d | 2 +- .../gdc.test/fail_compilation/diag10319.d | 2 +- .../gdc.test/fail_compilation/diag10805.d | 2 +- .../gdc.test/fail_compilation/diag13281.d | 6 +- .../gdc.test/fail_compilation/diag15713.d | 4 +- .../gdc.test/fail_compilation/diag16977.d | 4 +- .../gdc.test/fail_compilation/dtor_attributes.d | 2 +- .../gdc.test/fail_compilation/fail10964.d | 2 +- .../gdc.test/fail_compilation/fail11375.d | 2 +- .../gdc.test/fail_compilation/fail11542.d | 8 +- .../gdc.test/fail_compilation/fail12809.d | 8 +- .../gdc.test/fail_compilation/fail14277.d | 10 + .../gdc.test/fail_compilation/fail14486.d | 45 +- .../gdc.test/fail_compilation/fail14554.d | 4 +- .../gdc.test/fail_compilation/fail15089.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail160.d | 2 +- .../gdc.test/fail_compilation/fail17906.d | 12 + .../gdc.test/fail_compilation/fail17969.d | 2 +- .../gdc.test/fail_compilation/fail18228.d | 6 +- .../gdc.test/fail_compilation/fail19441.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail196.d | 10 +- .../gdc.test/fail_compilation/fail19897.d | 2 +- .../gdc.test/fail_compilation/fail19911b.d | 2 +- .../gdc.test/fail_compilation/fail19911c.d | 2 +- .../gdc.test/fail_compilation/fail19922.d | 2 +- .../gdc.test/fail_compilation/fail19923.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail20.d | 2 +- .../gdc.test/fail_compilation/fail20800.d | 2 +- .../gdc.test/fail_compilation/fail22127.d | 11 + .../gdc.test/fail_compilation/fail22634.d | 12 + .../gdc.test/fail_compilation/fail22780.d | 12 + gcc/testsuite/gdc.test/fail_compilation/fail2361.d | 3 +- gcc/testsuite/gdc.test/fail_compilation/fail258.d | 12 +- gcc/testsuite/gdc.test/fail_compilation/fail332.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail349.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail354.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail4082.d | 4 +- .../gdc.test/fail_compilation/fail4269a.d | 2 +- .../gdc.test/fail_compilation/fail4269b.d | 2 +- .../gdc.test/fail_compilation/fail4269c.d | 2 +- .../gdc.test/fail_compilation/fail4375d.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail6968.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail7848.d | 4 +- .../gdc.test/fail_compilation/fail80_m32.d | 2 +- .../gdc.test/fail_compilation/fail80_m64.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail8724.d | 2 +- .../gdc.test/fail_compilation/fail_arrayop2.d | 6 +- .../gdc.test/fail_compilation/fail_typeof.d | 82 + .../gdc.test/fail_compilation/faildeleteaa.d | 3 +- .../gdc.test/fail_compilation/ice10727a.d | 2 + .../gdc.test/fail_compilation/ice10727b.d | 2 + gcc/testsuite/gdc.test/fail_compilation/ice11968.d | 3 +- gcc/testsuite/gdc.test/fail_compilation/ice18753.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/lexer1.d | 4 +- .../gdc.test/fail_compilation/no_Throwable.d | 2 +- .../gdc.test/fail_compilation/no_TypeInfo.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/nogc1.d | 9 +- .../gdc.test/fail_compilation/noreturn2.d | 2 +- .../gdc.test/fail_compilation/scope_type.d | 2 +- .../gdc.test/fail_compilation/test12228.d | 6 +- .../gdc.test/fail_compilation/test16195.d | 3 +- .../gdc.test/fail_compilation/test17307.d | 2 +- .../gdc.test/fail_compilation/test20245.d | 53 +- .../gdc.test/fail_compilation/test22145.d | 28 + .../gdc.test/fail_compilation/test22686.d | 21 + gcc/testsuite/gdc.test/runnable/b18034.d | 10 +- gcc/testsuite/gdc.test/runnable/imports/a15079.d | 2 +- gcc/testsuite/gdc.test/runnable/imports/a19a.d | 2 +- .../gdc.test/runnable/imports/link12144a.d | 2 +- .../gdc.test/runnable/imports/test11745b.d | 12 +- gcc/testsuite/gdc.test/runnable/imports/test46c.d | 2 +- gcc/testsuite/gdc.test/runnable/inline7625.d | 185 + gcc/testsuite/gdc.test/runnable/interface.d | 12 +- gcc/testsuite/gdc.test/runnable/interface2.d | 11 +- gcc/testsuite/gdc.test/runnable/interpret.d | 91 +- gcc/testsuite/gdc.test/runnable/link12144.d | 6 - gcc/testsuite/gdc.test/runnable/link15017.d | 8 +- gcc/testsuite/gdc.test/runnable/mixin1.d | 7 +- gcc/testsuite/gdc.test/runnable/newdel.d | 8 +- gcc/testsuite/gdc.test/runnable/sdtor.d | 26 +- gcc/testsuite/gdc.test/runnable/test11934.d | 2 +- gcc/testsuite/gdc.test/runnable/test17684.d | 20 +- gcc/testsuite/gdc.test/runnable/test17899.d | 2 +- gcc/testsuite/gdc.test/runnable/test20.d | 8 +- gcc/testsuite/gdc.test/runnable/test22136.d | 25 + gcc/testsuite/gdc.test/runnable/test22163.d | 13 + gcc/testsuite/gdc.test/runnable/test22717.d | 31 + gcc/testsuite/gdc.test/runnable/test4.d | 8 +- gcc/testsuite/gdc.test/runnable/testappend.d | 16 +- gcc/testsuite/gdc.test/runnable/testconst.d | 4 +- gcc/testsuite/gdc.test/runnable/testdstress.d | 8 +- gcc/testsuite/gdc.test/runnable/testptrref.d | 10 +- gcc/testsuite/gdc.test/runnable/xpostblit.d | 2 +- gcc/testsuite/gdc.test/runnable_cxx/cppa.d | 2 +- libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/__builtins.di | 65 + libphobos/libdruntime/core/attribute.d | 49 + libphobos/libdruntime/core/bitop.d | 13 - libphobos/libdruntime/core/int128.d | 2 + .../libdruntime/core/internal/array/appending.d | 8 +- .../libdruntime/core/internal/array/comparison.d | 33 +- libphobos/libdruntime/core/internal/convert.d | 22 - libphobos/libdruntime/core/lifetime.d | 4 +- libphobos/libdruntime/core/math.d | 1 + libphobos/libdruntime/core/runtime.d | 2 +- libphobos/libdruntime/core/stdc/stdio.d | 17 +- libphobos/libdruntime/core/sys/linux/config.d | 3 + libphobos/libdruntime/core/sys/linux/dlfcn.d | 22 +- libphobos/libdruntime/core/sys/linux/errno.d | 2 +- libphobos/libdruntime/core/sys/linux/netinet/in_.d | 10 +- libphobos/libdruntime/core/sys/linux/string.d | 2 +- libphobos/libdruntime/core/sys/linux/sys/mman.d | 72 +- libphobos/libdruntime/core/sys/posix/aio.d | 132 +- libphobos/libdruntime/core/sys/posix/config.d | 58 +- libphobos/libdruntime/core/sys/posix/spawn.d | 12 +- libphobos/libdruntime/core/sys/posix/sys/ipc.d | 65 +- libphobos/libdruntime/core/sys/posix/sys/mman.d | 4 +- libphobos/libdruntime/core/sys/posix/sys/shm.d | 12 + libphobos/libdruntime/core/sys/posix/sys/socket.d | 32 +- libphobos/libdruntime/core/sys/posix/sys/stat.d | 24 +- libphobos/libdruntime/core/sys/posix/sys/statvfs.d | 2 +- libphobos/libdruntime/core/sys/posix/sys/types.d | 2 +- libphobos/libdruntime/object.d | 4 +- libphobos/libdruntime/rt/util/typeinfo.d | 289 +- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/internal.d | 2 + libphobos/src/std/bigint.d | 16 +- libphobos/src/std/container/rbtree.d | 16 +- libphobos/src/std/conv.d | 2 +- libphobos/src/std/file.d | 27 +- libphobos/src/std/functional.d | 9 +- libphobos/src/std/internal/math/biguintcore.d | 6 +- libphobos/src/std/socket.d | 17 +- libphobos/src/std/sumtype.d | 20 + libphobos/src/std/typecons.d | 42 +- libphobos/src/std/uni/package.d | 2 +- libphobos/src/std/zip.d | 35 +- libphobos/testsuite/libphobos.betterc/test19933.d | 11 + libphobos/testsuite/libphobos.hash/test_hash.d | 2 +- 245 files changed, 5541 insertions(+), 4939 deletions(-) create mode 100644 gcc/testsuite/gdc.dg/special1.d create mode 100644 gcc/testsuite/gdc.test/compilable/dlangui_crash.d create mode 100644 gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp22734.c create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test22714a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test22714b.d create mode 100644 gcc/testsuite/gdc.test/compilable/issue16472.d delete mode 100644 gcc/testsuite/gdc.test/compilable/test17906.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21177.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21196.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22632.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22714.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22734.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14277.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17906.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22127.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22634.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22780.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test22145.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test22686.d create mode 100644 gcc/testsuite/gdc.test/runnable/inline7625.d create mode 100644 gcc/testsuite/gdc.test/runnable/test22136.d create mode 100644 gcc/testsuite/gdc.test/runnable/test22163.d create mode 100644 gcc/testsuite/gdc.test/runnable/test22717.d create mode 100644 libphobos/testsuite/libphobos.betterc/test19933.d diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index b08d797..7ec0caf 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -2235,7 +2235,7 @@ aggregate_initializer_decl (AggregateDeclaration *decl) tree layout_class_initializer (ClassDeclaration *cd) { - NewExp *ne = NewExp::create (cd->loc, NULL, NULL, cd->type, NULL); + NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL); ne->type = cd->type; Expression *e = ne->ctfeInterpret (); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 91cdc9f..b92f376 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -52844d4b1e9d6714bfd2e535f25a72074a046209 +cb49e99f80e8111c71035b88fe47fe7d855c300f 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/VERSION b/gcc/d/dmd/VERSION index 0aa03f4..12042ff 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.098.1 +v2.099.0-beta.1 diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d index 75b4af1..ac2c80e 100644 --- a/gcc/d/dmd/apply.d +++ b/gcc/d/dmd/apply.d @@ -110,13 +110,13 @@ public: override void visit(NewExp e) { //printf("NewExp::apply(): %s\n", toChars()); - doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); + doCond(e.thisexp) || doCond(e.arguments) || applyTo(e); } override void visit(NewAnonClassExp e) { //printf("NewAnonClassExp::apply(): %s\n", toChars()); - doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); + doCond(e.thisexp) || doCond(e.arguments) || applyTo(e); } override void visit(TypeidExp e) diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index faf427d..745e552 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -114,9 +114,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN import dmd.id : Id; auto sd = ts.sym; - if (sd.dtor && ce.f.ident == Id._d_delstruct) - checkFuncThrows(ce, sd.dtor); - else if (sd.postblit && + if (sd.postblit && (ce.f.ident == Id._d_arrayctor || ce.f.ident == Id._d_arraysetctor)) { checkFuncThrows(ce, sd.postblit); @@ -175,14 +173,6 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN ad = tb.isTypeClass().sym; break; - case Tpointer: - case Tarray: - auto ts = tb.nextOf().baseElemOf().isTypeStruct(); - if (!ts) - return; - ad = ts.sym; - break; - default: assert(0); // error should have been detected by semantic() } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 1a143cb..a6dbd8e 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -521,9 +521,9 @@ FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc) /****************************************** * Build __xopEquals for TypeInfo_Struct - * static bool __xopEquals(ref const S p, ref const S q) + * bool __xopEquals(ref const S p) const * { - * return p == q; + * return this == p; * } * * This is called by TypeInfo.equals(p1, p2). If the struct does not support @@ -570,14 +570,15 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) Loc declLoc; // loc is unnecessary so __xopEquals is never called directly Loc loc; // loc is unnecessary so errors are gagged auto parameters = new Parameters(); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)) - .push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null)); - auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d); + parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); + auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d, STC.const_); + tf = tf.addSTC(STC.const_).toTypeFunction(); Identifier id = Id.xopEquals; - auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); + auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf); fop.generated = true; - Expression e1 = new IdentifierExp(loc, Id.p); - Expression e2 = new IdentifierExp(loc, Id.q); + fop.parent = sd; + Expression e1 = new IdentifierExp(loc, Id.This); + Expression e2 = new IdentifierExp(loc, Id.p); Expression e = new EqualExp(EXP.equal, loc, e1, e2); fop.fbody = new ReturnStatement(loc, e); uint errors = global.startGagging(); // Do not report errors @@ -594,9 +595,9 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) /****************************************** * Build __xopCmp for TypeInfo_Struct - * static bool __xopCmp(ref const S p, ref const S q) + * int __xopCmp(ref const S p) const * { - * return p.opCmp(q); + * return this.opCmp(p); * } * * This is called by TypeInfo.compare(p1, p2). If the struct does not support @@ -691,17 +692,15 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) Loc loc; // loc is unnecessary so errors are gagged auto parameters = new Parameters(); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); - parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null)); - auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d); + auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d, STC.const_); + tf = tf.addSTC(STC.const_).toTypeFunction(); Identifier id = Id.xopCmp; - auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); + auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf); fop.generated = true; - Expression e1 = new IdentifierExp(loc, Id.p); - Expression e2 = new IdentifierExp(loc, Id.q); - version (IN_GCC) - Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2); - else - Expression e = new CallExp(loc, new DotIdExp(loc, e2, Id.cmp), e1); + fop.parent = sd; + Expression e1 = new IdentifierExp(loc, Id.This); + Expression e2 = new IdentifierExp(loc, Id.p); + Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2); fop.fbody = new ReturnStatement(loc, e); uint errors = global.startGagging(); // Do not report errors Scope* sc2 = sc.push(); diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 16f7b2f..7bc890f 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -827,9 +827,9 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e else { cmp = 1; // if dim1 winds up being 0 - for (size_t i = 0; i < dim1; i++) + foreach (i; 0 .. dim1) { - uinteger_t c = es1.charAt(i); + uinteger_t c = es1.getCodeUnit(i); auto ee2 = es2[i]; if (ee2.isConst() != 1) { @@ -1247,7 +1247,7 @@ UnionExp Index(Type type, Expression e1, Expression e2) } else { - emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type); + emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type); } } else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64) diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 38a78a0..0fe6459 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -197,6 +197,7 @@ final class CParser(AST) : Parser!AST } break; + case TOK.charLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -264,6 +265,7 @@ final class CParser(AST) : Parser!AST case TOK.const_: case TOK.volatile: case TOK.restrict: + case TOK.__stdcall: // alignment-specifier case TOK._Alignas: @@ -635,6 +637,7 @@ final class CParser(AST) : Parser!AST nextToken(); break; + case TOK.charLiteral: case TOK.int32Literal: e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32); nextToken(); @@ -1585,7 +1588,7 @@ final class CParser(AST) : Parser!AST if (tspec && specifier.mod & MOD.xconst) { tspec = toConst(tspec); - specifier.mod = MOD.xnone; // 'used' it + specifier.mod &= ~MOD.xnone; // 'used' it } bool first = true; @@ -1708,7 +1711,7 @@ final class CParser(AST) : Parser!AST symbols.push(stag); if (tt.tok == TOK.enum_) { - if (!tt.members) + if (!stag.members) error(tt.loc, "`enum %s` has no members", stag.toChars()); isalias = false; s = new AST.AliasDeclaration(token.loc, id, stag); @@ -1842,8 +1845,8 @@ final class CParser(AST) : Parser!AST /* Since there were declarations, the parameter-list must have been * an identifier-list. */ + ft.parameterList.hasIdentifierList = true; // semantic needs to know to adjust parameter types auto pl = ft.parameterList; - pl.hasIdentifierList = true; // semantic needs to know to adjust parameter types if (pl.varargs != AST.VarArg.none && pl.length) error("function identifier-list cannot end with `...`"); ft.parameterList.varargs = AST.VarArg.variadic; // but C11 allows extra arguments @@ -2071,6 +2074,7 @@ final class CParser(AST) : Parser!AST case TOK.const_: modx = MOD.xconst; break; case TOK.volatile: modx = MOD.xvolatile; break; case TOK.restrict: modx = MOD.xrestrict; break; + case TOK.__stdcall: modx = MOD.x__stdcall; break; // Type specifiers case TOK.char_: tkwx = TKW.xchar; break; @@ -2409,6 +2413,13 @@ final class CParser(AST) : Parser!AST * T ((*fp))(); */ nextToken(); + + if (token.value == TOK.__stdcall) // T (__stdcall*fp)(); + { + specifier.mod |= MOD.x__stdcall; + nextToken(); + } + ts = parseDecl(t); check(TOK.rightParenthesis); break; @@ -2544,7 +2555,8 @@ final class CParser(AST) : Parser!AST this.symbols = null; auto parameterList = cparseParameterList(); - AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, 0); + const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage; + AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, 0); // tf = tf.addSTC(storageClass); // TODO insertTx(ts, tf, t); // ts -> ... -> tf -> t @@ -2612,6 +2624,7 @@ final class CParser(AST) : Parser!AST * restrict * volatile * _Atomic + * __stdcall */ MOD cparseTypeQualifierList() { @@ -2624,6 +2637,7 @@ final class CParser(AST) : Parser!AST case TOK.volatile: mod |= MOD.xvolatile; break; case TOK.restrict: mod |= MOD.xrestrict; break; case TOK._Atomic: mod |= MOD.x_Atomic; break; + case TOK.__stdcall: mod |= MOD.x__stdcall; break; default: return mod; @@ -3708,6 +3722,7 @@ final class CParser(AST) : Parser!AST case TOK.const_: case TOK.volatile: case TOK.restrict: + case TOK.__stdcall: t = peek(t); any = true; continue; @@ -3948,6 +3963,7 @@ final class CParser(AST) : Parser!AST case TOK.restrict: case TOK.volatile: case TOK._Atomic: + case TOK.__stdcall: t = peek(t); continue; @@ -4000,6 +4016,7 @@ final class CParser(AST) : Parser!AST case TOK.const_: case TOK.restrict: case TOK.volatile: + case TOK.__stdcall: // Type Specifiers case TOK.char_: @@ -4202,6 +4219,7 @@ final class CParser(AST) : Parser!AST switch (t.value) { case TOK.identifier: + case TOK.charLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -4283,6 +4301,7 @@ final class CParser(AST) : Parser!AST xvolatile = 2, xrestrict = 4, x_Atomic = 8, + x__stdcall = 0x10, // Windows linkage extension } /********************************** diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 43dce4b..9bc453d 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -1565,7 +1565,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len); return CTFEExp.cantexp; } - emplaceExp!IntegerExp(pue, loc, es1.charAt(indx), type); + emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type); return pue.exp(); } diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 91b3861..f1afa76 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -64,160 +64,151 @@ enum LOG = false; */ Expression implicitCastTo(Expression e, Scope* sc, Type t) { - extern (C++) final class ImplicitCastTo : Visitor + Expression visit(Expression e) { - alias visit = Visitor.visit; - public: - Type t; - Scope* sc; - Expression result; + //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); - extern (D) this(Scope* sc, Type t) + if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t)) { - this.sc = sc; - this.t = t; - } - - override void visit(Expression e) - { - //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); + if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t))) + { + /* Do not emit CastExp for const conversions and + * unique conversions on rvalue. + */ + auto result = e.copy(); + result.type = t; + return result; + } - if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t)) + auto ad = isAggregate(e.type); + if (ad && ad.aliasthis) { - if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t))) - { - /* Do not emit CastExp for const conversions and - * unique conversions on rvalue. - */ - result = e.copy(); - result.type = t; - return; - } + auto ts = ad.type.isTypeStruct(); + const adMatch = ts + ? ts.implicitConvToWithoutAliasThis(t) + : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t); - auto ad = isAggregate(e.type); - if (ad && ad.aliasthis) + if (!adMatch) { - auto ts = ad.type.isTypeStruct(); - const adMatch = ts - ? ts.implicitConvToWithoutAliasThis(t) - : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t); - - if (!adMatch) + Type tob = t.toBasetype(); + Type t1b = e.type.toBasetype(); + if (ad != isAggregate(tob)) { - Type tob = t.toBasetype(); - Type t1b = e.type.toBasetype(); - if (ad != isAggregate(tob)) + if (t1b.ty == Tclass && tob.ty == Tclass) { - if (t1b.ty == Tclass && tob.ty == Tclass) + ClassDeclaration t1cd = t1b.isClassHandle(); + ClassDeclaration tocd = tob.isClassHandle(); + int offset; + if (tocd.isBaseOf(t1cd, &offset)) { - ClassDeclaration t1cd = t1b.isClassHandle(); - ClassDeclaration tocd = tob.isClassHandle(); - int offset; - if (tocd.isBaseOf(t1cd, &offset)) - { - result = new CastExp(e.loc, e, t); - result.type = t; - return; - } + auto result = new CastExp(e.loc, e, t); + result.type = t; + return result; } + } - /* Forward the cast to our alias this member, rewrite to: - * cast(to)e1.aliasthis - */ - result = resolveAliasThis(sc, e); - result = result.castTo(sc, t); - return; - } - } + /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + auto result = resolveAliasThis(sc, e); + return result.castTo(sc, t); + } } - - result = e.castTo(sc, t); - return; } - result = e.optimize(WANTvalue); - if (result != e) - { - result.accept(this); - return; - } + return e.castTo(sc, t); + } - if (t.ty != Terror && e.type.ty != Terror) - { - if (!t.deco) - { - e.error("forward reference to type `%s`", t.toChars()); - } - else - { - //printf("type %p ty %d deco %p\n", type, type.ty, type.deco); - //type = type.typeSemantic(loc, sc); - //printf("type %s t %s\n", type.deco, t.deco); - auto ts = toAutoQualChars(e.type, t); - e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", - e.toChars(), ts[0], ts[1]); - } - } - result = ErrorExp.get(); + auto result = e.optimize(WANTvalue); + if (result != e) + { + return implicitCastTo(result, sc, t); } - override void visit(StringExp e) + if (t.ty != Terror && e.type.ty != Terror) { - //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); - visit(cast(Expression)e); - if (auto se = result.isStringExp()) + if (!t.deco) + { + e.error("forward reference to type `%s`", t.toChars()); + } + else { - // Retain polysemous nature if it started out that way - se.committed = e.committed; + //printf("type %p ty %d deco %p\n", type, type.ty, type.deco); + //type = type.typeSemantic(loc, sc); + //printf("type %s t %s\n", type.deco, t.deco); + auto ts = toAutoQualChars(e.type, t); + e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", + e.toChars(), ts[0], ts[1]); } } + return ErrorExp.get(); + } - override void visit(ErrorExp e) + Expression visitString(StringExp e) + { + //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); + auto result = visit(e); + if (auto se = result.isStringExp()) { - result = e; + // Retain polysemous nature if it started out that way + se.committed = e.committed; } + return result; + } + + Expression visitError(ErrorExp e) + { + return e; + } - override void visit(FuncExp e) + Expression visitFunc(FuncExp e) + { + //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); + FuncExp fe; + if (e.matchType(t, sc, &fe) > MATCH.nomatch) { - //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); - FuncExp fe; - if (e.matchType(t, sc, &fe) > MATCH.nomatch) - { - result = fe; - return; - } - visit(cast(Expression)e); + return fe; } + return visit(e); + } - override void visit(ArrayLiteralExp e) - { - visit(cast(Expression)e); + Expression visitArrayLiteral(ArrayLiteralExp e) + { + auto result = visit(e); - Type tb = result.type.toBasetype(); - if (auto ta = tb.isTypeDArray()) - if (global.params.useTypeInfo && Type.dtypeinfo) - semanticTypeInfo(sc, ta.next); - } + Type tb = result.type.toBasetype(); + if (auto ta = tb.isTypeDArray()) + if (global.params.useTypeInfo && Type.dtypeinfo) + semanticTypeInfo(sc, ta.next); + return result; + } - override void visit(SliceExp e) - { - visit(cast(Expression)e); + Expression visitSlice(SliceExp e) + { + auto result = visit(e); - if (auto se = result.isSliceExp()) - if (auto ale = se.e1.isArrayLiteralExp()) - { - Type tb = t.toBasetype(); - Type tx = (tb.ty == Tsarray) - ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0) - : tb.nextOf().arrayOf(); - se.e1 = ale.implicitCastTo(sc, tx); - } - } + if (auto se = result.isSliceExp()) + if (auto ale = se.e1.isArrayLiteralExp()) + { + Type tb = t.toBasetype(); + Type tx = (tb.ty == Tsarray) + ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0) + : tb.nextOf().arrayOf(); + se.e1 = ale.implicitCastTo(sc, tx); + } + + return result; } - scope ImplicitCastTo v = new ImplicitCastTo(sc, t); - e.accept(v); - return v.result; + switch (e.op) + { + default : return visit (e); + case EXP.string_ : return visitString (e.isStringExp()); + case EXP.error : return visitError (e.isErrorExp()); + case EXP.function_ : return visitFunc (e.isFuncExp()); + case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); + case EXP.slice : return visitSlice (e.isSliceExp()); + } } /** @@ -236,1242 +227,1244 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) */ MATCH implicitConvTo(Expression e, Type t) { - extern (C++) final class ImplicitConvTo : Visitor + MATCH visit(Expression e) { - alias visit = Visitor.visit; - public: - Type t; - MATCH result; + version (none) + { + printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + //static int nest; if (++nest == 10) assert(0); + if (t == Type.terror) + return MATCH.nomatch; + if (!e.type) + { + e.error("`%s` is not an expression", e.toChars()); + e.type = Type.terror; + } - extern (D) this(Type t) + Expression ex = e.optimize(WANTvalue); + if (ex.type.equals(t)) + { + return MATCH.exact; + } + if (ex != e) { - this.t = t; - result = MATCH.nomatch; + //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); + return ex.implicitConvTo(t); } - override void visit(Expression e) + MATCH match = e.type.implicitConvTo(t); + if (match != MATCH.nomatch) { - version (none) - { - printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - //static int nest; if (++nest == 10) assert(0); - if (t == Type.terror) - return; - if (!e.type) - { - e.error("`%s` is not an expression", e.toChars()); - e.type = Type.terror; - } + return match; + } - Expression ex = e.optimize(WANTvalue); - if (ex.type.equals(t)) - { - result = MATCH.exact; - return; - } - if (ex != e) + /* See if we can do integral narrowing conversions + */ + if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic()) + { + IntRange src = getIntRange(e); + IntRange target = IntRange.fromType(t); + if (target.contains(src)) { - //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); - result = ex.implicitConvTo(t); - return; + return MATCH.convert; } + } + return MATCH.nomatch; + } - MATCH match = e.type.implicitConvTo(t); - if (match != MATCH.nomatch) - { - result = match; - return; - } + /****** + * Given expression e of type t, see if we can implicitly convert e + * to type tprime, where tprime is type t with mod bits added. + * Returns: + * match level + */ + static MATCH implicitMod(Expression e, Type t, MOD mod) + { + Type tprime; + if (t.ty == Tpointer) + tprime = t.nextOf().castMod(mod).pointerTo(); + else if (t.ty == Tarray) + tprime = t.nextOf().castMod(mod).arrayOf(); + else if (t.ty == Tsarray) + tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size()); + else + tprime = t.castMod(mod); - /* See if we can do integral narrowing conversions - */ - if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic()) - { - IntRange src = getIntRange(e); - IntRange target = IntRange.fromType(t); - if (target.contains(src)) - { - result = MATCH.convert; - return; - } - } - } + return e.implicitConvTo(tprime); + } - /****** - * Given expression e of type t, see if we can implicitly convert e - * to type tprime, where tprime is type t with mod bits added. - * Returns: - * match level + static MATCH implicitConvToAddMin(BinExp e, Type t) + { + /* Is this (ptr +- offset)? If so, then ask ptr + * if the conversion can be done. + * This is to support doing things like implicitly converting a mutable unique + * pointer to an immutable pointer. */ - static MATCH implicitMod(Expression e, Type t, MOD mod) - { - Type tprime; - if (t.ty == Tpointer) - tprime = t.nextOf().castMod(mod).pointerTo(); - else if (t.ty == Tarray) - tprime = t.nextOf().castMod(mod).arrayOf(); - else if (t.ty == Tsarray) - tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size()); - else - tprime = t.castMod(mod); - return e.implicitConvTo(tprime); + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); + + if (typeb.ty != Tpointer || tb.ty != Tpointer) + return MATCH.nomatch; + + Type t1b = e.e1.type.toBasetype(); + Type t2b = e.e2.type.toBasetype(); + if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb)) + { + // ptr + offset + // ptr - offset + MATCH m = e.e1.implicitConvTo(t); + return (m > MATCH.constant) ? MATCH.constant : m; } + if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb)) + { + // offset + ptr + MATCH m = e.e2.implicitConvTo(t); + return (m > MATCH.constant) ? MATCH.constant : m; + } + + return MATCH.nomatch; + } - static MATCH implicitConvToAddMin(BinExp e, Type t) + MATCH visitAdd(AddExp e) + { + version (none) { - /* Is this (ptr +- offset)? If so, then ask ptr - * if the conversion can be done. - * This is to support doing things like implicitly converting a mutable unique - * pointer to an immutable pointer. - */ + printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + auto result = visit(e); + if (result == MATCH.nomatch) + result = implicitConvToAddMin(e, t); + return result; + } - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + MATCH visitMin(MinExp e) + { + version (none) + { + printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + auto result = visit(e); + if (result == MATCH.nomatch) + result = implicitConvToAddMin(e, t); + return result; + } - if (typeb.ty != Tpointer || tb.ty != Tpointer) - return MATCH.nomatch; + MATCH visitInteger(IntegerExp e) + { + version (none) + { + printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + MATCH m = e.type.implicitConvTo(t); + if (m >= MATCH.constant) + { + return m; + } - Type t1b = e.e1.type.toBasetype(); - Type t2b = e.e2.type.toBasetype(); - if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb)) - { - // ptr + offset - // ptr - offset - MATCH m = e.e1.implicitConvTo(t); - return (m > MATCH.constant) ? MATCH.constant : m; - } - if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb)) - { - // offset + ptr - MATCH m = e.e2.implicitConvTo(t); - return (m > MATCH.constant) ? MATCH.constant : m; - } + TY ty = e.type.toBasetype().ty; + TY toty = t.toBasetype().ty; + TY oldty = ty; + if (m == MATCH.nomatch && t.ty == Tenum) return MATCH.nomatch; - } - override void visit(AddExp e) + if (auto tv = t.isTypeVector()) { - version (none) - { - printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - visit(cast(Expression)e); - if (result == MATCH.nomatch) - result = implicitConvToAddMin(e, t); + TypeBasic tb = tv.elementType(); + if (tb.ty == Tvoid) + return MATCH.nomatch; + toty = tb.ty; } - override void visit(MinExp e) + switch (ty) { - version (none) - { - printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - visit(cast(Expression)e); - if (result == MATCH.nomatch) - result = implicitConvToAddMin(e, t); + case Tbool: + case Tint8: + case Tchar: + case Tuns8: + case Tint16: + case Tuns16: + case Twchar: + ty = Tint32; + break; + + case Tdchar: + ty = Tuns32; + break; + + default: + break; } - override void visit(IntegerExp e) + // Only allow conversion if no change in value + immutable dinteger_t value = e.toInteger(); + + bool isLosslesslyConvertibleToFP(T)() { - version (none) + if (e.type.isunsigned()) { - printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - MATCH m = e.type.implicitConvTo(t); - if (m >= MATCH.constant) - { - result = m; - return; + const f = cast(T) value; + return cast(dinteger_t) f == value; } - TY ty = e.type.toBasetype().ty; - TY toty = t.toBasetype().ty; - TY oldty = ty; - - if (m == MATCH.nomatch && t.ty == Tenum) - return; + const f = cast(T) cast(sinteger_t) value; + return cast(sinteger_t) f == cast(sinteger_t) value; + } - if (auto tv = t.isTypeVector()) - { - TypeBasic tb = tv.elementType(); - if (tb.ty == Tvoid) - return; - toty = tb.ty; - } + switch (toty) + { + case Tbool: + if ((value & 1) != value) + return MATCH.nomatch; + break; - switch (ty) - { - case Tbool: - case Tint8: - case Tchar: - case Tuns8: - case Tint16: - case Tuns16: - case Twchar: - ty = Tint32; - break; + case Tint8: + if (ty == Tuns64 && value & ~0x7FU) + return MATCH.nomatch; + else if (cast(byte)value != value) + return MATCH.nomatch; + break; - case Tdchar: - ty = Tuns32; - break; + case Tchar: + if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) + return MATCH.nomatch; + goto case Tuns8; + case Tuns8: + //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); + if (cast(ubyte)value != value) + return MATCH.nomatch; + break; - default: - break; - } + case Tint16: + if (ty == Tuns64 && value & ~0x7FFFU) + return MATCH.nomatch; + else if (cast(short)value != value) + return MATCH.nomatch; + break; - // Only allow conversion if no change in value - immutable dinteger_t value = e.toInteger(); + case Twchar: + if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) + return MATCH.nomatch; + goto case Tuns16; + case Tuns16: + if (cast(ushort)value != value) + return MATCH.nomatch; + break; - bool isLosslesslyConvertibleToFP(T)() + case Tint32: + if (ty == Tuns32) { - if (e.type.isunsigned()) - { - const f = cast(T) value; - return cast(dinteger_t) f == value; - } - - const f = cast(T) cast(sinteger_t) value; - return cast(sinteger_t) f == cast(sinteger_t) value; } + else if (ty == Tuns64 && value & ~0x7FFFFFFFU) + return MATCH.nomatch; + else if (cast(int)value != value) + return MATCH.nomatch; + break; - switch (toty) + case Tuns32: + if (ty == Tint32) { - case Tbool: - if ((value & 1) != value) - return; - break; - - case Tint8: - if (ty == Tuns64 && value & ~0x7FU) - return; - else if (cast(byte)value != value) - return; - break; - - case Tchar: - if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) - return; - goto case Tuns8; - case Tuns8: - //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); - if (cast(ubyte)value != value) - return; - break; - - case Tint16: - if (ty == Tuns64 && value & ~0x7FFFU) - return; - else if (cast(short)value != value) - return; - break; - - case Twchar: - if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) - return; - goto case Tuns16; - case Tuns16: - if (cast(ushort)value != value) - return; - break; + } + else if (cast(uint)value != value) + return MATCH.nomatch; + break; - case Tint32: - if (ty == Tuns32) - { - } - else if (ty == Tuns64 && value & ~0x7FFFFFFFU) - return; - else if (cast(int)value != value) - return; - break; + case Tdchar: + if (value > 0x10FFFFU) + return MATCH.nomatch; + break; - case Tuns32: - if (ty == Tint32) - { - } - else if (cast(uint)value != value) - return; - break; + case Tfloat32: + if (!isLosslesslyConvertibleToFP!float) + return MATCH.nomatch; + break; - case Tdchar: - if (value > 0x10FFFFU) - return; - break; + case Tfloat64: + if (!isLosslesslyConvertibleToFP!double) + return MATCH.nomatch; + break; - case Tfloat32: - if (!isLosslesslyConvertibleToFP!float) - return; - break; + case Tfloat80: + if (!isLosslesslyConvertibleToFP!real_t) + return MATCH.nomatch; + break; - case Tfloat64: - if (!isLosslesslyConvertibleToFP!double) - return; + case Tpointer: + //printf("type = %s\n", type.toBasetype()->toChars()); + //printf("t = %s\n", t.toBasetype()->toChars()); + if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty) + { + /* Allow things like: + * const char* P = cast(char *)3; + * char* q = P; + */ break; + } + goto default; - case Tfloat80: - if (!isLosslesslyConvertibleToFP!real_t) - return; - break; + default: + return visit(e); + } - case Tpointer: - //printf("type = %s\n", type.toBasetype()->toChars()); - //printf("t = %s\n", t.toBasetype()->toChars()); - if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty) - { - /* Allow things like: - * const char* P = cast(char *)3; - * char* q = P; - */ - break; - } - goto default; + //printf("MATCH.convert\n"); + return MATCH.convert; + } - default: - visit(cast(Expression)e); - return; - } + MATCH visitError(ErrorExp e) + { + return MATCH.nomatch; + } - //printf("MATCH.convert\n"); - result = MATCH.convert; + MATCH visitNull(NullExp e) + { + version (none) + { + printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } - - override void visit(ErrorExp e) + if (e.type.equals(t)) { - // no match + return MATCH.exact; } - override void visit(NullExp e) + /* Allow implicit conversions from immutable to mutable|const, + * and mutable to immutable. It works because, after all, a null + * doesn't actually point to anything. + */ + if (t.equivalent(e.type)) { - version (none) - { - printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - if (e.type.equals(t)) - { - result = MATCH.exact; - return; - } + return MATCH.constant; + } - /* Allow implicit conversions from immutable to mutable|const, - * and mutable to immutable. It works because, after all, a null - * doesn't actually point to anything. - */ - if (t.equivalent(e.type)) - { - result = MATCH.constant; - return; - } + return visit(e); + } - visit(cast(Expression)e); + MATCH visitStructLiteral(StructLiteralExp e) + { + version (none) + { + printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } - - override void visit(StructLiteralExp e) + auto result = visit(e); + if (result != MATCH.nomatch) + return result; + if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym) { - version (none) - { - printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; - if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym) + result = MATCH.constant; + foreach (i, el; (*e.elements)[]) { - result = MATCH.constant; - foreach (i, el; (*e.elements)[]) - { - if (!el) - continue; - Type te = e.sd.fields[i].type.addMod(t.mod); - MATCH m2 = el.implicitConvTo(te); - //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2); - if (m2 < result) - result = m2; - } + if (!el) + continue; + Type te = e.sd.fields[i].type.addMod(t.mod); + MATCH m2 = el.implicitConvTo(te); + //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2); + if (m2 < result) + result = m2; } } + return result; + } - override void visit(StringExp e) + MATCH visitString(StringExp e) + { + version (none) { - version (none) - { - printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars()); - } - if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) - return; + printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars()); + } + if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) + return MATCH.nomatch; - if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer)) - return visit(cast(Expression)e); + if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer)) + return visit(e); - TY tyn = e.type.nextOf().ty; + TY tyn = e.type.nextOf().ty; - if (!tyn.isSomeChar) - return visit(cast(Expression)e); + if (!tyn.isSomeChar) + return visit(e); - switch (t.ty) + switch (t.ty) + { + case Tsarray: + if (e.type.ty == Tsarray) { - case Tsarray: - if (e.type.ty == Tsarray) + TY tynto = t.nextOf().ty; + if (tynto == tyn) { - TY tynto = t.nextOf().ty; - if (tynto == tyn) - { - if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger()) - { - result = MATCH.exact; - } - return; - } - if (tynto.isSomeChar) - { - if (e.committed && tynto != tyn) - return; - size_t fromlen = e.numberOfCodeUnits(tynto); - size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger(); - if (tolen < fromlen) - return; - if (tolen != fromlen) - { - // implicit length extending - result = MATCH.convert; - return; - } - } - if (!e.committed && tynto.isSomeChar) + if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger()) { - result = MATCH.exact; - return; + return MATCH.exact; } + return MATCH.nomatch; } - else if (e.type.ty == Tarray) + if (tynto.isSomeChar) { - TY tynto = t.nextOf().ty; - if (tynto.isSomeChar) - { - if (e.committed && tynto != tyn) - return; - size_t fromlen = e.numberOfCodeUnits(tynto); - size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger(); - if (tolen < fromlen) - return; - if (tolen != fromlen) - { - // implicit length extending - result = MATCH.convert; - return; - } - } - if (tynto == tyn) + if (e.committed && tynto != tyn) + return MATCH.nomatch; + size_t fromlen = e.numberOfCodeUnits(tynto); + size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger(); + if (tolen < fromlen) + return MATCH.nomatch; + if (tolen != fromlen) { - result = MATCH.exact; - return; + // implicit length extending + return MATCH.convert; } - if (!e.committed && tynto.isSomeChar) + } + if (!e.committed && tynto.isSomeChar) + { + return MATCH.exact; + } + } + else if (e.type.ty == Tarray) + { + TY tynto = t.nextOf().ty; + if (tynto.isSomeChar) + { + if (e.committed && tynto != tyn) + return MATCH.nomatch; + size_t fromlen = e.numberOfCodeUnits(tynto); + size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger(); + if (tolen < fromlen) + return MATCH.nomatch; + if (tolen != fromlen) { - result = MATCH.exact; - return; + // implicit length extending + return MATCH.convert; } } - goto case; /+ fall through +/ - case Tarray: - case Tpointer: - Type tn = t.nextOf(); - MATCH m = MATCH.exact; - if (e.type.nextOf().mod != tn.mod) + if (tynto == tyn) { - // https://issues.dlang.org/show_bug.cgi?id=16183 - if (!tn.isConst() && !tn.isImmutable()) - return; - m = MATCH.constant; + return MATCH.exact; } - if (!e.committed) + if (!e.committed && tynto.isSomeChar) { - switch (tn.ty) + return MATCH.exact; + } + } + goto case; /+ fall through +/ + case Tarray: + case Tpointer: + Type tn = t.nextOf(); + MATCH m = MATCH.exact; + if (e.type.nextOf().mod != tn.mod) + { + // https://issues.dlang.org/show_bug.cgi?id=16183 + if (!tn.isConst() && !tn.isImmutable()) + return MATCH.nomatch; + m = MATCH.constant; + } + if (!e.committed) + { + switch (tn.ty) + { + case Tchar: + if (e.postfix == 'w' || e.postfix == 'd') + m = MATCH.convert; + return m; + case Twchar: + if (e.postfix != 'w') + m = MATCH.convert; + return m; + case Tdchar: + if (e.postfix != 'd') + m = MATCH.convert; + return m; + case Tenum: + if (tn.isTypeEnum().sym.isSpecial()) { - case Tchar: - if (e.postfix == 'w' || e.postfix == 'd') - m = MATCH.convert; - result = m; - return; - case Twchar: - if (e.postfix != 'w') - m = MATCH.convert; - result = m; - return; - case Tdchar: - if (e.postfix != 'd') - m = MATCH.convert; - result = m; - return; - case Tenum: - if (tn.isTypeEnum().sym.isSpecial()) - { - /* Allow string literal -> const(wchar_t)[] - */ - if (TypeBasic tob = tn.toBasetype().isTypeBasic()) - result = tn.implicitConvTo(tob); - return; - } - break; - default: - break; + /* Allow string literal -> const(wchar_t)[] + */ + if (TypeBasic tob = tn.toBasetype().isTypeBasic()) + return tn.implicitConvTo(tob); } + break; + default: + break; } - break; - - default: - break; } + break; - visit(cast(Expression)e); + default: + break; } - override void visit(ArrayLiteralExp e) + return visit(e); + } + + MATCH visitArrayLiteral(ArrayLiteralExp e) + { + version (none) { - version (none) + printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); + + auto result = MATCH.nomatch; + if ((tb.ty == Tarray || tb.ty == Tsarray) && + (typeb.ty == Tarray || typeb.ty == Tsarray)) + { + result = MATCH.exact; + Type typen = typeb.nextOf().toBasetype(); + + if (auto tsa = tb.isTypeSArray()) { - printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + if (e.elements.dim != tsa.dim.toInteger()) + result = MATCH.nomatch; } - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); - if ((tb.ty == Tarray || tb.ty == Tsarray) && - (typeb.ty == Tarray || typeb.ty == Tsarray)) + Type telement = tb.nextOf(); + if (!e.elements.dim) { - result = MATCH.exact; - Type typen = typeb.nextOf().toBasetype(); - - if (auto tsa = tb.isTypeSArray()) - { - if (e.elements.dim != tsa.dim.toInteger()) - result = MATCH.nomatch; - } - - Type telement = tb.nextOf(); - if (!e.elements.dim) - { - if (typen.ty != Tvoid) - result = typen.implicitConvTo(telement); - } - else - { - if (e.basis) - { - MATCH m = e.basis.implicitConvTo(telement); - if (m < result) - result = m; - } - for (size_t i = 0; i < e.elements.dim; i++) - { - Expression el = (*e.elements)[i]; - if (result == MATCH.nomatch) - break; - if (!el) - continue; - MATCH m = el.implicitConvTo(telement); - if (m < result) - result = m; // remember worst match - } - } - - if (!result) - result = e.type.implicitConvTo(t); - - return; + if (typen.ty != Tvoid) + result = typen.implicitConvTo(telement); } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) + else { - result = MATCH.exact; - // Convert array literal to vector type - TypeVector tv = tb.isTypeVector(); - TypeSArray tbase = tv.basetype.isTypeSArray(); - assert(tbase); - const edim = e.elements.dim; - const tbasedim = tbase.dim.toInteger(); - if (edim > tbasedim) - { - result = MATCH.nomatch; - return; - } - - Type telement = tv.elementType(); - if (edim < tbasedim) + if (e.basis) { - Expression el = typeb.nextOf.defaultInitLiteral(e.loc); - MATCH m = el.implicitConvTo(telement); + MATCH m = e.basis.implicitConvTo(telement); if (m < result) - result = m; // remember worst match + result = m; } - foreach (el; (*e.elements)[]) + for (size_t i = 0; i < e.elements.dim; i++) { + Expression el = (*e.elements)[i]; + if (result == MATCH.nomatch) + break; + if (!el) + continue; MATCH m = el.implicitConvTo(telement); if (m < result) result = m; // remember worst match - if (result == MATCH.nomatch) - break; // no need to check for worse } - return; } - visit(cast(Expression)e); - } + if (!result) + result = e.type.implicitConvTo(t); - override void visit(AssocArrayLiteralExp e) + return result; + } + else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) { - auto taa = t.toBasetype().isTypeAArray(); - Type typeb = e.type.toBasetype(); - - if (!(taa && typeb.ty == Taarray)) - return visit(cast(Expression)e); - result = MATCH.exact; - foreach (i, el; (*e.keys)[]) + // Convert array literal to vector type + TypeVector tv = tb.isTypeVector(); + TypeSArray tbase = tv.basetype.isTypeSArray(); + assert(tbase); + const edim = e.elements.dim; + const tbasedim = tbase.dim.toInteger(); + if (edim > tbasedim) + { + return MATCH.nomatch; + } + + Type telement = tv.elementType(); + if (edim < tbasedim) { - MATCH m = el.implicitConvTo(taa.index); + Expression el = typeb.nextOf.defaultInitLiteral(e.loc); + MATCH m = el.implicitConvTo(telement); if (m < result) result = m; // remember worst match - if (result == MATCH.nomatch) - break; // no need to check for worse - el = (*e.values)[i]; - m = el.implicitConvTo(taa.nextOf()); + } + foreach (el; (*e.elements)[]) + { + MATCH m = el.implicitConvTo(telement); if (m < result) result = m; // remember worst match if (result == MATCH.nomatch) break; // no need to check for worse } + return result; } - override void visit(CallExp e) + return visit(e); + } + + MATCH visitAssocArrayLiteral(AssocArrayLiteralExp e) + { + auto taa = t.toBasetype().isTypeAArray(); + Type typeb = e.type.toBasetype(); + + if (!(taa && typeb.ty == Taarray)) + return visit(e); + + auto result = MATCH.exact; + foreach (i, el; (*e.keys)[]) { - enum LOG = false; - static if (LOG) - { - printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } + MATCH m = el.implicitConvTo(taa.index); + if (m < result) + result = m; // remember worst match + if (result == MATCH.nomatch) + break; // no need to check for worse + el = (*e.values)[i]; + m = el.implicitConvTo(taa.nextOf()); + if (m < result) + result = m; // remember worst match + if (result == MATCH.nomatch) + break; // no need to check for worse + } + return result; + } - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; + MATCH visitCall(CallExp e) + { + enum LOG = false; + static if (LOG) + { + printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } - /* Allow the result of strongly pure functions to - * convert to immutable - */ - if (e.f && - // lots of legacy code breaks with the following purity check - (global.params.useDIP1000 != FeatureState.enabled || e.f.isPure() >= PURE.const_) && - e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive. - ) - { - result = e.type.immutableOf().implicitConvTo(t); - if (result > MATCH.constant) // Match level is MATCH.constant at best. - result = MATCH.constant; - return; - } + auto result = visit(e); + if (result != MATCH.nomatch) + return result; - /* Conversion is 'const' conversion if: - * 1. function is pure (weakly pure is ok) - * 2. implicit conversion only fails because of mod bits - * 3. each function parameter can be implicitly converted to the mod bits - */ - auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction(); - if (!tf) - return; + /* Allow the result of strongly pure functions to + * convert to immutable + */ + if (e.f && + // lots of legacy code breaks with the following purity check + (global.params.useDIP1000 != FeatureState.enabled || e.f.isPure() >= PURE.const_) && + e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive. + ) + { + result = e.type.immutableOf().implicitConvTo(t); + if (result > MATCH.constant) // Match level is MATCH.constant at best. + result = MATCH.constant; + return result; + } - if (tf.purity == PURE.impure) - return; - if (e.f && e.f.isNested()) - return; + /* Conversion is 'const' conversion if: + * 1. function is pure (weakly pure is ok) + * 2. implicit conversion only fails because of mod bits + * 3. each function parameter can be implicitly converted to the mod bits + */ + auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction(); + if (!tf) + return result; + + if (tf.purity == PURE.impure) + return result; + if (e.f && e.f.isNested()) + return result; + + /* See if fail only because of mod bits. + * + * https://issues.dlang.org/show_bug.cgi?id=14155 + * All pure functions can access global immutable data. + * So the returned pointer may refer an immutable global data, + * and then the returned pointer that points non-mutable object + * cannot be unique pointer. + * + * Example: + * immutable g; + * static this() { g = 1; } + * const(int*) foo() pure { return &g; } + * void test() { + * immutable(int*) ip = foo(); // OK + * int* mp = foo(); // should be disallowed + * } + */ + if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) + { + return result; + } + // Allow a conversion to immutable type, or + // conversions of mutable types between thread-local and shared. - /* See if fail only because of mod bits. - * - * https://issues.dlang.org/show_bug.cgi?id=14155 - * All pure functions can access global immutable data. - * So the returned pointer may refer an immutable global data, - * and then the returned pointer that points non-mutable object - * cannot be unique pointer. - * - * Example: - * immutable g; - * static this() { g = 1; } - * const(int*) foo() pure { return &g; } - * void test() { - * immutable(int*) ip = foo(); // OK - * int* mp = foo(); // should be disallowed - * } - */ - if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) - { - return; - } - // Allow a conversion to immutable type, or - // conversions of mutable types between thread-local and shared. + /* Get mod bits of what we're converting to + */ + Type tb = t.toBasetype(); + MOD mod = tb.mod; + if (tf.isref) + { + } + else + { + if (Type ti = getIndirection(t)) + mod = ti.mod; + } + static if (LOG) + { + printf("mod = x%x\n", mod); + } + if (mod & MODFlags.wild) + return result; // not sure what to do with this - /* Get mod bits of what we're converting to - */ - Type tb = t.toBasetype(); - MOD mod = tb.mod; - if (tf.isref) - { - } - else - { - if (Type ti = getIndirection(t)) - mod = ti.mod; - } - static if (LOG) - { - printf("mod = x%x\n", mod); - } - if (mod & MODFlags.wild) - return; // not sure what to do with this + /* Apply mod bits to each function parameter, + * and see if we can convert the function argument to the modded type + */ - /* Apply mod bits to each function parameter, - * and see if we can convert the function argument to the modded type + size_t nparams = tf.parameterList.length; + size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended + if (auto dve = e.e1.isDotVarExp()) + { + /* Treat 'this' as just another function argument */ - - size_t nparams = tf.parameterList.length; - size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended - if (auto dve = e.e1.isDotVarExp()) + Type targ = dve.e1.type; + if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) + return result; + } + foreach (const i; j .. e.arguments.dim) + { + Expression earg = (*e.arguments)[i]; + Type targ = earg.type.toBasetype(); + static if (LOG) { - /* Treat 'this' as just another function argument - */ - Type targ = dve.e1.type; - if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) - return; + printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); } - foreach (const i; j .. e.arguments.dim) + if (i - j < nparams) { - Expression earg = (*e.arguments)[i]; - Type targ = earg.type.toBasetype(); - static if (LOG) + Parameter fparam = tf.parameterList[i - j]; + if (fparam.storageClass & STC.lazy_) + return result; // not sure what to do with this + Type tparam = fparam.type; + if (!tparam) + continue; + if (fparam.isReference()) { - printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); + if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) + return result; + continue; } - if (i - j < nparams) - { - Parameter fparam = tf.parameterList[i - j]; - if (fparam.storageClass & STC.lazy_) - return; // not sure what to do with this - Type tparam = fparam.type; - if (!tparam) - continue; - if (fparam.isReference()) - { - if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) - return; - continue; - } - } - static if (LOG) - { - printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); - } - if (implicitMod(earg, targ, mod) == MATCH.nomatch) - return; } - - /* Success - */ - result = MATCH.constant; + static if (LOG) + { + printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); + } + if (implicitMod(earg, targ, mod) == MATCH.nomatch) + return result; } - override void visit(AddrExp e) + /* Success + */ + return MATCH.constant; + } + + MATCH visitAddr(AddrExp e) + { + version (none) { - version (none) - { - printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - result = e.type.implicitConvTo(t); - //printf("\tresult = %d\n", result); + printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + auto result = e.type.implicitConvTo(t); + //printf("\tresult = %d\n", result); - if (result != MATCH.nomatch) - return; + if (result != MATCH.nomatch) + return result; - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - // Look for pointers to functions where the functions are overloaded. - if (e.e1.op == EXP.overloadSet && - (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + // Look for pointers to functions where the functions are overloaded. + if (e.e1.op == EXP.overloadSet && + (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + { + OverExp eo = e.e1.isOverExp(); + FuncDeclaration f = null; + foreach (s; eo.vars.a[]) { - OverExp eo = e.e1.isOverExp(); - FuncDeclaration f = null; - foreach (s; eo.vars.a[]) + FuncDeclaration f2 = s.isFuncDeclaration(); + assert(f2); + if (f2.overloadExactMatch(tb.nextOf())) { - FuncDeclaration f2 = s.isFuncDeclaration(); - assert(f2); - if (f2.overloadExactMatch(tb.nextOf())) + if (f) { - if (f) - { - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol.multiplyDefined(e.loc, f, f2); - } - else - f = f2; - result = MATCH.exact; + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol.multiplyDefined(e.loc, f, f2); } + else + f = f2; + result = MATCH.exact; } } + } - if (e.e1.op == EXP.variable && - typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && - tb.ty == Tpointer && tb.nextOf().ty == Tfunction) - { - /* I don't think this can ever happen - - * it should have been - * converted to a SymOffExp. - */ - assert(0); - } - - //printf("\tresult = %d\n", result); + if (e.e1.op == EXP.variable && + typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && + tb.ty == Tpointer && tb.nextOf().ty == Tfunction) + { + /* I don't think this can ever happen - + * it should have been + * converted to a SymOffExp. + */ + assert(0); } - override void visit(SymOffExp e) + //printf("\tresult = %d\n", result); + return result; + } + + MATCH visitSymOff(SymOffExp e) + { + version (none) { - version (none) - { - printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - result = e.type.implicitConvTo(t); - //printf("\tresult = %d\n", result); - if (result != MATCH.nomatch) - return; + printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + auto result = e.type.implicitConvTo(t); + //printf("\tresult = %d\n", result); + if (result != MATCH.nomatch) + return result; - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - // Look for pointers to functions where the functions are overloaded. - if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && - (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + // Look for pointers to functions where the functions are overloaded. + if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && + (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + { + if (FuncDeclaration f = e.var.isFuncDeclaration()) { - if (FuncDeclaration f = e.var.isFuncDeclaration()) + f = f.overloadExactMatch(tb.nextOf()); + if (f) { - f = f.overloadExactMatch(tb.nextOf()); - if (f) + if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) || + (tb.ty == Tpointer && !(f.needThis() || f.isNested()))) { - if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) || - (tb.ty == Tpointer && !(f.needThis() || f.isNested()))) - { - result = MATCH.exact; - } + result = MATCH.exact; } } } - //printf("\tresult = %d\n", result); } + //printf("\tresult = %d\n", result); + return result; + } - override void visit(DelegateExp e) + MATCH visitDelegate(DelegateExp e) + { + version (none) { - version (none) - { - printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - result = e.type.implicitConvTo(t); - if (result != MATCH.nomatch) - return; + printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + auto result = e.type.implicitConvTo(t); + if (result != MATCH.nomatch) + return result; - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - // Look for pointers to functions where the functions are overloaded. - if (typeb.ty == Tdelegate && tb.ty == Tdelegate) - { - if (e.func && e.func.overloadExactMatch(tb.nextOf())) - result = MATCH.exact; - } + // Look for pointers to functions where the functions are overloaded. + if (typeb.ty == Tdelegate && tb.ty == Tdelegate) + { + if (e.func && e.func.overloadExactMatch(tb.nextOf())) + result = MATCH.exact; } + return result; + } - override void visit(FuncExp e) + MATCH visitFunc(FuncExp e) + { + //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); + MATCH m = e.matchType(t, null, null, 1); + if (m > MATCH.nomatch) { - //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); - MATCH m = e.matchType(t, null, null, 1); - if (m > MATCH.nomatch) - { - result = m; - return; - } - visit(cast(Expression)e); + return m; } + return visit(e); + } - override void visit(AndExp e) - { - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; + MATCH visitAnd(AndExp e) + { + auto result = visit(e); + if (result != MATCH.nomatch) + return result; - MATCH m1 = e.e1.implicitConvTo(t); - MATCH m2 = e.e2.implicitConvTo(t); + MATCH m1 = e.e1.implicitConvTo(t); + MATCH m2 = e.e2.implicitConvTo(t); - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } + // Pick the worst match + return (m1 < m2) ? m1 : m2; + } - override void visit(OrExp e) - { - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; + MATCH visitOr(OrExp e) + { + auto result = visit(e); + if (result != MATCH.nomatch) + return result; - MATCH m1 = e.e1.implicitConvTo(t); - MATCH m2 = e.e2.implicitConvTo(t); + MATCH m1 = e.e1.implicitConvTo(t); + MATCH m2 = e.e2.implicitConvTo(t); - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } + // Pick the worst match + return (m1 < m2) ? m1 : m2; + } - override void visit(XorExp e) - { - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; + MATCH visitXor(XorExp e) + { + auto result = visit(e); + if (result != MATCH.nomatch) + return result; - MATCH m1 = e.e1.implicitConvTo(t); - MATCH m2 = e.e2.implicitConvTo(t); + MATCH m1 = e.e1.implicitConvTo(t); + MATCH m2 = e.e2.implicitConvTo(t); - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } + // Pick the worst match + return (m1 < m2) ? m1 : m2; + } - override void visit(CondExp e) - { - MATCH m1 = e.e1.implicitConvTo(t); - MATCH m2 = e.e2.implicitConvTo(t); - //printf("CondExp: m1 %d m2 %d\n", m1, m2); + MATCH visitCond(CondExp e) + { + MATCH m1 = e.e1.implicitConvTo(t); + MATCH m2 = e.e2.implicitConvTo(t); + //printf("CondExp: m1 %d m2 %d\n", m1, m2); - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } + // Pick the worst match + return (m1 < m2) ? m1 : m2; + } - override void visit(CommaExp e) + MATCH visitComma(CommaExp e) + { + return e.e2.implicitConvTo(t); + } + + MATCH visitCast(CastExp e) + { + version (none) { - e.e2.accept(this); + printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } + auto result = e.type.implicitConvTo(t); + if (result != MATCH.nomatch) + return result; - override void visit(CastExp e) - { - version (none) - { - printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - result = e.type.implicitConvTo(t); - if (result != MATCH.nomatch) - return; + if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch) + result = MATCH.convert; + else + result = visit(e); + return result; + } - if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch) - result = MATCH.convert; - else - visit(cast(Expression)e); + MATCH visitNew(NewExp e) + { + version (none) + { + printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } + auto result = visit(e); + if (result != MATCH.nomatch) + return result; - override void visit(NewExp e) - { - version (none) - { - printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; + /* Calling new() is like calling a pure function. We can implicitly convert the + * return from new() to t using the same algorithm as in CallExp, with the function + * 'arguments' being: + * thisexp + * arguments + * .init + * 'member' need to be pure. + */ - /* Calling new() is like calling a pure function. We can implicitly convert the - * return from new() to t using the same algorithm as in CallExp, with the function - * 'arguments' being: - * thisexp - * newargs - * arguments - * .init - * 'member' need to be pure. - */ + /* See if fail only because of mod bits + */ + if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch) + return MATCH.nomatch; - /* See if fail only because of mod bits - */ - if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch) - return; + /* Get mod bits of what we're converting to + */ + Type tb = t.toBasetype(); + MOD mod = tb.mod; + if (Type ti = getIndirection(t)) + mod = ti.mod; + static if (LOG) + { + printf("mod = x%x\n", mod); + } + if (mod & MODFlags.wild) + return MATCH.nomatch; // not sure what to do with this - /* Get mod bits of what we're converting to - */ - Type tb = t.toBasetype(); - MOD mod = tb.mod; - if (Type ti = getIndirection(t)) - mod = ti.mod; - static if (LOG) - { - printf("mod = x%x\n", mod); - } - if (mod & MODFlags.wild) - return; // not sure what to do with this + /* Apply mod bits to each argument, + * and see if we can convert the argument to the modded type + */ - /* Apply mod bits to each argument, - * and see if we can convert the argument to the modded type + if (e.thisexp) + { + /* Treat 'this' as just another function argument */ + Type targ = e.thisexp.type; + if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) + return MATCH.nomatch; + } - if (e.thisexp) + /* Check call to 'member' + */ + if (e.member) + { + FuncDeclaration fd = e.member; + if (fd.errors || fd.type.ty != Tfunction) + return MATCH.nomatch; // error + TypeFunction tf = fd.type.isTypeFunction(); + if (tf.purity == PURE.impure) + return MATCH.nomatch; // impure + + if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) { - /* Treat 'this' as just another function argument - */ - Type targ = e.thisexp.type; - if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) - return; + return MATCH.nomatch; } + // Allow a conversion to immutable type, or + // conversions of mutable types between thread-local and shared. - /* Check call to 'member' - */ - if (e.member) - { - FuncDeclaration fd = e.member; - if (fd.errors || fd.type.ty != Tfunction) - return; // error - TypeFunction tf = fd.type.isTypeFunction(); - if (tf.purity == PURE.impure) - return; // impure + Expressions* args = e.arguments; - if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) + size_t nparams = tf.parameterList.length; + // if TypeInfoArray was prepended + size_t j = tf.isDstyleVariadic(); + for (size_t i = j; i < e.arguments.dim; ++i) + { + Expression earg = (*args)[i]; + Type targ = earg.type.toBasetype(); + static if (LOG) { - return; + printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); } - // Allow a conversion to immutable type, or - // conversions of mutable types between thread-local and shared. - - Expressions* args = e.arguments; - - size_t nparams = tf.parameterList.length; - // if TypeInfoArray was prepended - size_t j = tf.isDstyleVariadic(); - for (size_t i = j; i < e.arguments.dim; ++i) + if (i - j < nparams) { - Expression earg = (*args)[i]; - Type targ = earg.type.toBasetype(); - static if (LOG) - { - printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); - } - if (i - j < nparams) - { - Parameter fparam = tf.parameterList[i - j]; - if (fparam.storageClass & STC.lazy_) - return; // not sure what to do with this - Type tparam = fparam.type; - if (!tparam) - continue; - if (fparam.isReference()) - { - if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) - return; - continue; - } - } - static if (LOG) + Parameter fparam = tf.parameterList[i - j]; + if (fparam.storageClass & STC.lazy_) + return MATCH.nomatch; // not sure what to do with this + Type tparam = fparam.type; + if (!tparam) + continue; + if (fparam.isReference()) { - printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); + if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) + return MATCH.nomatch; + continue; } - if (implicitMod(earg, targ, mod) == MATCH.nomatch) - return; } + static if (LOG) + { + printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); + } + if (implicitMod(earg, targ, mod) == MATCH.nomatch) + return MATCH.nomatch; } + } - /* If no 'member', then construction is by simple assignment, - * and just straight check 'arguments' - */ - if (!e.member && e.arguments) + /* If no 'member', then construction is by simple assignment, + * and just straight check 'arguments' + */ + if (!e.member && e.arguments) + { + for (size_t i = 0; i < e.arguments.dim; ++i) { - for (size_t i = 0; i < e.arguments.dim; ++i) + Expression earg = (*e.arguments)[i]; + if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853 + // if it's on overlapped field + continue; + Type targ = earg.type.toBasetype(); + static if (LOG) { - Expression earg = (*e.arguments)[i]; - if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853 - // if it's on overlapped field - continue; - Type targ = earg.type.toBasetype(); - static if (LOG) - { - printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); - printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); - } - if (implicitMod(earg, targ, mod) == MATCH.nomatch) - return; + printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); + printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); } + if (implicitMod(earg, targ, mod) == MATCH.nomatch) + return MATCH.nomatch; } + } - /* Consider the .init expression as an argument + /* Consider the .init expression as an argument + */ + Type ntb = e.newtype.toBasetype(); + if (ntb.ty == Tarray) + ntb = ntb.nextOf().toBasetype(); + if (auto ts = ntb.isTypeStruct()) + { + // Don't allow nested structs - uplevel reference may not be convertible + StructDeclaration sd = ts.sym; + sd.size(e.loc); // resolve any forward references + if (sd.isNested()) + return MATCH.nomatch; + } + if (ntb.isZeroInit(e.loc)) + { + /* Zeros are implicitly convertible, except for special cases. */ - Type ntb = e.newtype.toBasetype(); - if (ntb.ty == Tarray) - ntb = ntb.nextOf().toBasetype(); - if (auto ts = ntb.isTypeStruct()) + if (auto tc = ntb.isTypeClass()) { - // Don't allow nested structs - uplevel reference may not be convertible - StructDeclaration sd = ts.sym; - sd.size(e.loc); // resolve any forward references - if (sd.isNested()) - return; - } - if (ntb.isZeroInit(e.loc)) - { - /* Zeros are implicitly convertible, except for special cases. + /* With new() must look at the class instance initializer. */ - if (auto tc = ntb.isTypeClass()) - { - /* With new() must look at the class instance initializer. - */ - ClassDeclaration cd = tc.sym; + ClassDeclaration cd = tc.sym; - cd.size(e.loc); // resolve any forward references + cd.size(e.loc); // resolve any forward references - if (cd.isNested()) - return; // uplevel reference may not be convertible + if (cd.isNested()) + return MATCH.nomatch; // uplevel reference may not be convertible - assert(!cd.isInterfaceDeclaration()); + assert(!cd.isInterfaceDeclaration()); - struct ClassCheck + struct ClassCheck + { + extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod) { - extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod) + for (size_t i = 0; i < cd.fields.dim; i++) { - for (size_t i = 0; i < cd.fields.dim; i++) + VarDeclaration v = cd.fields[i]; + Initializer _init = v._init; + if (_init) { - VarDeclaration v = cd.fields[i]; - Initializer _init = v._init; - if (_init) + if (_init.isVoidInitializer()) + { + } + else if (ExpInitializer ei = _init.isExpInitializer()) { - if (_init.isVoidInitializer()) - { - } - else if (ExpInitializer ei = _init.isExpInitializer()) - { - // https://issues.dlang.org/show_bug.cgi?id=21319 - // This is to prevent re-analyzing the same expression - // over and over again. - if (ei.exp == e) - return false; - Type tb = v.type.toBasetype(); - if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch) - return false; - } - else - { - /* Enhancement: handle StructInitializer and ArrayInitializer - */ + // https://issues.dlang.org/show_bug.cgi?id=21319 + // This is to prevent re-analyzing the same expression + // over and over again. + if (ei.exp == e) + return false; + Type tb = v.type.toBasetype(); + if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch) return false; - } } - else if (!v.type.isZeroInit(e.loc)) + else + { + /* Enhancement: handle StructInitializer and ArrayInitializer + */ return false; + } } - return cd.baseClass ? convertible(e, cd.baseClass, mod) : true; + else if (!v.type.isZeroInit(e.loc)) + return false; } + return cd.baseClass ? convertible(e, cd.baseClass, mod) : true; } - - if (!ClassCheck.convertible(e, cd, mod)) - return; } - } - else - { - Expression earg = e.newtype.defaultInitLiteral(e.loc); - Type targ = e.newtype.toBasetype(); - if (implicitMod(earg, targ, mod) == MATCH.nomatch) - return; + if (!ClassCheck.convertible(e, cd, mod)) + return MATCH.nomatch; } + } + else + { + Expression earg = e.newtype.defaultInitLiteral(e.loc); + Type targ = e.newtype.toBasetype(); - /* Success - */ - result = MATCH.constant; + if (implicitMod(earg, targ, mod) == MATCH.nomatch) + return MATCH.nomatch; } - override void visit(SliceExp e) - { - //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars()); - visit(cast(Expression)e); - if (result != MATCH.nomatch) - return; + /* Success + */ + return MATCH.constant; + } + + MATCH visitSlice(SliceExp e) + { + //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars()); + auto result = visit(e); + if (result != MATCH.nomatch) + return result; - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - if (tb.ty == Tsarray && typeb.ty == Tarray) + if (tb.ty == Tsarray && typeb.ty == Tarray) + { + typeb = toStaticArrayType(e); + if (typeb) { - typeb = toStaticArrayType(e); - if (typeb) - { - // Try: T[] -> T[dim] - // (Slice with compile-time known boundaries to static array) - result = typeb.implicitConvTo(t); - if (result > MATCH.convert) - result = MATCH.convert; // match with implicit conversion at most - } - return; + // Try: T[] -> T[dim] + // (Slice with compile-time known boundaries to static array) + result = typeb.implicitConvTo(t); + if (result > MATCH.convert) + result = MATCH.convert; // match with implicit conversion at most } + return result; + } - /* If the only reason it won't convert is because of the mod bits, - * then test for conversion by seeing if e1 can be converted with those - * same mod bits. - */ - Type t1b = e.e1.type.toBasetype(); - if (tb.ty == Tarray && typeb.equivalent(tb)) - { - Type tbn = tb.nextOf(); - Type tx = null; + /* If the only reason it won't convert is because of the mod bits, + * then test for conversion by seeing if e1 can be converted with those + * same mod bits. + */ + Type t1b = e.e1.type.toBasetype(); + if (tb.ty == Tarray && typeb.equivalent(tb)) + { + Type tbn = tb.nextOf(); + Type tx = null; - /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1 - * is equivalent with the uniqueness of the referred data. And in here - * we can have arbitrary typed reference for that. - */ - if (t1b.ty == Tarray) - tx = tbn.arrayOf(); - if (t1b.ty == Tpointer) - tx = tbn.pointerTo(); - - /* If e.e1 is static array, at least it should be an rvalue. - * If not, e.e1 is a reference, and its uniqueness does not link - * to the uniqueness of the referred data. - */ - if (t1b.ty == Tsarray && !e.e1.isLvalue()) - tx = tbn.sarrayOf(t1b.size() / tbn.size()); + /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1 + * is equivalent with the uniqueness of the referred data. And in here + * we can have arbitrary typed reference for that. + */ + if (t1b.ty == Tarray) + tx = tbn.arrayOf(); + if (t1b.ty == Tpointer) + tx = tbn.pointerTo(); + + /* If e.e1 is static array, at least it should be an rvalue. + * If not, e.e1 is a reference, and its uniqueness does not link + * to the uniqueness of the referred data. + */ + if (t1b.ty == Tsarray && !e.e1.isLvalue()) + tx = tbn.sarrayOf(t1b.size() / tbn.size()); - if (tx) - { - result = e.e1.implicitConvTo(tx); - if (result > MATCH.constant) // Match level is MATCH.constant at best. - result = MATCH.constant; - } + if (tx) + { + result = e.e1.implicitConvTo(tx); + if (result > MATCH.constant) // Match level is MATCH.constant at best. + result = MATCH.constant; } - - // Enhancement 10724 - if (tb.ty == Tpointer && e.e1.op == EXP.string_) - e.e1.accept(this); } - override void visit(TupleExp e) - { - result = e.type.implicitConvTo(t); - if (result != MATCH.nomatch) - return; + // Enhancement 10724 + if (tb.ty == Tpointer && e.e1.op == EXP.string_) + result = e.e1.implicitConvTo(t); + return result; + } - /* If target type is a tuple of same length, test conversion of - * each expression to the corresponding type in the tuple. - */ - TypeTuple totuple = t.isTypeTuple(); - if (totuple && e.exps.length == totuple.arguments.length) + MATCH visitTuple(TupleExp e) + { + auto result = e.type.implicitConvTo(t); + if (result != MATCH.nomatch) + return result; + + /* If target type is a tuple of same length, test conversion of + * each expression to the corresponding type in the tuple. + */ + TypeTuple totuple = t.isTypeTuple(); + if (totuple && e.exps.length == totuple.arguments.length) + { + result = MATCH.exact; + foreach (i, ex; *e.exps) { - result = MATCH.exact; - foreach (i, ex; *e.exps) - { - auto to = (*totuple.arguments)[i].type; - MATCH mi = ex.implicitConvTo(to); - if (mi < result) - result = mi; - } + auto to = (*totuple.arguments)[i].type; + MATCH mi = ex.implicitConvTo(to); + if (mi < result) + result = mi; } } + return result; } - scope ImplicitConvTo v = new ImplicitConvTo(t); - e.accept(v); - return v.result; + switch (e.op) + { + default : return visit(e); + case EXP.add : return visitAdd(e.isAddExp()); + case EXP.min : return visitMin(e.isMinExp()); + case EXP.int64 : return visitInteger(e.isIntegerExp()); + case EXP.error : return visitError(e.isErrorExp()); + case EXP.null_ : return visitNull(e.isNullExp()); + case EXP.structLiteral : return visitStructLiteral(e.isStructLiteralExp()); + case EXP.string_ : return visitString(e.isStringExp()); + case EXP.arrayLiteral : return visitArrayLiteral(e.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); + case EXP.call : return visitCall(e.isCallExp()); + case EXP.address : return visitAddr(e.isAddrExp()); + case EXP.symbolOffset : return visitSymOff(e.isSymOffExp()); + case EXP.delegate_ : return visitDelegate(e.isDelegateExp()); + case EXP.function_ : return visitFunc(e.isFuncExp()); + case EXP.and : return visitAnd(e.isAndExp()); + case EXP.or : return visitOr(e.isOrExp()); + case EXP.xor : return visitXor(e.isXorExp()); + case EXP.question : return visitCond(e.isCondExp()); + case EXP.comma : return visitComma(e.isCommaExp()); + case EXP.cast_ : return visitCast(e.isCastExp()); + case EXP.new_ : return visitNew(e.isNewExp()); + case EXP.slice : return visitSlice(e.isSliceExp()); + case EXP.tuple : return visitTuple(e.isTupleExp()); + } } /** @@ -1536,1124 +1529,1081 @@ Type toStaticArrayType(SliceExp e) */ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { - extern (C++) final class CastTo : Visitor + Expression visit(Expression e) { - alias visit = Visitor.visit; - public: - Type t; - Scope* sc; - Expression result; - - extern (D) this(Scope* sc, Type t) + //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars()); + version (none) { - this.sc = sc; - this.t = t; + printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } - - override void visit(Expression e) + if (e.type.equals(t)) { - //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars()); - version (none) - { - printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } - if (e.type.equals(t)) - { - result = e; - return; - } - if (auto ve = e.isVarExp()) + return e; + } + if (auto ve = e.isVarExp()) + { + VarDeclaration v = ve.var.isVarDeclaration(); + if (v && v.storage_class & STC.manifest) { - VarDeclaration v = ve.var.isVarDeclaration(); - if (v && v.storage_class & STC.manifest) - { - result = e.ctfeInterpret(); - /* https://issues.dlang.org/show_bug.cgi?id=18236 - * - * The expression returned by ctfeInterpret points - * to the line where the manifest constant was declared - * so we need to update the location before trying to cast - */ - result.loc = e.loc; - result = result.castTo(sc, t); - return; - } + auto result = e.ctfeInterpret(); + /* https://issues.dlang.org/show_bug.cgi?id=18236 + * + * The expression returned by ctfeInterpret points + * to the line where the manifest constant was declared + * so we need to update the location before trying to cast + */ + result.loc = e.loc; + return result.castTo(sc, t); } + } - Type tob = t.toBasetype(); - Type t1b = e.type.toBasetype(); - if (tob.equals(t1b)) - { - result = e.copy(); // because of COW for assignment to e.type - result.type = t; - return; - } + Type tob = t.toBasetype(); + Type t1b = e.type.toBasetype(); + if (tob.equals(t1b)) + { + auto result = e.copy(); // because of COW for assignment to e.type + result.type = t; + return result; + } - /* Make semantic error against invalid cast between concrete types. - * Assume that 'e' is never be any placeholder expressions. - * The result of these checks should be consistent with CastExp::toElem(). - */ + /* Make semantic error against invalid cast between concrete types. + * Assume that 'e' is never be any placeholder expressions. + * The result of these checks should be consistent with CastExp::toElem(). + */ - // Fat Value types - const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector); - const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector); + // Fat Value types + const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector); + const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector); - // Fat Reference types - const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate); - const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate); + // Fat Reference types + const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate); + const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate); - // Reference types - const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass); - const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass); + // Reference types + const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass); + const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass); - // Arithmetic types (== valueable basic types) - const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector); - const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector); + // Arithmetic types (== valueable basic types) + const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector); + const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector); - // Try casting the alias this member. - // Return the expression if it succeeds, null otherwise. - Expression tryAliasThisCast() - { - if (isRecursiveAliasThis(att, t1b)) - return null; + // Try casting the alias this member. + // Return the expression if it succeeds, null otherwise. + Expression tryAliasThisCast() + { + if (isRecursiveAliasThis(att, t1b)) + return null; - /* Forward the cast to our alias this member, rewrite to: - * cast(to)e1.aliasthis - */ - auto exp = resolveAliasThis(sc, e); - const errors = global.startGagging(); - exp = castTo(exp, sc, t, att); - return global.endGagging(errors) ? null : exp; - } + /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + auto exp = resolveAliasThis(sc, e); + const errors = global.startGagging(); + exp = castTo(exp, sc, t, att); + return global.endGagging(errors) ? null : exp; + } - bool hasAliasThis; - if (AggregateDeclaration t1ad = isAggregate(t1b)) - { - AggregateDeclaration toad = isAggregate(tob); - if (t1ad != toad && t1ad.aliasthis) - { - if (t1b.ty == Tclass && tob.ty == Tclass) - { - ClassDeclaration t1cd = t1b.isClassHandle(); - ClassDeclaration tocd = tob.isClassHandle(); - int offset; - if (tocd.isBaseOf(t1cd, &offset)) - goto Lok; - } - hasAliasThis = true; - } - } - else if (tob.ty == Tvector && t1b.ty != Tvector) - { - //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); - TypeVector tv = tob.isTypeVector(); - result = new CastExp(e.loc, e, tv.elementType()); - result = new VectorExp(e.loc, result, tob); - result = result.expressionSemantic(sc); - return; - } - else if (tob.ty != Tvector && t1b.ty == Tvector) + bool hasAliasThis; + if (AggregateDeclaration t1ad = isAggregate(t1b)) + { + AggregateDeclaration toad = isAggregate(tob); + if (t1ad != toad && t1ad.aliasthis) { - // T[n] <-- __vector(U[m]) - if (tob.ty == Tsarray) + if (t1b.ty == Tclass && tob.ty == Tclass) { - if (t1b.size(e.loc) == tob.size(e.loc)) + ClassDeclaration t1cd = t1b.isClassHandle(); + ClassDeclaration tocd = tob.isClassHandle(); + int offset; + if (tocd.isBaseOf(t1cd, &offset)) goto Lok; } - goto Lfail; + hasAliasThis = true; } - else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf())) + } + else if (tob.ty == Tvector && t1b.ty != Tvector) + { + //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); + TypeVector tv = tob.isTypeVector(); + Expression result = new CastExp(e.loc, e, tv.elementType()); + result = new VectorExp(e.loc, result, tob); + result = result.expressionSemantic(sc); + return result; + } + else if (tob.ty != Tvector && t1b.ty == Tvector) + { + // T[n] <-- __vector(U[m]) + if (tob.ty == Tsarray) { - result = e.copy(); - result.type = t; - return; + if (t1b.size(e.loc) == tob.size(e.loc)) + goto Lok; } + goto Lfail; + } + else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf())) + { + auto result = e.copy(); + result.type = t; + return result; + } - // arithmetic values vs. other arithmetic values - // arithmetic values vs. T* - if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer)) - { - goto Lok; - } + // arithmetic values vs. other arithmetic values + // arithmetic values vs. T* + if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer)) + { + goto Lok; + } + + // arithmetic values vs. references or fat values + if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV)) + { + goto Lfail; + } - // arithmetic values vs. references or fat values - if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV)) + // Bugzlla 3133: A cast between fat values is possible only when the sizes match. + if (tob_isFV && t1b_isFV) + { + if (hasAliasThis) { - goto Lfail; + auto result = tryAliasThisCast(); + if (result) + return result; } - // Bugzlla 3133: A cast between fat values is possible only when the sizes match. - if (tob_isFV && t1b_isFV) - { - if (hasAliasThis) - { - result = tryAliasThisCast(); - if (result) - return; - } + if (t1b.size(e.loc) == tob.size(e.loc)) + goto Lok; - if (t1b.size(e.loc) == tob.size(e.loc)) - goto Lok; + auto ts = toAutoQualChars(e.type, t); + e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes", + e.toChars(), ts[0], ts[1]); + return ErrorExp.get(); + } - auto ts = toAutoQualChars(e.type, t); - e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes", - e.toChars(), ts[0], ts[1]); - result = ErrorExp.get(); - return; + // Fat values vs. null or references + if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR)) + { + if (tob.ty == Tpointer && t1b.ty == Tsarray) + { + // T[n] sa; + // cast(U*)sa; // ==> cast(U*)sa.ptr; + return new AddrExp(e.loc, e, t); } - - // Fat values vs. null or references - if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR)) + if (tob.ty == Tarray && t1b.ty == Tsarray) { - if (tob.ty == Tpointer && t1b.ty == Tsarray) + // T[n] sa; + // cast(U[])sa; // ==> cast(U[])sa[]; + if (global.params.useDIP1000 == FeatureState.enabled) { - // T[n] sa; - // cast(U*)sa; // ==> cast(U*)sa.ptr; - result = new AddrExp(e.loc, e, t); - return; - } - if (tob.ty == Tarray && t1b.ty == Tsarray) - { - // T[n] sa; - // cast(U[])sa; // ==> cast(U[])sa[]; - if (global.params.useDIP1000 == FeatureState.enabled) + if (auto v = expToVariable(e)) { - if (auto v = expToVariable(e)) - { - if (e.type.hasPointers() && !checkAddressVar(sc, e, v)) - goto Lfail; - } + if (e.type.hasPointers() && !checkAddressVar(sc, e, v)) + goto Lfail; } - 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 fsize = t1b.nextOf().size(); + const tsize = tob.nextOf().size(); + if (fsize == SIZE_INVALID || tsize == SIZE_INVALID) + { + return ErrorExp.get(); + } + if (fsize != tsize) + { + const dim = t1b.isTypeSArray().dim.toInteger(); + if (tsize == 0 || (dim * fsize) % tsize != 0) { - const dim = t1b.isTypeSArray().dim.toInteger(); - if (tsize == 0 || (dim * fsize) % tsize != 0) - { - e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", - e.toChars(), e.type.toChars(), t.toChars()); - result = ErrorExp.get(); - return; - } + e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", + e.toChars(), e.type.toChars(), t.toChars()); + return ErrorExp.get(); } - goto Lok; } - goto Lfail; + goto Lok; } + goto Lfail; + } - /* For references, any reinterpret casts are allowed to same 'ty' type. - * T* to U* - * R1 function(P1) to R2 function(P2) - * R1 delegate(P1) to R2 delegate(P2) - * T[] to U[] - * V1[K1] to V2[K2] - * class/interface A to B (will be a dynamic cast if possible) - */ - if (tob.ty == t1b.ty && tob_isR && t1b_isR) - goto Lok; + /* For references, any reinterpret casts are allowed to same 'ty' type. + * T* to U* + * R1 function(P1) to R2 function(P2) + * R1 delegate(P1) to R2 delegate(P2) + * T[] to U[] + * V1[K1] to V2[K2] + * class/interface A to B (will be a dynamic cast if possible) + */ + if (tob.ty == t1b.ty && tob_isR && t1b_isR) + goto Lok; - // typeof(null) <-- non-null references or values - if (tob.ty == Tnull && t1b.ty != Tnull) - goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629 - // typeof(null) --> non-null references or arithmetic values - if (t1b.ty == Tnull && tob.ty != Tnull) - goto Lok; + // typeof(null) <-- non-null references or values + if (tob.ty == Tnull && t1b.ty != Tnull) + goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629 + // typeof(null) --> non-null references or arithmetic values + if (t1b.ty == Tnull && tob.ty != Tnull) + goto Lok; - // Check size mismatch of references. - // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof. - if (tob_isFR && t1b_isR || t1b_isFR && tob_isR) + // Check size mismatch of references. + // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof. + if (tob_isFR && t1b_isR || t1b_isFR && tob_isR) + { + if (tob.ty == Tpointer && t1b.ty == Tarray) { - if (tob.ty == Tpointer && t1b.ty == Tarray) - { - // T[] da; - // cast(U*)da; // ==> cast(U*)da.ptr; - goto Lok; - } - if (tob.ty == Tpointer && t1b.ty == Tdelegate) - { - // void delegate() dg; - // cast(U*)dg; // ==> cast(U*)dg.ptr; - // Note that it happens even when U is a Tfunction! - e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars()); - goto Lok; - } - goto Lfail; + // T[] da; + // cast(U*)da; // ==> cast(U*)da.ptr; + goto Lok; } - - if (t1b.ty == Tvoid && tob.ty != Tvoid) + if (tob.ty == Tpointer && t1b.ty == Tdelegate) { - Lfail: - /* if the cast cannot be performed, maybe there is an alias - * this that can be used for casting. - */ - if (hasAliasThis) - { - result = tryAliasThisCast(); - if (result) - return; - } - e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars()); - result = ErrorExp.get(); - return; + // void delegate() dg; + // cast(U*)dg; // ==> cast(U*)dg.ptr; + // Note that it happens even when U is a Tfunction! + e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars()); + goto Lok; } - - Lok: - result = new CastExp(e.loc, e, t); - result.type = t; // Don't call semantic() - //printf("Returning: %s\n", result.toChars()); + goto Lfail; } - override void visit(ErrorExp e) + if (t1b.ty == Tvoid && tob.ty != Tvoid) { - result = e; + Lfail: + /* if the cast cannot be performed, maybe there is an alias + * this that can be used for casting. + */ + if (hasAliasThis) + { + auto result = tryAliasThisCast(); + if (result) + return result; + } + e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars()); + return ErrorExp.get(); } - override void visit(RealExp e) + Lok: + auto result = new CastExp(e.loc, e, t); + result.type = t; // Don't call semantic() + //printf("Returning: %s\n", result.toChars()); + return result; + } + + Expression visitError(ErrorExp e) + { + return e; + } + + Expression visitReal(RealExp e) + { + if (!e.type.equals(t)) { - if (!e.type.equals(t)) + if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary())) { - if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary())) - { - result = e.copy(); - result.type = t; - } - else - visit(cast(Expression)e); - return; + auto result = e.copy(); + result.type = t; + return result; } - result = e; + else + return visit(e); } + return e; + } - override void visit(ComplexExp e) + Expression visitComplex(ComplexExp e) + { + if (!e.type.equals(t)) { - if (!e.type.equals(t)) + if (e.type.iscomplex() && t.iscomplex()) { - if (e.type.iscomplex() && t.iscomplex()) - { - result = e.copy(); - result.type = t; - } - else - visit(cast(Expression)e); - return; + auto result = e.copy(); + result.type = t; + return result; } - result = e; + else + return visit(e); } + return e; + } + + Expression visitStructLiteral(StructLiteralExp e) + { + auto result = visit(e); + if (auto sle = result.isStructLiteralExp()) + sle.stype = t; // commit type + return result; + } + + Expression visitString(StringExp e) + { + /* This follows copy-on-write; any changes to 'this' + * will result in a copy. + * The this.string member is considered immutable. + */ + int copied = 0; - override void visit(StructLiteralExp e) + //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed); + + if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid && + (!sc || !(sc.flags & SCOPE.Cfile))) { - visit(cast(Expression)e); - if (auto sle = result.isStructLiteralExp()) - sle.stype = t; // commit type + e.error("cannot convert string literal to `void*`"); + return ErrorExp.get(); } - override void visit(StringExp e) + StringExp se = e; + + Expression lcast() { - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this.string member is considered immutable. - */ - int copied = 0; + auto result = new CastExp(e.loc, se, t); + result.type = t; // so semantic() won't be run on e + return result; + } - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed); + if (!e.committed) + { + se = e.copy().isStringExp(); + se.committed = 1; + copied = 1; + } + + if (e.type.equals(t)) + { + return se; + } + + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); + + //printf("\ttype = %s\n", e.type.toChars()); + if (tb.ty == Tdelegate && typeb.ty != Tdelegate) + { + return visit(e); + } - if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid && - (!sc || !(sc.flags & SCOPE.Cfile))) + if (typeb.equals(tb)) + { + if (!copied) { - e.error("cannot convert string literal to `void*`"); - result = ErrorExp.get(); - return; + se = e.copy().isStringExp(); + copied = 1; } + se.type = t; + return se; + } - StringExp se = e; + /* Handle reinterpret casts: + * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000] + * cast(wchar[2])"abcd"c --> [\u6261, \u6463] + * cast(wchar[1])"abcd"c --> [\u6261] + * cast(char[4])"a" --> ['a', 0, 0, 0] + */ + if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) + { + se = e.copy().isStringExp(); + d_uns64 szx = tb.nextOf().size(); + assert(szx <= 255); + se.sz = cast(ubyte)szx; + se.len = cast(size_t)tb.isTypeSArray().dim.toInteger(); + se.committed = 1; + se.type = t; - void lcast() + /* If larger than source, pad with zeros. + */ + const fullSize = (se.len + 1) * se.sz; // incl. terminating 0 + if (fullSize > (e.len + 1) * e.sz) { - result = new CastExp(e.loc, se, t); - result.type = t; // so semantic() won't be run on e + void* s = mem.xmalloc(fullSize); + const srcSize = e.len * e.sz; + const data = se.peekData(); + memcpy(s, data.ptr, srcSize); + memset(s + srcSize, 0, fullSize - srcSize); + se.setData(s, se.len, se.sz); } + return se; + } - if (!e.committed) + if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer) + { + if (!copied) { se = e.copy().isStringExp(); - se.committed = 1; copied = 1; } - - if (e.type.equals(t)) + return lcast(); + } + if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer) + { + if (!copied) { - result = se; - return; + se = e.copy().isStringExp(); + copied = 1; } + return lcast(); + } - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); - - //printf("\ttype = %s\n", e.type.toChars()); - if (tb.ty == Tdelegate && typeb.ty != Tdelegate) + const nextSz = typeb.nextOf().size(); + if (nextSz == SIZE_INVALID) + { + return ErrorExp.get(); + } + if (nextSz == tb.nextOf().size()) + { + if (!copied) { - visit(cast(Expression)e); - return; + se = e.copy().isStringExp(); + copied = 1; } + if (tb.ty == Tsarray) + goto L2; // handle possible change in static array dimension + se.type = t; + return se; + } + + if (e.committed) + goto Lcast; + + auto X(T, U)(T tf, U tt) + { + return (cast(int)tf * 256 + cast(int)tt); + } - if (typeb.equals(tb)) + { + OutBuffer buffer; + size_t newlen = 0; + int tfty = typeb.nextOf().toBasetype().ty; + int ttty = tb.nextOf().toBasetype().ty; + switch (X(tfty, ttty)) { - if (!copied) + case X(Tchar, Tchar): + case X(Twchar, Twchar): + case X(Tdchar, Tdchar): + break; + + case X(Tchar, Twchar): + for (size_t u = 0; u < e.len;) { - se = e.copy().isStringExp(); - copied = 1; + dchar c; + if (const s = utf_decodeChar(se.peekString(), u, c)) + e.error("%.*s", cast(int)s.length, s.ptr); + else + buffer.writeUTF16(c); } - se.type = t; - result = se; - return; - } + newlen = buffer.length / 2; + buffer.writeUTF16(0); + goto L1; - /* Handle reinterpret casts: - * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000] - * cast(wchar[2])"abcd"c --> [\u6261, \u6463] - * cast(wchar[1])"abcd"c --> [\u6261] - * cast(char[4])"a" --> ['a', 0, 0, 0] - */ - if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) - { - se = e.copy().isStringExp(); - d_uns64 szx = tb.nextOf().size(); - assert(szx <= 255); - se.sz = cast(ubyte)szx; - se.len = cast(size_t)tb.isTypeSArray().dim.toInteger(); - se.committed = 1; - se.type = t; - - /* If larger than source, pad with zeros. - */ - const fullSize = (se.len + 1) * se.sz; // incl. terminating 0 - if (fullSize > (e.len + 1) * e.sz) + case X(Tchar, Tdchar): + for (size_t u = 0; u < e.len;) { - void* s = mem.xmalloc(fullSize); - const srcSize = e.len * e.sz; - const data = se.peekData(); - memcpy(s, data.ptr, srcSize); - memset(s + srcSize, 0, fullSize - srcSize); - se.setData(s, se.len, se.sz); + dchar c; + if (const s = utf_decodeChar(se.peekString(), u, c)) + e.error("%.*s", cast(int)s.length, s.ptr); + buffer.write4(c); + newlen++; } - result = se; - return; - } + buffer.write4(0); + goto L1; - if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer) - { - if (!copied) + case X(Twchar, Tchar): + for (size_t u = 0; u < e.len;) { - se = e.copy().isStringExp(); - copied = 1; + dchar c; + if (const s = utf_decodeWchar(se.peekWstring(), u, c)) + e.error("%.*s", cast(int)s.length, s.ptr); + else + buffer.writeUTF8(c); } - return lcast(); - } - if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer) - { - if (!copied) + newlen = buffer.length; + buffer.writeUTF8(0); + goto L1; + + case X(Twchar, Tdchar): + for (size_t u = 0; u < e.len;) { - se = e.copy().isStringExp(); - copied = 1; + dchar c; + if (const s = utf_decodeWchar(se.peekWstring(), u, c)) + e.error("%.*s", cast(int)s.length, s.ptr); + buffer.write4(c); + newlen++; } - return lcast(); - } + buffer.write4(0); + goto L1; - const nextSz = typeb.nextOf().size(); - if (nextSz == SIZE_INVALID) - { - result = ErrorExp.get(); - return; - } - if (nextSz == tb.nextOf().size()) - { - if (!copied) + case X(Tdchar, Tchar): + for (size_t u = 0; u < e.len; u++) { - se = e.copy().isStringExp(); - copied = 1; + uint c = se.peekDstring()[u]; + if (!utf_isValidDchar(c)) + e.error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF8(c); + newlen++; } - if (tb.ty == Tsarray) - goto L2; // handle possible change in static array dimension - se.type = t; - result = se; - return; - } - - if (e.committed) - goto Lcast; - - auto X(T, U)(T tf, U tt) - { - return (cast(int)tf * 256 + cast(int)tt); - } + newlen = buffer.length; + buffer.writeUTF8(0); + goto L1; - { - OutBuffer buffer; - size_t newlen = 0; - int tfty = typeb.nextOf().toBasetype().ty; - int ttty = tb.nextOf().toBasetype().ty; - switch (X(tfty, ttty)) + case X(Tdchar, Twchar): + for (size_t u = 0; u < e.len; u++) { - case X(Tchar, Tchar): - case X(Twchar, Twchar): - case X(Tdchar, Tdchar): - break; - - case X(Tchar, Twchar): - for (size_t u = 0; u < e.len;) - { - dchar c; - if (const s = utf_decodeChar(se.peekString(), u, c)) - e.error("%.*s", cast(int)s.length, s.ptr); - else - buffer.writeUTF16(c); - } - newlen = buffer.length / 2; - buffer.writeUTF16(0); - goto L1; - - case X(Tchar, Tdchar): - for (size_t u = 0; u < e.len;) - { - dchar c; - if (const s = utf_decodeChar(se.peekString(), u, c)) - e.error("%.*s", cast(int)s.length, s.ptr); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Twchar, Tchar): - for (size_t u = 0; u < e.len;) - { - dchar c; - if (const s = utf_decodeWchar(se.peekWstring(), u, c)) - e.error("%.*s", cast(int)s.length, s.ptr); - else - buffer.writeUTF8(c); - } - newlen = buffer.length; - buffer.writeUTF8(0); - goto L1; - - case X(Twchar, Tdchar): - for (size_t u = 0; u < e.len;) - { - dchar c; - if (const s = utf_decodeWchar(se.peekWstring(), u, c)) - e.error("%.*s", cast(int)s.length, s.ptr); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Tdchar, Tchar): - for (size_t u = 0; u < e.len; u++) - { - uint c = se.peekDstring()[u]; - if (!utf_isValidDchar(c)) - e.error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF8(c); - newlen++; - } - newlen = buffer.length; - buffer.writeUTF8(0); - goto L1; - - case X(Tdchar, Twchar): - for (size_t u = 0; u < e.len; u++) - { - uint c = se.peekDstring()[u]; - if (!utf_isValidDchar(c)) - e.error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF16(c); - newlen++; - } - newlen = buffer.length / 2; - buffer.writeUTF16(0); - goto L1; - - L1: - if (!copied) - { - se = e.copy().isStringExp(); - copied = 1; - } - - { - d_uns64 szx = tb.nextOf().size(); - assert(szx <= 255); - se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx); - } - break; - - default: - assert(typeb.nextOf().size() != tb.nextOf().size()); - goto Lcast; + uint c = se.peekDstring()[u]; + if (!utf_isValidDchar(c)) + e.error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF16(c); + newlen++; } - } - L2: - assert(copied); + newlen = buffer.length / 2; + buffer.writeUTF16(0); + goto L1; - // See if need to truncate or extend the literal - if (auto tsa = tb.isTypeSArray()) - { - size_t dim2 = cast(size_t)tsa.dim.toInteger(); - //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2); + L1: + if (!copied) + { + se = e.copy().isStringExp(); + copied = 1; + } - // Changing dimensions - if (dim2 != se.len) { - // Copy when changing the string literal - const newsz = se.sz; - const d = (dim2 < se.len) ? dim2 : se.len; - void* s = mem.xmalloc((dim2 + 1) * newsz); - memcpy(s, se.peekData().ptr, d * newsz); - // Extend with 0, add terminating 0 - memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz); - se.setData(s, dim2, newsz); + d_uns64 szx = tb.nextOf().size(); + assert(szx <= 255); + se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx); } - } - se.type = t; - result = se; - return; + break; - Lcast: - result = new CastExp(e.loc, se, t); - result.type = t; // so semantic() won't be run on e + default: + assert(typeb.nextOf().size() != tb.nextOf().size()); + goto Lcast; + } } + L2: + assert(copied); - override void visit(AddrExp e) + // See if need to truncate or extend the literal + if (auto tsa = tb.isTypeSArray()) { - version (none) + size_t dim2 = cast(size_t)tsa.dim.toInteger(); + //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2); + + // Changing dimensions + if (dim2 != se.len) { - printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + // Copy when changing the string literal + const newsz = se.sz; + const d = (dim2 < se.len) ? dim2 : se.len; + void* s = mem.xmalloc((dim2 + 1) * newsz); + memcpy(s, se.peekData().ptr, d * newsz); + // Extend with 0, add terminating 0 + memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz); + se.setData(s, dim2, newsz); } - result = e; + } + se.type = t; + return se; - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + Lcast: + auto result = new CastExp(e.loc, se, t); + result.type = t; // so semantic() won't be run on e + return result; + } - if (tb.equals(typeb)) - { - result = e.copy(); - result.type = t; - return; - } + Expression visitAddr(AddrExp e) + { + version (none) + { + printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - // Look for pointers to functions where the functions are overloaded. - if (e.e1.isOverExp() && - (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) - { - OverExp eo = e.e1.isOverExp(); - FuncDeclaration f = null; - for (size_t i = 0; i < eo.vars.a.dim; i++) - { - auto s = eo.vars.a[i]; - auto f2 = s.isFuncDeclaration(); - assert(f2); - if (f2.overloadExactMatch(tb.nextOf())) - { - if (f) - { - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol.multiplyDefined(e.loc, f, f2); - } - else - f = f2; - } - } - if (f) - { - f.tookAddressOf++; - auto se = new SymOffExp(e.loc, f, 0, false); - auto se2 = se.expressionSemantic(sc); - // Let SymOffExp::castTo() do the heavy lifting - visit(se2); - return; - } - } + if (tb.equals(typeb)) + { + auto result = e.copy(); + result.type = t; + return result; + } - if (e.e1.isVarExp() && - typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && - tb.ty == Tpointer && tb.nextOf().ty == Tfunction) + // Look for pointers to functions where the functions are overloaded. + if (e.e1.isOverExp() && + (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + { + OverExp eo = e.e1.isOverExp(); + FuncDeclaration f = null; + for (size_t i = 0; i < eo.vars.a.dim; i++) { - auto ve = e.e1.isVarExp(); - auto f = ve.var.isFuncDeclaration(); - if (f) + auto s = eo.vars.a[i]; + auto f2 = s.isFuncDeclaration(); + assert(f2); + if (f2.overloadExactMatch(tb.nextOf())) { - assert(f.isImportedSymbol()); - f = f.overloadExactMatch(tb.nextOf()); if (f) { - result = new VarExp(e.loc, f, false); - result.type = f.type; - result = new AddrExp(e.loc, result, t); - return; + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol.multiplyDefined(e.loc, f, f2); } + else + f = f2; } } + if (f) + { + f.tookAddressOf++; + auto se = new SymOffExp(e.loc, f, 0, false); + auto se2 = se.expressionSemantic(sc); + // Let SymOffExp::castTo() do the heavy lifting + return visit(se2); + } + } - if (auto f = isFuncAddress(e)) + if (e.e1.isVarExp() && + typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && + tb.ty == Tpointer && tb.nextOf().ty == Tfunction) + { + auto ve = e.e1.isVarExp(); + auto f = ve.var.isFuncDeclaration(); + if (f) { - if (f.checkForwardRef(e.loc)) + assert(f.isImportedSymbol()); + f = f.overloadExactMatch(tb.nextOf()); + if (f) { - result = ErrorExp.get(); - return; + Expression result = new VarExp(e.loc, f, false); + result.type = f.type; + result = new AddrExp(e.loc, result, t); + return result; } } - - visit(cast(Expression)e); } - override void visit(TupleExp e) + if (auto f = isFuncAddress(e)) { - if (e.type.equals(t)) + if (f.checkForwardRef(e.loc)) { - result = e; - return; + return ErrorExp.get(); } - - /* If target type is a tuple of same length, cast each expression to - * the corresponding type in the tuple. - */ - TypeTuple totuple; - if (auto tt = t.isTypeTuple()) - totuple = e.exps.length == tt.arguments.length ? tt : null; - - TupleExp te = e.copy().isTupleExp(); - te.e0 = e.e0 ? e.e0.copy() : null; - te.exps = e.exps.copy(); - for (size_t i = 0; i < te.exps.dim; i++) - { - Expression ex = (*te.exps)[i]; - ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t); - (*te.exps)[i] = ex; - } - if (totuple) - te.type = totuple; - result = te; - - /* Questionable behavior: In here, result.type is not set to t - * if target type is not a tuple of same length. - * Therefoe: - * TypeTuple!(int, int) values; - * auto values2 = cast(long)values; - * // typeof(values2) == TypeTuple!(int, int) !! - * - * Only when the casted tuple is immediately expanded, it would work. - * auto arr = [cast(long)values]; - * // typeof(arr) == long[] - */ } - override void visit(ArrayLiteralExp e) + return visit(e); + } + + Expression visitTuple(TupleExp e) + { + if (e.type.equals(t)) { - version (none) - { - printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); - } + return e; + } - ArrayLiteralExp ae = e; + /* If target type is a tuple of same length, cast each expression to + * the corresponding type in the tuple. + */ + TypeTuple totuple; + if (auto tt = t.isTypeTuple()) + totuple = e.exps.length == tt.arguments.length ? tt : null; + + TupleExp te = e.copy().isTupleExp(); + te.e0 = e.e0 ? e.e0.copy() : null; + te.exps = e.exps.copy(); + for (size_t i = 0; i < te.exps.dim; i++) + { + Expression ex = (*te.exps)[i]; + ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t); + (*te.exps)[i] = ex; + } + if (totuple) + te.type = totuple; + return te; + + /* Questionable behavior: In here, result.type is not set to t + * if target type is not a tuple of same length. + * Therefoe: + * TypeTuple!(int, int) values; + * auto values2 = cast(long)values; + * // typeof(values2) == TypeTuple!(int, int) !! + * + * Only when the casted tuple is immediately expanded, it would work. + * auto arr = [cast(long)values]; + * // typeof(arr) == long[] + */ + } - Type tb = t.toBasetype(); - if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled) - { - if (checkArrayLiteralEscape(sc, ae, false)) - { - result = ErrorExp.get(); - return; - } - } + Expression visitArrayLiteral(ArrayLiteralExp e) + { + version (none) + { + printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + + ArrayLiteralExp ae = e; - if (e.type == t) + Type tb = t.toBasetype(); + if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled) + { + if (checkArrayLiteralEscape(sc, ae, false)) { - result = e; - return; + return ErrorExp.get(); } - Type typeb = e.type.toBasetype(); + } - if ((tb.ty == Tarray || tb.ty == Tsarray) && - (typeb.ty == Tarray || typeb.ty == Tsarray)) - { - if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid) - { - // Don't do anything to cast non-void[] to void[] - } - else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid) - { - // Don't do anything for casting void[n] to others - } - else - { - if (auto tsa = tb.isTypeSArray()) - { - if (e.elements.dim != tsa.dim.toInteger()) - goto L1; - } + if (e.type == t) + { + return e; + } + Type typeb = e.type.toBasetype(); - ae = e.copy().isArrayLiteralExp(); - if (e.basis) - ae.basis = e.basis.castTo(sc, tb.nextOf()); - ae.elements = e.elements.copy(); - for (size_t i = 0; i < e.elements.dim; i++) - { - Expression ex = (*e.elements)[i]; - if (!ex) - continue; - ex = ex.castTo(sc, tb.nextOf()); - (*ae.elements)[i] = ex; - } - ae.type = t; - result = ae; - return; - } + if ((tb.ty == Tarray || tb.ty == Tsarray) && + (typeb.ty == Tarray || typeb.ty == Tsarray)) + { + if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid) + { + // Don't do anything to cast non-void[] to void[] } - else if (tb.ty == Tpointer && typeb.ty == Tsarray) + else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid) { - Type tp = typeb.nextOf().pointerTo(); - if (!tp.equals(ae.type)) - { - ae = e.copy().isArrayLiteralExp(); - ae.type = tp; - } + // Don't do anything for casting void[n] to others } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) + else { - // Convert array literal to vector type - TypeVector tv = tb.isTypeVector(); - TypeSArray tbase = tv.basetype.isTypeSArray(); - assert(tbase.ty == Tsarray); - const edim = e.elements.dim; - const tbasedim = tbase.dim.toInteger(); - if (edim > tbasedim) - goto L1; + if (auto tsa = tb.isTypeSArray()) + { + if (e.elements.dim != tsa.dim.toInteger()) + goto L1; + } ae = e.copy().isArrayLiteralExp(); - ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642 + if (e.basis) + ae.basis = e.basis.castTo(sc, tb.nextOf()); ae.elements = e.elements.copy(); - Type telement = tv.elementType(); - foreach (i; 0 .. edim) + for (size_t i = 0; i < e.elements.dim; i++) { Expression ex = (*e.elements)[i]; - ex = ex.castTo(sc, telement); - (*ae.elements)[i] = ex; - } - // Fill in the rest with the default initializer - ae.elements.setDim(cast(size_t)tbasedim); - foreach (i; edim .. cast(size_t)tbasedim) - { - Expression ex = typeb.nextOf.defaultInitLiteral(e.loc); - ex = ex.castTo(sc, telement); + if (!ex) + continue; + ex = ex.castTo(sc, tb.nextOf()); (*ae.elements)[i] = ex; } - Expression ev = new VectorExp(e.loc, ae, tb); - ev = ev.expressionSemantic(sc); - result = ev; - return; + ae.type = t; + return ae; } - L1: - visit(cast(Expression)ae); } - - override void visit(AssocArrayLiteralExp e) + else if (tb.ty == Tpointer && typeb.ty == Tsarray) { - //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); - if (e.type == t) - { - result = e; - return; - } - - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); - - if (tb.ty == Taarray && typeb.ty == Taarray && - tb.nextOf().toBasetype().ty != Tvoid) + Type tp = typeb.nextOf().pointerTo(); + if (!tp.equals(ae.type)) { - AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp(); - ae.keys = e.keys.copy(); - ae.values = e.values.copy(); - assert(e.keys.dim == e.values.dim); - for (size_t i = 0; i < e.keys.dim; i++) - { - Expression ex = (*e.values)[i]; - ex = ex.castTo(sc, tb.nextOf()); - (*ae.values)[i] = ex; - - ex = (*e.keys)[i]; - ex = ex.castTo(sc, tb.isTypeAArray().index); - (*ae.keys)[i] = ex; - } - ae.type = t; - result = ae; - return; + ae = e.copy().isArrayLiteralExp(); + ae.type = tp; } - visit(cast(Expression)e); } - - override void visit(SymOffExp e) + else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) { - version (none) + // Convert array literal to vector type + TypeVector tv = tb.isTypeVector(); + TypeSArray tbase = tv.basetype.isTypeSArray(); + assert(tbase.ty == Tsarray); + const edim = e.elements.dim; + const tbasedim = tbase.dim.toInteger(); + if (edim > tbasedim) + goto L1; + + ae = e.copy().isArrayLiteralExp(); + ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642 + ae.elements = e.elements.copy(); + Type telement = tv.elementType(); + foreach (i; 0 .. edim) { - printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + Expression ex = (*e.elements)[i]; + ex = ex.castTo(sc, telement); + (*ae.elements)[i] = ex; } - if (e.type == t && !e.hasOverloads) + // Fill in the rest with the default initializer + ae.elements.setDim(cast(size_t)tbasedim); + foreach (i; edim .. cast(size_t)tbasedim) { - result = e; - return; + Expression ex = typeb.nextOf.defaultInitLiteral(e.loc); + ex = ex.castTo(sc, telement); + (*ae.elements)[i] = ex; } + Expression ev = new VectorExp(e.loc, ae, tb); + ev = ev.expressionSemantic(sc); + return ev; + } + L1: + return visit(ae); + } + + Expression visitAssocArrayLiteral(AssocArrayLiteralExp e) + { + //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); + if (e.type == t) + { + return e; + } - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - if (tb.equals(typeb)) + if (tb.ty == Taarray && typeb.ty == Taarray && + tb.nextOf().toBasetype().ty != Tvoid) + { + AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp(); + ae.keys = e.keys.copy(); + ae.values = e.values.copy(); + assert(e.keys.dim == e.values.dim); + for (size_t i = 0; i < e.keys.dim; i++) { - result = e.copy(); - result.type = t; - result.isSymOffExp().hasOverloads = false; - return; + Expression ex = (*e.values)[i]; + ex = ex.castTo(sc, tb.nextOf()); + (*ae.values)[i] = ex; + + ex = (*e.keys)[i]; + ex = ex.castTo(sc, tb.isTypeAArray().index); + (*ae.keys)[i] = ex; } + ae.type = t; + return ae; + } + return visit(e); + } + + Expression visitSymOff(SymOffExp e) + { + version (none) + { + printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + if (e.type == t && !e.hasOverloads) + { + return e; + } + + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); + + if (tb.equals(typeb)) + { + auto result = e.copy(); + result.type = t; + result.isSymOffExp().hasOverloads = false; + return result; + } - // Look for pointers to functions where the functions are overloaded. - if (e.hasOverloads && - typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && - (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + // Look for pointers to functions where the functions are overloaded. + if (e.hasOverloads && + typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && + (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + { + FuncDeclaration f = e.var.isFuncDeclaration(); + f = f ? f.overloadExactMatch(tb.nextOf()) : null; + if (f) { - FuncDeclaration f = e.var.isFuncDeclaration(); - f = f ? f.overloadExactMatch(tb.nextOf()) : null; - if (f) + Expression result; + if (tb.ty == Tdelegate) { - if (tb.ty == Tdelegate) + if (f.needThis() && hasThis(sc)) { - if (f.needThis() && hasThis(sc)) - { - result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false); - result = result.expressionSemantic(sc); - } - else if (f.needThis()) - { - e.error("no `this` to create delegate for `%s`", f.toChars()); - result = ErrorExp.get(); - return; - } - else if (f.isNested()) - { - result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false); - result = result.expressionSemantic(sc); - } - else - { - e.error("cannot cast from function pointer to delegate"); - result = ErrorExp.get(); - return; - } + result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false); + result = result.expressionSemantic(sc); + } + else if (f.needThis()) + { + e.error("no `this` to create delegate for `%s`", f.toChars()); + return ErrorExp.get(); + } + else if (f.isNested()) + { + result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false); + result = result.expressionSemantic(sc); } else { - result = new SymOffExp(e.loc, f, 0, false); - result.type = t; + e.error("cannot cast from function pointer to delegate"); + return ErrorExp.get(); } - f.tookAddressOf++; - return; } - } - - if (auto f = isFuncAddress(e)) - { - if (f.checkForwardRef(e.loc)) + else { - result = ErrorExp.get(); - return; + result = new SymOffExp(e.loc, f, 0, false); + result.type = t; } + f.tookAddressOf++; + return result; } - - visit(cast(Expression)e); } - override void visit(DelegateExp e) + if (auto f = isFuncAddress(e)) { - version (none) + if (f.checkForwardRef(e.loc)) { - printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + return ErrorExp.get(); } - __gshared const(char)* msg = "cannot form delegate due to covariant return type"; + } - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + return visit(e); + } - if (tb.equals(typeb) && !e.hasOverloads) - { - int offset; - e.func.tookAddressOf++; - if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) - e.error("%s", msg); - result = e.copy(); - result.type = t; - return; - } + Expression visitDelegate(DelegateExp e) + { + version (none) + { + printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); + } + __gshared const(char)* msg = "cannot form delegate due to covariant return type"; - // Look for delegates to functions where the functions are overloaded. - if (typeb.ty == Tdelegate && tb.ty == Tdelegate) - { - if (e.func) - { - auto f = e.func.overloadExactMatch(tb.nextOf()); - if (f) - { - int offset; - if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) - e.error("%s", msg); - if (f != e.func) // if address not already marked as taken - f.tookAddressOf++; - result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2); - result.type = t; - return; - } - if (e.func.tintro) - e.error("%s", msg); - } - } + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); + + if (tb.equals(typeb) && !e.hasOverloads) + { + int offset; + e.func.tookAddressOf++; + if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) + e.error("%s", msg); + auto result = e.copy(); + result.type = t; + return result; + } - if (auto f = isFuncAddress(e)) + // Look for delegates to functions where the functions are overloaded. + if (typeb.ty == Tdelegate && tb.ty == Tdelegate) + { + if (e.func) { - if (f.checkForwardRef(e.loc)) + auto f = e.func.overloadExactMatch(tb.nextOf()); + if (f) { - result = ErrorExp.get(); - return; + int offset; + if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) + e.error("%s", msg); + if (f != e.func) // if address not already marked as taken + f.tookAddressOf++; + auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2); + result.type = t; + return result; } + if (e.func.tintro) + e.error("%s", msg); } - - visit(cast(Expression)e); } - override void visit(FuncExp e) + if (auto f = isFuncAddress(e)) { - //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars()); - FuncExp fe; - if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch) + if (f.checkForwardRef(e.loc)) { - result = fe; - return; + return ErrorExp.get(); } - visit(cast(Expression)e); } - override void visit(CondExp e) + return visit(e); + } + + Expression visitFunc(FuncExp e) + { + //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars()); + FuncExp fe; + if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch) { - if (!e.type.equals(t)) - { - result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t)); - result.type = t; - return; - } - result = e; + return fe; } + return visit(e); + } - override void visit(CommaExp e) + Expression visitCond(CondExp e) + { + if (!e.type.equals(t)) { - Expression e2c = e.e2.castTo(sc, t); - - if (e2c != e.e2) - { - result = new CommaExp(e.loc, e.e1, e2c); - result.type = e2c.type; - } - else - { - result = e; - result.type = e.e2.type; - } + auto result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t)); + result.type = t; + return result; } + return e; + } - override void visit(SliceExp e) + Expression visitComma(CommaExp e) + { + Expression e2c = e.e2.castTo(sc, t); + + if (e2c != e.e2) + { + auto result = new CommaExp(e.loc, e.e1, e2c); + result.type = e2c.type; + return result; + } + else { - //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars()); + e.type = e.e2.type; + return e; + } + } + + Expression visitSlice(SliceExp e) + { + //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars()); + + Type tb = t.toBasetype(); + Type typeb = e.type.toBasetype(); - Type tb = t.toBasetype(); - Type typeb = e.type.toBasetype(); + if (e.type.equals(t) || typeb.ty != Tarray || + (tb.ty != Tarray && tb.ty != Tsarray)) + { + return visit(e); + } - if (e.type.equals(t) || typeb.ty != Tarray || - (tb.ty != Tarray && tb.ty != Tsarray)) + if (tb.ty == Tarray) + { + if (typeb.nextOf().equivalent(tb.nextOf())) { - visit(cast(Expression)e); - return; + // T[] to const(T)[] + auto result = e.copy(); + result.type = t; + return result; } - - if (tb.ty == Tarray) + else { - if (typeb.nextOf().equivalent(tb.nextOf())) - { - // T[] to const(T)[] - result = e.copy(); - result.type = t; - } - else - { - visit(cast(Expression)e); - } - return; + return visit(e); } + } - // Handle the cast from Tarray to Tsarray with CT-known slicing + // Handle the cast from Tarray to Tsarray with CT-known slicing - TypeSArray tsa = toStaticArrayType(e).isTypeSArray(); - if (tsa && tsa.size(e.loc) == tb.size(e.loc)) - { - /* Match if the sarray sizes are equal: - * T[a .. b] to const(T)[b-a] - * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim) - * - * If a SliceExp has Tsarray, it will become lvalue. - * That's handled in SliceExp::isLvalue and toLvalue - */ - result = e.copy(); - result.type = t; - return; - } - if (tsa && tsa.dim.equals(tb.isTypeSArray().dim)) + TypeSArray tsa = toStaticArrayType(e).isTypeSArray(); + if (tsa && tsa.size(e.loc) == tb.size(e.loc)) + { + /* Match if the sarray sizes are equal: + * T[a .. b] to const(T)[b-a] + * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim) + * + * If a SliceExp has Tsarray, it will become lvalue. + * That's handled in SliceExp::isLvalue and toLvalue + */ + auto result = e.copy(); + result.type = t; + return result; + } + if (tsa && tsa.dim.equals(tb.isTypeSArray().dim)) + { + /* Match if the dimensions are equal + * with the implicit conversion of e.e1: + * cast(float[2]) [2.0, 1.0, 0.0][0..2]; + */ + Type t1b = e.e1.type.toBasetype(); + if (t1b.ty == Tsarray) + t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger()); + else if (t1b.ty == Tarray) + t1b = tb.nextOf().arrayOf(); + else if (t1b.ty == Tpointer) + t1b = tb.nextOf().pointerTo(); + else + assert(0); + if (e.e1.implicitConvTo(t1b) > MATCH.nomatch) { - /* Match if the dimensions are equal - * with the implicit conversion of e.e1: - * cast(float[2]) [2.0, 1.0, 0.0][0..2]; - */ - Type t1b = e.e1.type.toBasetype(); - if (t1b.ty == Tsarray) - t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger()); - else if (t1b.ty == Tarray) - t1b = tb.nextOf().arrayOf(); - else if (t1b.ty == Tpointer) - t1b = tb.nextOf().pointerTo(); - else - assert(0); - if (e.e1.implicitConvTo(t1b) > MATCH.nomatch) - { - Expression e1x = e.e1.implicitCastTo(sc, t1b); - assert(e1x.op != EXP.error); - e = e.copy().isSliceExp(); - e.e1 = e1x; - e.type = t; - result = e; - return; - } + Expression e1x = e.e1.implicitCastTo(sc, t1b); + assert(e1x.op != EXP.error); + e = e.copy().isSliceExp(); + e.e1 = e1x; + e.type = t; + return e; } - auto ts = toAutoQualChars(tsa ? tsa : e.type, t); - e.error("cannot cast expression `%s` of type `%s` to `%s`", - e.toChars(), ts[0], ts[1]); - result = ErrorExp.get(); } + auto ts = toAutoQualChars(tsa ? tsa : e.type, t); + e.error("cannot cast expression `%s` of type `%s` to `%s`", + e.toChars(), ts[0], ts[1]); + return ErrorExp.get(); } // Casting to noreturn isn't an actual cast @@ -2673,9 +2623,25 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) return Expression.combine(e, ini); } - scope CastTo v = new CastTo(sc, t); - e.accept(v); - return v.result; + switch (e.op) + { + default : return visit(e); + case EXP.error : return visitError(e.isErrorExp()); + case EXP.float64 : return visitReal(e.isRealExp()); + case EXP.complex80 : return visitComplex(e.isComplexExp()); + case EXP.structLiteral : return visitStructLiteral(e.isStructLiteralExp()); + case EXP.string_ : return visitString(e.isStringExp()); + case EXP.address : return visitAddr(e.isAddrExp()); + case EXP.tuple : return visitTuple(e.isTupleExp()); + case EXP.arrayLiteral : return visitArrayLiteral(e.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); + case EXP.symbolOffset : return visitSymOff(e.isSymOffExp()); + case EXP.delegate_ : return visitDelegate(e.isDelegateExp()); + case EXP.function_ : return visitFunc(e.isFuncExp()); + case EXP.question : return visitCond(e.isCondExp()); + case EXP.comma : return visitComma(e.isCommaExp()); + case EXP.slice : return visitSlice(e.isSliceExp()); + } } /**************************************** @@ -3731,172 +3697,187 @@ extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2) * This is used to determine if implicit narrowing conversions will * be allowed. */ +@trusted IntRange getIntRange(Expression e) { - extern (C++) final class IntRangeVisitor : Visitor + IntRange visit(Expression e) { - alias visit = Visitor.visit; - - public: - IntRange range; + return IntRange.fromType(e.type); + } - override void visit(Expression e) - { - range = IntRange.fromType(e.type); - } + IntRange visitInteger(IntegerExp e) + { + return IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type); + } - override void visit(IntegerExp e) - { - range = IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type); - } + IntRange visitCast(CastExp e) + { + return getIntRange(e.e1)._cast(e.type); + } - override void visit(CastExp e) - { - range = getIntRange(e.e1)._cast(e.type); - } + IntRange visitAdd(AddExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); + return (ir1 + ir2)._cast(e.type); + } - override void visit(AddExp e) - { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); - range = (ir1 + ir2)._cast(e.type); - } + IntRange visitMin(MinExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); + return (ir1 - ir2)._cast(e.type); + } - override void visit(MinExp e) - { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); - range = (ir1 - ir2)._cast(e.type); - } + IntRange visitDiv(DivExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); - override void visit(DivExp e) - { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); + return (ir1 / ir2)._cast(e.type); + } - range = (ir1 / ir2)._cast(e.type); - } + IntRange visitMul(MulExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); - override void visit(MulExp e) - { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); + return (ir1 * ir2)._cast(e.type); + } - range = (ir1 * ir2)._cast(e.type); - } + IntRange visitMod(ModExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); - override void visit(ModExp e) + // Modding on 0 is invalid anyway. + if (!ir2.absNeg().imin.negative) { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); - - // Modding on 0 is invalid anyway. - if (!ir2.absNeg().imin.negative) - { - visit(cast(Expression)e); - return; - } - range = (ir1 % ir2)._cast(e.type); + return visit(e); } + return (ir1 % ir2)._cast(e.type); + } - override void visit(AndExp e) - { - IntRange result; - bool hasResult = false; - result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult); + IntRange visitAnd(AndExp e) + { + IntRange result; + bool hasResult = false; + result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult); - assert(hasResult); - range = result._cast(e.type); - } + assert(hasResult); + return result._cast(e.type); + } - override void visit(OrExp e) - { - IntRange result; - bool hasResult = false; - result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult); + IntRange visitOr(OrExp e) + { + IntRange result; + bool hasResult = false; + result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult); - assert(hasResult); - range = result._cast(e.type); - } + assert(hasResult); + return result._cast(e.type); + } - override void visit(XorExp e) - { - IntRange result; - bool hasResult = false; - result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult); + IntRange visitXor(XorExp e) + { + IntRange result; + bool hasResult = false; + result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult); - assert(hasResult); - range = result._cast(e.type); - } + assert(hasResult); + return result._cast(e.type); + } - override void visit(ShlExp e) - { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); + IntRange visitShl(ShlExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); - range = (ir1 << ir2)._cast(e.type); - } + return (ir1 << ir2)._cast(e.type); + } - override void visit(ShrExp e) - { - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); + IntRange visitShr(ShrExp e) + { + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); - range = (ir1 >> ir2)._cast(e.type); - } + return (ir1 >> ir2)._cast(e.type); + } - override void visit(UshrExp e) - { - IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type); - IntRange ir2 = getIntRange(e.e2); + IntRange visitUshr(UshrExp e) + { + IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type); + IntRange ir2 = getIntRange(e.e2); - range = (ir1 >>> ir2)._cast(e.type); - } + return (ir1 >>> ir2)._cast(e.type); + } - override void visit(AssignExp e) - { - range = getIntRange(e.e2)._cast(e.type); - } + IntRange visitAssign(AssignExp e) + { + return getIntRange(e.e2)._cast(e.type); + } - override void visit(CondExp e) - { - // No need to check e.econd; assume caller has called optimize() - IntRange ir1 = getIntRange(e.e1); - IntRange ir2 = getIntRange(e.e2); - range = ir1.unionWith(ir2)._cast(e.type); - } + IntRange visitCond(CondExp e) + { + // No need to check e.econd; assume caller has called optimize() + IntRange ir1 = getIntRange(e.e1); + IntRange ir2 = getIntRange(e.e2); + return ir1.unionWith(ir2)._cast(e.type); + } - override void visit(VarExp e) - { - Expression ie; - VarDeclaration vd = e.var.isVarDeclaration(); - if (vd && vd.range) - range = vd.range._cast(e.type); - else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null) - ie.accept(this); - else - visit(cast(Expression)e); - } + IntRange visitVar(VarExp e) + { + Expression ie; + VarDeclaration vd = e.var.isVarDeclaration(); + if (vd && vd.range) + return vd.range._cast(e.type); + else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null) + return getIntRange(ie); + else + return visit(e); + } - override void visit(CommaExp e) - { - e.e2.accept(this); - } + IntRange visitComma(CommaExp e) + { + return getIntRange(e.e2); + } - override void visit(ComExp e) - { - IntRange ir = getIntRange(e.e1); - range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type); - } + IntRange visitCom(ComExp e) + { + IntRange ir = getIntRange(e.e1); + return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type); + } - override void visit(NegExp e) - { - IntRange ir = getIntRange(e.e1); - range = (-ir)._cast(e.type); - } + IntRange visitNeg(NegExp e) + { + IntRange ir = getIntRange(e.e1); + return (-ir)._cast(e.type); } - scope IntRangeVisitor v = new IntRangeVisitor(); - e.accept(v); - return v.range; + switch (e.op) + { + default : return visit(e); + case EXP.int64 : return visitInteger(e.isIntegerExp()); + case EXP.cast_ : return visitCast(e.isCastExp()); + case EXP.add : return visitAdd(e.isAddExp()); + case EXP.min : return visitMin(e.isMinExp()); + case EXP.div : return visitDiv(e.isDivExp()); + case EXP.mul : return visitMul(e.isMulExp()); + case EXP.mod : return visitMod(e.isModExp()); + case EXP.and : return visitAnd(e.isAndExp()); + case EXP.or : return visitOr(e.isOrExp()); + case EXP.xor : return visitXor(e.isXorExp()); + case EXP.leftShift : return visitShl(e.isShlExp()); + case EXP.rightShift : return visitShr(e.isShrExp()); + case EXP.unsignedRightShift : return visitUshr(e.isUshrExp()); + case EXP.blit : return visitAssign(e.isBlitExp()); + case EXP.construct : return visitAssign(e.isConstructExp()); + case EXP.assign : return visitAssign(e.isAssignExp()); + case EXP.question : return visitCond(e.isCondExp()); + case EXP.variable : return visitVar(e.isVarExp()); + case EXP.comma : return visitComma(e.isCommaExp()); + case EXP.tilde : return visitCom(e.isComExp()); + case EXP.negate : return visitNeg(e.isNegExp()); + } } + diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 494b60f..cdf9355 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1064,9 +1064,8 @@ extern (C++) class VarDeclaration : Declaration // Both these mean the var is not rebindable once assigned, // and the destructor gets run when it goes out of scope bool onstack; // it is a class that was allocated on the stack - bool mynew; // it is a class new'd with custom operator new - byte canassign; // it can be assigned to + byte canassign; // it can be assigned to bool overlapped; // if it is a field and has overlapping bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe bool doNotInferScope; // do not infer 'scope' for this variable @@ -1452,7 +1451,7 @@ extern (C++) class VarDeclaration : Declaration //if (cd.isInterfaceDeclaration()) // error("interface `%s` cannot be scope", cd.toChars()); - if (mynew || onstack) // if any destructors + if (onstack) // if any destructors { // delete'ing C++ classes crashes (and delete is deprecated anyway) if (cd.classKind == ClassKind.cpp) diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 353d36c..e30acb4 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -248,7 +248,6 @@ public: 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 bool overlapped; // if it is a field and has overlapping bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index b55b981..6c3454d 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -3820,6 +3820,21 @@ public: payload = &(*sle.elements)[fieldi]; oldval = *payload; + if (auto ival = newval.isIntegerExp()) + { + if (auto bf = v.isBitFieldDeclaration()) + { + sinteger_t value = ival.toInteger(); + if (bf.type.isunsigned()) + value &= (1L << bf.fieldWidth) - 1; // zero extra bits + else + { // sign extend extra bits + value = value << (64 - bf.fieldWidth); + value = value >> (64 - bf.fieldWidth); + } + ival.setInteger(value); + } + } } else if (auto ie = e1.isIndexExp()) { @@ -4851,47 +4866,6 @@ public: result = interpret(ce, istate); return; } - else if (fd.ident == Id._d_delstruct) - { - // Only interpret the dtor and the argument. - assert(e.arguments.dim == 1); - - Type tb = (*e.arguments)[0].type.toBasetype(); - auto ts = tb.nextOf().baseElemOf().isTypeStruct(); - if (ts) - { - result = interpretRegion((*e.arguments)[0], istate); - if (exceptionOrCant(result)) - return; - - if (result.op == EXP.null_) - { - result = CTFEExp.voidexp; - return; - } - - 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; - return; - } - - auto sd = ts.sym; - if (sd.dtor) - { - auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1; - result = interpretFunction(pue, sd.dtor, istate, null, sle); - if (exceptionOrCant(result)) - return; - - result = CTFEExp.voidexp; - } - } - - return; - } } else if (auto soe = ecall.isSymOffExp()) { @@ -5835,56 +5809,6 @@ public: break; - case Tpointer: - tb = (cast(TypePointer)tb).next.toBasetype(); - if (tb.ty == Tstruct) - { - 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; - return; - } - - auto sd = (cast(TypeStruct)tb).sym; - auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1; - - if (sd.dtor) - { - result = interpretFunction(pue, sd.dtor, istate, null, sle); - if (exceptionOrCant(result)) - return; - } - } - break; - - case Tarray: - auto tv = tb.nextOf().baseElemOf(); - if (tv.ty == Tstruct) - { - if (result.op != EXP.arrayLiteral) - { - e.error("`delete` on invalid struct array `%s`", result.toChars()); - result = CTFEExp.cantexp; - return; - } - - auto sd = (cast(TypeStruct)tv).sym; - - if (sd.dtor) - { - auto ale = cast(ArrayLiteralExp)result; - foreach (el; *ale.elements) - { - result = interpretFunction(pue, sd.dtor, istate, null, el); - if (exceptionOrCant(result)) - return; - } - } - } - break; - default: assert(0); } diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 78d17b2..ad305f9 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -726,7 +726,8 @@ public: extern (D) static const(char)[] externallyMangledIdentifier(Declaration d) { const par = d.toParent(); //toParent() skips over mixin templates - if (!par || par.isModule() || d.linkage == LINK.cpp) + if (!par || par.isModule() || d.linkage == LINK.cpp || + (d.linkage == LINK.c && d.isCsymbol() && d.isFuncDeclaration())) { if (d.linkage != LINK.d && d.localNum) d.error("the same declaration cannot be in multiple scopes with non-D linkage"); diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 46e89d0..84e29fe 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -524,17 +524,8 @@ extern (C++) final class Module : Package buf.printf("%s\t(%s)", ident.toChars(), m.srcfile.toChars()); message("import %s", buf.peekChars()); } - m = m.parse(); + if((m = m.parse()) is null) return null; - // Call onImport here because if the module is going to be compiled then we - // need to determine it early because it affects semantic analysis. This is - // being done after parsing the module so the full module name can be taken - // from whatever was declared in the file. - if (!m.isRoot() && Compiler.onImport(m)) - { - m.importedFrom = m; - assert(m.isRoot()); - } return m; } @@ -727,7 +718,7 @@ extern (C++) final class Module : Package if (buf.length & 3) { error("odd length of UTF-32 char source %llu", cast(ulong) buf.length); - fatal(); + return null; } const (uint)[] eBuf = cast(const(uint)[])buf; @@ -743,7 +734,7 @@ extern (C++) final class Module : Package if (u > 0x10FFFF) { error("UTF-32 value %08x greater than 0x10FFFF", u); - fatal(); + return null; } dbuf.writeUTF8(u); } @@ -773,7 +764,7 @@ extern (C++) final class Module : Package if (buf.length & 1) { error("odd length of UTF-16 char source %llu", cast(ulong) buf.length); - fatal(); + return null; } const (ushort)[] eBuf = cast(const(ushort)[])buf; @@ -793,13 +784,13 @@ extern (C++) final class Module : Package if (i >= eBuf.length) { error("surrogate UTF-16 high value %04x at end of file", u); - fatal(); + return null; } const u2 = readNext(&eBuf[i]); if (u2 < 0xDC00 || 0xE000 <= u2) { error("surrogate UTF-16 low value %04x out of range", u2); - fatal(); + return null; } u = (u - 0xD7C0) << 10; u |= (u2 - 0xDC00); @@ -807,12 +798,12 @@ extern (C++) final class Module : Package else if (u >= 0xDC00 && u <= 0xDFFF) { error("unpaired surrogate UTF-16 value %04x", u); - fatal(); + return null; } else if (u == 0xFFFE || u == 0xFFFF) { error("illegal UTF-16 value %04x", u); - fatal(); + return null; } dbuf.writeUTF8(u); } @@ -899,7 +890,7 @@ extern (C++) final class Module : Package if (buf[0] >= 0x80) { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); - fatal(); + return null; } } } @@ -929,6 +920,8 @@ extern (C++) final class Module : Package ? UTF32ToUTF8!(Endian.little)(buf) : UTF32ToUTF8!(Endian.big)(buf); } + // an error happened on UTF conversion + if (buf is null) return null; } /* If it starts with the string "Ddoc", then it's a documentation @@ -962,6 +955,16 @@ extern (C++) final class Module : Package isHdrFile = true; } + /// Promote `this` to a root module if requested via `-i` + void checkCompiledImport() + { + if (!this.isRoot() && Compiler.onImport(this)) + this.importedFrom = this; + } + + DsymbolTable dst; + Package ppack = null; + /* If it has the extension ".c", it is a "C" file. * If it has the extension ".i", it is a preprocessed "C" file. */ @@ -971,33 +974,41 @@ extern (C++) final class Module : Package scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c); p.nextToken(); + checkCompiledImport(); members = p.parseModule(); - md = p.md; + assert(!p.md); // C doesn't have module declarations numlines = p.scanloc.linnum; } else { scope p = new Parser!AST(this, buf, cast(bool) docfile); p.nextToken(); - members = p.parseModule(); + p.parseModuleDeclaration(); md = p.md; + + if (md) + { + /* A ModuleDeclaration, md, was provided. + * The ModuleDeclaration sets the packages this module appears in, and + * the name of this module. + */ + this.ident = md.id; + dst = Package.resolve(md.packages, &this.parent, &ppack); + } + + // Done after parsing the module header because `module x.y.z` may override the file name + checkCompiledImport(); + + members = p.parseModuleContent(); numlines = p.scanloc.linnum; } srcBuffer.destroy(); srcBuffer = null; /* The symbol table into which the module is to be inserted. */ - DsymbolTable dst; + if (md) { - /* A ModuleDeclaration, md, was provided. - * The ModuleDeclaration sets the packages this module appears in, and - * the name of this module. - */ - this.ident = md.id; - Package ppack = null; - dst = Package.resolve(md.packages, &this.parent, &ppack); - // Mark the package path as accessible from the current module // https://issues.dlang.org/show_bug.cgi?id=21661 // Code taken from Import.addPackageAccess() @@ -1201,10 +1212,13 @@ extern (C++) final class Module : Package if (StringExp se = msg ? msg.toStringExp() : null) { const slice = se.peekString(); - deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr); + if (slice.length) + { + deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr); + return; + } } - else - deprecation(loc, "is deprecated"); + deprecation(loc, "is deprecated"); } } diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 2a3777b..936d19a 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -692,7 +692,7 @@ struct Scope } /******************************************** - * Search enclosing scopes for ClassDeclaration. + * Search enclosing scopes for ClassDeclaration or StructDeclaration. */ extern (C++) AggregateDeclaration getStructClassScope() { diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 7823351..200cb76 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -51,6 +51,7 @@ import dmd.root.rootobject; import dmd.root.speller; import dmd.root.string; import dmd.statement; +import dmd.staticassert; import dmd.tokens; import dmd.visitor; @@ -1305,9 +1306,10 @@ extern (C++) class Dsymbol : ASTNode inout(AttribDeclaration) isAttribDeclaration() inout { return null; } inout(AnonDeclaration) isAnonDeclaration() inout { return null; } inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; } - inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; } + inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; } inout(OverloadSet) isOverloadSet() inout { return null; } inout(CompileDeclaration) isCompileDeclaration() inout { return null; } + inout(StaticAssert) isStaticAssert() inout { return null; } } /*********************************************************** @@ -2500,12 +2502,15 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (fd.fbody) // fd is the definition { sds.symtab.update(fd); // replace fd2 in symbol table with fd + fd.overnext = fd2; return fd; } - /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it. - * FuncDeclaration::semantic2() can detect this, but it relies overnext being set. + /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it. + * FuncDeclaration::semantic() detects this, but it relies on .overnext being set. */ + fd2.overloadInsert(fd); + return fd2; } diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index a6bd999..03d5c3d 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -71,6 +71,7 @@ class Expression; class ExpressionDsymbol; class AliasAssign; class OverloadSet; +class StaticAssert; struct AA; #ifdef IN_GCC typedef union tree_node Symbol; @@ -307,6 +308,7 @@ public: virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; } virtual OverloadSet *isOverloadSet() { return NULL; } virtual CompileDeclaration *isCompileDeclaration() { return NULL; } + virtual StaticAssert *isStaticAssert() { return NULL; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 1cb167a..8ad0178 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -847,11 +847,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`"); } - // @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint // Deprecated in 2.087 // Remove this when the feature is removed from the language - if (0 && // deprecation disabled for now to accommodate existing extensive use - !(dsym.storage_class & STC.scope_)) + if (!(dsym.storage_class & STC.scope_)) { if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym) dsym.error("reference to `scope class` must be `scope`"); @@ -1040,15 +1039,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // See if initializer is a NewExp that can be allocated on the stack if (dsym.type.toBasetype().ty == Tclass) { - if (ne.newargs && ne.newargs.dim > 1) - { - dsym.mynew = true; - } - else - { - ne.onstack = 1; - dsym.onstack = true; - } + ne.onstack = 1; + dsym.onstack = true; } } else if (auto fe = ex.isFuncExp()) @@ -2438,8 +2430,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) ? em.ed.memtype : eprev.type; - - Expression emax = tprev.getProperty(sc, em.ed.loc, Id.max, 0); + /* + https://issues.dlang.org/show_bug.cgi?id=20777 + Previously this used getProperty, which doesn't consider anything user defined, + this construct does do that and thus fixes the bug. + */ + Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); emax = emax.expressionSemantic(sc); emax = emax.ctfeInterpret(); @@ -2979,10 +2975,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor void funcDeclarationSemantic(FuncDeclaration funcdecl) { - TypeFunction f; - AggregateDeclaration ad; - InterfaceDeclaration id; - version (none) { printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); @@ -3023,7 +3015,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function funcdecl.storage_class |= sc.stc & ~STC.ref_; - ad = funcdecl.isThis(); + AggregateDeclaration ad = funcdecl.isThis(); // Don't nest structs b/c of generated methods which should not access the outer scopes. // https://issues.dlang.org/show_bug.cgi?id=16627 if (ad && !funcdecl.generated) @@ -3042,21 +3034,22 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sc.flags & SCOPE.compile) funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function - FuncLiteralDeclaration fld = funcdecl.isFuncLiteralDeclaration(); - if (fld && fld.treq) + funcdecl.linkage = sc.linkage; + if (auto fld = funcdecl.isFuncLiteralDeclaration()) { - Type treq = fld.treq; - assert(treq.nextOf().ty == Tfunction); - if (treq.ty == Tdelegate) - fld.tok = TOK.delegate_; - else if (treq.isPtrToFunction()) - fld.tok = TOK.function_; - else - assert(0); - funcdecl.linkage = treq.nextOf().toTypeFunction().linkage; + if (fld.treq) + { + Type treq = fld.treq; + assert(treq.nextOf().ty == Tfunction); + if (treq.ty == Tdelegate) + fld.tok = TOK.delegate_; + else if (treq.isPtrToFunction()) + fld.tok = TOK.function_; + else + assert(0); + funcdecl.linkage = treq.nextOf().toTypeFunction().linkage; + } } - else - funcdecl.linkage = sc.linkage; // evaluate pragma(inline) if (auto pragmadecl = sc.inlining) @@ -3078,16 +3071,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!funcdecl.originalType) funcdecl.originalType = funcdecl.type.syntaxCopy(); - if (funcdecl.type.ty != Tfunction) + + static TypeFunction getFunctionType(FuncDeclaration fd) { - if (funcdecl.type.ty != Terror) + if (auto tf = fd.type.isTypeFunction()) + return tf; + + if (!fd.type.isTypeError()) { - funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars()); - funcdecl.type = Type.terror; + fd.error("`%s` must be a function instead of `%s`", fd.toChars(), fd.type.toChars()); + fd.type = Type.terror; } - funcdecl.errors = true; - return; + fd.errors = true; + return null; } + + if (!getFunctionType(funcdecl)) + return; + if (!funcdecl.type.deco) { sc = sc.push(); @@ -3147,14 +3148,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc |= STC.property; if (tf.purity == PURE.fwdref) sc.stc |= STC.pure_; + if (tf.trust != TRUST.default_) + { sc.stc &= ~STC.safeGroup; - if (tf.trust == TRUST.safe) - sc.stc |= STC.safe; - if (tf.trust == TRUST.system) - sc.stc |= STC.system; - if (tf.trust == TRUST.trusted) - sc.stc |= STC.trusted; + if (tf.trust == TRUST.safe) + sc.stc |= STC.safe; + else if (tf.trust == TRUST.system) + sc.stc |= STC.system; + else if (tf.trust == TRUST.trusted) + sc.stc |= STC.trusted; + } if (funcdecl.isCtorDeclaration()) { @@ -3206,37 +3210,46 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); sc = sc.pop(); } - if (funcdecl.type.ty != Tfunction) - { - if (funcdecl.type.ty != Terror) - { - funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars()); - funcdecl.type = Type.terror; - } - funcdecl.errors = true; - return; - } - else + + auto f = getFunctionType(funcdecl); + if (!f) + return; // funcdecl's type is not a function + { // Merge back function attributes into 'originalType'. // It's used for mangling, ddoc, and json output. TypeFunction tfo = funcdecl.originalType.toTypeFunction(); - TypeFunction tfx = funcdecl.type.toTypeFunction(); - tfo.mod = tfx.mod; - tfo.isScopeQual = tfx.isScopeQual; - tfo.isreturninferred = tfx.isreturninferred; - tfo.isscopeinferred = tfx.isscopeinferred; - tfo.isref = tfx.isref; - tfo.isnothrow = tfx.isnothrow; - tfo.isnogc = tfx.isnogc; - tfo.isproperty = tfx.isproperty; - tfo.purity = tfx.purity; - tfo.trust = tfx.trust; + tfo.mod = f.mod; + tfo.isScopeQual = f.isScopeQual; + tfo.isreturninferred = f.isreturninferred; + tfo.isscopeinferred = f.isscopeinferred; + tfo.isref = f.isref; + tfo.isnothrow = f.isnothrow; + tfo.isnogc = f.isnogc; + tfo.isproperty = f.isproperty; + tfo.purity = f.purity; + tfo.trust = f.trust; funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); } - f = cast(TypeFunction)funcdecl.type; + if (funcdecl.overnext && funcdecl.isCsymbol()) + { + /* C does not allow function overloading, but it does allow + * redeclarations of the same function. If .overnext points + * to a redeclaration, ok. Error if it is an overload. + */ + auto fnext = funcdecl.overnext.isFuncDeclaration(); + funcDeclarationSemantic(fnext); + auto fn = fnext.type.isTypeFunction(); + if (!fn || !cFuncEquivalence(f, fn)) + { + funcdecl.error("redeclaration with different type"); + //printf("t1: %s\n", f.toChars()); + //printf("t2: %s\n", fn.toChars()); + } + funcdecl.overnext = null; // don't overload the redeclarations + } if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) funcdecl.error("storage class `auto` has no effect if return type is not inferred"); @@ -3355,8 +3368,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } - id = parent.isInterfaceDeclaration(); - if (id) + if (auto id = parent.isInterfaceDeclaration()) { funcdecl.storage_class |= STC.abstract_; if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) @@ -3364,6 +3376,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (funcdecl.fbody && funcdecl.isVirtual()) funcdecl.error("function body only allowed in `final` functions in interface `%s`", id.toChars()); } + if (UnionDeclaration ud = parent.isUnionDeclaration()) { if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) @@ -3449,8 +3462,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); if (s) { - FuncDeclaration f2 = s.isFuncDeclaration(); - if (f2) + if (auto f2 = s.isFuncDeclaration()) { f2 = f2.overloadExactMatch(funcdecl.type); if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) @@ -3802,11 +3814,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { if (b.sym) { - Dsymbol s = search_function(b.sym, funcdecl.ident); - if (s) + if (auto s = search_function(b.sym, funcdecl.ident)) { - FuncDeclaration f2 = s.isFuncDeclaration(); - if (f2) + if (auto f2 = s.isFuncDeclaration()) { f2 = f2.overloadExactMatch(funcdecl.type); if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) @@ -3853,8 +3863,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ if (funcdecl.isVirtual()) { - TemplateInstance ti = parent.isTemplateInstance(); - if (ti) + if (auto ti = parent.isTemplateInstance()) { // Take care of nested templates while (1) @@ -4426,7 +4435,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; int errors = global.errors; - //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, sd.toPrettyChars(), sd.sizeok); + //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); Scope* scx = null; if (sd._scope) { @@ -5275,7 +5284,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - // @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint // Deprecated in 2.087 // Make an error in 2.091 // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 @@ -5582,12 +5591,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec); - // @@@DEPRECATED@@@https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint // Deprecated in 2.087 - // Remove in 2.091 + // Made an error in 2.100, but removal depends on `scope class` being removed too // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 if (idec.storage_class & STC.scope_) - deprecation(idec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site."); } } @@ -5879,13 +5888,16 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* scope v = new InstMemberWalker(tempinst.inst); tempinst.inst.accept(v); - if (tempinst.minst) // if inst was not speculative + if (!global.params.allInst && + tempinst.minst) // if inst was not speculative... { - /* Add 'inst' once again to the root module members[], then the - * instance members will get codegen chances. - */ + assert(!tempinst.minst.isRoot()); // ... it was previously appended to a non-root module + // Append again to the root module members[], so that the instance will + // get codegen chances (depending on `tempinst.inst.needsCodegen()`). tempinst.inst.appendToModuleMember(); } + + assert(tempinst.inst.memberOf && tempinst.inst.memberOf.isRoot(), "no codegen chances"); } // modules imported by an existing instance should be added to the module diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 9fe8472..457c5d1 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -5125,15 +5125,6 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars()); if (e.thisexp) e.thisexp.accept(this); - if (!result && e.newargs) - { - foreach (ea; *e.newargs) - { - ea.accept(this); - if (result) - return; - } - } result = e.newtype.reliesOnTemplateParameters(tparams); if (!result && e.arguments) { @@ -7351,12 +7342,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol // toPrettyChars(), // enclosing ? enclosing.toPrettyChars() : null, // mi ? mi.toPrettyChars() : null); - if (!mi || mi.isRoot()) + if (global.params.allInst || !mi || mi.isRoot()) { /* If the instantiated module is speculative or root, insert to the * member of a root module. Then: * - semantic3 pass will get called on the instance members. - * - codegen pass will get a selection chance to do/skip it. + * - codegen pass will get a selection chance to do/skip it (needsCodegen()). */ static Dsymbol getStrictEnclosing(TemplateInstance ti) { @@ -7374,8 +7365,18 @@ extern (C++) class TemplateInstance : ScopeDsymbol // where tempdecl is declared. mi = (enc ? enc : tempdecl).getModule(); if (!mi.isRoot()) - mi = mi.importedFrom; - assert(mi.isRoot()); + { + if (mi.importedFrom) + { + mi = mi.importedFrom; + assert(mi.isRoot()); + } + else + { + // This can happen when using the frontend as a library. + // Append it to the non-root module. + } + } } else { @@ -7383,24 +7384,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol * non-root module. Then: * - semantic3 pass won't be called on the instance. * - codegen pass won't reach to the instance. + * Unless it is re-appended to a root module later (with changed minst). */ } //printf("\t-. mi = %s\n", mi.toPrettyChars()); - if (memberOf is mi) // already a member - { - debug // make sure it really is a member - { - auto a = mi.members; - for (size_t i = 0; 1; ++i) - { - assert(i != a.dim); - if (this == (*a)[i]) - break; - } - } - return null; - } + assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module"); Dsymbols* a = mi.members; a.push(this); @@ -7801,15 +7790,22 @@ struct TemplateInstanceBox { bool res = void; if (ti.inst && s.ti.inst) + { /* This clause is only used when an instance with errors * is replaced with a correct instance. */ res = ti is s.ti; + } else + { /* Used when a proposed instance is used to see if there's * an existing instance. */ - res = (cast()s.ti).equalsx(cast()ti); + static if (__VERSION__ >= 2099) + res = (cast()ti).equalsx(cast()s.ti); + else // https://issues.dlang.org/show_bug.cgi?id=22717 + res = (cast()s.ti).equalsx(cast()ti); + } debug (FindExistingInstance) ++(res ? nHits : nCollisions); return res; diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 5871ada..a34e2cc 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -2545,29 +2545,9 @@ public: buf.writeByte('U'); buf.writeByte('"'); - for (size_t i = 0; i < e.len; i++) + foreach (i; 0 .. e.len) { - uint c = e.charAt(i); - switch (c) - { - case '"': - case '\\': - buf.writeByte('\\'); - goto default; - default: - if (c <= 0xFF) - { - if (c >= 0x20 && c < 0x80) - buf.writeByte(c); - else - buf.printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf.printf("\\u%04x", c); - else - buf.printf("\\U%08x", c); - break; - } + writeCharLiteral(*buf, e.getCodeUnit(i)); } buf.writeByte('"'); } diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index d2a9060..35c1f76 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -380,7 +380,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp notMaybeScope(v); - if (!v.isReference() && p == sc.func) + if (p == sc.func) { if (psr == ScopeRef.Scope || psr == ScopeRef.RefScope || diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 4258e9b..b3aa0b2 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -1742,11 +1742,21 @@ extern (C++) abstract class Expression : ASTNode 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 - { - return null; + inout(UnaExp) isUnaExp() pure inout nothrow @nogc + { + return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null; + } + + inout(BinExp) isBinExp() pure inout nothrow @nogc + { + return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null; + } + + inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc + { + return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null; + } } override void accept(Visitor v) @@ -2716,29 +2726,6 @@ extern (C++) final class StringExp : Expression return ErrorExp.get(); } - uint charAt(uinteger_t i) const - { - uint value; - switch (sz) - { - case 1: - value = (cast(char*)string)[cast(size_t)i]; - break; - - case 2: - value = (cast(ushort*)string)[cast(size_t)i]; - break; - - case 4: - value = (cast(uint*)string)[cast(size_t)i]; - break; - - default: - assert(0); - } - return value; - } - /******************************** * Convert string contents to a 0 terminated string, * allocated by mem.xmalloc(). @@ -3516,12 +3503,11 @@ extern (C++) final class TemplateExp : Expression } /*********************************************************** - * thisexp.new(newargs) newtype(arguments) + * newtype(arguments) */ extern (C++) final class NewExp : Expression { Expression thisexp; // if !=null, 'this' for class being allocated - Expressions* newargs; // Array of Expression's to call new operator Type newtype; Expressions* arguments; // Array of Expression's @@ -3530,25 +3516,23 @@ extern (C++) final class NewExp : Expression bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement - extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments) + extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) { super(loc, EXP.new_, __traits(classInstanceSize, NewExp)); this.thisexp = thisexp; - this.newargs = newargs; this.newtype = newtype; this.arguments = arguments; } - static NewExp create(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments) + static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) { - return new NewExp(loc, thisexp, newargs, newtype, arguments); + return new NewExp(loc, thisexp, newtype, arguments); } override NewExp syntaxCopy() { return new NewExp(loc, thisexp ? thisexp.syntaxCopy() : null, - arraySyntaxCopy(newargs), newtype.syntaxCopy(), arraySyntaxCopy(arguments)); } @@ -3560,27 +3544,25 @@ extern (C++) final class NewExp : Expression } /*********************************************************** - * thisexp.new(newargs) class baseclasses { } (arguments) + * class baseclasses { } (arguments) */ extern (C++) final class NewAnonClassExp : Expression { Expression thisexp; // if !=null, 'this' for class being allocated - Expressions* newargs; // Array of Expression's to call new operator ClassDeclaration cd; // class being instantiated Expressions* arguments; // Array of Expression's to call class constructor - extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments) + extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) { super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp)); this.thisexp = thisexp; - this.newargs = newargs; this.cd = cd; this.arguments = arguments; } override NewAnonClassExp syntaxCopy() { - return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cd.syntaxCopy(null), arraySyntaxCopy(arguments)); + return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments)); } override void accept(Visitor v) @@ -4593,11 +4575,6 @@ extern (C++) class BinAssignExp : BinExp return toLvalue(sc, this); } - override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc @safe - { - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -7055,3 +7032,53 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable } } + +/****************************** + * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp() + */ +private immutable ubyte[EXP.max + 1] exptab = +() { + ubyte[EXP.max + 1] tab; + with (EXPFLAGS) + { + foreach (i; Eunary) { tab[i] |= unary; } + foreach (i; Ebinary) { tab[i] |= unary | binary; } + foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; } + } + return tab; +} (); + +private enum EXPFLAGS : ubyte +{ + unary = 1, + binary = 2, + binaryAssign = 4, +} + +private enum Eunary = + [ + EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration, + EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call, + EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_, + EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer, + EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus, + ]; + +private enum Ebinary = + [ + EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign, + EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift, + EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr, + EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual, + EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity, + EXP.question, + EXP.construct, EXP.blit, + ]; + +private enum EbinaryAssign = + [ + EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign, + EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign, + EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign, + EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign, + ]; diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 18ef90a..9522b23 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -234,7 +234,10 @@ public: FuncInitExp* isFuncInitExp(); PrettyFuncInitExp* isPrettyFuncInitExp(); ClassReferenceExp* isClassReferenceExp(); - virtual BinAssignExp* isBinAssignExp(); + ThrownExceptionExp* isThrownExceptionExp(); + UnaExp* isUnaExp(); + BinExp* isBinExp(); + BinAssignExp* isBinAssignExp(); void accept(Visitor *v) { v->visit(this); } }; @@ -374,13 +377,14 @@ public: static StringExp *create(const Loc &loc, const void *s, size_t len); static void emplace(UnionExp *pue, const Loc &loc, const char *s); bool equals(const RootObject *o) const; + char32_t getCodeUnit(size_t i) const; + void setCodeUnit(size_t i, char32_t c); StringExp *toStringExp(); StringExp *toUTF8(Scope *sc); Optional toBool(); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); - unsigned charAt(uinteger_t i) const; void accept(Visitor *v) { v->visit(this); } size_t numberOfCodeUnits(int tynto = 0) const; void writeTo(void* dest, bool zero, int tyto = 0) const; @@ -519,10 +523,9 @@ public: class NewExp : public Expression { public: - /* thisexp.new(newargs) newtype(arguments) + /* newtype(arguments) */ Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator Type *newtype; Expressions *arguments; // Array of Expression's @@ -532,7 +535,7 @@ public: bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement - static NewExp *create(const Loc &loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments); + static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments); NewExp *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } @@ -541,10 +544,9 @@ public: class NewAnonClassExp : public Expression { public: - /* thisexp.new(newargs) class baseclasses { } (arguments) + /* class baseclasses { } (arguments) */ Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator ClassDeclaration *cd; // class being instantiated Expressions *arguments; // Array of Expression's to call class constructor @@ -716,7 +718,6 @@ public: bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *ex); Expression *modifiableLvalue(Scope *sc, Expression *e); - BinAssignExp* isBinAssignExp(); void accept(Visitor *v) { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 6eda688..0320f66 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -1236,21 +1236,21 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = tthis = null; goto Lfd; } - else if (e1.op == EXP.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration())) + else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration())) { - DotVarExp dve = cast(DotVarExp)e1; + DotVarExp dve = e1.isDotVarExp(); s = dve.var; tiargs = null; tthis = dve.e1.type; goto Lfd; } - else if (sc && sc.flags & SCOPE.Cfile && e1.op == EXP.variable && !e2) + else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2) { // ImportC: do not implicitly call function if no ( ) are present } - else if (e1.op == EXP.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration())) + else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration())) { - s = (cast(VarExp)e1).var; + s = e1.isVarExp().var; tiargs = null; tthis = null; Lfd: @@ -1272,9 +1272,9 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = return ErrorExp.get(); if (!checkSymbolAccess(sc, fd)) { - // @@@DEPRECATED_2020-10@@@ + // @@@DEPRECATED_2.105@@@ // When turning into error, uncomment the return statement - TypeFunction tf = cast(TypeFunction)fd.type; + TypeFunction tf = fd.type.isTypeFunction(); deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`", fd.toPrettyChars(), tf.toChars, sc._module.toChars); //return ErrorExp.get(); @@ -1290,13 +1290,12 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = { if (fd.errors) return ErrorExp.get(); - assert(fd.type.ty == Tfunction); - TypeFunction tf = cast(TypeFunction)fd.type; + TypeFunction tf = fd.type.isTypeFunction(); if (!e2 || tf.isref) { if (!checkSymbolAccess(sc, fd)) { - // @@@DEPRECATED_2020-10@@@ + // @@@DEPRECATED_2.105@@@ // When turning into error, uncomment the return statement deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`", fd.toPrettyChars(), tf.toChars, sc._module.toChars); @@ -1319,17 +1318,18 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) goto Leprop; } - if (e1.op == EXP.variable) + if (auto ve = e1.isVarExp()) { - VarExp ve = cast(VarExp)e1; - VarDeclaration v = ve.var.isVarDeclaration(); - if (v && ve.checkPurity(sc, v)) - return ErrorExp.get(); + if (auto v = ve.var.isVarDeclaration()) + { + if (ve.checkPurity(sc, v)) + return ErrorExp.get(); + } } if (e2) return null; - if (e1.type && e1.op != EXP.type) // function type is not a property + if (e1.type && !e1.isTypeExp()) // 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 @@ -1340,15 +1340,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = Expression e = new CallExp(loc, e1); return e.expressionSemantic(sc); } - else if (e1.op == EXP.dotVariable) + else if (e1.isDotVarExp()) { // Check for reading overlapped pointer field in @safe code. if (checkUnsafeAccess(sc, e1, true, true)) return ErrorExp.get(); } - else if (e1.op == EXP.call) + else if (auto ce = e1.isCallExp()) { - CallExp ce = cast(CallExp)e1; // Check for reading overlapped pointer field in @safe code. if (checkUnsafeAccess(sc, ce.e1, true, true)) return ErrorExp.get(); @@ -1560,14 +1559,12 @@ private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expres */ private Expression rewriteOpAssign(BinExp exp) { - Expression e; - - assert(exp.e1.op == EXP.arrayLength); - ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1; - if (ale.e1.op == EXP.variable) + ArrayLengthExp ale = exp.e1.isArrayLengthExp(); + if (ale.e1.isVarExp()) { - e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); + Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); e = new AssignExp(exp.loc, ale.syntaxCopy(), e); + return e; } else { @@ -1578,11 +1575,11 @@ private Expression rewriteOpAssign(BinExp exp) Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp))); Expression elvalue = e1.syntaxCopy(); - e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); + Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); e = new AssignExp(exp.loc, elvalue, e); e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e); + return e; } - return e; } /**************************************** @@ -1650,10 +1647,9 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo */ private bool checkDefCtor(Loc loc, Type t) { - t = t.baseElemOf(); - if (t.ty == Tstruct) + if (auto ts = t.baseElemOf().isTypeStruct()) { - StructDeclaration sd = (cast(TypeStruct)t).sym; + StructDeclaration sd = ts.sym; if (sd.noDefaultCtor) { sd.error(loc, "default construction is disabled"); @@ -1846,7 +1842,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, auto args = new Expressions(nargs - i); foreach (u; i .. nargs) (*args)[u - i] = (*arguments)[u]; - arg = new NewExp(loc, null, null, p.type, args); + arg = new NewExp(loc, null, p.type, args); break; } default: @@ -1923,7 +1919,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } else if (auto ff = s.isFuncDeclaration()) { - if ((cast(TypeFunction)ff.type).iswild) + if (ff.type.isTypeFunction().iswild) return errorInout(wildmatch); if (ff.isNested() || ff.isThis()) @@ -1969,7 +1965,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ? p.type.substWildTo(wildmatch) : p.type; - const hasCopyCtor = (arg.type.ty == Tstruct) && (cast(TypeStruct)arg.type).sym.hasCopyCtor; + const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor; const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf()); if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type))) { @@ -2059,8 +2055,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* Argument value cannot escape from the called function. */ Expression a = arg; - if (a.op == EXP.cast_) - a = (cast(CastExp)a).e1; + if (auto ce = a.isCastExp()) + a = ce.e1; ArrayLiteralExp ale; if (p.type.toBasetype().ty == Tarray && @@ -2074,26 +2070,22 @@ private bool functionParameters(const ref Loc loc, Scope* sc, arg = CommaExp.combine(declareTmp, castToSlice); arg = arg.expressionSemantic(sc); } - else if (a.op == EXP.function_) + else if (auto fe = a.isFuncExp()) { /* Function literals can only appear once, so if this * appearance was scoped, there cannot be any others. */ - FuncExp fe = cast(FuncExp)a; fe.fd.tookAddressOf = 0; } - else if (a.op == EXP.delegate_) + else if (auto de = a.isDelegateExp()) { /* 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 == EXP.variable) + if (auto ve = de.e1.isVarExp()) { - VarExp ve = cast(VarExp)de.e1; - FuncDeclaration f = ve.var.isFuncDeclaration(); - if (f) + if (auto f = ve.var.isFuncDeclaration()) { if (f.tookAddressOf) --f.tookAddressOf; @@ -2174,9 +2166,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, // Convert static arrays to dynamic arrays // BUG: I don't think this is right for D2 Type tb = arg.type.toBasetype(); - if (tb.ty == Tsarray) + if (auto ts = tb.isTypeSArray()) { - TypeSArray ts = cast(TypeSArray)tb; Type ta = ts.next.arrayOf(); if (ts.size(arg.loc) == 0) arg = new NullExp(arg.loc, ta); @@ -2188,9 +2179,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, //arg = callCpCtor(sc, arg); } // Give error for overloaded function addresses - if (arg.op == EXP.symbolOffset) + if (auto se = arg.isSymOffExp()) { - SymOffExp se = cast(SymOffExp)arg; if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) { arg.error("function `%s` is overloaded", arg.toChars()); @@ -3469,10 +3459,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // T should be analyzed first and edim should go into arguments iff it's // not a tuple. Expression edim = null; - if (!exp.arguments && exp.newtype.ty == Tsarray) + if (!exp.arguments && exp.newtype.isTypeSArray()) { - edim = (cast(TypeSArray)exp.newtype).dim; - exp.newtype = (cast(TypeNext)exp.newtype).next; + auto ts = exp.newtype.isTypeSArray(); + edim = ts.dim; + exp.newtype = ts.next; } ClassDeclaration cdthis = null; @@ -3522,11 +3513,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.newtype = exp.type; // in case type gets cast to something else Type tb = exp.type.toBasetype(); //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); - if (arrayExpressionSemantic(exp.newargs, sc) || - preFunctionParameters(sc, exp.newargs)) - { - return setError(); - } if (arrayExpressionSemantic(exp.arguments, sc)) { return setError(); @@ -3556,9 +3542,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor const size_t nargs = exp.arguments ? exp.arguments.dim : 0; Expression newprefix = null; - if (tb.ty == Tclass) + if (auto tc = tb.isTypeClass()) { - auto cd = (cast(TypeClass)tb).sym; + auto cd = tc.sym; cd.size(exp.loc); if (cd.sizeok != Sizeok.done) return setError(); @@ -3692,14 +3678,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor originalNewtype.toChars()); return setError(); } - else - { - if (exp.newargs && exp.newargs.dim) - { - exp.error("no allocator for `%s`", cd.toChars()); - return setError(); - } - } if (cd.ctor) { @@ -3710,7 +3688,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor checkFunctionAttributes(exp, sc, f); checkAccess(cd, exp.loc, sc, f); - TypeFunction tf = cast(TypeFunction)f.type; + TypeFunction tf = f.type.isTypeFunction(); if (!exp.arguments) exp.arguments = new Expressions(); if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) @@ -3744,9 +3722,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } - else if (tb.ty == Tstruct) + else if (auto ts = tb.isTypeStruct()) { - auto sd = (cast(TypeStruct)tb).sym; + auto sd = ts.sym; sd.size(exp.loc); if (sd.sizeok != Sizeok.done) return setError(); @@ -3765,14 +3743,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor originalNewtype.toChars()); return setError(); } - else - { - if (exp.newargs && exp.newargs.dim) - { - exp.error("no allocator for `%s`", sd.toChars()); - return setError(); - } - } if (sd.hasRegularCtor() && nargs) { @@ -3783,7 +3753,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor checkFunctionAttributes(exp, sc, f); checkAccess(sd, exp.loc, sc, f); - TypeFunction tf = cast(TypeFunction)f.type; + TypeFunction tf = f.type.isTypeFunction(); if (!exp.arguments) exp.arguments = new Expressions(); if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) @@ -3861,7 +3831,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } (*exp.arguments)[i] = arg; - tb = (cast(TypeDArray)tb).next.toBasetype(); + tb = tb.isTypeDArray().next.toBasetype(); } } else if (tb.isscalar()) @@ -3924,7 +3894,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sds.members.push(e.cd); } - Expression n = new NewExp(e.loc, e.thisexp, e.newargs, e.cd.type, e.arguments); + Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments); Expression c = new CommaExp(e.loc, d, n); result = c.expressionSemantic(sc); @@ -4097,6 +4067,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Type is a "delegate to" or "pointer to" the function literal if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate)) { + // https://issues.dlang.org/show_bug.cgi?id=22686 + // if the delegate return type is an error + // abort semantic of the FuncExp and propagate + // the error + if (exp.fd.type.isTypeError()) + { + e = ErrorExp.get(); + goto Ldone; + } exp.type = new TypeDelegate(exp.fd.type.isTypeFunction()); exp.type = exp.type.typeSemantic(exp.loc, sc); @@ -5239,21 +5218,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor break; } - VarDeclaration v = s.isVarDeclaration(); - if (v) - { - // Do semantic() on initializer first, so: - // int a = a; - // will be illegal. - e.declaration.dsymbolSemantic(sc); - s.parent = sc.parent; - } - //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); // Insert into both local scope and function scope. // Must be unique in both. if (s.ident) { + VarDeclaration v = s.isVarDeclaration(); + if (v && !(sc.flags & SCOPE.Cfile)) + { + /* Do semantic() on initializer first so this will be illegal: + * int a = a; + */ + e.declaration.dsymbolSemantic(sc); + s.parent = sc.parent; + } + if (!sc.insert(s)) { auto conflict = sc.search(Loc.initial, s.ident, null); @@ -5262,7 +5241,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor conflict.kind(), conflict.toChars()); return setError(); } - else if (sc.func) + + if (v && (sc.flags & SCOPE.Cfile)) + { + /* Do semantic() on initializer last so this will be legal: + * int a = a; + */ + e.declaration.dsymbolSemantic(sc); + s.parent = sc.parent; + } + + if (sc.func) { // https://issues.dlang.org/show_bug.cgi?id=11720 if ((s.isFuncDeclaration() || @@ -5278,14 +5267,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Perturb the name mangling so that the symbols can co-exist // instead of colliding s.localNum = cast(ushort)(originalSymbol.localNum + 1); - assert(s.localNum); // 65535 should be enough for anyone + // 65535 should be enough for anyone + if (!s.localNum) + { + e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars()); + return setError(); + } // Replace originalSymbol with s, which updates the localCount sc.func.localsymtab.update(s); // The mangling change only works for D mangling } -// else + { /* https://issues.dlang.org/show_bug.cgi?id=21272 * If we are in a foreach body we need to extract the @@ -6943,15 +6937,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (!exp.e1.type.deco) { - if (exp.e1.op == EXP.variable) + // try to resolve the type + exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null); + if (!exp.e1.type.deco) // still couldn't resolve it { - VarExp ve = cast(VarExp)exp.e1; - Declaration d = ve.var; - exp.error("forward reference to %s `%s`", d.kind(), d.toChars()); + if (auto ve = exp.e1.isVarExp()) + { + Declaration d = ve.var; + exp.error("forward reference to %s `%s`", d.kind(), d.toChars()); + } + else + exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars()); + return setError(); } - else - exp.error("forward reference to `%s`", exp.e1.toChars()); - return setError(); } exp.type = exp.e1.type.pointerTo(); @@ -7327,14 +7325,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(DeleteExp exp) { - if (!sc.isDeprecated) + // @@@DEPRECATED_2.109@@@ + // 1. Deprecated since 2.079 + // 2. Error since 2.099 + // 3. Removal of keyword, "delete" can be used for other identities + if (!exp.isRAII) { - // @@@DEPRECATED_2019-02@@@ - // 1. Deprecation for 1 year - // 2. Error for 1 year - // 3. Removal of keyword, "delete" can be used for other identities - if (!exp.isRAII) - deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead."); + error(exp.loc, "The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead."); + return setError(); } Expression e = exp; @@ -7353,89 +7351,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.type = Type.tvoid; - AggregateDeclaration ad = null; Type tb = exp.e1.type.toBasetype(); - switch (tb.ty) - { - case Tclass: - { - auto cd = (cast(TypeClass)tb).sym; - if (cd.isCOMinterface()) - { - /* Because COM classes are deleted by IUnknown.Release() - */ - exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars()); - return setError(); - } - ad = cd; - break; - } - case Tpointer: - tb = (cast(TypePointer)tb).next.toBasetype(); - if (tb.ty == Tstruct) - { - ad = (cast(TypeStruct)tb).sym; - - Identifier hook = global.params.tracegc ? Id._d_delstructTrace : Id._d_delstruct; - if (!verifyHookExist(exp.loc, *sc, Id._d_delstructImpl, "deleting struct with dtor", Id.object)) - return setError(); - // Lower to .object._d_delstruct{,Trace}(exp.e1) - Expression id = new IdentifierExp(exp.loc, Id.empty); - id = new DotIdExp(exp.loc, id, Id.object); - - auto tiargs = new Objects(); - tiargs.push(exp.e1.type); - id = new DotTemplateInstanceExp(exp.loc, id, Id._d_delstructImpl, tiargs); - id = new DotIdExp(exp.loc, id, hook); - - e = new CallExp(exp.loc, id, exp.e1); - /* Gag errors generated by calls to `_d_delstruct`, because they display - * internal compiler information, which is unnecessary to the user. - */ - uint errors = global.startGagging(); - e = e.expressionSemantic(sc); - global.endGagging(errors); - } - break; - - case Tarray: - { - Type tv = tb.nextOf().baseElemOf(); - if (tv.ty == Tstruct) - { - ad = (cast(TypeStruct)tv).sym; - if (ad.dtor) - semanticTypeInfo(sc, ad.type); - } - break; - } - default: + /* Now that `delete` in user code is an error, we only get here when + * `isRAII` has been set to true for the deletion of a `scope class`. */ + if (tb.ty != Tclass) + { exp.error("cannot delete type `%s`", exp.e1.type.toChars()); return setError(); } - bool err = false; - if (ad) + ClassDeclaration cd = (cast(TypeClass)tb).sym; + if (cd.isCOMinterface()) { - if (ad.dtor) - { - err |= !ad.dtor.functionSemantic(); - err |= exp.checkPurity(sc, ad.dtor); - err |= exp.checkSafety(sc, ad.dtor); - err |= exp.checkNogc(sc, ad.dtor); - } - if (err) - return setError(); + /* Because COM classes are deleted by IUnknown.Release() + */ + exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars()); + return setError(); } - if (!sc.intypeof && sc.func && - !exp.isRAII && - !(sc.flags & SCOPE.debug_) && - sc.func.setUnsafe()) + bool err = false; + if (cd.dtor) { - exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars()); - err = true; + err |= !cd.dtor.functionSemantic(); + err |= exp.checkPurity(sc, cd.dtor); + err |= exp.checkSafety(sc, cd.dtor); + err |= exp.checkNogc(sc, cd.dtor); } if (err) return setError(); @@ -7457,12 +7398,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if ((sc && sc.flags & SCOPE.Cfile) && - exp.to && exp.to.ty == Tident && + exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) && (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 + * ( identifier [expression]) cast-expression * If we determine that `identifier` is a variable, and cast-expression * is one of the unary operators (& * + -), then rewrite this cast * as a binary expression. @@ -9858,7 +9800,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { VarExp ve = cast(VarExp)exp.e1; VarDeclaration vd = ve.var.isVarDeclaration(); - if (vd && (vd.onstack || vd.mynew)) + if (vd && vd.onstack) { assert(t1.ty == Tclass); exp.error("cannot rebind scope variables"); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index f3aeb0f..39cb845 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -567,7 +567,8 @@ extern (C++) class FuncDeclaration : Declaration * do existing practice. But we should examine how TypeFunction does * it, for consistency. */ - if (!tf.isref && isRefReturnScope(vthis.storage_class)) + if (global.params.useDIP1000 != FeatureState.enabled && + !tf.isref && isRefReturnScope(vthis.storage_class)) { /* if `ref return scope`, evaluate to `ref` `return scope` */ diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 43b63f1..6b8ecc5 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -991,8 +991,9 @@ public: override void visit(VisibilityDeclaration d) { visibilityToBuffer(buf, d.visibility); - buf.writeByte(' '); AttribDeclaration ad = cast(AttribDeclaration)d; + if (ad.decl.dim <= 1) + buf.writeByte(' '); if (ad.decl.dim == 1 && (*ad.decl)[0].isVisibilityDeclaration) visit(cast(AttribDeclaration)(*ad.decl)[0]); else @@ -1693,17 +1694,8 @@ public: override void visit(DtorDeclaration d) { - if (d.storage_class & STC.trusted) - buf.writestring("@trusted "); - if (d.storage_class & STC.safe) - buf.writestring("@safe "); - if (d.storage_class & STC.nogc) - buf.writestring("@nogc "); - if (d.storage_class & STC.live) - buf.writestring("@live "); - if (d.storage_class & STC.disable) - buf.writestring("@disable "); - + if (stcToBuffer(buf, d.storage_class)) + buf.writeByte(' '); buf.writestring("~this()"); bodyToBuffer(d); } @@ -1992,29 +1984,9 @@ public: { buf.writeByte('"'); const o = buf.length; - for (size_t i = 0; i < e.len; i++) + foreach (i; 0 .. e.len) { - const c = e.charAt(i); - switch (c) - { - case '"': - case '\\': - buf.writeByte('\\'); - goto default; - default: - if (c <= 0xFF) - { - if (c <= 0x7F && isprint(c)) - buf.writeByte(c); - else - buf.printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); - else - buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); - break; - } + writeCharLiteral(*buf, e.getCodeUnit(i)); } if (hgs.ddoc) escapeDdocString(buf, o); @@ -2113,12 +2085,6 @@ public: buf.writeByte('.'); } buf.writestring("new "); - if (e.newargs && e.newargs.dim) - { - buf.writeByte('('); - argsToBuffer(e.newargs, buf, hgs); - buf.writeByte(')'); - } typeToBuffer(e.newtype, null, buf, hgs); if (e.arguments && e.arguments.dim) { @@ -2136,12 +2102,6 @@ public: buf.writeByte('.'); } buf.writestring("new"); - if (e.newargs && e.newargs.dim) - { - buf.writeByte('('); - argsToBuffer(e.newargs, buf, hgs); - buf.writeByte(')'); - } buf.writestring(" class "); if (e.arguments && e.arguments.dim) { @@ -2909,22 +2869,6 @@ string stcToString(ref StorageClass stc) return null; } -/// Ditto -extern (D) string trustToString(TRUST trust) pure nothrow -{ - final switch (trust) - { - case TRUST.default_: - return null; - case TRUST.system: - return "@system"; - case TRUST.trusted: - return "@trusted"; - case TRUST.safe: - return "@safe"; - } -} - private void linkageToBuffer(OutBuffer* buf, LINK linkage) { const s = linkageToString(linkage); @@ -3902,7 +3846,7 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) buf.writeByte(' '); if (t.id) buf.writestring(t.id.toChars()); - if (t.base.ty != TY.Tint32) + if (t.tok == TOK.enum_ && t.base.ty != TY.Tint32) { buf.writestring(" : "); visitWithMask(t.base, t.mod, buf, hgs); diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 495126d..7d4fbc3 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -84,7 +84,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) case TOK.string_: constraint = p.parsePrimaryExp(); - // @@@DEPRECATED@@@ + // @@@DEPRECATED_2.101@@@ // Old parser allowed omitting parentheses around the expression. // Deprecated in 2.091. Can be made permanent error after 2.100 if (p.token.value != TOK.leftParenthesis) diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 7f51e92..31a44db 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -115,7 +115,6 @@ immutable Msgtable[] msgtable = { "line" }, { "empty", "" }, { "p" }, - { "q" }, { "__vptr" }, { "__monitor" }, { "gate", "__gate" }, @@ -311,9 +310,6 @@ immutable Msgtable[] msgtable = { "__ArrayPostblit" }, { "__ArrayDtor" }, { "_d_delThrowable" }, - { "_d_delstructImpl" }, - { "_d_delstruct" }, - { "_d_delstructTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 1b92386..a48b339 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -260,3 +260,50 @@ Expression castCallAmbiguity(Expression e, Scope* sc) } } +/******************************************** + * Implement the C11 notion of function equivalence, + * which allows prototyped functions to match K+R functions, + * even though they are different. + * Params: + * tf1 = type of first function + * tf2 = type of second function + * Returns: + * true if C11 considers them equivalent + */ + +bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2) +{ + if (tf1.equals(tf2)) + return true; + + if (tf1.linkage != tf2.linkage) + return false; + + // Allow func(void) to match func() + if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0) + return true; + + if (!tf1.parameterList.hasIdentifierList && + !tf2.parameterList.hasIdentifierList) + return false; // both functions are prototyped + + // Otherwise ignore variadicness, as K+R functions are all variadic + + if (!tf1.nextOf().equals(tf2.nextOf())) + return false; // function return types don't match + + if (tf1.parameterList.length != tf2.parameterList.length) + return false; + + foreach (i, fparam ; tf1.parameterList) + { + Type t1 = fparam.type; + Type t2 = tf2.parameterList[i].type; + if (!t1.equals(t2)) + return false; + } + + //printf("t1: %s\n", tf1.toChars()); + //printf("t2: %s\n", tf2.toChars()); + return true; +} diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 6b10ace..bc02bf9 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -590,7 +590,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = ErrorExp.get(); } } + Type et = i.exp.type; + const errors = global.startGagging(); i.exp = i.exp.implicitCastTo(sc, t); + if (global.endGagging(errors)) + currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars()); } L1: if (i.exp.op == EXP.error) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index e74b192..7c8b504 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -38,172 +38,6 @@ import dmd.utils; nothrow: -private enum LS = 0x2028; // UTF line separator -private enum PS = 0x2029; // UTF paragraph separator - -/******************************************** - * Do our own char maps - */ -private static immutable cmtable = () { - ubyte[256] table; - foreach (const c; 0 .. table.length) - { - if ('0' <= c && c <= '7') - table[c] |= CMoctal; - if (c_isxdigit(c)) - table[c] |= CMhex; - if (c_isalnum(c) || c == '_') - table[c] |= CMidchar; - - switch (c) - { - case 'x': case 'X': - case 'b': case 'B': - table[c] |= CMzerosecond; - break; - - case '0': .. case '9': - case 'e': case 'E': - case 'f': case 'F': - case 'l': case 'L': - case 'p': case 'P': - case 'u': case 'U': - case 'i': - case '.': - case '_': - table[c] |= CMzerosecond | CMdigitsecond; - break; - - default: - break; - } - - switch (c) - { - case '\\': - case '\n': - case '\r': - case 0: - case 0x1A: - case '\'': - break; - default: - if (!(c & 0x80)) - table[c] |= CMsinglechar; - break; - } - } - return table; -}(); - -private -{ - enum CMoctal = 0x1; - enum CMhex = 0x2; - enum CMidchar = 0x4; - enum CMzerosecond = 0x8; - enum CMdigitsecond = 0x10; - enum CMsinglechar = 0x20; -} - -private bool isoctal(const char c) pure @nogc @safe -{ - return (cmtable[c] & CMoctal) != 0; -} - -private bool ishex(const char c) pure @nogc @safe -{ - return (cmtable[c] & CMhex) != 0; -} - -private bool isidchar(const char c) pure @nogc @safe -{ - return (cmtable[c] & CMidchar) != 0; -} - -private bool isZeroSecond(const char c) pure @nogc @safe -{ - return (cmtable[c] & CMzerosecond) != 0; -} - -private bool isDigitSecond(const char c) pure @nogc @safe -{ - return (cmtable[c] & CMdigitsecond) != 0; -} - -private bool issinglechar(const char c) pure @nogc @safe -{ - return (cmtable[c] & CMsinglechar) != 0; -} - -private bool c_isxdigit(const int c) pure @nogc @safe -{ - return (( c >= '0' && c <= '9') || - ( c >= 'a' && c <= 'f') || - ( c >= 'A' && c <= 'F')); -} - -private bool c_isalnum(const int c) pure @nogc @safe -{ - return (( c >= '0' && c <= '9') || - ( c >= 'a' && c <= 'z') || - ( c >= 'A' && c <= 'Z')); -} - -unittest -{ - //printf("lexer.unittest\n"); - /* Not much here, just trying things out. - */ - string text = "int"; // We rely on the implicit null-terminator - scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); - TOK tok; - tok = lex1.nextToken(); - //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); - assert(tok == TOK.int32); - tok = lex1.nextToken(); - assert(tok == TOK.endOfFile); - tok = lex1.nextToken(); - assert(tok == TOK.endOfFile); - tok = lex1.nextToken(); - assert(tok == TOK.endOfFile); -} - -unittest -{ - // We don't want to see Lexer error output during these tests. - uint errors = global.startGagging(); - scope(exit) global.endGagging(errors); - - // Test malformed input: even malformed input should end in a TOK.endOfFile. - static immutable char[][] testcases = - [ // Testcase must end with 0 or 0x1A. - [0], // not malformed, but pathological - ['\'', 0], - ['\'', 0x1A], - ['{', '{', 'q', '{', 0], - [0xFF, 0], - [0xFF, 0x80, 0], - [0xFF, 0xFF, 0], - [0xFF, 0xFF, 0], - ['x', '"', 0x1A], - ]; - - foreach (testcase; testcases) - { - scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); - TOK tok = lex2.nextToken(); - size_t iterations = 1; - while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) - { - tok = lex2.nextToken(); - } - assert(tok == TOK.endOfFile); - tok = lex2.nextToken(); - assert(tok == TOK.endOfFile); - } -} - version (DMDLIB) { version = LocOffset; @@ -440,7 +274,7 @@ class Lexer if (issinglechar(p[1]) && p[2] == '\'') { t.unsvalue = p[1]; // simple one character literal - t.value = Ccompile ? TOK.int32Literal : TOK.charLiteral; + t.value = TOK.charLiteral; p += 3; } else if (Ccompile) @@ -1716,9 +1550,11 @@ class Lexer if (*p == '"') p++; else if (hereid) - error("delimited string must end in %s\"", hereid.toChars()); + error("delimited string must end in `%s\"`", hereid.toChars()); + else if (isspace(delimright)) + error("delimited string must end in `\"`"); else - error("delimited string must end in %c\"", delimright); + error("delimited string must end in `%c\"`", delimright); result.setString(stringbuffer); stringPostfix(result); } @@ -2030,7 +1866,7 @@ class Lexer default: assert(0); } - t.value = TOK.int32Literal; + t.value = n == 1 ? TOK.charLiteral : TOK.int32Literal; t.unsvalue = u; } @@ -2113,7 +1949,11 @@ class Lexer if (p[1] == '.') goto Ldone; // if ".." if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80) + { + if (Ccompile && (p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L')) + goto Lreal; // if `0.f` or `0.L` goto Ldone; // if ".identifier" or ".unicode" + } goto Lreal; // '.' is part of current token case 'i': case 'f': @@ -2182,7 +2022,12 @@ class Lexer if (p[1] == '.') goto Ldone; // if ".." if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)) + { + if (Ccompile && base == 10 && + (p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L')) + goto Lreal; // if `1.f` or `1.L` goto Ldone; // if ".identifier" or ".unicode" + } if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80)) goto Ldone; // if ".identifier" or ".unicode" if (base == 2) @@ -2421,11 +2266,6 @@ class Lexer flags = cast(FLAGS)(flags | f); } - void overflow() - { - error("integer overflow"); - } - TOK result = TOK.int32Literal; // default switch (flags) { @@ -2438,71 +2278,35 @@ class Lexer * First that fits: int, unsigned, long, unsigned long, * long long, unsigned long long */ - if (longsize == 4) - { - if (n & 0x8000000000000000L) - result = TOK.uns64Literal; - else if (n & 0xFFFFFFFF00000000L) - result = TOK.int64Literal; - else if (n & 0x80000000) - result = TOK.uns32Literal; - else - result = TOK.int32Literal; - } + if (n & 0x8000000000000000L) + result = TOK.uns64Literal; // unsigned long + else if (n & 0xFFFFFFFF00000000L) + result = TOK.int64Literal; // long + else if (n & 0x80000000) + result = TOK.uns32Literal; else - { - if (n & 0x8000000000000000L) - result = TOK.uns64Literal; // unsigned long - else if (n & 0xFFFFFFFF00000000L) - result = TOK.int64Literal; // long - else if (n & 0x80000000) - result = TOK.uns32Literal; - else - result = TOK.int32Literal; - } + result = TOK.int32Literal; break; case FLAGS.decimal: /* First that fits: int, long, long long */ - if (longsize == 4) - { - if (n & 0x8000000000000000L) - result = TOK.uns64Literal; - else if (n & 0xFFFFFFFF80000000L) - result = TOK.int64Literal; - else - result = TOK.int32Literal; - } + if (n & 0x8000000000000000L) + result = TOK.uns64Literal; // unsigned long + else if (n & 0xFFFFFFFF80000000L) + result = TOK.int64Literal; // long else - { - if (n & 0x8000000000000000L) - result = TOK.uns64Literal; // unsigned long - else if (n & 0xFFFFFFFF80000000L) - result = TOK.int64Literal; // long - else - result = TOK.int32Literal; - } + result = TOK.int32Literal; break; case FLAGS.octalhex | FLAGS.unsigned: case FLAGS.decimal | FLAGS.unsigned: /* First that fits: unsigned, unsigned long, unsigned long long */ - if (longsize == 4) - { - if (n & 0xFFFFFFFF00000000L) - result = TOK.uns64Literal; - else - result = TOK.uns32Literal; - } + if (n & 0xFFFFFFFF00000000L) + result = TOK.uns64Literal; // unsigned long else - { - if (n & 0xFFFFFFFF00000000L) - result = TOK.uns64Literal; // unsigned long - else - result = TOK.uns32Literal; - } + result = TOK.uns32Literal; break; case FLAGS.decimal | FLAGS.long_: @@ -2510,19 +2314,14 @@ class Lexer */ if (longsize == 4) { - if (n & 0x8000000000000000L) - overflow(); - else if (n & 0xFFFFFFFF_80000000L) + if (n & 0xFFFFFFFF_80000000L) result = TOK.int64Literal; else - result = TOK.int32Literal; // long + result = TOK.int32Literal; // long } else { - if (n & 0x8000000000000000L) - overflow(); - else - result = TOK.int64Literal; // long + result = TOK.int64Literal; // long } break; @@ -3353,6 +3152,11 @@ class Lexer } } + +/******************************* Private *****************************************/ + +private: + /// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__` private struct TimeStampInfo { @@ -3389,6 +3193,121 @@ private struct TimeStampInfo } } +private enum LS = 0x2028; // UTF line separator +private enum PS = 0x2029; // UTF paragraph separator + +/******************************************** + * Do our own char maps + */ +private static immutable cmtable = () +{ + ubyte[256] table; + foreach (const c; 0 .. table.length) + { + if ('0' <= c && c <= '7') + table[c] |= CMoctal; + if (c_isxdigit(c)) + table[c] |= CMhex; + if (c_isalnum(c) || c == '_') + table[c] |= CMidchar; + + switch (c) + { + case 'x': case 'X': + case 'b': case 'B': + table[c] |= CMzerosecond; + break; + + case '0': .. case '9': + case 'e': case 'E': + case 'f': case 'F': + case 'l': case 'L': + case 'p': case 'P': + case 'u': case 'U': + case 'i': + case '.': + case '_': + table[c] |= CMzerosecond | CMdigitsecond; + break; + + default: + break; + } + + switch (c) + { + case '\\': + case '\n': + case '\r': + case 0: + case 0x1A: + case '\'': + break; + default: + if (!(c & 0x80)) + table[c] |= CMsinglechar; + break; + } + } + return table; +}(); + +private +{ + enum CMoctal = 0x1; + enum CMhex = 0x2; + enum CMidchar = 0x4; + enum CMzerosecond = 0x8; + enum CMdigitsecond = 0x10; + enum CMsinglechar = 0x20; +} + +private bool isoctal(const char c) pure @nogc @safe +{ + return (cmtable[c] & CMoctal) != 0; +} + +private bool ishex(const char c) pure @nogc @safe +{ + return (cmtable[c] & CMhex) != 0; +} + +private bool isidchar(const char c) pure @nogc @safe +{ + return (cmtable[c] & CMidchar) != 0; +} + +private bool isZeroSecond(const char c) pure @nogc @safe +{ + return (cmtable[c] & CMzerosecond) != 0; +} + +private bool isDigitSecond(const char c) pure @nogc @safe +{ + return (cmtable[c] & CMdigitsecond) != 0; +} + +private bool issinglechar(const char c) pure @nogc @safe +{ + return (cmtable[c] & CMsinglechar) != 0; +} + +private bool c_isxdigit(const int c) pure @nogc @safe +{ + return (( c >= '0' && c <= '9') || + ( c >= 'a' && c <= 'f') || + ( c >= 'A' && c <= 'F')); +} + +private bool c_isalnum(const int c) pure @nogc @safe +{ + return (( c >= '0' && c <= '9') || + ( c >= 'a' && c <= 'z') || + ( c >= 'A' && c <= 'Z')); +} + +/******************************* Unittest *****************************************/ + unittest { import dmd.console; @@ -3441,6 +3360,7 @@ unittest diagnosticHandler = null; } + unittest { import dmd.console; @@ -3510,3 +3430,59 @@ unittest diagnosticHandler = null; } + +unittest +{ + //printf("lexer.unittest\n"); + /* Not much here, just trying things out. + */ + string text = "int"; // We rely on the implicit null-terminator + scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); + TOK tok; + tok = lex1.nextToken(); + //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); + assert(tok == TOK.int32); + tok = lex1.nextToken(); + assert(tok == TOK.endOfFile); + tok = lex1.nextToken(); + assert(tok == TOK.endOfFile); + tok = lex1.nextToken(); + assert(tok == TOK.endOfFile); +} + +unittest +{ + // We don't want to see Lexer error output during these tests. + uint errors = global.startGagging(); + scope(exit) global.endGagging(errors); + + // Test malformed input: even malformed input should end in a TOK.endOfFile. + static immutable char[][] testcases = + [ // Testcase must end with 0 or 0x1A. + [0], // not malformed, but pathological + ['\'', 0], + ['\'', 0x1A], + ['{', '{', 'q', '{', 0], + [0xFF, 0], + [0xFF, 0x80, 0], + [0xFF, 0xFF, 0], + [0xFF, 0xFF, 0], + ['x', '"', 0x1A], + ]; + + foreach (testcase; testcases) + { + scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); + TOK tok = lex2.nextToken(); + size_t iterations = 1; + while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) + { + tok = lex2.nextToken(); + } + assert(tok == TOK.endOfFile); + tok = lex2.nextToken(); + assert(tok == TOK.endOfFile); + } +} + + diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index fefad28..2897877 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -206,6 +206,32 @@ string MODtoString(MOD mod) nothrow pure } } +/************************************************* + * Pick off one of the trust flags from trust, + * and return a string representation of it. + */ +string trustToString(TRUST trust) pure nothrow @nogc @safe +{ + final switch (trust) + { + case TRUST.default_: + return null; + case TRUST.system: + return "@system"; + case TRUST.trusted: + return "@trusted"; + case TRUST.safe: + return "@safe"; + } +} + +unittest +{ + assert(trustToString(TRUST.default_) == ""); + assert(trustToString(TRUST.system) == "@system"); + assert(trustToString(TRUST.trusted) == "@trusted"); + assert(trustToString(TRUST.safe) == "@safe"); +} /************************************ * Convert MODxxxx to STCxxx @@ -400,7 +426,7 @@ extern (C++) abstract class Type : ASTNode extern (C++) __gshared Type[TMAX] basic; extern (D) __gshared StringTable!Type stringtable; - extern (D) private __gshared ubyte[TMAX] sizeTy = () + extern (D) private static immutable ubyte[TMAX] sizeTy = () { ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic); sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray); @@ -2604,6 +2630,10 @@ extern (C++) abstract class Type : ASTNode default: assert(0); } + // @@@DEPRECATED_2.117@@@ + // Deprecated in 2.097 - Can be made an error from 2.117. + // The deprecation period is longer than usual as `cfloat`, + // `cdouble`, and `creal` were quite widely used. if (t.iscomplex()) { deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", @@ -4219,9 +4249,9 @@ extern (C++) final class TypeFunction : TypeNext this.trust = TRUST.default_; if (stc & STC.safe) this.trust = TRUST.safe; - if (stc & STC.system) + else if (stc & STC.system) this.trust = TRUST.system; - if (stc & STC.trusted) + else if (stc & STC.trusted) this.trust = TRUST.trusted; } @@ -6346,7 +6376,7 @@ extern (C++) final class TypeClass : Type /* Conversion derived to const(base) */ int offset = 0; - if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod)) + if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod)) { // Disallow: // derived to base @@ -7253,10 +7283,9 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma if (trustAttrib == TRUST.default_) { - if (trustFormat == TRUSTformatSystem) - trustAttrib = TRUST.system; - else - return; // avoid calling with an empty string + if (trustFormat != TRUSTformatSystem) + return; + trustAttrib = TRUST.system; // avoid calling with an empty string } dg(trustToString(trustAttrib)); diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index f25e779..d6735d4 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -84,20 +84,6 @@ public: } f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } - else if (fd.ident == Id._d_delstruct) - { - // In expressionsem.d, `delete s` was lowererd to `_d_delstruct(s)`. - // The following code handles the call like the original expression, - // so the error is menaningful to the user. - if (f.setGC()) - { - e.error("cannot use `delete` in `@nogc` %s `%s`", f.kind(), - f.toPrettyChars()); - err = true; - return; - } - f.printGCUsage(e.loc, "`delete` requires the GC"); - } } override void visit(ArrayLiteralExp e) @@ -158,32 +144,8 @@ public: return; // delete for scope allocated class object } - Type tb = e.e1.type.toBasetype(); - AggregateDeclaration ad = null; - switch (tb.ty) - { - case Tclass: - ad = (cast(TypeClass)tb).sym; - break; - - case Tpointer: - tb = (cast(TypePointer)tb).next.toBasetype(); - if (tb.ty == Tstruct) - ad = (cast(TypeStruct)tb).sym; - break; - - default: - break; - } - - if (f.setGC()) - { - e.error("cannot use `delete` in `@nogc` %s `%s`", - f.kind(), f.toPrettyChars()); - err = true; - return; - } - f.printGCUsage(e.loc, "`delete` requires the GC"); + // Semantic should have already handled this case. + assert(0); } override void visit(IndexExp e) diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 5d6128b..01708d6 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -272,31 +272,17 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE */ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { - extern (C++) final class OpOverload : Visitor - { - alias visit = Visitor.visit; - public: - Scope* sc; - EXP* pop; - Expression result; - - extern (D) this(Scope* sc, EXP* pop) - { - this.sc = sc; - this.pop = pop; - } - - override void visit(Expression e) + Expression visit(Expression e) { assert(0); } - override void visit(UnaExp e) + Expression visitUna(UnaExp e) { //printf("UnaExp::op_overload() (%s)\n", e.toChars()); - if (e.e1.op == EXP.array) + Expression result; + if (auto ae = e.e1.isArrayExp()) { - ArrayExp ae = cast(ArrayExp)e.e1; ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; @@ -304,15 +290,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == EXP.interval); - ie = cast(IntervalExp)(*ae.arguments)[0]; + ie = (*ae.arguments)[0].isIntervalExp(); } while (true) { if (ae.e1.op == EXP.error) { - result = ae.e1; - return; + return ae.e1; } Expression e0 = null; Expression ae1save = ae.e1; @@ -328,7 +312,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) goto Lfallback; if (result.op == EXP.error) - return; + return result; /* Rewrite op(a[arguments]) as: * a.opIndexUnary!(op)(arguments) */ @@ -342,8 +326,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = result.expressionSemantic(sc); if (result) { - result = Expression.combine(e0, result); - return; + return Expression.combine(e0, result); } } Lfallback: @@ -352,7 +335,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); if (result.op == EXP.error) - return; + return result; /* Rewrite op(a[i..j]) as: * a.opSliceUnary!(op)(i, j) */ @@ -367,7 +350,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = new CallExp(e.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); - return; + return result; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) @@ -388,8 +371,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) e.e1 = resolveProperties(sc, e.e1); if (e.e1.op == EXP.error) { - result = e.e1; - return; + return e.e1; } AggregateDeclaration ad = isAggregate(e.e1.type); if (ad) @@ -405,7 +387,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); result = new CallExp(e.loc, result); result = result.expressionSemantic(sc); - return; + return result; } // D1-style operator overloads, deprecated if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus) @@ -420,7 +402,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) 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; + return result; } } // Didn't find it. Forward to aliasthis @@ -434,12 +416,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) UnaExp ue = cast(UnaExp)e.copy(); ue.e1 = e1; result = ue.trySemantic(sc); - return; + return result; } } + return result; } - override void visit(ArrayExp ae) + Expression visitArray(ArrayExp ae) { //printf("ArrayExp::op_overload() (%s)\n", ae.toChars()); ae.e1 = ae.e1.expressionSemantic(sc); @@ -449,15 +432,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == EXP.interval); - ie = cast(IntervalExp)(*ae.arguments)[0]; + ie = (*ae.arguments)[0].isIntervalExp(); } + Expression result; while (true) { if (ae.e1.op == EXP.error) { - result = ae.e1; - return; + return ae.e1; } Expression e0 = null; Expression ae1save = ae.e1; @@ -475,14 +457,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); - return; + return result; } // Convert to IndexExp if (ae.arguments.dim == 1) { result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]); result = result.expressionSemantic(sc); - return; + return result; } } break; @@ -494,7 +476,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (!result) // a[i..j] might be: a.opSlice(i, j) goto Lfallback; if (result.op == EXP.error) - return; + return result; /* Rewrite e1[arguments] as: * e1.opIndex(arguments) */ @@ -507,8 +489,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = result.expressionSemantic(sc); if (result) { - result = Expression.combine(e0, result); - return; + return Expression.combine(e0, result); } } Lfallback: @@ -517,7 +498,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); - return; + return result; } if (maybeSlice && search_function(ad, Id.slice)) { @@ -529,7 +510,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (!e0 && !search_function(ad, Id.dollar)) { ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars()); } - return; + return result; } /* Rewrite a[i..j] as: * a.opSlice(i, j) @@ -544,7 +525,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = new CallExp(ae.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); - return; + return result; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) @@ -561,15 +542,17 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } ae.e1 = ae1old; // recovery ae.lengthVar = null; + return result; } /*********************************************** * This is mostly the same as UnaryExp::op_overload(), but has * a different rewrite. */ - override void visit(CastExp e) + Expression visitCast(CastExp e) { //printf("CastExp::op_overload() (%s)\n", e.toChars()); + Expression result; AggregateDeclaration ad = isAggregate(e.e1.type); if (ad) { @@ -586,8 +569,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (fd.isFuncDeclaration()) { // Rewrite as: e1.opCast() - result = build_overload(e.loc, sc, e.e1, null, fd); - return; + return build_overload(e.loc, sc, e.e1, null, fd); } } auto tiargs = new Objects(); @@ -595,7 +577,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); result = new CallExp(e.loc, result); result = result.expressionSemantic(sc); - return; + return result; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type)) @@ -608,13 +590,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = e.copy(); (cast(UnaExp)result).e1 = e1; result = result.op_overload(sc); - return; + return result; } } } + return result; } - override void visit(BinExp e) + Expression visitBin(BinExp e) { //printf("BinExp::op_overload() (%s)\n", e.toChars()); Identifier id = opId(e); @@ -635,7 +618,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) (sd.hasBlitAssign && !e.e2.isLvalue()))) { /* This is bitwise struct assignment. */ - return; + return null; } } Dsymbol s = null; @@ -645,7 +628,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { // Bug4099 fix if (ad1 && search_function(ad1, Id.opUnary)) - return; + return null; } if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus) { @@ -657,8 +640,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s && !s.isTemplateDeclaration()) { e.e1.error("`%s.opBinary` isn't a template", e.e1.toChars()); - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } if (ad2) @@ -667,8 +649,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s_r && !s_r.isTemplateDeclaration()) { e.e2.error("`%s.opBinaryRight` isn't a template", e.e2.toChars()); - result = ErrorExp.get(); - return; + return ErrorExp.get(); } if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778 s_r = null; @@ -735,8 +716,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } FuncDeclaration lastf = m.lastf; @@ -745,8 +725,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } if (m.count > 1) @@ -766,19 +745,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) // as unary, but it's implemented as a binary. // Rewrite (e1 ++ e2) as e1.postinc() // Rewrite (e1 -- e2) as e1.postdec() - result = build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s); + return build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s); } else if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch) { // Rewrite (e1 op e2) as e1.opfunc(e2) - result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); + return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); } else { // Rewrite (e1 op e2) as e2.opfunc_r(e1) - result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); + return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); } - return; } L1: version (all) @@ -820,8 +798,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } FuncDeclaration lastf = m.lastf; @@ -830,8 +807,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } if (m.count > 1) @@ -847,27 +823,26 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (lastf && m.lastf == lastf || !s && m.last == MATCH.nomatch) { // Rewrite (e1 op e2) as e1.opfunc_r(e2) - result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r); + return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r); } else { // Rewrite (e1 op e2) as e2.opfunc(e1) - result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s); + Expression result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s); // When reversing operands of comparison operators, // need to reverse the sense of the op if (pop) *pop = reverseRelation(e.op); + return result; } - return; } } } - Expression tempResult; + Expression rewrittenLhs; if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { - result = checkAliasThisForLhs(ad1, sc, e); - if (result) + if (Expression result = checkAliasThisForLhs(ad1, sc, e)) { /* https://issues.dlang.org/show_bug.cgi?id=19441 * @@ -880,43 +855,42 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis` * condition. */ - if (e.op != EXP.assign || e.e1.op == EXP.type) - return; + if (result.op != EXP.assign) + return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)` + + auto ae = result.isAssignExp(); + if (ae.e1.op != EXP.dotVariable) + return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2` - if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis)) + auto dve = ae.e1.isDotVarExp(); + if (auto ad = dve.var.isMember2()) { - auto var = ad1.aliasthis.sym.isVarDeclaration(); - if (var && var.type == ad1.fields[0].type) - return; - - auto func = ad1.aliasthis.sym.isFuncDeclaration(); - auto tf = cast(TypeFunction)(func.type); - if (tf.isref && ad1.fields[0].type == tf.next) - return; + // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2` + // Ensure that `var` is the only field member in `ad` + if (ad.fields.dim == 1 || (ad.fields.dim == 2 && ad.vthis)) + { + if (dve.var == ad.aliasthis.sym) + return result; + } } - tempResult = result; + rewrittenLhs = ae.e1; } } if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { - result = checkAliasThisForRhs(ad2, sc, e); - if (result) - return; + if (Expression result = checkAliasThisForRhs(ad2, sc, e)) + return result; } - - // @@@DEPRECATED_2019-02@@@ - // 1. Deprecation for 1 year - // 2. Turn to error after - if (tempResult) + if (rewrittenLhs) { - // move this line where tempResult is assigned to result and turn to error when derecation period is over - e.deprecation("Cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", e.e1.toChars(), ad1.toChars(), (cast(BinExp)tempResult).e1.toChars()); - // delete this line when deprecation period is over - result = tempResult; + e.error("cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", + e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars()); + return ErrorExp.get(); } + return null; } - override void visit(EqualExp e) + Expression visitEqual(EqualExp e) { //printf("EqualExp::op_overload() (%s)\n", e.toChars()); Type t1 = e.e1.type.toBasetype(); @@ -929,7 +903,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { - return; + return null; } /* Check for class equality with null literal or typeof(null). @@ -940,14 +914,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) e.error("use `%s` instead of `%s` when comparing with `null`", EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, EXPtoString(e.op).ptr); - result = ErrorExp.get(); - return; + return ErrorExp.get(); } if (t1.ty == Tclass && t2.ty == Tnull || t1.ty == Tnull && t2.ty == Tclass) { // Comparing a class with typeof(null) should not call opEquals - return; + return null; } /* Check for class equality. @@ -973,26 +946,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (cd2.isInterfaceDeclaration()) e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf()); - result = new IdentifierExp(e.loc, Id.empty); + Expression result = new IdentifierExp(e.loc, Id.empty); 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 == EXP.notEqual) result = new NotExp(e.loc, result); result = result.expressionSemantic(sc); - return; + return result; } } - result = compare_overload(e, sc, Id.eq, null); - if (result) + if (Expression result = compare_overload(e, sc, Id.eq, null)) { if (lastComma(result).op == EXP.call && e.op == EXP.notEqual) { result = new NotExp(result.loc, result); result = result.expressionSemantic(sc); } - return; + return result; } /* Check for pointer equality. @@ -1008,27 +980,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * as the backend input. */ 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; + Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2); + return r.expressionSemantic(sc); } /* Check for struct equality without opEquals. */ if (t1.ty == Tstruct && t2.ty == Tstruct) { - auto sd = (cast(TypeStruct)t1).sym; - if (sd != (cast(TypeStruct)t2).sym) - return; + auto sd = t1.isTypeStruct().sym; + if (sd != t2.isTypeStruct().sym) + return null; import dmd.clone : needOpEquals; if (!global.params.fieldwise && !needOpEquals(sd)) { // Use bitwise equality. 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; + Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2); + return r.expressionSemantic(sc); } /* Do memberwise equality. @@ -1042,10 +1012,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * also compare the parent class's equality. Otherwise, compares * the identity of parent context through void*. */ - if (e.att1 && t1.equivalent(e.att1)) return; - if (e.att2 && t2.equivalent(e.att2)) return; + if (e.att1 && t1.equivalent(e.att1)) return null; + if (e.att2 && t2.equivalent(e.att2)) return null; - e = cast(EqualExp)e.copy(); + e = e.copy().isEqualExp(); if (!e.att1) e.att1 = t1; if (!e.att2) e.att2 = t2; e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof); @@ -1053,38 +1023,38 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) auto sc2 = sc.push(); sc2.flags |= SCOPE.noaccesscheck; - result = e.expressionSemantic(sc2); + Expression r = e.expressionSemantic(sc2); sc2.pop(); /* https://issues.dlang.org/show_bug.cgi?id=15292 * if the rewrite result is same with the original, * the equality is unresolvable because it has recursive definition. */ - if (result.op == e.op && - (cast(EqualExp)result).e1.type.toBasetype() == t1) + if (r.op == e.op && + r.isEqualExp().e1.type.toBasetype() == t1) { e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition", t1.toChars()); - result = ErrorExp.get(); + return ErrorExp.get(); } - return; + return r; } /* Check for tuple equality. */ if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple) { - auto tup1 = cast(TupleExp)e.e1; - auto tup2 = cast(TupleExp)e.e2; + auto tup1 = e.e1.isTupleExp(); + auto tup2 = e.e2.isTupleExp(); size_t dim = tup1.exps.dim; if (dim != tup2.exps.dim) { e.error("mismatched tuple lengths, `%d` and `%d`", cast(int)dim, cast(int)tup2.exps.dim); - result = ErrorExp.get(); - return; + return ErrorExp.get(); } + Expression result; if (dim == 0) { // zero-length tuple comparison should always return true or false. @@ -1112,25 +1082,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = Expression.combine(tup1.e0, tup2.e0, result); result = result.expressionSemantic(sc); - return; + return result; } + return null; } - override void visit(CmpExp e) + Expression visitCmp(CmpExp e) { //printf("CmpExp:: () (%s)\n", e.toChars()); - result = compare_overload(e, sc, Id.cmp, pop); + return compare_overload(e, sc, Id.cmp, pop); } /********************************* * Operator overloading for op= */ - override void visit(BinAssignExp e) + Expression visitBinAssign(BinAssignExp e) { //printf("BinAssignExp::op_overload() (%s)\n", e.toChars()); - if (e.e1.op == EXP.array) + if (auto ae = e.e1.isArrayExp()) { - ArrayExp ae = cast(ArrayExp)e.e1; ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; @@ -1138,15 +1108,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == EXP.interval); - ie = cast(IntervalExp)(*ae.arguments)[0]; + ie = (*ae.arguments)[0].isIntervalExp(); } while (true) { if (ae.e1.op == EXP.error) { - result = ae.e1; - return; + return ae.e1; } Expression e0 = null; Expression ae1save = ae.e1; @@ -1158,14 +1126,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (search_function(ad, Id.opIndexOpAssign)) { // Deal with $ - result = resolveOpDollar(sc, ae, &e0); + Expression 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 == EXP.error) - return; + return result; result = e.e2.expressionSemantic(sc); if (result.op == EXP.error) - return; + return result; e.e2 = result; /* Rewrite a[arguments] op= e2 as: * a.opIndexOpAssign!(op)(e2, arguments) @@ -1181,20 +1149,19 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = result.expressionSemantic(sc); if (result) { - result = Expression.combine(e0, result); - return; + return Expression.combine(e0, result); } } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceOpAssign)) { // Deal with $ - result = resolveOpDollar(sc, ae, ie, &e0); + Expression result = resolveOpDollar(sc, ae, ie, &e0); if (result.op == EXP.error) - return; + return result; result = e.e2.expressionSemantic(sc); if (result.op == EXP.error) - return; + return result; e.e2 = result; /* Rewrite (a[i..j] op= e2) as: * a.opSliceOpAssign!(op)(e2, i, j) @@ -1211,7 +1178,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) result = new CallExp(e.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); - return; + return result; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) @@ -1228,14 +1195,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) ae.e1 = ae1old; // recovery ae.lengthVar = null; } - result = e.binSemanticProp(sc); + Expression result = e.binSemanticProp(sc); if (result) - return; + return result; // Don't attempt 'alias this' if an error occurred if (e.e1.type.ty == Terror || e.e2.type.ty == Terror) { - result = ErrorExp.get(); - return; + return ErrorExp.get(); } Identifier id = opId(e); Expressions args2; @@ -1250,8 +1216,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s && !s.isTemplateDeclaration()) { e.error("`%s.opOpAssign` isn't a template", e.e1.toChars()); - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } // Set tiargs, the template argument list, which will be the operator string @@ -1290,8 +1255,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { - result = ErrorExp.get(); - return; + return ErrorExp.get(); } } if (m.count > 1) @@ -1306,23 +1270,38 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) m.lastf = null; } // Rewrite (e1 op e2) as e1.opOpAssign(e2) - result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); - return; + return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); } L1: result = checkAliasThisForLhs(ad1, sc, e); if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs - return; + return result; - result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); + return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); } - } if (pop) *pop = e.op; - scope OpOverload v = new OpOverload(sc, pop); - e.accept(v); - return v.result; + + switch (e.op) + { + case EXP.cast_ : return visitCast(e.isCastExp()); + case EXP.array : return visitArray(e.isArrayExp()); + + case EXP.notEqual : + case EXP.equal : return visitEqual(e.isEqualExp()); + + case EXP.lessOrEqual : + case EXP.greaterThan : + case EXP.greaterOrEqual: + case EXP.lessThan : return visitCmp(cast(CmpExp)e); + + default: + if (auto ex = e.isBinAssignExp()) return visitBinAssign(ex); + if (auto ex = e.isBinExp()) return visitBin(ex); + if (auto ex = e.isUnaExp()) return visitUna(ex); + return visit(e); + } } /****************************************** @@ -1505,8 +1484,8 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out case Tclass: case Tstruct: { - AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym - : (cast(TypeStruct)tab).sym; + AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym + : tab.isTypeStruct().sym; if (!sliced) { sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse); @@ -1547,9 +1526,9 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out } case Tdelegate: // https://dlang.org/spec/statement.html#foreach_over_delegates - if (aggr.op == EXP.delegate_) + if (auto de = aggr.isDelegateExp()) { - sapply = (cast(DelegateExp)aggr).func; + sapply = de.func; } break; @@ -1600,7 +1579,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) else { assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_); - ethis = (cast(DelegateExp)fes.aggr).e1; + ethis = fes.aggr.isDelegateExp().e1; } /* Look for like an @@ -1613,7 +1592,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) if (fdapply) { // Fill in any missing types on foreach parameters[] - matchParamsToOpApply(cast(TypeFunction)fdapply.type, fes.parameters, true); + matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true); sapply = fdapply; return true; } @@ -1649,7 +1628,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) case Taarray: { - TypeAArray taa = cast(TypeAArray)tab; + TypeAArray taa = tab.isTypeAArray(); if (fes.parameters.dim == 2) { if (!p.type) @@ -1672,8 +1651,8 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) case Tclass: case Tstruct: { - AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym - : (cast(TypeStruct)tab).sym; + AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym + : tab.isTypeStruct().sym; if (fes.parameters.dim == 1) { if (!p.type) @@ -1697,7 +1676,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) { } else if (s && s.isDeclaration()) - p.type = (cast(Declaration)s).type; + p.type = s.isDeclaration().type; else break; } @@ -1707,9 +1686,12 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) } case Tdelegate: - if (!matchParamsToOpApply(cast(TypeFunction)tab.nextOf(), fes.parameters, true)) + { + auto td = tab.isTypeDelegate(); + if (!matchParamsToOpApply(td.next.isTypeFunction(), fes.parameters, true)) return false; break; + } default: break; // ignore error, caught later @@ -1738,7 +1720,7 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f auto f = s.isFuncDeclaration(); if (!f) return 0; // continue - auto tf = cast(TypeFunction)f.type; + auto tf = f.type.isTypeFunction(); MATCH m = MATCH.exact; if (f.isThis()) { @@ -1825,10 +1807,10 @@ private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool /* Get the type of opApply's dg parameter */ Parameter p0 = tf.parameterList[0]; - if (p0.type.ty != Tdelegate) + auto de = p0.type.isTypeDelegate(); + if (!de) return nomatch; - TypeFunction tdg = cast(TypeFunction)p0.type.nextOf(); - assert(tdg.ty == Tfunction); + TypeFunction tdg = de.next.isTypeFunction(); /* We now have tdg, the type of the delegate. * tdg's parameters must match that of the foreach arglist (i.e. parameters). diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 5b4ebd7..3653aa8 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -631,13 +631,6 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) { expOptimize(e.thisexp, WANTvalue); // Optimize parameters - if (e.newargs) - { - for (size_t i = 0; i < e.newargs.dim; i++) - { - expOptimize((*e.newargs)[i], WANTvalue); - } - } if (e.arguments) { for (size_t i = 0; i < e.arguments.dim; i++) diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 63afeb2..e83b326 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -28,268 +28,6 @@ import dmd.root.rootobject; import dmd.root.string; import dmd.tokens; -// How multiple declarations are parsed. -// If 1, treat as C. -// If 0, treat: -// int *p, i; -// as: -// int* p; -// int* i; -private enum CDECLSYNTAX = 0; - -// Support C cast syntax: -// (type)(expression) -private enum CCASTSYNTAX = 1; - -// Support postfix C array declarations, such as -// int a[3][4]; -private enum CARRAYDECL = 1; - -/********************************** - * Set operator precedence for each operator. - * - * Used by hdrgen - */ -immutable PREC[EXP.max + 1] precedence = -[ - 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 - 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.throw_ : 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. - */ - 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 -{ - semi = 1, // empty ';' statements are allowed, but deprecated - scope_ = 2, // start a new scope - curly = 4, // { } statement is required - curlyScope = 8, // { } starts a new scope - semiOk = 0x10, // empty ';' are really ok -} - -struct PrefixAttributes(AST) -{ - StorageClass storageClass; - AST.Expression depmsg; - LINK link; - AST.Visibility visibility; - bool setAlignment; - AST.Expression ealign; - AST.Expressions* udas; - const(char)* comment; -} - -/// The result of the `ParseLinkage` function -struct ParsedLinkage(AST) -{ - /// What linkage was specified - LINK link; - /// If `extern(C++, class|struct)`, contains the `class|struct` - CPPMANGLE cppmangle; - /// If `extern(C++, some.identifier)`, will be the identifiers - AST.Identifiers* idents; - /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions - AST.Expressions* identExps; -} - -/***************************** - * Destructively extract storage class from pAttrs. - */ -private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs) -{ - StorageClass stc = STC.undefined_; - if (pAttrs) - { - stc = pAttrs.storageClass; - pAttrs.storageClass = STC.undefined_; - } - return stc; -} - -/************************************** - * dump mixin expansion to file for better debugging - */ -private bool writeMixin(const(char)[] s, ref Loc loc) -{ - if (!global.params.mixinOut) - return false; - - OutBuffer* ob = global.params.mixinOut; - - ob.writestring("// expansion at "); - ob.writestring(loc.toChars()); - ob.writenl(); - - global.params.mixinLines++; - - loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum); - - // write by line to create consistent line endings - size_t lastpos = 0; - for (size_t i = 0; i < s.length; ++i) - { - // detect LF and CRLF - const c = s[i]; - if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n')) - { - ob.writestring(s[lastpos .. i]); - ob.writenl(); - global.params.mixinLines++; - if (c == '\r') - ++i; - lastpos = i + 1; - } - } - - if(lastpos < s.length) - ob.writestring(s[lastpos .. $]); - - if (s.length == 0 || s[$-1] != '\n') - { - ob.writenl(); // ensure empty line after expansion - global.params.mixinLines++; - } - ob.writenl(); - global.params.mixinLines++; - - return true; -} - /*********************************************************** */ class Parser(AST) : Lexer @@ -344,80 +82,49 @@ class Parser(AST) : Lexer //nextToken(); // start up the scanner } + /++ + + Parse a module, i.e. the optional `module x.y.z` declaration and all declarations + + found in the current file. + + + + Returns: the list of declarations or an empty list in case of malformed declarations, + + the module declaration will be stored as `this.md` if found + +/ AST.Dsymbols* parseModule() { + if (!parseModuleDeclaration()) + return errorReturn(); + + return parseModuleContent(); + } + + /++ + + Parse the optional module declaration + + + + Returns: false if a malformed module declaration was found + +/ + final bool parseModuleDeclaration() + { const comment = token.blockComment; bool isdeprecated = false; AST.Expression msg = null; - AST.Expressions* udas = null; - AST.Dsymbols* decldefs; - AST.Dsymbol lastDecl = mod; // for attaching ddoc unittests to module decl - - Token* tk; - if (skipAttributes(&token, &tk) && tk.value == TOK.module_) - { - while (token.value != TOK.module_) - { - switch (token.value) - { - case TOK.deprecated_: - { - // deprecated (...) module ... - if (isdeprecated) - error("there is only one deprecation attribute allowed for module declaration"); - isdeprecated = true; - nextToken(); - if (token.value == TOK.leftParenthesis) - { - check(TOK.leftParenthesis); - msg = parseAssignExp(); - check(TOK.rightParenthesis); - } - break; - } - case TOK.at: - { - AST.Expressions* exps = null; - const stc = parseAttribute(exps); - if (stc & atAttrGroup) - { - error("`@%s` attribute for module declaration is not supported", token.toChars()); - } - else - { - udas = AST.UserAttributeDeclaration.concat(udas, exps); - } - if (stc) - nextToken(); - break; - } - default: - { - error("`module` expected instead of `%s`", token.toChars()); - nextToken(); - break; - } - } - } - } - if (udas) - { - auto a = new AST.Dsymbols(); - auto udad = new AST.UserAttributeDeclaration(udas, a); - mod.userAttribDecl = udad; - } + // Parse optional module attributes + parseModuleAttributes(msg, isdeprecated); - // ModuleDeclation leads off + // ModuleDeclaration leads off if (token.value == TOK.module_) { const loc = token.loc; - nextToken(); + + /* parse ModuleFullyQualifiedName + * https://dlang.org/spec/module.html#ModuleFullyQualifiedName + */ + if (token.value != TOK.identifier) { error("identifier expected following `module`"); - goto Lerr; + return false; } Identifier[] a; @@ -430,7 +137,7 @@ class Parser(AST) : Lexer if (token.value != TOK.identifier) { error("identifier expected following `package`"); - goto Lerr; + return false; } id = token.ident; } @@ -442,29 +149,115 @@ class Parser(AST) : Lexer nextToken(); addComment(mod, comment); } + return true; + } - decldefs = parseDeclDefs(0, &lastDecl); + /++ + + Parse the content of a module, i.e. all declarations found until the end of file. + + + + Returns: the list of declarations or an empty list in case of malformed declarations + +/ + final AST.Dsymbols* parseModuleContent() + { + AST.Dsymbol lastDecl = mod; + AST.Dsymbols* decldefs = parseDeclDefs(0, &lastDecl); if (token.value == TOK.rightCurly) { error(token.loc, "unmatched closing brace"); - goto Lerr; + return errorReturn(); } if (token.value != TOK.endOfFile) { error(token.loc, "unrecognized declaration"); - goto Lerr; + return errorReturn(); } return decldefs; + } - Lerr: + /++ + + Skips to the end of the current declaration - denoted by either `;` or EOF + + + + Returns: An empty list of Dsymbols + +/ + private AST.Dsymbols* errorReturn() + { while (token.value != TOK.semicolon && token.value != TOK.endOfFile) nextToken(); nextToken(); return new AST.Dsymbols(); } + /********************************** + * Parse the ModuleAttributes preceding a module declaration. + * ModuleDeclaration: + * ModuleAttributes(opt) module ModuleFullyQualifiedName ; + * https://dlang.org/spec/module.html#ModuleAttributes + * Params: + * msg = set to the AssignExpression from DeprecatedAttribute https://dlang.org/spec/module.html#DeprecatedAttribute + * isdeprecated = set to true if a DeprecatedAttribute is seen + */ + private + void parseModuleAttributes(out AST.Expression msg, out bool isdeprecated) + { + Token* tk; + if (!(skipAttributes(&token, &tk) && tk.value == TOK.module_)) + return; // no module attributes + + AST.Expressions* udas = null; + while (token.value != TOK.module_) + { + switch (token.value) + { + case TOK.deprecated_: + { + // deprecated (...) module ... + if (isdeprecated) + error("there is only one deprecation attribute allowed for module declaration"); + isdeprecated = true; + nextToken(); + if (token.value == TOK.leftParenthesis) + { + check(TOK.leftParenthesis); + msg = parseAssignExp(); + check(TOK.rightParenthesis); + } + break; + } + case TOK.at: + { + AST.Expressions* exps = null; + const stc = parseAttribute(exps); + if (stc & atAttrGroup) + { + error("`@%s` attribute for module declaration is not supported", token.toChars()); + } + else + { + udas = AST.UserAttributeDeclaration.concat(udas, exps); + } + if (stc) + nextToken(); + break; + } + default: + { + error("`module` expected instead of `%s`", token.toChars()); + nextToken(); + break; + } + } + } + + if (udas) + { + auto a = new AST.Dsymbols(); + auto udad = new AST.UserAttributeDeclaration(udas, a); + mod.userAttribDecl = udad; + } + } + final: /** @@ -914,7 +707,7 @@ class Parser(AST) : Lexer tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo || tk.value == TOK.identifier && tk.ident == Id._body)) { - // @@@DEPRECATED@@@ + // @@@DEPRECATED_2.117@@@ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md // Deprecated in 2.097 - Can be removed from 2.117 // The deprecation period is longer than usual as `body` @@ -1418,6 +1211,15 @@ class Parser(AST) : Lexer */ private StorageClass appendStorageClass(StorageClass orig, StorageClass added) { + void checkConflictSTCGroup(bool at = false)(StorageClass group) + { + if (added & group && orig & group & ((orig & group) - 1)) + error( + at ? "conflicting attribute `@%s`" + : "conflicting attribute `%s`", + token.toChars()); + } + if (orig & added) { OutBuffer buf; @@ -1460,24 +1262,9 @@ class Parser(AST) : Lexer return orig; } - if (added & (STC.const_ | STC.immutable_ | STC.manifest)) - { - StorageClass u = orig & (STC.const_ | STC.immutable_ | STC.manifest); - if (u & (u - 1)) - error("conflicting attribute `%s`", Token.toChars(token.value)); - } - if (added & (STC.gshared | STC.shared_ | STC.tls)) - { - StorageClass u = orig & (STC.gshared | STC.shared_ | STC.tls); - if (u & (u - 1)) - error("conflicting attribute `%s`", Token.toChars(token.value)); - } - if (added & STC.safeGroup) - { - StorageClass u = orig & STC.safeGroup; - if (u & (u - 1)) - error("conflicting attribute `@%s`", token.toChars()); - } + checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest); + checkConflictSTCGroup(STC.gshared | STC.shared_ | STC.tls); + checkConflictSTCGroup!true(STC.safeGroup); return orig; } @@ -2885,7 +2672,7 @@ class Parser(AST) : Lexer } nextToken(); - /* @@@DEPRECATED_2.098@@@ + /* @@@DEPRECATED_2.108@@@ * After deprecation period (2.108), remove all code in the version(all) block. */ version (all) @@ -4614,7 +4401,7 @@ class Parser(AST) : Lexer (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { - // @@@DEPRECATED@@@ + // @@@DEPRECATED_2.117@@@ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md // Deprecated in 2.097 - Can be removed from 2.117 // The deprecation period is longer than usual as `body` @@ -5028,12 +4815,18 @@ class Parser(AST) : Lexer // parseAttributes shouldn't have set these variables assert(link == linkage && !setAlignment && ealign is null); auto tpl_ = cast(AST.TemplateDeclaration) s; - assert(tpl_ !is null && tpl_.members.dim == 1); - auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0]; - auto tf = cast(AST.TypeFunction) fd.type; - assert(tf.parameterList.parameters.dim > 0); - auto as = new AST.Dsymbols(); - (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as); + if (tpl_ is null || tpl_.members.dim != 1) + { + error("user-defined attributes are not allowed on `alias` declarations"); + } + else + { + auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0]; + auto tf = cast(AST.TypeFunction) fd.type; + assert(tf.parameterList.parameters.dim > 0); + auto as = new AST.Dsymbols(); + (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as); + } } v = new AST.AliasDeclaration(loc, ident, s); @@ -5060,7 +4853,7 @@ class Parser(AST) : Lexer { OutBuffer buf; AST.stcToBuffer(&buf, remStc); - // @@@DEPRECATED_2.093@@@ + // @@@DEPRECATED_2.103@@@ // Deprecated in 2020-07, can be made an error in 2.103 deprecation("storage class `%s` has no effect in type aliases", buf.peekChars()); } @@ -5287,7 +5080,7 @@ class Parser(AST) : Lexer case TOK.identifier: if (token.ident == Id._body) { - // @@@DEPRECATED@@@ + // @@@DEPRECATED_2.117@@@ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md // Deprecated in 2.097 - Can be removed from 2.117 // The deprecation period is longer than usual as `body` @@ -7607,7 +7400,7 @@ LagainStc: case TOK.identifier: if (t.ident == Id._body) { - // @@@DEPRECATED@@@ + // @@@DEPRECATED_2.117@@@ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md // Deprecated in 2.097 - Can be removed from 2.117 // The deprecation period is longer than usual as `body` @@ -8652,6 +8445,9 @@ LagainStc: break; case TOK.delete_: + // @@@DEPRECATED_2.109@@@ + // Use of `delete` keyword has been an error since 2.099. + // Remove from the parser after 2.109. nextToken(); e = parseUnaryExp(); e = new AST.DeleteExp(loc, e, false); @@ -9409,12 +9205,7 @@ LagainStc: const loc = token.loc; nextToken(); - AST.Expressions* newargs = null; AST.Expressions* arguments = null; - if (token.value == TOK.leftParenthesis) - { - newargs = parseArguments(); - } // An anonymous nested class starts with "class" if (token.value == TOK.class_) @@ -9444,7 +9235,7 @@ LagainStc: } auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false); - auto e = new AST.NewAnonClassExp(loc, thisexp, newargs, cd, arguments); + auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments); return e; } @@ -9469,7 +9260,7 @@ LagainStc: arguments = parseArguments(); } - auto e = new AST.NewExp(loc, thisexp, newargs, t, arguments); + auto e = new AST.NewExp(loc, thisexp, t, arguments); return e; } @@ -9519,7 +9310,7 @@ LagainStc: STC.live | /*STC.future |*/ // probably should be included STC.disable; - } +} enum PREC : int { @@ -9541,3 +9332,276 @@ enum PREC : int unary, primary, } + +/********************************** + * Set operator precedence for each operator. + * + * Used by hdrgen + */ +immutable PREC[EXP.max + 1] precedence = +[ + 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 + 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.throw_ : 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. + */ + 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 +{ + semi = 1, // empty ';' statements are allowed, but deprecated + scope_ = 2, // start a new scope + curly = 4, // { } statement is required + curlyScope = 8, // { } starts a new scope + semiOk = 0x10, // empty ';' are really ok +} + +struct PrefixAttributes(AST) +{ + StorageClass storageClass; + AST.Expression depmsg; + LINK link; + AST.Visibility visibility; + bool setAlignment; + AST.Expression ealign; + AST.Expressions* udas; + const(char)* comment; +} + +/// The result of the `ParseLinkage` function +struct ParsedLinkage(AST) +{ + /// What linkage was specified + LINK link; + /// If `extern(C++, class|struct)`, contains the `class|struct` + CPPMANGLE cppmangle; + /// If `extern(C++, some.identifier)`, will be the identifiers + AST.Identifiers* idents; + /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions + AST.Expressions* identExps; +} + + +/*********************************** Private *************************************/ + +/*********************** + * How multiple declarations are parsed. + * If 1, treat as C. + * If 0, treat: + * int *p, i; + * as: + * int* p; + * int* i; + */ +private enum CDECLSYNTAX = 0; + +/***** + * Support C cast syntax: + * (type)(expression) + */ +private enum CCASTSYNTAX = 1; + +/***** + * Support postfix C array declarations, such as + * int a[3][4]; + */ +private enum CARRAYDECL = 1; + +/***************************** + * Destructively extract storage class from pAttrs. + */ +private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs) +{ + StorageClass stc = STC.undefined_; + if (pAttrs) + { + stc = pAttrs.storageClass; + pAttrs.storageClass = STC.undefined_; + } + return stc; +} + +/************************************** + * dump mixin expansion to file for better debugging + */ +private bool writeMixin(const(char)[] s, ref Loc loc) +{ + if (!global.params.mixinOut) + return false; + + OutBuffer* ob = global.params.mixinOut; + + ob.writestring("// expansion at "); + ob.writestring(loc.toChars()); + ob.writenl(); + + global.params.mixinLines++; + + loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum); + + // write by line to create consistent line endings + size_t lastpos = 0; + for (size_t i = 0; i < s.length; ++i) + { + // detect LF and CRLF + const c = s[i]; + if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n')) + { + ob.writestring(s[lastpos .. i]); + ob.writenl(); + global.params.mixinLines++; + if (c == '\r') + ++i; + lastpos = i + 1; + } + } + + if(lastpos < s.length) + ob.writestring(s[lastpos .. $]); + + if (s.length == 0 || s[$-1] != '\n') + { + ob.writenl(); // ensure empty line after expansion + global.params.mixinLines++; + } + ob.writenl(); + global.params.mixinLines++; + + return true; +} + + diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index 6133145..571c3fc 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -122,6 +122,16 @@ extern (C++) final class PrintASTVisitor : Visitor printAST(e.e1, indent + 2); } + override void visit(CastExp e) + { + printIndent(indent); + auto s = EXPtoString(e.op); + printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : ""); + printIndent(indent + 2); + printf(".to: %s\n", e.to.toChars()); + printAST(e.e1, indent + 2); + } + override void visit(VectorExp e) { printIndent(indent); diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index f36cdc9..85c4d5b 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -422,7 +422,7 @@ private extern(C++) final class Semantic2Visitor : Visitor const sameParams = tf1.parameterList == tf2.parameterList; // Allow the hack to declare overloads with different parameters/STC's - // @@@DEPRECATED_2.094@@@ + // @@@DEPRECATED_2.104@@@ // Deprecated in 2020-08, make this an error in 2.104 if (parent1.isModule() && f1.linkage != LINK.d && f1.linkage != LINK.cpp && diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 7bcb7ec..3f01966 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -377,6 +377,12 @@ private extern(C++) final class Semantic3Visitor : Visitor // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710 // No compiler supports this, and there was never any spec for it. + // @@@DEPRECATED_2.116@@@ + // Deprecated in 2.096, can be made an error in 2.116. + // The deprecation period is longer than usual as dual-context + // functions may be widely used by dmd-compiled projects. + // It also gives more time for the implementation of dual-context + // functions to be reworked as a frontend-only feature. if (funcdecl.isThis2) { funcdecl.deprecation("function requires a dual-context, which is deprecated"); @@ -746,7 +752,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // Check for errors related to 'nothrow'. const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow); if (f.isnothrow && blockexit & BE.throw_) - error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars()); + error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars()); if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches)) { @@ -1146,14 +1152,16 @@ private extern(C++) final class Semantic3Visitor : Visitor s = s.statementSemantic(sc2); - bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess); + immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess); const blockexit = s.blockExit(funcdecl, isnothrow); if (blockexit & BE.throw_) + { funcdecl.eh_none = false; - if (f.isnothrow && isnothrow && blockexit & BE.throw_) - error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars()); - if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_) - f.isnothrow = false; + if (isnothrow) + error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars()); + else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + f.isnothrow = false; + } if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru) sbody = new CompoundStatement(Loc.initial, sbody, s); @@ -1402,7 +1410,7 @@ private extern(C++) final class Semantic3Visitor : Visitor auto sexp = new ExpStatement(ctor.loc, ce); auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc); - // @@@DEPRECATED_2096@@@ + // @@@DEPRECATED_2.106@@@ // Allow negligible attribute violations to allow for a smooth // transition. Remove this after the usual deprecation period // after 2.106. diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 1f7f3e4..5dbe5b6 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -1608,7 +1608,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor * Params: * sc = context * fs = ForeachStatement - * tfld = type of function literal to be created, can be null + * tfld = type of function literal to be created (type of opApply() function if any), can be null * Returns: * Function literal created, as an expression * null if error. @@ -1619,7 +1619,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor foreach (i; 0 .. fs.parameters.dim) { Parameter p = (*fs.parameters)[i]; - StorageClass stc = STC.ref_; + StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_); Identifier id; p.type = p.type.typeSemantic(fs.loc, sc); @@ -1628,17 +1628,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor { Parameter prm = tfld.parameterList[i]; //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars()); - stc = prm.storageClass & STC.ref_; - id = p.ident; // argument copy is not need. - if ((p.storageClass & STC.ref_) != stc) + stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_); + if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_)) { - if (!stc) + if (!(prm.storageClass & STC.ref_)) { fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars()); return null; } goto LcopyArg; } + id = p.ident; // argument copy is not need. } else if (p.storageClass & STC.ref_) { @@ -1655,7 +1655,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id)); auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie); - v.storage_class |= STC.temp; + v.storage_class |= STC.temp | (stc & STC.scope_); Statement s = new ExpStatement(fs.loc, v); fs._body = new CompoundStatement(fs.loc, s, fs._body); } @@ -3567,7 +3567,6 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor tcs.tryBody = sc.tryBody; // chain on the in-flight tryBody tcs._body = tcs._body.semanticScope(sc, null, null, tcs); - assert(tcs._body); /* Even if body is empty, still do semantic analysis on catches */ @@ -3610,6 +3609,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor if (catchErrors) return setError(); + // No actual code in the try (i.e. omitted any conditionally compiled code) + // Could also be extended to check for hasCode + if (!tcs._body) + return; + if (tcs._body.isErrorStatement()) { result = tcs._body; @@ -4764,161 +4768,71 @@ private Statements* flatten(Statement statement, Scope* sc) } /*********************************************************** - * Convert TemplateMixin members (== Dsymbols) to Statements. + * Convert TemplateMixin members (which are Dsymbols) to Statements. + * Params: + * s = the symbol to convert to a Statement + * Returns: + * s redone as a Statement */ private Statement toStatement(Dsymbol s) { - extern (C++) final class ToStmt : Visitor - { - alias visit = Visitor.visit; - public: - Statement result; - - Statement visitMembers(Loc loc, Dsymbols* a) - { - if (!a) - return null; - - auto statements = new Statements(); - foreach (s; *a) - { - statements.push(toStatement(s)); - } - return new CompoundStatement(loc, statements); - } + Statement result; - override void visit(Dsymbol s) + if (auto tm = s.isTemplateMixin()) + { + auto a = new Statements(); + foreach (m; *tm.members) { - .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars()); - result = new ErrorStatement(); + if (Statement sx = toStatement(m)) + a.push(sx); } - - override void visit(TemplateMixin tm) - { - auto a = new Statements(); - foreach (m; *tm.members) - { - Statement s = toStatement(m); - if (s) - a.push(s); - } - result = new CompoundStatement(tm.loc, a); - } - + result = new CompoundStatement(tm.loc, a); + } + else if (s.isVarDeclaration() || + s.isAggregateDeclaration() || + s.isFuncDeclaration() || + s.isEnumDeclaration() || + s.isAliasDeclaration() || + s.isTemplateDeclaration()) + { + /* Perhaps replace the above with isScopeDsymbol() || isDeclaration() + */ /* An actual declaration symbol will be converted to DeclarationExp * with ExpStatement. */ - Statement declStmt(Dsymbol s) - { - auto de = new DeclarationExp(s.loc, s); - de.type = Type.tvoid; // avoid repeated semantic - return new ExpStatement(s.loc, de); - } - - override void visit(VarDeclaration d) - { - result = declStmt(d); - } - - override void visit(AggregateDeclaration d) - { - result = declStmt(d); - } - - override void visit(FuncDeclaration d) - { - result = declStmt(d); - } - - override void visit(EnumDeclaration d) - { - result = declStmt(d); - } - - override void visit(AliasDeclaration d) - { - result = declStmt(d); - } - - override void visit(TemplateDeclaration d) - { - result = declStmt(d); - } - + auto de = new DeclarationExp(s.loc, s); + de.type = Type.tvoid; // avoid repeated semantic + result = new ExpStatement(s.loc, de); + } + else if (auto d = s.isAttribDeclaration()) + { /* All attributes have been already picked by the semantic analysis of * 'bottom' declarations (function, struct, class, etc). * So we don't have to copy them. */ - override void visit(StorageClassDeclaration d) - { - result = visitMembers(d.loc, d.decl); - } - - override void visit(DeprecatedDeclaration d) - { - result = visitMembers(d.loc, d.decl); - } - - override void visit(LinkDeclaration d) - { - result = visitMembers(d.loc, d.decl); - } - - override void visit(VisibilityDeclaration d) - { - result = visitMembers(d.loc, d.decl); - } - - override void visit(AlignDeclaration d) + if (Dsymbols* a = d.include(null)) { - result = visitMembers(d.loc, d.decl); - } - - override void visit(UserAttributeDeclaration d) - { - result = visitMembers(d.loc, d.decl); - } - - override void visit(ForwardingAttribDeclaration d) - { - result = visitMembers(d.loc, d.decl); - } - - override void visit(StaticAssert s) - { - } - - override void visit(Import s) - { - } - - override void visit(PragmaDeclaration d) - { - } - - override void visit(ConditionalDeclaration d) - { - result = visitMembers(d.loc, d.include(null)); - } - - override void visit(StaticForeachDeclaration d) - { - assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe); - result = visitMembers(d.loc, d.include(null)); - } - - override void visit(CompileDeclaration d) - { - result = visitMembers(d.loc, d.include(null)); + auto statements = new Statements(); + foreach (sx; *a) + { + statements.push(toStatement(sx)); + } + result = new CompoundStatement(d.loc, statements); } } + else if (s.isStaticAssert() || + s.isImport()) + { + /* Ignore as they are not Statements + */ + } + else + { + .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars()); + result = new ErrorStatement(); + } - if (!s) - return null; - - scope ToStmt v = new ToStmt(); - s.accept(v); - return v.result; + return result; } /** diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d index 7daf7cd..c7d3148 100644 --- a/gcc/d/dmd/staticassert.d +++ b/gcc/d/dmd/staticassert.d @@ -59,6 +59,11 @@ extern (C++) final class StaticAssert : Dsymbol return "static assert"; } + override inout(StaticAssert) isStaticAssert() inout + { + return this; + } + override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h index 5c00b46..38142bc 100644 --- a/gcc/d/dmd/staticassert.h +++ b/gcc/d/dmd/staticassert.h @@ -24,5 +24,6 @@ public: void addMember(Scope *sc, ScopeDsymbol *sds); bool oneMember(Dsymbol **ps, Identifier *ident); const char *kind() const; + StaticAssert *isStaticAssert() { return this; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 20b8711..9c24df0 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -35,7 +35,6 @@ enum TOK : ubyte leftCurly, rightCurly, colon, - negate, semicolon, dotDotDot, endOfFile, @@ -44,26 +43,18 @@ enum TOK : ubyte assert_, true_, false_, - array, - call, - address, - type, throw_, new_, delete_, - star, variable, slice, version_, module_, dollar, template_, - declaration, typeof_, pragma_, typeid_, - uadd, - remove, comment, // Operators @@ -75,7 +66,6 @@ enum TOK : ubyte notEqual, identity, notIdentity, - index, is_, leftShift, @@ -281,6 +271,7 @@ enum TOK : ubyte _import, __cdecl, __declspec, + __stdcall, __attribute__, } @@ -589,6 +580,7 @@ private immutable TOK[] keywords = TOK._import, TOK.__cdecl, TOK.__declspec, + TOK.__stdcall, TOK.__attribute__, ]; @@ -617,7 +609,7 @@ static immutable TOK[TOK.max + 1] Ckeywords = restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_, union_, unsigned, void_, volatile, while_, asm_, _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, - _Static_assert, _Thread_local, _import, __cdecl, __declspec, __attribute__ ]; + _Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __attribute__ ]; foreach (kw; Ckwds) tab[kw] = cast(TOK) kw; @@ -805,18 +797,11 @@ extern (C++) struct Token TOK.andAnd: "&&", TOK.or: "|", TOK.orOr: "||", - TOK.array: "[]", - TOK.index: "[i]", - TOK.address: "&", - TOK.star: "*", TOK.tilde: "~", TOK.dollar: "$", TOK.plusPlus: "++", TOK.minusMinus: "--", - TOK.type: "type", TOK.question: "?", - TOK.negate: "-", - TOK.uadd: "+", TOK.variable: "var", TOK.addAssign: "+=", TOK.minAssign: "-=", @@ -829,7 +814,6 @@ extern (C++) struct Token TOK.andAssign: "&=", TOK.orAssign: "|=", TOK.concatenateAssign: "~=", - TOK.call: "call", TOK.identity: "is", TOK.notIdentity: "!is", TOK.identifier: "identifier", @@ -844,14 +828,12 @@ extern (C++) struct Token // For debugging TOK.error: "error", TOK.string_: "string", - TOK.declaration: "declaration", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", TOK.onScopeFailure: "scope(failure)", // Finish up TOK.reserved: "reserved", - TOK.remove: "remove", TOK.comment: "comment", TOK.int32Literal: "int32v", TOK.uns32Literal: "uns32v", @@ -896,6 +878,7 @@ extern (C++) struct Token TOK._import : "__import", TOK.__cdecl : "__cdecl", TOK.__declspec : "__declspec", + TOK.__stdcall : "__stdcall", TOK.__attribute__ : "__attribute__", ]; @@ -963,12 +946,20 @@ nothrow: sprintf(&buffer[0], "%d", cast(d_int32)intvalue); break; case TOK.uns32Literal: - case TOK.charLiteral: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.wchar_tLiteral: sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue); break; + case TOK.charLiteral: + { + const v = cast(d_int32)intvalue; + if (v >= ' ' && v <= '~') + sprintf(&buffer[0], "'%c'", v); + else + sprintf(&buffer[0], "'\\x%02x'", v); + break; + } case TOK.int64Literal: sprintf(&buffer[0], "%lldL", cast(long)intvalue); break; @@ -1006,29 +997,7 @@ nothrow: { dchar c; utf_decodeChar(ustring[0 .. len], i, c); - switch (c) - { - case 0: - break; - case '"': - case '\\': - buf.writeByte('\\'); - goto default; - default: - if (c <= 0x7F) - { - if (isprint(c)) - buf.writeByte(c); - else - buf.printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf.printf("\\u%04x", c); - else - buf.printf("\\U%08x", c); - continue; - } - break; + writeCharLiteral(buf, c); } buf.writeByte('"'); if (postfix) @@ -1103,3 +1072,64 @@ nothrow: } } +/** + * Write a character, using a readable escape sequence if needed + * + * Useful for printing "" string literals in e.g. error messages, ddoc, or the `.stringof` property + * + * Params: + * buf = buffer to append character in + * c = code point to write + */ +nothrow +void writeCharLiteral(ref OutBuffer buf, dchar c) +{ + switch (c) + { + case '\0': + buf.writestring("\\0"); + break; + case '\n': + buf.writestring("\\n"); + break; + case '\r': + buf.writestring("\\r"); + break; + case '\t': + buf.writestring("\\t"); + break; + case '\b': + buf.writestring("\\b"); + break; + case '\f': + buf.writestring("\\f"); + break; + case '"': + case '\\': + buf.writeByte('\\'); + goto default; + default: + if (c <= 0x7F) + { + if (isprint(c)) + buf.writeByte(c); + else + buf.printf("\\x%02x", c); + } + else if (c <= 0xFFFF) + buf.printf("\\u%04x", c); + else + buf.printf("\\U%08x", c); + break; + } +} + +unittest +{ + OutBuffer buf; + foreach(dchar d; "a\n\r\t\b\f\0\x11\u7233\U00017233"d) + { + writeCharLiteral(buf, d); + } + assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`); +} diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index a7c9aa5..a9f5028 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -44,7 +44,6 @@ enum class TOK : unsigned char leftCurly, rightCurly, colon, - negate, semicolon, dotDotDot, endOfFile, @@ -53,26 +52,18 @@ enum class TOK : unsigned char assert_, true_, false_, - array, - call, - address, - type, throw_, new_, delete_, - star, variable, slice, version_, module_, dollar, template_, - declaration, typeof_, pragma_, typeid_, - uadd, - remove, comment, // Operators @@ -84,7 +75,6 @@ enum class TOK : unsigned char notEqual, identity, notIdentity, - index, is_, leftShift, // 64 @@ -288,8 +278,9 @@ enum class TOK : unsigned char // C only extended keywords _import, - cdecl, + cdecl_, declspec, + stdcall, attribute__, MAX, diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 8b6ca65..615c49f 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -961,8 +961,6 @@ package mixin template ParseVisitMethods(AST) //printf("Visiting NewExp\n"); if (e.thisexp) e.thisexp.accept(this); - if (e.newargs && e.newargs.dim) - visitArgs(e.newargs); visitType(e.newtype); if (e.arguments && e.arguments.dim) visitArgs(e.arguments); @@ -973,8 +971,6 @@ package mixin template ParseVisitMethods(AST) //printf("Visiting NewAnonClassExp\n"); if (e.thisexp) e.thisexp.accept(this); - if (e.newargs && e.newargs.dim) - visitArgs(e.newargs); if (e.arguments && e.arguments.dim) visitArgs(e.arguments); if (e.cd) diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index e11f1f7..637b32e 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -210,6 +210,9 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars()); else if (const q = Scope.search_correct_C(id)) error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q); + else if ((id == Id.This && sc.getStructClassScope()) || + (id == Id._super && sc.getClassScope())) + error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p); else error(loc, "undefined identifier `%s`", p); @@ -273,7 +276,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb // Same check as in Expression.semanticY(DotIdExp) else if (sm.isPackage() && checkAccess(sc, sm.isPackage())) { - // @@@DEPRECATED_2.096@@@ + // @@@DEPRECATED_2.106@@@ // Should be an error in 2.106. Just remove the deprecation call // and uncomment the null assignment deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars()); @@ -2040,6 +2043,22 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) return mtype.resolved; } + /* Find the current scope by skipping tag scopes. + * In C, tag scopes aren't considered scopes. + */ + Scope* sc2 = sc; + while (1) + { + sc2 = sc2.inner(); + auto scopesym = sc2.scopesym; + if (scopesym.isStructDeclaration()) + { + sc2 = sc2.enclosing; + continue; + } + break; + } + /* Declare mtype as a struct/union/enum declaration */ void declareTag() @@ -2047,16 +2066,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) void declare(ScopeDsymbol sd) { sd.members = mtype.members; - auto scopesym = sc.inner().scopesym; + auto scopesym = sc2.inner().scopesym; if (scopesym.members) scopesym.members.push(sd); if (scopesym.symtab && !scopesym.symtabInsert(sd)) { Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id); - handleTagSymbols(*sc, sd, s2, scopesym); + handleTagSymbols(*sc2, sd, s2, scopesym); } - sd.parent = sc.parent; - sd.dsymbolSemantic(sc); + sd.parent = sc2.parent; + sd.dsymbolSemantic(sc2); } switch (mtype.tok) @@ -2098,7 +2117,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) /* look for pre-existing declaration */ Dsymbol scopesym; - auto s = sc.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace); + auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace); if (!s || s.isModule()) { // no pre-existing declaration, so declare it @@ -2111,7 +2130,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) /* A redeclaration only happens if both declarations are in * the same scope */ - const bool redeclar = (scopesym == sc.inner().scopesym); + const bool redeclar = (scopesym == sc2.inner().scopesym); if (redeclar) { @@ -2154,7 +2173,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) * picked up and added to the symtab. */ sd.semanticRun = PASS.semantic; - sd.dsymbolSemantic(sc); + sd.dsymbolSemantic(sc2); } } else @@ -2985,44 +3004,21 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type void visitIdentifier(TypeIdentifier mt) { //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars()); - if ((mt.ident.equals(Id._super) || mt.ident.equals(Id.This)) && !hasThis(sc)) - { - // @@@DEPRECATED_v2.091@@@. - // Made an error in 2.086. - // Eligible for removal in 2.091. - if (mt.ident.equals(Id._super)) - { - error(mt.loc, "Using `super` as a type is obsolete. Use `typeof(super)` instead"); - } - // @@@DEPRECATED_v2.091@@@. - // Made an error in 2.086. - // Eligible for removal in 2.091. - if (mt.ident.equals(Id.This)) - { - error(mt.loc, "Using `this` as a type is obsolete. Use `typeof(this)` instead"); - } - if (AggregateDeclaration ad = sc.getStructClassScope()) - { - if (ClassDeclaration cd = ad.isClassDeclaration()) - { - if (mt.ident.equals(Id.This)) - mt.ident = cd.ident; - else if (cd.baseClass && mt.ident.equals(Id._super)) - mt.ident = cd.baseClass.ident; - } - else - { - StructDeclaration sd = ad.isStructDeclaration(); - if (sd && mt.ident.equals(Id.This)) - mt.ident = sd.ident; - } - } - } if (mt.ident == Id.ctfe) { error(loc, "variable `__ctfe` cannot be read at compile time"); return returnError(); } + if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h + { + /* Since we don't support __builtin_va_start, -arg, -end, we don't + * have to actually care what -list is. A void* will do. + * If we ever do care, import core.stdc.stdarg and pull + * the definition out of that, similarly to how std.math is handled for PowExp + */ + pt = target.va_listType(loc, sc); + return; + } Dsymbol scopesym; Dsymbol s = sc.search(loc, mt.ident, &scopesym); @@ -3821,7 +3817,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) * e.opDot().ident */ e = build_overload(e.loc, sc, e, null, fd); - // @@@DEPRECATED_2.087@@@. + // @@@DEPRECATED_2.092@@@. e.deprecation("`opDot` is deprecated. Use `alias this`"); e = new DotIdExp(e.loc, e, ident); return returnExp(e.expressionSemantic(sc)); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index dd7ebc8..d5e4df7 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #include "dmd/aggregate.h" #include "dmd/ctfe.h" #include "dmd/declaration.h" +#include "dmd/enum.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/init.h" @@ -1460,40 +1461,6 @@ public: t1 = build_address (t1); this->result_ = build_libcall (libcall, Type::tvoid, 1, t1); } - else if (tb1->ty == TY::Tarray) - { - /* For dynamic arrays, the garbage collector is called to immediately - release the memory. */ - Type *telem = tb1->nextOf ()->baseElemOf (); - tree ti = null_pointer_node; - - if (TypeStruct *ts = telem->isTypeStruct ()) - { - /* Might need to run destructor on array contents. */ - if (ts->sym->dtor) - ti = build_typeinfo (e->loc, tb1->nextOf ()); - } - - /* Generate: _delarray_t (&t1, ti); */ - this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2, - build_address (t1), ti); - } - else if (tb1->ty == TY::Tpointer) - { - /* For pointers to a struct instance, if the struct has overloaded - operator delete, then that operator is called. */ - t1 = build_address (t1); - Type *tnext = tb1->isTypePointer ()->next->toBasetype (); - - /* This case should have been rewritten to `_d_delstruct` in the - semantic phase. */ - if (TypeStruct *ts = tnext->isTypeStruct ()) - gcc_assert (!ts->sym->dtor); - - /* Otherwise, the garbage collector is called to immediately free the - memory allocated for the pointer. */ - this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1); - } else { error ("don%'t know how to delete %qs", e->e1->toChars ()); @@ -1936,10 +1903,17 @@ public: else { tree object = build_expr (e->e1); + Type *tb = e->e1->type->toBasetype (); - if (e->e1->type->toBasetype ()->ty != TY::Tstruct) + if (tb->ty != TY::Tstruct) object = build_deref (object); + /* __complex is represented as a struct in the front-end, but + underlying is really a complex type. */ + if (e->e1->type->ty == TY::Tenum + && e->e1->type->isTypeEnum ()->sym->isSpecial ()) + object = build_vconvert (build_ctype (tb), object); + this->result_ = component_ref (object, get_symbol_decl (vd)); } } @@ -2604,7 +2578,7 @@ public: for (size_t i = 0; i < e->len; i++) { - tree value = build_integer_cst (e->charAt (i), etype); + tree value = build_integer_cst (e->getCodeUnit (i), etype); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index d6e0c7b..acb610f 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -83,9 +83,6 @@ DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT), DEF_D_RUNTIME (NEWITEMT, "_d_newitemT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0) DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0) -/* Used when calling delete on a pointer. */ -DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0) - /* Used when calling new on an array. The `i' variant is for when the initializer is nonzero, and the `m' variant is when initializing a multi-dimensional array. */ @@ -102,10 +99,6 @@ DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID), DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR), P2(CONST_TYPEINFO, SIZE_T), 0) -/* Used when calling delete on an array. */ -DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID), - P2(ARRAYPTR_VOID, CONST_TYPEINFO), 0) - /* Used for value equality (x == y) and comparisons (x < y) of non-trivial arrays. Such as an array of structs or classes. */ DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT), diff --git a/gcc/d/types.cc b/gcc/d/types.cc index 8ae6ea1..d897ec4 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -993,13 +993,17 @@ public: t->ctype = build_variant_type_copy (build_ctype (underlying)); build_type_decl (t->ctype, t->sym); } - else if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE) + else if (t->sym->ident == NULL + || !INTEGRAL_TYPE_P (basetype) + || TREE_CODE (basetype) == BOOLEAN_TYPE) { - /* Enums in D2 can have a base type that is not necessarily integral. - For these, we simplify this a little by using the base type directly - instead of building an ENUMERAL_TYPE. */ + /* Enums in D2 can either be anonymous, or have a base type that is not + necessarily integral. For these, we simplify this a little by using + the base type directly instead of building an ENUMERAL_TYPE. */ t->ctype = build_variant_type_copy (basetype); - build_type_decl (t->ctype, t->sym); + + if (t->sym->ident != NULL) + build_type_decl (t->ctype, t->sym); } else { diff --git a/gcc/testsuite/gdc.dg/special1.d b/gcc/testsuite/gdc.dg/special1.d new file mode 100644 index 0000000..8881dd0 --- /dev/null +++ b/gcc/testsuite/gdc.dg/special1.d @@ -0,0 +1,12 @@ +// { dg-do compile } + +struct _Complex(T) { T re; T im; } +enum __c_complex_float : _Complex!float; + +bool equals(__c_complex_float[] lhs, __c_complex_float[] rhs) +{ + foreach (i; 0 .. lhs.length) + if (lhs.ptr[i] != rhs.ptr[i]) + return false; + return true; +} diff --git a/gcc/testsuite/gdc.test/compilable/99bottles.d b/gcc/testsuite/gdc.test/compilable/99bottles.d index 5341a49..ac416eb 100644 --- a/gcc/testsuite/gdc.test/compilable/99bottles.d +++ b/gcc/testsuite/gdc.test/compilable/99bottles.d @@ -3,7 +3,7 @@ // http://www.99-bottles-of-beer.net/language-d-1212.html // Generates the "99 bottles of beer" song at compile time, -// using the template metaprograming facilities of D. +// using the template metaprograming facilities of D. // No executable is generated. No libraries are used. // Illustrates template default values, template string value parameters, // compile-time concatenation of constant strings, static if. @@ -24,13 +24,13 @@ template itoa(ulong n) template showHowMany(int n, string where, bool needcapital = false) { - static if ( n > 1 ) + static if ( n > 1 ) const string showHowMany = itoa!(n) ~ " bottles of beer" ~ where ~ "\n"; else static if ( n == 1 ) const string showHowMany = "1 bottle of beer" ~ where ~ "\n"; else static if ( needcapital ) const string showHowMany = "No more bottles of beer" ~ where ~ "\n"; - else + else const string showHowMany = "no more bottles of beer" ~ where ~ "\n"; } @@ -39,514 +39,514 @@ template beer(int maxbeers, int n = maxbeers) static if ( n > 0 ) const string beer = showHowMany!(n, " on the wall,", true) ~ showHowMany!(n, ".") - ~ "Take one down and pass it around, " ~ "\n" - ~ showHowMany!( n - 1 , " on the wall.") + ~ "Take one down and pass it around," ~ "\n" + ~ showHowMany!( n - 1 , " on the wall.") ~ "\n" ~ beer!(maxbeers, n - 1); // recurse for subsequent verses. else const string beer = showHowMany!(n, " on the wall,", true) ~ showHowMany!(n, ".") - ~ "Go to the store and buy some more, " ~ "\n" + ~ "Go to the store and buy some more," ~ "\n" ~ showHowMany!( maxbeers, " on the wall."); } enum expected = `99 bottles of beer on the wall, 99 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 98 bottles of beer on the wall. 98 bottles of beer on the wall, 98 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 97 bottles of beer on the wall. 97 bottles of beer on the wall, 97 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 96 bottles of beer on the wall. 96 bottles of beer on the wall, 96 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 95 bottles of beer on the wall. 95 bottles of beer on the wall, 95 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 94 bottles of beer on the wall. 94 bottles of beer on the wall, 94 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 93 bottles of beer on the wall. 93 bottles of beer on the wall, 93 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 92 bottles of beer on the wall. 92 bottles of beer on the wall, 92 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 91 bottles of beer on the wall. 91 bottles of beer on the wall, 91 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 90 bottles of beer on the wall. 90 bottles of beer on the wall, 90 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 89 bottles of beer on the wall. 89 bottles of beer on the wall, 89 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 88 bottles of beer on the wall. 88 bottles of beer on the wall, 88 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 87 bottles of beer on the wall. 87 bottles of beer on the wall, 87 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 86 bottles of beer on the wall. 86 bottles of beer on the wall, 86 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 85 bottles of beer on the wall. 85 bottles of beer on the wall, 85 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 84 bottles of beer on the wall. 84 bottles of beer on the wall, 84 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 83 bottles of beer on the wall. 83 bottles of beer on the wall, 83 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 82 bottles of beer on the wall. 82 bottles of beer on the wall, 82 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 81 bottles of beer on the wall. 81 bottles of beer on the wall, 81 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 80 bottles of beer on the wall. 80 bottles of beer on the wall, 80 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 79 bottles of beer on the wall. 79 bottles of beer on the wall, 79 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 78 bottles of beer on the wall. 78 bottles of beer on the wall, 78 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 77 bottles of beer on the wall. 77 bottles of beer on the wall, 77 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 76 bottles of beer on the wall. 76 bottles of beer on the wall, 76 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 75 bottles of beer on the wall. 75 bottles of beer on the wall, 75 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 74 bottles of beer on the wall. 74 bottles of beer on the wall, 74 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 73 bottles of beer on the wall. 73 bottles of beer on the wall, 73 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 72 bottles of beer on the wall. 72 bottles of beer on the wall, 72 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 71 bottles of beer on the wall. 71 bottles of beer on the wall, 71 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 70 bottles of beer on the wall. 70 bottles of beer on the wall, 70 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 69 bottles of beer on the wall. 69 bottles of beer on the wall, 69 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 68 bottles of beer on the wall. 68 bottles of beer on the wall, 68 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 67 bottles of beer on the wall. 67 bottles of beer on the wall, 67 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 66 bottles of beer on the wall. 66 bottles of beer on the wall, 66 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 65 bottles of beer on the wall. 65 bottles of beer on the wall, 65 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 64 bottles of beer on the wall. 64 bottles of beer on the wall, 64 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 63 bottles of beer on the wall. 63 bottles of beer on the wall, 63 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 62 bottles of beer on the wall. 62 bottles of beer on the wall, 62 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 61 bottles of beer on the wall. 61 bottles of beer on the wall, 61 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 60 bottles of beer on the wall. 60 bottles of beer on the wall, 60 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 59 bottles of beer on the wall. 59 bottles of beer on the wall, 59 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 58 bottles of beer on the wall. 58 bottles of beer on the wall, 58 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 57 bottles of beer on the wall. 57 bottles of beer on the wall, 57 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 56 bottles of beer on the wall. 56 bottles of beer on the wall, 56 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 55 bottles of beer on the wall. 55 bottles of beer on the wall, 55 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 54 bottles of beer on the wall. 54 bottles of beer on the wall, 54 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 53 bottles of beer on the wall. 53 bottles of beer on the wall, 53 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 52 bottles of beer on the wall. 52 bottles of beer on the wall, 52 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 51 bottles of beer on the wall. 51 bottles of beer on the wall, 51 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 50 bottles of beer on the wall. 50 bottles of beer on the wall, 50 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 49 bottles of beer on the wall. 49 bottles of beer on the wall, 49 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 48 bottles of beer on the wall. 48 bottles of beer on the wall, 48 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 47 bottles of beer on the wall. 47 bottles of beer on the wall, 47 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 46 bottles of beer on the wall. 46 bottles of beer on the wall, 46 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 45 bottles of beer on the wall. 45 bottles of beer on the wall, 45 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 44 bottles of beer on the wall. 44 bottles of beer on the wall, 44 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 43 bottles of beer on the wall. 43 bottles of beer on the wall, 43 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 42 bottles of beer on the wall. 42 bottles of beer on the wall, 42 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 41 bottles of beer on the wall. 41 bottles of beer on the wall, 41 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 40 bottles of beer on the wall. 40 bottles of beer on the wall, 40 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 39 bottles of beer on the wall. 39 bottles of beer on the wall, 39 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 38 bottles of beer on the wall. 38 bottles of beer on the wall, 38 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 37 bottles of beer on the wall. 37 bottles of beer on the wall, 37 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 36 bottles of beer on the wall. 36 bottles of beer on the wall, 36 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 35 bottles of beer on the wall. 35 bottles of beer on the wall, 35 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 34 bottles of beer on the wall. 34 bottles of beer on the wall, 34 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 33 bottles of beer on the wall. 33 bottles of beer on the wall, 33 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 32 bottles of beer on the wall. 32 bottles of beer on the wall, 32 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 31 bottles of beer on the wall. 31 bottles of beer on the wall, 31 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 30 bottles of beer on the wall. 30 bottles of beer on the wall, 30 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 29 bottles of beer on the wall. 29 bottles of beer on the wall, 29 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 28 bottles of beer on the wall. 28 bottles of beer on the wall, 28 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 27 bottles of beer on the wall. 27 bottles of beer on the wall, 27 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 26 bottles of beer on the wall. 26 bottles of beer on the wall, 26 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 25 bottles of beer on the wall. 25 bottles of beer on the wall, 25 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 24 bottles of beer on the wall. 24 bottles of beer on the wall, 24 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 23 bottles of beer on the wall. 23 bottles of beer on the wall, 23 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 22 bottles of beer on the wall. 22 bottles of beer on the wall, 22 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 21 bottles of beer on the wall. 21 bottles of beer on the wall, 21 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 20 bottles of beer on the wall. 20 bottles of beer on the wall, 20 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 19 bottles of beer on the wall. 19 bottles of beer on the wall, 19 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 18 bottles of beer on the wall. 18 bottles of beer on the wall, 18 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 17 bottles of beer on the wall. 17 bottles of beer on the wall, 17 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 16 bottles of beer on the wall. 16 bottles of beer on the wall, 16 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 15 bottles of beer on the wall. 15 bottles of beer on the wall, 15 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 14 bottles of beer on the wall. 14 bottles of beer on the wall, 14 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 13 bottles of beer on the wall. 13 bottles of beer on the wall, 13 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 12 bottles of beer on the wall. 12 bottles of beer on the wall, 12 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 11 bottles of beer on the wall. 11 bottles of beer on the wall, 11 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 10 bottles of beer on the wall. 10 bottles of beer on the wall, 10 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 9 bottles of beer on the wall. 9 bottles of beer on the wall, 9 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 8 bottles of beer on the wall. 8 bottles of beer on the wall, 8 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 7 bottles of beer on the wall. 7 bottles of beer on the wall, 7 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 6 bottles of beer on the wall. 6 bottles of beer on the wall, 6 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 5 bottles of beer on the wall. 5 bottles of beer on the wall, 5 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 4 bottles of beer on the wall. 4 bottles of beer on the wall, 4 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 3 bottles of beer on the wall. 3 bottles of beer on the wall, 3 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 2 bottles of beer on the wall. 2 bottles of beer on the wall, 2 bottles of beer. -Take one down and pass it around, +Take one down and pass it around, 1 bottle of beer on the wall. 1 bottle of beer on the wall, 1 bottle of beer. -Take one down and pass it around, +Take one down and pass it around, no more bottles of beer on the wall. No more bottles of beer on the wall, no more bottles of beer. -Go to the store and buy some more, +Go to the store and buy some more, 99 bottles of beer on the wall. `; diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d index 5dcaeca..3bc699a 100644 --- a/gcc/testsuite/gdc.test/compilable/b18242.d +++ b/gcc/testsuite/gdc.test/compilable/b18242.d @@ -5,14 +5,14 @@ module object; class Object { } class TypeInfo { } -class TypeInfo_Class : TypeInfo -{ +class TypeInfo_Class : TypeInfo +{ version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; } } class Throwable { } -int _d_run_main() +int _d_run_main() { try { } catch(Throwable e) { return 1; } return 0; diff --git a/gcc/testsuite/gdc.test/compilable/b19294.d b/gcc/testsuite/gdc.test/compilable/b19294.d index 063a9df..ed1a717 100644 --- a/gcc/testsuite/gdc.test/compilable/b19294.d +++ b/gcc/testsuite/gdc.test/compilable/b19294.d @@ -51,19 +51,19 @@ void test() MT s = MyStruct!int(1); MT[] arr = [s, 2 * s, 3 * s, 4 * s, 5 * s, 6 * s]; MT[] result = new MT[arr.length]; - + result[] = arr[] + s; result[] = s + arr[]; - + result[] = arr[] - s; result[] = s - arr[]; - + result[] = arr[] * s; result[] = s * arr[]; - + result[] = arr[] / s; result[] = s / arr[]; - + result[] = arr[] ^^ s; result[] = s ^^ arr[]; } diff --git a/gcc/testsuite/gdc.test/compilable/b20938.d b/gcc/testsuite/gdc.test/compilable/b20938.d index efcf4aa..ba3565a 100644 --- a/gcc/testsuite/gdc.test/compilable/b20938.d +++ b/gcc/testsuite/gdc.test/compilable/b20938.d @@ -12,11 +12,11 @@ void fun() { immutable S _is; Object o; immutable Object io; - + auto a = [pi, ipi]; - auto b = [ai, iai]; + auto b = [ai, iai]; auto c = [s, _is]; auto d = [o, io]; - + auto e = [A.a, B.b]; } diff --git a/gcc/testsuite/gdc.test/compilable/b21285.d b/gcc/testsuite/gdc.test/compilable/b21285.d index 11eea74..482faa7 100644 --- a/gcc/testsuite/gdc.test/compilable/b21285.d +++ b/gcc/testsuite/gdc.test/compilable/b21285.d @@ -1,27 +1,27 @@ // REQUIRED_ARGS: -unittest -// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master). +// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master). unittest { string path; int bank; static string path2; static int bank2; - + // delegates auto a = [ (string arg) { path = arg; }, (string arg) { bank = 1; throw new Exception(""); } ]; - + // functions auto ab = [ (string arg) { path2 = arg; }, (string arg) { bank2 = 1; throw new Exception(""); } ]; - + alias dg = void delegate(string) pure @safe; alias fn = void function(string) @safe; - + static assert(is(typeof(a[0]) == dg)); static assert(is(typeof(ab[0]) == fn)); } diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d index 076e29b..a740994 100644 --- a/gcc/testsuite/gdc.test/compilable/commontype.d +++ b/gcc/testsuite/gdc.test/compilable/commontype.d @@ -196,7 +196,8 @@ static assert(is( X!( C***, B*** ) == const(B**)* )); // `B***` static assert(is( X!( C*, I* ) == I* )); static assert(is( X!( I*, C* ) == I* )); -static assert(Error!( C**, I** )); +//static assert(Error!( C**, I** )); +static assert(is( X!( C**, I** ) == const(I*)* )); static assert(Error!( C*, D* )); // should work @@ -303,13 +304,15 @@ static assert(is( X!(C[4], B[4]) )); static assert(Error!( C[4], I[4] )); static assert(Error!( C[4], D[4] )); static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] )); -static assert(Error!( C[4], const(I)[4] )); +//static assert(Error!( C[4], const(I)[4] )); +static assert(is( X!( C[4], const(I)[4] ) == const(I)[] )); static assert(Error!( C[4], const(D)[4] )); static assert(Error!( C*[4], B*[4] )); static assert(Error!( C*[4], I*[4] )); static assert(Error!( C*[4], D*[4] )); static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !? -static assert(Error!( C*[4], const(I*)[4] )); +//static assert(Error!( C*[4], const(I*)[4] )); +static assert(is( X!( C*[4], const(I*)[4] ) == const(I*)[] )); static assert(Error!( C*[4], const(D*)[4] )); static assert(Error!( C*[4], B**[4] )); static assert(Error!( C*[4], const(B*)*[4] )); diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10.d b/gcc/testsuite/gdc.test/compilable/ddoc10.d index 6a7a481..2f61409 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc10.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc10.d @@ -171,7 +171,7 @@ struct T /**** */ this(A...)(A args) { } - + /// this(int){} } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11.d b/gcc/testsuite/gdc.test/compilable/ddoc11.d index 3fcf2ca..0082455 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc11.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc11.d @@ -49,7 +49,7 @@ struct lldiv_t { long quot,rem; } - void *calloc(size_t, size_t); /// + void *calloc(size_t, size_t); /// void *malloc(size_t); /// dittx /** diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14.d b/gcc/testsuite/gdc.test/compilable/ddoc14.d index a8b6d4d..fae99d4 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc14.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc14.d @@ -77,7 +77,7 @@ interface Interface { V mColon(lazy P p) ; /// 10 } +/ - + public P variable; /// 0 V mNone(lazy P p) {} /// 1 pure nothrow V mPrefix(lazy P p) {} /// 2 diff --git a/gcc/testsuite/gdc.test/compilable/ddoc3.d b/gcc/testsuite/gdc.test/compilable/ddoc3.d index 1bcae41..3b47497 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc3.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc3.d @@ -42,7 +42,7 @@ * $(TROW 4, 5, 6) * ) * - * $(D_CODE + * $(D_CODE $(B pragma)( $(I name) ); $(B pragma)( $(I name) , $(I option) [ $(I option) ] ); $(U $(LPAREN)) diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5.d b/gcc/testsuite/gdc.test/compilable/ddoc5.d index 4ddc123..5a964f3 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc5.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc5.d @@ -15,10 +15,10 @@ class TestMembers(TemplateArg) public: /** - a static method + a static method Params: idx = index - + */ static void PublicStaticMethod(int idx) { diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446.d b/gcc/testsuite/gdc.test/compilable/ddoc5446.d index 0596088..29cb8c9 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc5446.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc5446.d @@ -30,41 +30,41 @@ struct Bar { /** */ alias A_Foo Bar_A_Foo; - + /** */ alias A_Foo_Alias Bar_A_Foo_Alias; - + /** */ alias A_Int Bar_A_Int; - + /** */ alias This_Foo Bar_This_Foo; - + /** */ alias This_Foo_Alias Bar_This_Foo_Alias; - + /** */ alias This_Int Bar_This_Int; - + /** */ alias Nested Nested_Alias; - + /** */ alias .Nested Fake_Nested; - + /** */ struct Nested { /** */ alias Bar Bar_Nested_Bar_Alias; - + /** */ alias .Bar Bar_Alias; - + /** */ struct Bar { - + } } } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9155.d b/gcc/testsuite/gdc.test/compilable/ddoc9155.d index 9f5a59a..e03d422 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc9155.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc9155.d @@ -12,12 +12,12 @@ module ddoc9155; + --- + import std.stdio; //& + writeln("Hello world!"); - + if (test) { + + if (test) { + writefln("D programming language"); + } + + algorithm; - + + + + xxx; //comment + yyy; + /* test @@ -28,7 +28,7 @@ module ddoc9155; +File f = File("./text.txt", "r"); +uint line = 0; + // The ElementType of data is not aggregation type - +foreach (encoded; Base64.encoder(data)) + +foreach (encoded; Base64.encoder(data)) + --- +/ @@ -45,12 +45,12 @@ module ddoc9155; * --- * import std.stdio; //& * writeln("Hello world!"); - * if (test) { + * if (test) { * writefln("D programming language"); * } * * algorithm; - * + * * xxx; //comment * yyy; * /+ test diff --git a/gcc/testsuite/gdc.test/compilable/debugInference.d b/gcc/testsuite/gdc.test/compilable/debugInference.d index 1d4f157..947d820 100644 --- a/gcc/testsuite/gdc.test/compilable/debugInference.d +++ b/gcc/testsuite/gdc.test/compilable/debugInference.d @@ -1,9 +1,5 @@ /* REQUIRED_ARGS: -debug -TEST_OUTPUT: ---- -compilable/debugInference.d(35): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- https://issues.dlang.org/show_bug.cgi?id=20507 */ @@ -32,7 +28,7 @@ void bar()() auto f2Ptr = &f2; S s; - delete s; + destroy(s); int* ptr = cast(int*) 0; int[] slice = ptr[0 .. 4]; diff --git a/gcc/testsuite/gdc.test/compilable/defa.d b/gcc/testsuite/gdc.test/compilable/defa.d index a922207..5b4e589 100644 --- a/gcc/testsuite/gdc.test/compilable/defa.d +++ b/gcc/testsuite/gdc.test/compilable/defa.d @@ -3,7 +3,7 @@ module defa; private import imports.defaa; - + public abstract class A { Display d; diff --git a/gcc/testsuite/gdc.test/compilable/dlangui_crash.d b/gcc/testsuite/gdc.test/compilable/dlangui_crash.d new file mode 100644 index 0000000..36617f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/dlangui_crash.d @@ -0,0 +1,34 @@ +// https://issues.dlang.org/show_bug.cgi?id=22365 + +class DrawableCache +{ + Ref _nullDrawable; + + this() + { + debug Log; + } +} + +class DrawableCacheEmpty +{ + Ref _nullDrawable; + + this() {} +} + +struct Ref +{ + + ~this() + { + } +} + +void foo() +{ + try + debug Log; + catch (Exception) + assert(false); +} diff --git a/gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d b/gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d new file mode 100644 index 0000000..4dbc56d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d @@ -0,0 +1,20 @@ +//https://issues.dlang.org/show_bug.cgi?id=20777 +struct FooInt +{ + int i; + auto opBinary(string op : "+")(int j) + { + return typeof(this)(i + j); + } + + static @property FooInt max() + { + return typeof(this)(int.max); + } +} + +enum foolist +{ + hi = FooInt(0), + bye +} diff --git a/gcc/testsuite/gdc.test/compilable/header18364.d b/gcc/testsuite/gdc.test/compilable/header18364.d index c7e1e67..080a096 100644 --- a/gcc/testsuite/gdc.test/compilable/header18364.d +++ b/gcc/testsuite/gdc.test/compilable/header18364.d @@ -8,7 +8,7 @@ TEST_OUTPUT: === ${RESULTS_DIR}/compilable/header18364.di // D import file generated from 'compilable/header18364.d' module foo.bar.ba; -nothrow pure @nogc @safe package(foo) +nothrow pure @nogc @safe package(foo) { void foo(); nothrow pure @nogc @safe package(foo.bar) void foo2(); diff --git a/gcc/testsuite/gdc.test/compilable/imports/b33a.d b/gcc/testsuite/gdc.test/compilable/imports/b33a.d index 5d52c66..bd8fd0c 100644 --- a/gcc/testsuite/gdc.test/compilable/imports/b33a.d +++ b/gcc/testsuite/gdc.test/compilable/imports/b33a.d @@ -6,10 +6,10 @@ struct IsEqual( T ) { return p1 == p2; } -} +} template find_( Elem, Pred = IsEqual!(Elem) ) -{ +{ size_t fn( char[] buf, Pred pred = Pred.init ) { return 3; diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp22734.c b/gcc/testsuite/gdc.test/compilable/imports/imp22734.c new file mode 100644 index 0000000..9df542b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp22734.c @@ -0,0 +1,3 @@ +typedef enum { C } E; + +int a = C; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test22714a.d b/gcc/testsuite/gdc.test/compilable/imports/test22714a.d new file mode 100644 index 0000000..7b77272 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test22714a.d @@ -0,0 +1,3 @@ +module imports.test22714a; +import imports.test22714b; +class Statement {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test22714b.d b/gcc/testsuite/gdc.test/compilable/imports/test22714b.d new file mode 100644 index 0000000..68bd95b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test22714b.d @@ -0,0 +1,12 @@ +module imports.test22714b; +import imports.test22714a; +struct Array(T) +{ + T[] data; + T[1] smallarray; +} +struct Ensure +{ + Statement ensure; + Array!Ensure* arraySyntaxCopy; +} diff --git a/gcc/testsuite/gdc.test/compilable/issue16472.d b/gcc/testsuite/gdc.test/compilable/issue16472.d new file mode 100644 index 0000000..a4353ce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue16472.d @@ -0,0 +1,42 @@ +// https://issues.dlang.org/show_bug.cgi?id=16472 +enum e() = 0; + +template t(alias v = e!()) {} //Error +alias dummy = t!(e!()); + +template E(F){ + enum E { + K = F(1) + } +} + +struct S(F = float, alias e_ = E!double.K) {} +S!float x; // Error: E!double.K is used as a type + +alias T = E!double.K; +struct S2(F = float, alias e_ = T) {} +S2!float y; // alias makes it okay... + +struct S3(F = float, alias e_ = (E!double.K)) {} +S3!float z; // just putting parens make it okay as well... wat!? + +// for coverage + +template G(T) +{ + struct G + { + alias I = int; + static int i; + } +} + +struct H(F = float, alias e_ = G!double) {} +H!float a; + +struct H1(F = float, alias e_ = G!double.I) {} +H1!float b; + +// https://issues.dlang.org/show_bug.cgi?id=21795 +// struct H2(F = float, alias e_ = G!double.i) {} +// H2!float c; diff --git a/gcc/testsuite/gdc.test/compilable/issue21340.d b/gcc/testsuite/gdc.test/compilable/issue21340.d index 22eda6e..03d37bd 100644 --- a/gcc/testsuite/gdc.test/compilable/issue21340.d +++ b/gcc/testsuite/gdc.test/compilable/issue21340.d @@ -5,7 +5,7 @@ version (CppRuntime_Sun) version = CppMangle_Itanium; template ScopeClass(C) if (is(C == class) && __traits(getLinkage, C) == "C++") { - + extern(C++, class) extern(C++, __traits(getCppNamespaces,C)) extern(C++, (ns)) @@ -35,4 +35,4 @@ alias ns = AliasSeq!(); immutable ns2 = AliasSeq!(); extern(C++,(ns)) class Bar {} extern(C++,) class Baz {} -extern(C++, (ns2)) class Quux {} +extern(C++, (ns2)) class Quux {} diff --git a/gcc/testsuite/gdc.test/compilable/issue21813b.d b/gcc/testsuite/gdc.test/compilable/issue21813b.d index ef22697..0af986b 100644 --- a/gcc/testsuite/gdc.test/compilable/issue21813b.d +++ b/gcc/testsuite/gdc.test/compilable/issue21813b.d @@ -4,7 +4,7 @@ Target.OS defaultTargetOS() return Target.OS.linux; } -struct Target +struct Target { enum OS { linux } OS os = defaultTargetOS(); diff --git a/gcc/testsuite/gdc.test/compilable/minimal.d b/gcc/testsuite/gdc.test/compilable/minimal.d index 6398328..155f0ed 100644 --- a/gcc/testsuite/gdc.test/compilable/minimal.d +++ b/gcc/testsuite/gdc.test/compilable/minimal.d @@ -10,7 +10,7 @@ struct S { } -enum E +enum E { e0 = 0, e1 = 1 diff --git a/gcc/testsuite/gdc.test/compilable/test10993.d b/gcc/testsuite/gdc.test/compilable/test10993.d index a69d0c6..9a99187 100644 --- a/gcc/testsuite/gdc.test/compilable/test10993.d +++ b/gcc/testsuite/gdc.test/compilable/test10993.d @@ -19,7 +19,7 @@ auto fun() { auto x = foo!()(test!(a=>a)()); // pragma(msg, "fun: " ~ typeof(x).mangleof); - + return x; } diff --git a/gcc/testsuite/gdc.test/compilable/test16107.d b/gcc/testsuite/gdc.test/compilable/test16107.d index 2267be3..3de4dd1 100644 --- a/gcc/testsuite/gdc.test/compilable/test16107.d +++ b/gcc/testsuite/gdc.test/compilable/test16107.d @@ -3,12 +3,12 @@ bool check() { bool result = false; - + result |= false; if (result) goto ret; - + result |= false; if (result) {} - + ret: return true; } diff --git a/gcc/testsuite/gdc.test/compilable/test17545.d b/gcc/testsuite/gdc.test/compilable/test17545.d index bb0c2ae..6285418 100644 --- a/gcc/testsuite/gdc.test/compilable/test17545.d +++ b/gcc/testsuite/gdc.test/compilable/test17545.d @@ -12,5 +12,5 @@ struct Attrib {} @Attrib enum TEST = 123; -pragma(msg, __traits(getAttributes, +pragma(msg, __traits(getAttributes, __traits(getMember, example, "TEST"))); diff --git a/gcc/testsuite/gdc.test/compilable/test17906.d b/gcc/testsuite/gdc.test/compilable/test17906.d deleted file mode 100644 index 9c4a547..0000000 --- a/gcc/testsuite/gdc.test/compilable/test17906.d +++ /dev/null @@ -1,7 +0,0 @@ -// REQUIRED_ARGS: -de -// https://issues.dlang.org/show_bug.cgi?id=18647 -deprecated void main () -{ - Object o = new Object; - delete o; -} diff --git a/gcc/testsuite/gdc.test/compilable/test18030.d b/gcc/testsuite/gdc.test/compilable/test18030.d index f742a40..37f8630 100644 --- a/gcc/testsuite/gdc.test/compilable/test18030.d +++ b/gcc/testsuite/gdc.test/compilable/test18030.d @@ -9,6 +9,6 @@ struct S(T) class C { alias Al = S!C; - + static void func(U)(U var) { } } diff --git a/gcc/testsuite/gdc.test/compilable/test19014.d b/gcc/testsuite/gdc.test/compilable/test19014.d index 7bbbc94..1110b28 100644 --- a/gcc/testsuite/gdc.test/compilable/test19014.d +++ b/gcc/testsuite/gdc.test/compilable/test19014.d @@ -8,5 +8,5 @@ void main() { static import core.stdc.math; } - static assert(!__traits(compiles, core.stdc.math.cos(0))); + static assert(!__traits(compiles, core.stdc.math.cos(0))); } diff --git a/gcc/testsuite/gdc.test/compilable/test19315.d b/gcc/testsuite/gdc.test/compilable/test19315.d index 0c31ab8..e95ecac 100644 --- a/gcc/testsuite/gdc.test/compilable/test19315.d +++ b/gcc/testsuite/gdc.test/compilable/test19315.d @@ -1,5 +1,5 @@ //https://issues.dlang.org/show_bug.cgi?id=19315 -void main() +void main() { #line 100 "file.d" enum code = q{ diff --git a/gcc/testsuite/gdc.test/compilable/test19557.d b/gcc/testsuite/gdc.test/compilable/test19557.d index f107e22..b11ae10 100644 --- a/gcc/testsuite/gdc.test/compilable/test19557.d +++ b/gcc/testsuite/gdc.test/compilable/test19557.d @@ -1,6 +1,6 @@ // https://issues.dlang.org/show_bug.cgi?id=19557 // Error: redundant linkage `extern (C++)` - + extern(C++, "ns") extern(C++, class) struct test {} diff --git a/gcc/testsuite/gdc.test/compilable/test19609.d b/gcc/testsuite/gdc.test/compilable/test19609.d index 4367df1..df8f891 100644 --- a/gcc/testsuite/gdc.test/compilable/test19609.d +++ b/gcc/testsuite/gdc.test/compilable/test19609.d @@ -3,9 +3,9 @@ /* TEST_OUTPUT: --- -compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated - +compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated compilable/test19609.d(12): Deprecation: module `imports.test19609b` is deprecated - hello -compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated - +compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated --- */ import imports.test19609a; diff --git a/gcc/testsuite/gdc.test/compilable/test21177.d b/gcc/testsuite/gdc.test/compilable/test21177.d new file mode 100644 index 0000000..b3b613b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21177.d @@ -0,0 +1,76 @@ +// https://issues.dlang.org/show_bug.cgi?id=21177 +/* +DISABLED: win +TEST_OUTPUT: +--- +compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(203): Deprecation: format specifier `"%m"` is invalid +compilable/test21177.d(204): Deprecation: format specifier `"%m"` is invalid +compilable/test21177.d(205): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*` +compilable/test21177.d(206): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*` +--- +*/ + +import core.stdc.stdio; +import core.stdc.string; +import core.stdc.stdlib; + +void main() +{ + version (CRuntime_Glibc) + { + #line 100 + printf("%m this is a string in errno"); + printf("%s %m", "str".ptr, 2); + printf("%a", 2.); + printf("%m %m %s"); + printf("%*m"); + + char* a, b; + sscanf("salut poilu", "%a %m", a, b); + assert(!strcmp(a, b)); + free(a); + free(b); + + char* t, p; + sscanf("Tomate Patate", "%ms %as", t, p); + free(t); + free(p); + + #line 150 + sscanf("150", "%m"); + sscanf("151", "%ms"); + sscanf("152", "%a"); + sscanf("153", "%as"); + + pragma(msg, "compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments"); + pragma(msg, "compilable/test21177.d(203): Deprecation: format specifier `\"%m\"` is invalid"); + pragma(msg, "compilable/test21177.d(204): Deprecation: format specifier `\"%m\"` is invalid"); + pragma(msg, "compilable/test21177.d(205): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`"); + pragma(msg, "compilable/test21177.d(206): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`"); + } + else + { + // fake it + pragma(msg, "compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments"); + pragma(msg, "compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments"); + pragma(msg, "compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments"); + pragma(msg, "compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments"); + pragma(msg, "compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments"); + + #line 200 + printf("%m"); + + char* c; + sscanf("204", "%m", c); + sscanf("205", "%ms", c); + sscanf("206", "%a", c); + sscanf("207", "%as", c); + + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test21196.d b/gcc/testsuite/gdc.test/compilable/test21196.d new file mode 100644 index 0000000..f8507b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21196.d @@ -0,0 +1,71 @@ +// https://issues.dlang.org/show_bug.cgi?id=21674 +// REQUIRED_ARGS: -de + +struct Module +{ + CachedString data; +} + +struct CachedString +{ + private size_t len; + + this (string data) { this.len = data.length; } + public string str () const { return null; } + public void str (string value) { this.len = value.length; } + + alias str this; +} + +void test21674a() +{ + Module m; + m.data = "Hello World"; +} + +////////////////////////////////////////// + +struct StaticGetter(T) +{ + private static T _impl; + static ref T value() { return _impl; } + alias value this; +} + +struct StaticWrapper +{ + StaticGetter!int get; + alias get this; +} + +void test21674b() +{ + StaticGetter!float sg; + sg = 4.2; + + StaticWrapper sw; + sw = 42; +} + +////////////////////////////////////////// + +EntryType arr; +auto getPtr() { return &arr; } + +struct EntryType +{ + bool _state; + alias _state this; +} + +struct S19441 +{ + @property auto ref entry() { return *getPtr(); } + alias entry this; +} + +void test19441() +{ + S19441 s19441; + s19441 = true; +} diff --git a/gcc/testsuite/gdc.test/compilable/test22224.d b/gcc/testsuite/gdc.test/compilable/test22224.d index d16b2f4..ef131e9 100644 --- a/gcc/testsuite/gdc.test/compilable/test22224.d +++ b/gcc/testsuite/gdc.test/compilable/test22224.d @@ -1,4 +1,4 @@ // REQUIRED_ARGS: -profile -c -import core.stdc.stdarg; +import core.stdc.stdarg; void error(...) { } diff --git a/gcc/testsuite/gdc.test/compilable/test22632.d b/gcc/testsuite/gdc.test/compilable/test22632.d new file mode 100644 index 0000000..673b51b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22632.d @@ -0,0 +1,4 @@ +// https://issues.dlang.org/show_bug.cgi?id=22632 + +static assert(["one": 1] != null); +static assert(null != ["one": 1]); diff --git a/gcc/testsuite/gdc.test/compilable/test22714.d b/gcc/testsuite/gdc.test/compilable/test22714.d new file mode 100644 index 0000000..2973e1d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22714.d @@ -0,0 +1,3 @@ +// EXTRA_FILES: imports/test22714a.d imports/test22714b.d +// https://issues.dlang.org/show_bug.cgi?id=22714 +import imports.test22714a; diff --git a/gcc/testsuite/gdc.test/compilable/test22734.d b/gcc/testsuite/gdc.test/compilable/test22734.d new file mode 100644 index 0000000..fdd962e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22734.d @@ -0,0 +1,6 @@ +// https://issues.dlang.org/show_bug.cgi?id=22734 +// EXTRA_FILES: imports/imp22734.c + +import imports.imp22734; + +auto dc = C; diff --git a/gcc/testsuite/gdc.test/compilable/test4375.d b/gcc/testsuite/gdc.test/compilable/test4375.d index f5c4e4a..1cc7a3a 100644 --- a/gcc/testsuite/gdc.test/compilable/test4375.d +++ b/gcc/testsuite/gdc.test/compilable/test4375.d @@ -256,7 +256,7 @@ label1: else assert(89); else - assert(12); + assert(12); with (x) @@ -299,7 +299,7 @@ label1: if (true) assert(110); else - assert(112); + assert(112); finally assert(111); @@ -316,7 +316,7 @@ label1: int w; static if (true) - int t; + int t; else static if (false) int u; else diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d index 859f29a..a4cf663 100644 --- a/gcc/testsuite/gdc.test/compilable/test7172.d +++ b/gcc/testsuite/gdc.test/compilable/test7172.d @@ -7,7 +7,7 @@ void main() static assert(!__traits(compiles, { class D : FinalC{} })); scope class ScopeC{} -// static assert(!__traits(compiles, { auto sc = new ScopeC(); })); + static assert(!__traits(compiles, { auto sc = new ScopeC(); })); static assert( __traits(compiles, { scope sc = new ScopeC(); })); synchronized class SyncC{ void f(){} } diff --git a/gcc/testsuite/gdc.test/compilable/test8296.d b/gcc/testsuite/gdc.test/compilable/test8296.d index d27ba15..cd175b5 100644 --- a/gcc/testsuite/gdc.test/compilable/test8296.d +++ b/gcc/testsuite/gdc.test/compilable/test8296.d @@ -10,7 +10,7 @@ struct bar2 class InnerBar { bar2 b; - + this() { b = bar2(0); @@ -21,7 +21,7 @@ struct bar1 { InnerBar b; } - + class Foo { bar1 m_bar1; diff --git a/gcc/testsuite/gdc.test/compilable/test8513.d b/gcc/testsuite/gdc.test/compilable/test8513.d index bcdc657..4b5d512 100644 --- a/gcc/testsuite/gdc.test/compilable/test8513.d +++ b/gcc/testsuite/gdc.test/compilable/test8513.d @@ -5,25 +5,25 @@ class Bar { interface I_Foo { void i_inner(); } class C_Foo { void c_inner() { } } - + class Impl1 : C_Foo, I_Foo { override void i_inner() { } override void c_inner() { } } - + class Impl2 : C_Foo, .I_Foo { override void i_outer() { } override void c_inner() { } } - + class Impl3 : .C_Foo, I_Foo { override void i_inner() { } override void c_outer() { } } - + class Impl4 : .C_Foo, .I_Foo { override void i_outer() { } diff --git a/gcc/testsuite/gdc.test/compilable/testpostblit.d b/gcc/testsuite/gdc.test/compilable/testpostblit.d index 60a0f4a..dff4bc5 100644 --- a/gcc/testsuite/gdc.test/compilable/testpostblit.d +++ b/gcc/testsuite/gdc.test/compilable/testpostblit.d @@ -14,4 +14,4 @@ struct Test1c { const Test1b b; @disable this(this); -} +} diff --git a/gcc/testsuite/gdc.test/compilable/testsctreturn.d b/gcc/testsuite/gdc.test/compilable/testsctreturn.d index 96b82da..7826cd4 100644 --- a/gcc/testsuite/gdc.test/compilable/testsctreturn.d +++ b/gcc/testsuite/gdc.test/compilable/testsctreturn.d @@ -17,3 +17,19 @@ void test() size_t* p; const ppi = const(PackedPtrImpl!(3))(p); } + +/************************************************/ + +// issues.dlang.org/show_bug.cgi?id=22541 + +struct S +{ + int i; + int* ptr; + + int* wannabeReturnRef() scope return + { + return &i; + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/typeid_name.d b/gcc/testsuite/gdc.test/compilable/typeid_name.d index e77d5c8..b2292bf 100644 --- a/gcc/testsuite/gdc.test/compilable/typeid_name.d +++ b/gcc/testsuite/gdc.test/compilable/typeid_name.d @@ -9,6 +9,6 @@ class Panzer {} class Tiger : Panzer {} static assert (() { - Panzer p = new Tiger(); return classname(p); + Panzer p = new Tiger(); return classname(p); } () == "Tiger"); diff --git a/gcc/testsuite/gdc.test/compilable/vgc1.d b/gcc/testsuite/gdc.test/compilable/vgc1.d index 8a11657..8bfe1d0 100644 --- a/gcc/testsuite/gdc.test/compilable/vgc1.d +++ b/gcc/testsuite/gdc.test/compilable/vgc1.d @@ -65,20 +65,9 @@ void testNewScope() /***************** DeleteExp *******************/ -/* -TEST_OUTPUT: ---- -compilable/vgc1.d(81): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -compilable/vgc1.d(81): vgc: `delete` requires the GC -compilable/vgc1.d(82): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -compilable/vgc1.d(82): vgc: `delete` requires the GC -compilable/vgc1.d(83): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -compilable/vgc1.d(83): vgc: `delete` requires the GC ---- -*/ void testDelete(int* p, Object o, S1* s) { - delete p; - delete o; - delete s; + destroy(p); + destroy(o); + destroy(s); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d index 669dd10..7baad47 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d @@ -37,4 +37,4 @@ void main() assignableByRef(s1.member); assignableByOut(s1.member); assignableByConstRef(s1.member); -} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b3841.d b/gcc/testsuite/gdc.test/fail_compilation/b3841.d index ceddc87..0dda8bd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b3841.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b3841.d @@ -47,7 +47,7 @@ void main() f!(op, long, short)(); f!(op, float, long)(); f!(op, double, float)(); - + // Should that really be OK ? f!(op, short, int)(); f!(op, float, double)(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d index 1818e0d..ca98797 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d @@ -7,7 +7,7 @@ void g() f(5, 6, 404); } -/* +/* TEST_OUTPUT: --- fail_compilation/bug16165.d(6): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(Object, Object, int)` diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d b/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d index a03f850..fab12c2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/bug8150a.d(14): Error: `object.Exception` is thrown but not caught -fail_compilation/bug8150a.d(12): Error: `nothrow` constructor `bug8150a.Foo.this` may throw +fail_compilation/bug8150a.d(12): Error: constructor `bug8150a.Foo.this` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d b/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d index 2091bc8..606b628 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/bug8150b.d(15): Error: `object.Exception` is thrown but not caught -fail_compilation/bug8150b.d(13): Error: `nothrow` constructor `bug8150b.Foo.__ctor!().this` may throw +fail_compilation/bug8150b.d(13): Error: constructor `bug8150b.Foo.__ctor!().this` may throw but is marked as `nothrow` fail_compilation/bug8150b.d(20): Error: template instance `bug8150b.Foo.__ctor!()` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ccast.d b/gcc/testsuite/gdc.test/fail_compilation/ccast.d index b4897d4..dab2984 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ccast.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ccast.d @@ -1,4 +1,4 @@ -/* +/* TEST_OUTPUT: --- fail_compilation/ccast.d(9): Error: C style cast illegal, use `cast(byte)i` diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d index 78e0891..0f12d99 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ctfe14731.d(16): Error: cannot implicitly convert expression `["a b"]` of type `string[]` to `string` +fail_compilation/ctfe14731.d(16): Error: cannot implicitly convert expression `split("a b")` of type `string[]` to `string` fail_compilation/ctfe14731.d(17): Error: cannot implicitly convert expression `split("a b")` of type `string[]` to `string` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d index 4a01c54..416d563 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d @@ -9,7 +9,7 @@ fail_compilation/diag10319.d(28): Error: `@safe` function `D main` cannot call ` fail_compilation/diag10319.d(18): `diag10319.bar!int.bar` is declared here fail_compilation/diag10319.d(27): Error: function `diag10319.foo` is not `nothrow` fail_compilation/diag10319.d(28): Error: function `diag10319.bar!int.bar` is not `nothrow` -fail_compilation/diag10319.d(25): Error: `nothrow` function `D main` may throw +fail_compilation/diag10319.d(25): Error: function `D main` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d index 3b5df6e..ed38167 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10805.d(12): Error: delimited string must end in FOO" +fail_compilation/diag10805.d(12): Error: delimited string must end in `FOO"` fail_compilation/diag10805.d(14): Error: unterminated string constant starting at fail_compilation/diag10805.d(14) fail_compilation/diag10805.d(14): Error: Implicit string concatenation is error-prone and disallowed in D fail_compilation/diag10805.d(14): Use the explicit syntax instead (concatenating literals is `@nogc`): "" ~ "" diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13281.d b/gcc/testsuite/gdc.test/fail_compilation/diag13281.d index c59b300..fc0d9f5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag13281.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13281.d @@ -11,9 +11,9 @@ fail_compilation/diag13281.d(26): Error: cannot implicitly convert expression `1 fail_compilation/diag13281.d(27): Error: cannot implicitly convert expression `123.4i` of type `idouble` to `int` fail_compilation/diag13281.d(28): Error: cannot implicitly convert expression `123.4Fi` of type `ifloat` to `int` fail_compilation/diag13281.d(29): Error: cannot implicitly convert expression `123.4Li` of type `ireal` to `int` -fail_compilation/diag13281.d(30): Error: cannot implicitly convert expression `(123.4+5.6i)` of type `cdouble` to `int` -fail_compilation/diag13281.d(31): Error: cannot implicitly convert expression `(123.4F+5.6Fi)` of type `cfloat` to `int` -fail_compilation/diag13281.d(32): Error: cannot implicitly convert expression `(123.4L+5.6Li)` of type `creal` to `int` +fail_compilation/diag13281.d(30): Error: cannot implicitly convert expression `123.4 + 5.6i` of type `cdouble` to `int` +fail_compilation/diag13281.d(31): Error: cannot implicitly convert expression `123.4F + 5.6Fi` of type `cfloat` to `int` +fail_compilation/diag13281.d(32): Error: cannot implicitly convert expression `123.4L + 5.6Li` of type `creal` to `int` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d index 34fc645..1c61408 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d @@ -2,8 +2,8 @@ TEST_OUTPUT: --- fail_compilation/diag15713.d(19): Error: no property `widthSign` for type `diag15713.WrData.Data` -fail_compilation/diag15713.d(39): Error: template instance `diag15713.conwritefImpl!("parse-int", "width", "\x0a", Data(null))` error instantiating -fail_compilation/diag15713.d(44): instantiated from here: `conwritefImpl!("main", "\x0a", Data(null))` +fail_compilation/diag15713.d(39): Error: template instance `diag15713.conwritefImpl!("parse-int", "width", "\n", Data(null))` error instantiating +fail_compilation/diag15713.d(44): instantiated from here: `conwritefImpl!("main", "\n", Data(null))` fail_compilation/diag15713.d(49): instantiated from here: `fdwritef!()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d index 9d8dcfd..73d6285 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d @@ -13,7 +13,7 @@ fail_compilation/diag16977.d(30): Error: template instance `diag16977.test.funcT --- */ -// when copying the expression of a default argument, location information is +// when copying the expression of a default argument, location information is // replaced by the location of the caller to improve debug information // verify error messages are displayed for the original location only @@ -26,7 +26,7 @@ void test() void badOp(int x, int y = 1 ~ "string") {} void lazyTemplate(int x, lazy int y = 4.templ) {} void funcTemplate(T)(T y = 5) {} - + funcTemplate!string(); undefinedId(1); badOp(2); diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d index 05c5d30..21a12ed 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d @@ -20,7 +20,7 @@ fail_compilation/dtor_attributes.d(118): Error: destructor `dtor_attributes.Stri fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is not nothrow because of the following field's destructors: fail_compilation/dtor_attributes.d(111): - HasDtor member fail_compilation/dtor_attributes.d(103): not nothrow `HasDtor.~this` is declared here -fail_compilation/dtor_attributes.d(116): Error: `nothrow` function `dtor_attributes.test1` may throw +fail_compilation/dtor_attributes.d(116): Error: function `dtor_attributes.test1` may throw but is marked as `nothrow` --- */ #line 100 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d index de3673f..9f38cb0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d @@ -7,7 +7,7 @@ fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is no 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(22): Error: `nothrow` function `fail10964.foo` may throw +fail_compilation/fail10964.d(22): Error: function `fail10964.foo` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d index 4f221bf..7592a5a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not `nothrow` -fail_compilation/fail11375.d(15): Error: `nothrow` function `D main` may throw +fail_compilation/fail11375.d(15): Error: function `D main` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d index 0198f64..3c2f9c1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d @@ -4,9 +4,9 @@ TEST_OUTPUT: --- fail_compilation/fail11542.d(15): Error: `object.Exception` is thrown but not caught -fail_compilation/fail11542.d(12): Error: `nothrow` function `fail11542.test_success1` may throw +fail_compilation/fail11542.d(12): Error: function `fail11542.test_success1` may throw but is marked as `nothrow` fail_compilation/fail11542.d(25): Error: `object.Exception` is thrown but not caught -fail_compilation/fail11542.d(22): Error: `nothrow` function `fail11542.test_success3` may throw +fail_compilation/fail11542.d(22): Error: function `fail11542.test_success3` may throw but is marked as `nothrow` --- */ void test_success1() nothrow @@ -29,7 +29,7 @@ void test_success3() nothrow TEST_OUTPUT: --- fail_compilation/fail11542.d(38): Error: `object.Exception` is thrown but not caught -fail_compilation/fail11542.d(35): Error: `nothrow` function `fail11542.test_failure1` may throw +fail_compilation/fail11542.d(35): Error: function `fail11542.test_failure1` may throw but is marked as `nothrow` --- */ void test_failure1() nothrow @@ -52,7 +52,7 @@ void est_failure3() nothrow TEST_OUTPUT: --- fail_compilation/fail11542.d(61): Error: `object.Exception` is thrown but not caught -fail_compilation/fail11542.d(58): Error: `nothrow` function `fail11542.test_exit1` may throw +fail_compilation/fail11542.d(58): Error: function `fail11542.test_exit1` may throw but is marked as `nothrow` --- */ void test_exit1() nothrow diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d index a5e9f72..65e89b1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d @@ -6,10 +6,10 @@ bool cond; TEST_OUTPUT: --- fail_compilation/fail12809.d(18): Error: `object.Exception` is thrown but not caught -fail_compilation/fail12809.d(15): Error: `nothrow` function `fail12809.test_finally1` may throw +fail_compilation/fail12809.d(15): Error: function `fail12809.test_finally1` may throw but is marked as `nothrow` fail_compilation/fail12809.d(34): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(38): Error: `object.Exception` is thrown but not caught -fail_compilation/fail12809.d(31): Error: `nothrow` function `fail12809.test_finally3` may throw +fail_compilation/fail12809.d(31): Error: function `fail12809.test_finally3` may throw but is marked as `nothrow` --- */ void test_finally1() nothrow @@ -44,10 +44,10 @@ void test_finally3() nothrow TEST_OUTPUT: --- fail_compilation/fail12809.d(58): Error: `object.Exception` is thrown but not caught -fail_compilation/fail12809.d(53): Error: `nothrow` function `fail12809.test_finally4` may throw +fail_compilation/fail12809.d(53): Error: function `fail12809.test_finally4` may throw but is marked as `nothrow` fail_compilation/fail12809.d(74): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(78): Error: `object.Exception` is thrown but not caught -fail_compilation/fail12809.d(69): Error: `nothrow` function `fail12809.test_finally6` may throw +fail_compilation/fail12809.d(69): Error: function `fail12809.test_finally6` may throw but is marked as `nothrow` --- */ void test_finally4() nothrow diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14277.d b/gcc/testsuite/gdc.test/fail_compilation/fail14277.d new file mode 100644 index 0000000..fd6e618 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14277.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=14277 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14277.d(10): Error: cannot implicitly convert expression `new char[](9999$?:32=u|64=LU$)` of type `char[]` to `ubyte[]` +--- +*/ + +ubyte[] u = new char[9999]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d index 07152f4..c7a2b89 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d @@ -3,39 +3,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail14486.d(56): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(56): Error: `delete c0` is not `@safe` but is used in `@safe` function `test1a` -fail_compilation/fail14486.d(57): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(57): Error: `pure` function `fail14486.test1a` cannot call impure destructor `fail14486.C1a.~this` -fail_compilation/fail14486.d(57): Error: `@safe` function `fail14486.test1a` cannot call `@system` destructor `fail14486.C1a.~this` -fail_compilation/fail14486.d(43): `fail14486.C1a.~this` is declared here -fail_compilation/fail14486.d(57): Error: `@nogc` function `fail14486.test1a` cannot call non-@nogc destructor `fail14486.C1a.~this` -fail_compilation/fail14486.d(62): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(63): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(63): Error: destructor `fail14486.C1b.~this` is not `nothrow` -fail_compilation/fail14486.d(60): Error: `nothrow` function `fail14486.test1b` may throw -fail_compilation/fail14486.d(68): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(68): Error: `delete s0` is not `@safe` but is used in `@safe` function `test2a` -fail_compilation/fail14486.d(69): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(69): Error: `pure` function `fail14486.test2a` cannot call impure destructor `fail14486.S1a.~this` -fail_compilation/fail14486.d(69): Error: `@safe` function `fail14486.test2a` cannot call `@system` destructor `fail14486.S1a.~this` -fail_compilation/fail14486.d(49): `fail14486.S1a.~this` is declared here -fail_compilation/fail14486.d(69): Error: `@nogc` function `fail14486.test2a` cannot call non-@nogc destructor `fail14486.S1a.~this` -fail_compilation/fail14486.d(74): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(75): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(75): Error: destructor `fail14486.S1b.~this` is not `nothrow` -fail_compilation/fail14486.d(72): Error: `nothrow` function `fail14486.test2b` may throw -fail_compilation/fail14486.d(80): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(80): Error: `delete a0` is not `@safe` but is used in `@safe` function `test3a` -fail_compilation/fail14486.d(81): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(81): Error: `pure` function `fail14486.test3a` cannot call impure destructor `fail14486.S1a.~this` -fail_compilation/fail14486.d(81): Error: `@safe` function `fail14486.test3a` cannot call `@system` destructor `fail14486.S1a.~this` -fail_compilation/fail14486.d(49): `fail14486.S1a.~this` is declared here -fail_compilation/fail14486.d(81): Error: `@nogc` function `fail14486.test3a` cannot call non-@nogc destructor `fail14486.S1a.~this` -fail_compilation/fail14486.d(86): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(87): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail14486.d(87): Error: destructor `fail14486.S1b.~this` is not `nothrow` -fail_compilation/fail14486.d(84): Error: `nothrow` function `fail14486.test3b` may throw +fail_compilation/fail14486.d(35): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(36): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(41): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(42): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(47): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(48): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(53): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(54): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(59): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(60): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(65): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/fail14486.d(66): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d index 73b0a78..b71a68e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d @@ -25,6 +25,6 @@ struct issue14554_2 { void test14554() { - issue14554_1.foo!bool(1); - issue14554_2.foo!bool(1); + issue14554_1.foo!bool(1); + issue14554_2.foo!bool(1); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15089.d b/gcc/testsuite/gdc.test/fail_compilation/fail15089.d index 221a978..9aa94f8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail15089.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15089.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail15089.d(10): Error: cannot implicitly convert expression `130` of type `int` to `byte` +fail_compilation/fail15089.d(10): Error: cannot implicitly convert expression `2 ^ 128` of type `int` to `byte` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail160.d b/gcc/testsuite/gdc.test/fail_compilation/fail160.d index c07c8d3..0c8a937 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail160.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail160.d @@ -14,7 +14,7 @@ template Wrapper(B, alias Func, int func) alias typeof(&Func) FuncPtr; private static FuncPtr get_funcptr() { return func; } -} +} int main(char[][] args) diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17906.d b/gcc/testsuite/gdc.test/fail_compilation/fail17906.d new file mode 100644 index 0000000..689dd48 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17906.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -de +/* TEST_OUTPUT: +--- +fail_compilation/fail17906.d(11): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=18647 +deprecated void main () +{ + Object o = new Object; + delete o; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d index 57fabbb..e6b9556 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d @@ -4,7 +4,7 @@ fail_compilation/fail17969.d(9): Error: no property `sum` for type `fail17969.__ --- * https://issues.dlang.org/show_bug.cgi?id=17969 */ - + alias fun = a => MapResult2!(b => b).sum; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18228.d b/gcc/testsuite/gdc.test/fail_compilation/fail18228.d index 983719a..8da0b8d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail18228.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail18228.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail18228.d(12): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead -fail_compilation/fail18228.d(13): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead -fail_compilation/fail18228.d(14): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead +fail_compilation/fail18228.d(12): Error: undefined identifier `this`, did you mean `typeof(this)`? +fail_compilation/fail18228.d(13): Error: undefined identifier `this`, did you mean `typeof(this)`? +fail_compilation/fail18228.d(14): Error: undefined identifier `super`, did you mean `typeof(super)`? --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19441.d b/gcc/testsuite/gdc.test/fail_compilation/fail19441.d index f1f1769..520eb76 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19441.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19441.d @@ -2,7 +2,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19441.d(44): Deprecation: Cannot use `alias this` to partially initialize variable `wrap[0]` of type `Wrap10595`. Use `wrap[0].i` +fail_compilation/fail19441.d(44): Error: cannot use `alias this` to partially initialize variable `wrap[0]` of type `Wrap10595`. Use `wrap[0].i` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail196.d b/gcc/testsuite/gdc.test/fail_compilation/fail196.d index c7b28cf..55c3bd8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail196.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail196.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/fail196.d(27): Error: delimited string must end in )" +fail_compilation/fail196.d(27): Error: delimited string must end in `)"` fail_compilation/fail196.d(27): Error: Implicit string concatenation is error-prone and disallowed in D -fail_compilation/fail196.d(27): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\x0a assert(s == " +fail_compilation/fail196.d(27): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n assert(s == " fail_compilation/fail196.d(28): Error: semicolon needed to end declaration of `s`, instead of `foo` fail_compilation/fail196.d(27): `s` declared here -fail_compilation/fail196.d(28): Error: found `");\x0a\x0a s = q"` when expecting `;` following statement -fail_compilation/fail196.d(30): Error: found `";\x0a assert(s == "` when expecting `;` following statement -fail_compilation/fail196.d(31): Error: found `");\x0a\x0a s = q"` when expecting `;` following statement +fail_compilation/fail196.d(28): Error: found `");\n\n s = q"` when expecting `;` following statement +fail_compilation/fail196.d(30): Error: found `";\n assert(s == "` when expecting `;` following statement +fail_compilation/fail196.d(31): Error: found `");\n\n s = q"` when expecting `;` following statement fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19897.d b/gcc/testsuite/gdc.test/fail_compilation/fail19897.d index 4f5804b..49df470 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19897.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19897.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19897.d(9): Error: cannot implicitly convert expression `[]` of type `const(char[0])` to `const(char)` +fail_compilation/fail19897.d(12): Error: cannot implicitly convert expression `a.x` of type `const(char[0])` to `const(char)` --- */ struct S diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d index c5d6a8a..9f2dbbb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d @@ -1,4 +1,4 @@ -/* +/* DFLAGS: EXTRA_SOURCES: extra-files/minimal/object.d TEST_OUTPUT: diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d b/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d index fbd7406..c1c6549 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d @@ -1,4 +1,4 @@ -/* +/* DFLAGS: TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19922.d b/gcc/testsuite/gdc.test/fail_compilation/fail19922.d index 201b124..1476666 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19922.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19922.d @@ -1,4 +1,4 @@ -/* +/* DFLAGS: TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19923.d b/gcc/testsuite/gdc.test/fail_compilation/fail19923.d index 1438151..d98dd03 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19923.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19923.d @@ -1,4 +1,4 @@ -/* +/* DFLAGS: TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20.d b/gcc/testsuite/gdc.test/fail_compilation/fail20.d index 6cc4d22..4528d36 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20.d @@ -14,6 +14,6 @@ void main() FOO one; FOO two; if (one < two){} // This should tell me that there - // is no opCmp() defined instead + // is no opCmp() defined instead // of crashing. } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d index 1184b8e..185baec 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d @@ -15,7 +15,7 @@ struct RegexMatch } static m() { return RegexMatch(); } -void fun(int a); +void fun(int a); void initCommands() { diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22127.d b/gcc/testsuite/gdc.test/fail_compilation/fail22127.d new file mode 100644 index 0000000..c6e3684 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22127.d @@ -0,0 +1,11 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail22127.d(101): Error: user-defined attributes are not allowed on `alias` declarations +--- + */ + +// https://issues.dlang.org/show_bug.cgi?id=22127 + +#line 100 + +alias getOne = @(0) function int () => 1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22634.d b/gcc/testsuite/gdc.test/fail_compilation/fail22634.d new file mode 100644 index 0000000..320d1eb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22634.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail22634.d(9): Error: more than 65535 symbols with name `i` generated +--- +*/ +void main() +{ + static foreach(i; 0..65537) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d new file mode 100644 index 0000000..dd83f75 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=22780 +/* TEST_OUTPUT: +--- +fail_compilation/fail22780.d(11): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope` +--- +*/ +scope class C10717 { } + +void test10717() +{ + C10717 c; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d index a969495..57edd3a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d @@ -1,8 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail2361.d(14): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail2361.d(14): Error: cannot modify `immutable` expression `c` +fail_compilation/fail2361.d(13): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail258.d b/gcc/testsuite/gdc.test/fail_compilation/fail258.d index 459d271..63cbfd4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail258.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail258.d @@ -1,13 +1,15 @@ /* TEST_OUTPUT: --- -fail_compilation/fail258.d(11): Error: delimiter cannot be whitespace -fail_compilation/fail258.d(11): Error: delimited string must end in -" -fail_compilation/fail258.d(11): Error: declaration expected, not `"X"` -fail_compilation/fail258.d(14): Error: unterminated string constant starting at fail_compilation/fail258.d(14) +fail_compilation/fail258.d(101): Error: delimiter cannot be whitespace +fail_compilation/fail258.d(101): Error: delimited string must end in `"` +fail_compilation/fail258.d(101): Error: declaration expected, not `"X"` +fail_compilation/fail258.d(104): Error: unterminated string constant starting at fail_compilation/fail258.d(104) --- */ + +#line 100 + q" X diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d index 12164b9..91f8046 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d @@ -21,7 +21,7 @@ void test() { foo(); foo(null); - + baz(""); baz(3, null); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail349.d b/gcc/testsuite/gdc.test/fail_compilation/fail349.d index 11a392c..215453e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail349.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail349.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail349.d(15): Error: function `fail349.bug6109throwing` is not `nothrow` -fail_compilation/fail349.d(13): Error: `nothrow` function `fail349.bug6109noThrow` may throw +fail_compilation/fail349.d(13): Error: function `fail349.bug6109noThrow` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail354.d b/gcc/testsuite/gdc.test/fail_compilation/fail354.d index 8689f61..2795acc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail354.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail354.d @@ -10,4 +10,4 @@ struct S(int N) { this(T!N) { } } -alias S!1 M; +alias S!1 M; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d index 6f9ee61..a09f725 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail4082.d(14): Error: destructor `fail4082.Foo.~this` is not `nothrow` -fail_compilation/fail4082.d(12): Error: `nothrow` function `fail4082.test1` may throw +fail_compilation/fail4082.d(12): Error: function `fail4082.test1` may throw but is marked as `nothrow` --- */ struct Foo @@ -22,7 +22,7 @@ NEXT: TEST_OUTPUT: --- fail_compilation/fail4082.d(32): Error: destructor `fail4082.Bar.~this` is not `nothrow` -fail_compilation/fail4082.d(32): Error: `nothrow` function `fail4082.test2` may throw +fail_compilation/fail4082.d(32): Error: function `fail4082.test2` may throw but is marked as `nothrow` --- */ struct Bar diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d index 6604f1f..69b142e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d @@ -10,6 +10,6 @@ enum bool WWW = is(typeof(A.x)); interface A { B blah; - void foo(B b){} + void foo(B b){} } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d index 2530133..e0ebd2f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d @@ -9,6 +9,6 @@ enum bool WWW = is(typeof(A.x)); struct A { B blah; - void foo(B b){} + void foo(B b){} } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d index 8bbfaac..5bba42e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d @@ -9,6 +9,6 @@ enum bool WWW = is(typeof(A.x)); class A { B blah; - void foo(B b){} + void foo(B b){} } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d index 7592779..9c6aaed 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d @@ -14,7 +14,7 @@ void main() { label2: if (true) assert(15); - else + else assert(16); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6968.d b/gcc/testsuite/gdc.test/fail_compilation/fail6968.d index b56a5db..aca90c6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail6968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6968.d @@ -29,4 +29,4 @@ template PredAny(A, B...) void main() { pragma(msg, PredAny!(int, long, float)); -} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d index 4fc269e..e8371c4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d @@ -8,13 +8,13 @@ fail_compilation/fail7848.d(27): Error: `@safe` function `fail7848.C.__unittest_ fail_compilation/fail7848.d(21): `fail7848.func` is declared here fail_compilation/fail7848.d(27): Error: `@nogc` function `fail7848.C.__unittest_L25_C30` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(27): Error: function `fail7848.func` is not `nothrow` -fail_compilation/fail7848.d(25): Error: `nothrow` function `fail7848.C.__unittest_L25_C30` may throw +fail_compilation/fail7848.d(25): Error: function `fail7848.C.__unittest_L25_C30` may throw but is marked as `nothrow` fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func` fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func` fail_compilation/fail7848.d(21): `fail7848.func` is declared here fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(32): Error: function `fail7848.func` is not `nothrow` -fail_compilation/fail7848.d(30): Error: `nothrow` function `fail7848.C.__invariant1` may throw +fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant1` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d index 11facfd..a378fbb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d @@ -23,7 +23,7 @@ class Test static Image[] images; - static void initIcons() + static void initIcons() { images["progress_rem"] = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis images["redo"] = ResourceManager.getImage("redo.gif"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d index 59c890e..e0cc871 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d @@ -23,7 +23,7 @@ class Test static Image[] images; - static void initIcons() + static void initIcons() { images["progress_rem"] = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis images["redo"] = ResourceManager.getImage("redo.gif"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d index c5ca98b..92d313a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/fail8724.d(14): Error: `object.Exception` is thrown but not caught -fail_compilation/fail8724.d(12): Error: `nothrow` constructor `fail8724.Foo.this` may throw +fail_compilation/fail8724.d(12): Error: constructor `fail8724.Foo.this` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d index ed228a9..7087b0c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d @@ -209,8 +209,7 @@ fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]` -fail_compilation/fail_arrayop2.d(281): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/fail_arrayop2.d(281): Error: `[1] * 6` is not an lvalue and cannot be modified +fail_compilation/fail_arrayop2.d(281): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified @@ -235,6 +234,7 @@ fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed --- */ + // Test all expressions, which can take arrays as their operands but cannot be a part of array operation. void test15407exp() { @@ -252,7 +252,7 @@ void test15407exp() // StructLiteralExp.elements <- preFunctionParameters in CallExp { auto r = S([1] * 6); } - // NewExp.newargs/arguments <- preFunctionParameters + // NewExp.arguments <- preFunctionParameters { auto r = new S([1] * 6); } // TODO: TypeidExp diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d new file mode 100644 index 0000000..392cebd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d @@ -0,0 +1,82 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail_typeof.d(18): Error: undefined identifier `this` +fail_compilation/fail_typeof.d(23): Error: `this` is not in a class or struct scope +fail_compilation/fail_typeof.d(23): Error: `this` is only defined in non-static member functions, not `fail_typeof` +fail_compilation/fail_typeof.d(28): Error: undefined identifier `super` +fail_compilation/fail_typeof.d(33): Error: `super` is not in a class scope +fail_compilation/fail_typeof.d(33): Error: `super` is only allowed in non-static class member functions +fail_compilation/fail_typeof.d(40): Error: undefined identifier `this`, did you mean `typeof(this)`? +fail_compilation/fail_typeof.d(50): Error: undefined identifier `super` +fail_compilation/fail_typeof.d(55): Error: `super` is not in a class scope +fail_compilation/fail_typeof.d(55): Error: `super` is only allowed in non-static class member functions +fail_compilation/fail_typeof.d(63): Error: undefined identifier `this`, did you mean `typeof(this)`? +fail_compilation/fail_typeof.d(73): Error: undefined identifier `super`, did you mean `typeof(super)`? +--- +*/ + +enum E1 : this +{ + fail, +} + +enum E2 : typeof(this) +{ + fail, +} + +enum E3 : super +{ + fail, +} + +enum E4 : typeof(super) +{ + fail, +} + +struct S1 +{ + enum E1 : this + { + fail, + } + + enum E2 : typeof(this) + { + ok = S1(), + } + + enum E3 : super + { + fail, + } + + enum E4 : typeof(super) + { + fail, + } +} + +class C1 +{ + enum E1 : this + { + fail, + } + + enum E2 : typeof(this) + { + ok = new C1, + } + + enum E3 : super + { + fail, + } + + enum E4 : typeof(super) + { + ok = new C1, + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d index 95663ea..0a29997 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d +++ b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d @@ -1,8 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/faildeleteaa.d(12): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/faildeleteaa.d(12): Error: cannot delete type `int` +fail_compilation/faildeleteaa.d(11): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d index ebefe33..6d3b223 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d @@ -4,6 +4,8 @@ TEST_OUTPUT: --- fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop` +fail_compilation/imports/foo10727a.d(26): Error: template instance `foo10727a.CirBuff!(Foo)` error instantiating +fail_compilation/imports/foo10727a.d(31): instantiated from here: `Bar!(Foo)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d index 125ac12..4a59d5c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d @@ -4,6 +4,8 @@ TEST_OUTPUT: --- fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop` +fail_compilation/imports/foo10727b.d(17): Error: template instance `foo10727b.CirBuff!(Foo)` error instantiating +fail_compilation/imports/foo10727b.d(22): instantiated from here: `Bar!(Foo)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11968.d b/gcc/testsuite/gdc.test/fail_compilation/ice11968.d index 651f162..ea44eae 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11968.d @@ -1,8 +1,7 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice11968.d(9): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/ice11968.d(9): Error: cannot modify string literal `"fail_compilation$?:windows=\\|/$ice11968.d"` +fail_compilation/ice11968.d(8): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice18753.d b/gcc/testsuite/gdc.test/fail_compilation/ice18753.d index 300eab2..253025cd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice18753.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice18753.d @@ -14,7 +14,7 @@ struct ChunkByImpl { struct Group { } - + static assert(isForwardRange!Group); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d index 088e897..6569d4c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d @@ -10,10 +10,10 @@ fail_compilation/lexer1.d(34): Error: declaration expected, not `0.1L` fail_compilation/lexer1.d(35): Error: declaration expected, not `0.1i` fail_compilation/lexer1.d(36): Error: declaration expected, not `0.1fi` fail_compilation/lexer1.d(37): Error: declaration expected, not `0.1Li` -fail_compilation/lexer1.d(38): Error: declaration expected, not `32U` +fail_compilation/lexer1.d(38): Error: declaration expected, not `' '` fail_compilation/lexer1.d(39): Error: declaration expected, not `55295U` fail_compilation/lexer1.d(40): Error: declaration expected, not `65536U` -fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a"d` +fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a\0ab"d` fail_compilation/lexer1.d(43): Error: declaration expected, not `module` fail_compilation/lexer1.d(45): Error: escape hex sequence has 1 hex digits instead of 2 fail_compilation/lexer1.d(46): Error: undefined escape hex sequence \xG diff --git a/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d b/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d index 29481e3..5a8af97 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d +++ b/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d @@ -1,4 +1,4 @@ -/* +/* DFLAGS: REQUIRED_ARGS: -c EXTRA_SOURCES: extra-files/minimal/object.d diff --git a/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d b/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d index 328f9b9..a55332a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d +++ b/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d @@ -1,4 +1,4 @@ -/* +/* DFLAGS: REQUIRED_ARGS: -c EXTRA_SOURCES: extra-files/minimal/object.d diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d index a862e52..8f18ec5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d @@ -63,12 +63,9 @@ fail_compilation/nogc1.d(55): Error: cannot use `new` in `@nogc` function `nogc1 /* TEST_OUTPUT: --- -fail_compilation/nogc1.d(76): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/nogc1.d(76): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete` -fail_compilation/nogc1.d(77): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/nogc1.d(77): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete` -fail_compilation/nogc1.d(78): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/nogc1.d(78): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete` +fail_compilation/nogc1.d(73): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/nogc1.d(74): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. +fail_compilation/nogc1.d(75): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. --- */ @nogc void testDelete(int* p, Object o, S1* s) diff --git a/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d b/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d index 2d27d6d..7bb2fa9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d @@ -93,7 +93,7 @@ auto returnVoid3(int i) TEST_OUTPUT: --- fail_compilation/noreturn2.d(104): Error: `object.Exception` is thrown but not caught -fail_compilation/noreturn2.d(100): Error: `nothrow` function `noreturn2.doesNestedThrow` may throw +fail_compilation/noreturn2.d(100): Error: function `noreturn2.doesNestedThrow` may throw but is marked as `nothrow` --- +/ diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d index b087411..1e152f5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d +++ b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d @@ -2,7 +2,7 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/scope_type.d(11): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +fail_compilation/scope_type.d(11): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12228.d b/gcc/testsuite/gdc.test/fail_compilation/test12228.d index 522bceb..a62eb86 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test12228.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test12228.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/test12228.d(13): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead +fail_compilation/test12228.d(13): Error: undefined identifier `this`, did you mean `typeof(this)`? fail_compilation/test12228.d(18): Error: no property `x` for type `object.Object` -fail_compilation/test12228.d(19): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead -fail_compilation/test12228.d(20): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead +fail_compilation/test12228.d(19): Error: undefined identifier `super`, did you mean `typeof(super)`? +fail_compilation/test12228.d(20): Error: undefined identifier `super`, did you mean `typeof(super)`? --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16195.d b/gcc/testsuite/gdc.test/fail_compilation/test16195.d index a315f33..6d6c51e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16195.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16195.d @@ -1,8 +1,7 @@ /* * TEST_OUTPUT: --- -fail_compilation/test16195.d(14): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -fail_compilation/test16195.d(14): Error: `delete p` is not `@safe` but is used in `@safe` function `test` +fail_compilation/test16195.d(13): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17307.d b/gcc/testsuite/gdc.test/fail_compilation/test17307.d index 470cfed..e73cca6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17307.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test17307.d @@ -1,4 +1,4 @@ -/* +/* TEST_OUTPUT: --- fail_compilation/test17307.d(9): Error: anonymous struct can only be a part of an aggregate, not module `test17307` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20245.d b/gcc/testsuite/gdc.test/fail_compilation/test20245.d index 24a6f99..74c5384 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20245.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test20245.d @@ -2,15 +2,23 @@ REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test20245.d(14): Error: scope variable `a` may not be returned -fail_compilation/test20245.d(18): Error: cannot take address of `scope` parameter `x` in `@safe` function `foo` -fail_compilation/test20245.d(33): Error: reference to local variable `price` assigned to non-scope `this.minPrice` +fail_compilation/test20245.d(20): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling test20245.escape +fail_compilation/test20245.d(21): Error: copying `&x` into allocated memory escapes a reference to parameter variable `x` +fail_compilation/test20245.d(22): Error: scope variable `a` may not be returned +fail_compilation/test20245.d(26): Error: cannot take address of `scope` parameter `x` in `@safe` function `foo` +fail_compilation/test20245.d(32): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling test20245.escape +fail_compilation/test20245.d(33): Error: copying `&x` into allocated memory escapes a reference to parameter variable `x` +fail_compilation/test20245.d(49): Error: reference to local variable `price` assigned to non-scope `this.minPrice` +fail_compilation/test20245.d(68): Error: reference to local variable `this` assigned to non-scope parameter `msg` calling object.Exception.this +fail_compilation/test20245.d(88): Error: reference to local variable `this` assigned to non-scope parameter `content` calling test20245.listUp --- */ // https://issues.dlang.org/show_bug.cgi?id=20245 @safe int* foo(ref int x) { int* a = &x; + escape(&x); + auto b = [&x]; return a; } @@ -21,9 +29,17 @@ fail_compilation/test20245.d(33): Error: reference to local variable `price` ass @safe int* foo(return ref int x) { int* a = &x; + escape(&x); + auto b = [&x]; return a; } +int* gPtr; +@safe void escape(int* ptr) +{ + gPtr = ptr; +} + // https://issues.dlang.org/show_bug.cgi?id=21212 class MinPointerRecorder { @@ -41,3 +57,34 @@ void main() @safe () { ulong[1000] stomp = 13; } (); auto x = *r.minPrice; // "13" } + +// https://issues.dlang.org/show_bug.cgi?id=22782 +struct DontDoThis +{ + immutable char[12] content; + @safe this(char ch) + { + content[] = ch; + throw new Exception(content[]); + } +} + +void main1() @safe +{ + DontDoThis('a'); +} + +// https://issues.dlang.org/show_bug.cgi?id=22783 +const(char)* charPtr; + +// argument is not, or should not be scope +auto listUp(const(char)* content) {charPtr = content;} + +struct DontDoThis2 +{ + char content; + @safe escape() + { + listUp(&content); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22145.d b/gcc/testsuite/gdc.test/fail_compilation/test22145.d new file mode 100644 index 0000000..3e9f747 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test22145.d @@ -0,0 +1,28 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test22145.d(115): Error: scope variable `x` assigned to non-scope `global` +--- + */ + +// issues.dlang.org/show_bug.cgi?id=22145 + +#line 100 + +struct S +{ + int opApply (scope int delegate (scope int* ptr) @safe dg) @safe + { + return 0; + } +} + +void test() @safe +{ + static int* global; + S s; + foreach (scope int* x; s) + { + global = x; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22686.d b/gcc/testsuite/gdc.test/fail_compilation/test22686.d new file mode 100644 index 0000000..ee500bc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test22686.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=22686 + +/* +TEST_OUTPUT: +--- +fail_compilation/test22686.d(15): Error: `this` is only defined in non-static member functions, not `create` +--- +*/ + +struct S +{ + int[] data; + static auto create() + { + auto self = &this; + return { + assert(data.length); + return self; + }; + } +} diff --git a/gcc/testsuite/gdc.test/runnable/b18034.d b/gcc/testsuite/gdc.test/runnable/b18034.d index 3981aaf..f4b825f 100644 --- a/gcc/testsuite/gdc.test/runnable/b18034.d +++ b/gcc/testsuite/gdc.test/runnable/b18034.d @@ -3,22 +3,22 @@ import core.simd; static if (__traits(compiles, { void16 a; ushort8 b; })) { - void check(void16 a) + void check(void16 a) { - foreach (x; (cast(ushort8)a).array) + foreach (x; (cast(ushort8)a).array) { assert(x == 1); } } - void make(ushort x) + void make(ushort x) { ushort8 v = ushort8(x); check(v); } - void main() - { + void main() + { make(1); } } diff --git a/gcc/testsuite/gdc.test/runnable/imports/a15079.d b/gcc/testsuite/gdc.test/runnable/imports/a15079.d index f8e3a82..82682f7 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/a15079.d +++ b/gcc/testsuite/gdc.test/runnable/imports/a15079.d @@ -41,7 +41,7 @@ void destroy(T)(ref T obj) if (is(T == struct)) _destructRecurse(obj); () @trusted { auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof]; - auto init = cast(ubyte[])typeid(T).init(); + const init = cast(ubyte[]) __traits(initSymbol, T); if (init.ptr is null) // null ptr means initialize to 0s buf[] = 0; else diff --git a/gcc/testsuite/gdc.test/runnable/imports/a19a.d b/gcc/testsuite/gdc.test/runnable/imports/a19a.d index 534ce9b..f3910cb 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/a19a.d +++ b/gcc/testsuite/gdc.test/runnable/imports/a19a.d @@ -11,5 +11,5 @@ struct TemplatedStruct(Param) void foo() { - alias TemplatedStruct!(Dummy) X; + alias TemplatedStruct!(Dummy) X; } diff --git a/gcc/testsuite/gdc.test/runnable/imports/link12144a.d b/gcc/testsuite/gdc.test/runnable/imports/link12144a.d index f4fc8eb..677282e 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/link12144a.d +++ b/gcc/testsuite/gdc.test/runnable/imports/link12144a.d @@ -28,7 +28,7 @@ void fun()() { alias P = S3*; auto p = new P; } { S4[int] aa; auto b = (aa == aa); } { S5[] a; a.length = 10; } - { S6[] a; delete a; } + { S6[] a; destroy(a); } { S7[] a = []; } { S8[] a = [S8.init]; } { S9[int] aa = [1:S9.init]; } diff --git a/gcc/testsuite/gdc.test/runnable/imports/test11745b.d b/gcc/testsuite/gdc.test/runnable/imports/test11745b.d index c4e95e2..abe4aee 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/test11745b.d +++ b/gcc/testsuite/gdc.test/runnable/imports/test11745b.d @@ -1,17 +1,17 @@ module imports.test11745b; -unittest +unittest { - + } -private unittest +private unittest { - + } private: -unittest +unittest { - + } diff --git a/gcc/testsuite/gdc.test/runnable/imports/test46c.d b/gcc/testsuite/gdc.test/runnable/imports/test46c.d index c0f3e9f..d5cc142 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/test46c.d +++ b/gcc/testsuite/gdc.test/runnable/imports/test46c.d @@ -3,5 +3,5 @@ module imports.test46c; class C(T) { void foo() { } -} +} diff --git a/gcc/testsuite/gdc.test/runnable/inline7625.d b/gcc/testsuite/gdc.test/runnable/inline7625.d new file mode 100644 index 0000000..eca5727 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/inline7625.d @@ -0,0 +1,185 @@ +// REQUIRED_ARGS: -inline + +/***************************************************/ + +pragma(inline, true) +{ + int foo1(int v) + { + return bar1(2 * v); + } + + int bar1(int a) + { + if (a > 0) + return 1; + else + return baz1(a); + } +} + +int baz1(int a) +{ + if (a > 0) + throw new Exception("a > 0"); + return a - 1; +} + +// --- + +pragma(inline, true) +{ + int foo2(int v) + { + return bar2(2 * v); + } + + int bar2(int a) + { + if (a > 0) + return 1; + // else + return baz2(a); + } +} + +int baz2(int a) +{ + if (a > 0) + throw new Exception("a > 0"); + return a - 1; +} + +// --- + +pragma(inline, true) +{ + int foo3(int v) + { + return bar3(2 * v); + } + + int bar3(int a) + { + if (a > 0) + a = 1; + else + return baz3(a); + return a; + } +} + +int baz3(int a) +{ + if (a > 0) + throw new Exception("a > 0"); + return a - 1; +} + +void test7625a() +{ + assert(foo1(1) == 1); + assert(foo1(0) == -1); + assert(foo2(1) == 1); + assert(foo2(0) == -1); + assert(foo3(1) == 1); + assert(foo3(0) == -1); +} + +/***************************************************/ + +@safe pragma(inline, true) +{ + int tembo(int x, int y) + { + if (y == 0) + return 0; + x++; + return x / y; + } + int pembo(int x, int y) + { + if (y == 0) + return 0; + else + { + x++; + return x / y; + } + } + + int twiga(int x, int y, int z) + { + auto w = tembo(x, y); + return w * z; + } + + int simba(int x, int y, int z) + { + auto w = pembo(x, y); + return w * z; + } +} + +void test7625b() +{ + assert(twiga(5, 3, 4) == 8); + assert(twiga(5, 0, 4) == 0); + + assert(simba(5, 3, 4) == 8); + assert(simba(5, 0, 4) == 0); +} + +/***************************************************/ + +@safe pragma(inline, true) +{ + bool inlineMe15483a(bool left) + { + if (left) + return true; + + return false; + } + + bool inlineMe15483b(bool left) + { + if (left) + return true; + + static if (false) + { + /* https://issues.dlang.org/show_bug.cgi?id=15483 + Even though it does absolutely nothing, + the mere presence of this block prevents inlining + of this function. + */ + } + + return false; + } +} + +int foo15483() +{ + auto r1 = inlineMe15483a(true); + auto r2 = inlineMe15483b(true); // OK <- NG + + return 128; +} + +void test15483() +{ + // Prevent inlining of test function call. + auto fp = &foo15483; + assert(fp() == 128); +} + +/***************************************************/ + +void main() +{ + test7625a(); + test7625b(); + test15483(); +} diff --git a/gcc/testsuite/gdc.test/runnable/interface.d b/gcc/testsuite/gdc.test/runnable/interface.d index 78a712e..a53c5ee 100644 --- a/gcc/testsuite/gdc.test/runnable/interface.d +++ b/gcc/testsuite/gdc.test/runnable/interface.d @@ -1,11 +1,3 @@ -/* -TEST_OUTPUT: ---- -runnable/interface.d(41): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interface.d(55): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ - import core.stdc.stdio; /*******************************************/ @@ -38,7 +30,7 @@ void test1() IO io = new IO(); printf("io = %p\n", io); foo(io, io); - delete io; + destroy(io); } /*******************************************/ @@ -52,7 +44,7 @@ class C : I void test2() { I i = new C(); - delete i; + destroy(i); { scope I j = new C(); diff --git a/gcc/testsuite/gdc.test/runnable/interface2.d b/gcc/testsuite/gdc.test/runnable/interface2.d index 328f839..fabbbfd 100644 --- a/gcc/testsuite/gdc.test/runnable/interface2.d +++ b/gcc/testsuite/gdc.test/runnable/interface2.d @@ -1,11 +1,4 @@ // PERMUTE_ARGS: -/* -TEST_OUTPUT: ---- -runnable/interface2.d(47): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interface2.d(98): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ extern(C) int printf(const char*, ...); @@ -44,7 +37,7 @@ void test1() printf("cast(Bar)f = %p\n", b2); assert(b is b2); - delete f; + destroy(f); } /*******************************************************/ @@ -95,7 +88,7 @@ class E3 : D3, C3 void test3() { C3 c = new E3(); - delete c; + destroy(c); } diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d index d8059d3..4d02a92 100644 --- a/gcc/testsuite/gdc.test/runnable/interpret.d +++ b/gcc/testsuite/gdc.test/runnable/interpret.d @@ -4,14 +4,6 @@ TEST_OUTPUT: true g &Test109S(&Test109S()) -runnable/interpret.d(3197): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3199): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3202): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3205): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3206): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3212): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3213): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/interpret.d(3216): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. tfoo tfoo Crash! @@ -3187,33 +3179,96 @@ auto test110 = [Test110f(1, Test110s(1, 2, 3))]; /************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6907 +// FIXME: Shouldn't this go in core.memory now that `delete` has been removed? int test6907() { + import core.memory : __delete; + int dtor1; class C { ~this() { ++dtor1; } } // delete on Object - { Object o; delete o; } + { Object o; if (!__ctfe) __delete(o); } { scope o = new Object(); } - { Object o = new Object(); delete o; } + { Object o = new Object(); if (!__ctfe) __delete(o); } // delete on C - { C c; delete c; } - { { scope c = new C(); } assert(dtor1 == 1); } - { { scope Object o = new C(); } assert(dtor1 == 2); } - { C c = new C(); delete c; assert(dtor1 == 3); } - { Object o = new C(); delete o; assert(dtor1 == 4); } + { + C c; + if (!__ctfe) + __delete(c); + } + { + { scope c = new C(); } + assert(dtor1 == 1); + } + { + { scope Object o = new C(); } + assert(dtor1 == 2); + } + { + C c = new C(); + if (__ctfe) + { + c.__dtor(); + c = null; + } + else + __delete(c); + assert(dtor1 == 3); + } + { + Object o = new C(); + if (__ctfe) + { + (cast(C)o).__dtor(); + o = null; + } + else + __delete(o); + assert(dtor1 == 4); + } int dtor2; struct S1 { ~this() { ++dtor2; } } // delete on S1 - { S1* p; delete p; } - { S1* p = new S1(); delete p; assert(dtor2 == 1); } + { + S1* p; + // https://issues.dlang.org/show_bug.cgi?id=22779 + // Uncomment after druntime fix + version (none) + { + if (!__ctfe) + __delete(p); + } + } + { + S1* p = new S1(); + if (__ctfe) + { + (*p).__dtor(); + destroy(p); + } + else + __delete(p); + assert(dtor2 == 1); + } // delete on S1[] - { S1[] a = [S1(), S1()]; delete a; assert(dtor2 == 3); } + { + S1[] a = [S1(), S1()]; + if (__ctfe) + { + a[1].__dtor(); + a[0].__dtor(); + destroy(a); + } + else + __delete(a); + assert(dtor2 == 3); + } return 1; } diff --git a/gcc/testsuite/gdc.test/runnable/link12144.d b/gcc/testsuite/gdc.test/runnable/link12144.d index e7bcf86..9092556 100644 --- a/gcc/testsuite/gdc.test/runnable/link12144.d +++ b/gcc/testsuite/gdc.test/runnable/link12144.d @@ -1,11 +1,5 @@ // COMPILE_SEPARATELY: -g // EXTRA_SOURCES: imports/link12144a.d -/* -TEST_OUTPUT: ---- -runnable/imports/link12144a.d(31): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ import imports.link12144a; diff --git a/gcc/testsuite/gdc.test/runnable/link15017.d b/gcc/testsuite/gdc.test/runnable/link15017.d index 5d39547..ef52dfb 100644 --- a/gcc/testsuite/gdc.test/runnable/link15017.d +++ b/gcc/testsuite/gdc.test/runnable/link15017.d @@ -1,11 +1,5 @@ // COMPILE_SEPARATELY: // EXTRA_SOURCES: imports/std15017variant.d -/* -TEST_OUTPUT: ---- -runnable/link15017.d(48): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ import imports.std15017variant; @@ -45,7 +39,7 @@ void test() // OK <- in DeleteExp::semantic Variant10* p10; - delete p10; + destroy(p10); static assert(Variant10.__dtor.mangleof == "_D7imports15std15017variant__T8VariantNVki10ZQp6__dtorMFNaNbNiNfZv"); } diff --git a/gcc/testsuite/gdc.test/runnable/mixin1.d b/gcc/testsuite/gdc.test/runnable/mixin1.d index d8b5516..d36d3f1 100644 --- a/gcc/testsuite/gdc.test/runnable/mixin1.d +++ b/gcc/testsuite/gdc.test/runnable/mixin1.d @@ -1,9 +1,4 @@ /* -TEST_OUTPUT: ---- -runnable/mixin1.d(948): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- - RUN_OUTPUT: --- Foo3.func() @@ -945,7 +940,7 @@ class Outer38 void test38() { Outer38 o = new Outer38(); - delete o; + destroy(o); assert(Outer38.c == 3); } diff --git a/gcc/testsuite/gdc.test/runnable/newdel.d b/gcc/testsuite/gdc.test/runnable/newdel.d index 3729b2e..8ba7a0c 100644 --- a/gcc/testsuite/gdc.test/runnable/newdel.d +++ b/gcc/testsuite/gdc.test/runnable/newdel.d @@ -1,10 +1,4 @@ // PERMUTE_ARGS: -/* -TEST_OUTPUT: ---- -runnable/newdel.d(46): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ import core.stdc.stdio; import core.stdc.stdlib; @@ -43,7 +37,7 @@ void test1() assert(f.d == 56); assert(Foo.flags == 0); - delete f; + destroy(f); assert(Foo.flags == 1); } diff --git a/gcc/testsuite/gdc.test/runnable/sdtor.d b/gcc/testsuite/gdc.test/runnable/sdtor.d index 56c5125..e6b3238 100644 --- a/gcc/testsuite/gdc.test/runnable/sdtor.d +++ b/gcc/testsuite/gdc.test/runnable/sdtor.d @@ -3,19 +3,13 @@ /* TEST_OUTPUT: --- -runnable/sdtor.d(36): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(59): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(93): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(117): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(143): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(177): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(203): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/sdtor.d(276): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. S7353 --- */ import core.vararg; +// FIXME: Shouldn't tests that use this go in core.memory now that `delete` has been removed? +import core.memory : __delete; extern (C) int printf(const(char*) fmt, ...) nothrow; @@ -33,7 +27,7 @@ struct S1 void test1() { S1* s = new S1(); - delete s; + __delete(s); assert(sdtor == 1); } @@ -56,7 +50,7 @@ void test3() { T3* s = new T3(); s.s.a = 3; - delete s; + __delete(s); assert(sdtor3 == 1); } @@ -90,7 +84,7 @@ void test4() { T4* s = new T4(); s.s.a = 4; - delete s; + __delete(s); assert(sdtor4 == 3); } @@ -114,7 +108,7 @@ struct T5 void test5() { T5* s = new T5(); - delete s; + __delete(s); assert(sdtor5 == 2); } @@ -140,7 +134,7 @@ class T6 void test6() { T6 s = new T6(); - delete s; + __delete(s); assert(sdtor6 == 2); } @@ -174,7 +168,7 @@ struct T7 void test7() { T7* s = new T7(); - delete s; + __delete(s); assert(sdtor7 == 4); } @@ -200,7 +194,7 @@ void test8() s[0].c = 2; s[1].c = 1; s[2].c = 0; - delete s; + __delete(s); assert(sdtor8 == 3); } @@ -273,7 +267,7 @@ class T11 void test11() { T11 s = new T11(); - delete s; + __delete(s); assert(sdtor11 == 2); } diff --git a/gcc/testsuite/gdc.test/runnable/test11934.d b/gcc/testsuite/gdc.test/runnable/test11934.d index 4ab65d2..7e6dc04 100644 --- a/gcc/testsuite/gdc.test/runnable/test11934.d +++ b/gcc/testsuite/gdc.test/runnable/test11934.d @@ -5,7 +5,7 @@ void main() this(int i) { instances++; } this(this) { instances++; } ~this() { instances--; } - static size_t instances = 0; + static size_t instances = 0; } struct Range11934 diff --git a/gcc/testsuite/gdc.test/runnable/test17684.d b/gcc/testsuite/gdc.test/runnable/test17684.d index d42baac..efdce08 100644 --- a/gcc/testsuite/gdc.test/runnable/test17684.d +++ b/gcc/testsuite/gdc.test/runnable/test17684.d @@ -7,17 +7,17 @@ struct StructField(T) struct StructProperty(T) { static T Field; - + static @property T property() { - return Field; + return Field; } - + static @property void property(T value) { - Field = value; + Field = value; } - + static alias property this; } @@ -30,17 +30,17 @@ class ClassField(T) class ClassProperty(T) { static T Field; - + static @property T property() { - return Field; + return Field; } - + static @property void property(T value) { - Field = value; + Field = value; } - + static alias property this; } diff --git a/gcc/testsuite/gdc.test/runnable/test17899.d b/gcc/testsuite/gdc.test/runnable/test17899.d index fdd75e8..2ad60d0 100644 --- a/gcc/testsuite/gdc.test/runnable/test17899.d +++ b/gcc/testsuite/gdc.test/runnable/test17899.d @@ -1,7 +1,7 @@ module test17899; // Test that the ICE in 13259 does not ICE but produces correct code -auto dg = delegate {}; +auto dg = delegate {}; int setme = 0; void delegate() bar1 = (){ setme = 1;}; diff --git a/gcc/testsuite/gdc.test/runnable/test20.d b/gcc/testsuite/gdc.test/runnable/test20.d index 5a1985a..5d47b06 100644 --- a/gcc/testsuite/gdc.test/runnable/test20.d +++ b/gcc/testsuite/gdc.test/runnable/test20.d @@ -1,9 +1,3 @@ -/* -TEST_OUTPUT: ---- -runnable/test20.d(448): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ import core.vararg; extern(C) int printf(const char*, ...); @@ -445,7 +439,7 @@ class Buffer void test20() { Buffer b = new Buffer(); - delete b; + destroy(b); } /*****************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/test22136.d b/gcc/testsuite/gdc.test/runnable/test22136.d new file mode 100644 index 0000000..8b5af24 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test22136.d @@ -0,0 +1,25 @@ + +interface IObject +{ + size_t toHash() @trusted nothrow; +} + +interface Dummy {} +interface Bug(E) : Dummy, IObject {} +interface OK(E) : IObject, Dummy {} + +void main() +{ + + { + Bug!string s; + size_t t = hashOf(s); + } + { + OK!string s; + size_t t = hashOf(s); + } + + static assert(is(immutable Bug!string* : immutable IObject*)); + static assert(is(immutable OK!string* : immutable IObject*)); +} diff --git a/gcc/testsuite/gdc.test/runnable/test22163.d b/gcc/testsuite/gdc.test/runnable/test22163.d new file mode 100644 index 0000000..2613763 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test22163.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=22163 +void fun(float[2] arr) +{ + assert(arr[0] == 10.0); + assert(arr[1] == 20.0); + auto dg = (int x) => arr[0]; +} + +void main() +{ + float[2] arr = [10.0, 20.0]; + fun(arr); +} diff --git a/gcc/testsuite/gdc.test/runnable/test22717.d b/gcc/testsuite/gdc.test/runnable/test22717.d new file mode 100644 index 0000000..75d54c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test22717.d @@ -0,0 +1,31 @@ +// PERMUTE_ARGS: -version=XopEquals + +void main() +{ + static struct S + { + int value; + + version (XopEquals) + { + bool opEquals(const S rhs) const + { + assert(this.value == 42); + return true; + } + } + else + { + bool opEquals(const ref S rhs) const + { + assert(this.value == 42); + return true; + } + } + } + + auto a = S(42); + auto b = S(24); + auto ti = typeid(S); + assert(ti.equals(&a, &b)); +} diff --git a/gcc/testsuite/gdc.test/runnable/test4.d b/gcc/testsuite/gdc.test/runnable/test4.d index 9811254..8a3f926 100644 --- a/gcc/testsuite/gdc.test/runnable/test4.d +++ b/gcc/testsuite/gdc.test/runnable/test4.d @@ -1,11 +1,5 @@ // PERMUTE_ARGS: // REQUIRED_ARGS: -/* -TEST_OUTPUT: ---- -runnable/test4.d(717): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ import core.exception; import core.stdc.math; @@ -714,7 +708,7 @@ void test29() Foo29 f = new Foo29(); - delete f; + destroy(f); assert(x29 == 3); } diff --git a/gcc/testsuite/gdc.test/runnable/testappend.d b/gcc/testsuite/gdc.test/runnable/testappend.d index f8bff3e..cedd8d7 100644 --- a/gcc/testsuite/gdc.test/runnable/testappend.d +++ b/gcc/testsuite/gdc.test/runnable/testappend.d @@ -1,13 +1,5 @@ /* PERMUTE_ARGS: -TEST_OUTPUT: ---- -runnable/testappend.d(54): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/testappend.d(55): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/testappend.d(76): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. -runnable/testappend.d(77): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- - RUN_OUTPUT: --- Success @@ -51,8 +43,8 @@ int main() { assert(isnan(v)); } - delete a; - delete b; + destroy(a); + destroy(b); a = null; for (int i = 0; i < 100000; i++) @@ -73,8 +65,8 @@ int main() { assert(v == k); } - delete a; - delete b; + destroy(a); + destroy(b); test12826(); printf("Success\n"); diff --git a/gcc/testsuite/gdc.test/runnable/testconst.d b/gcc/testsuite/gdc.test/runnable/testconst.d index 764bb1b..502dca0 100644 --- a/gcc/testsuite/gdc.test/runnable/testconst.d +++ b/gcc/testsuite/gdc.test/runnable/testconst.d @@ -2175,13 +2175,13 @@ void test4251b() // derived class to const(base interface) in tail interface I {} class X : I {} - static assert(!is( X[] : const(I)[] )); + static assert(is( X[] : const(I)[] )); // interface to const(base interface) in tail interface J {} interface K : I, J {} static assert( is( K[] : const(I)[] )); // OK, runtime offset is same - static assert(!is( K[] : const(J)[] )); // NG, runtime offset is different + static assert(is( K[] : const(J)[] )); // !? NG, runtime offset is different } /************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/testdstress.d b/gcc/testsuite/gdc.test/runnable/testdstress.d index 6ca5500..03af207 100644 --- a/gcc/testsuite/gdc.test/runnable/testdstress.d +++ b/gcc/testsuite/gdc.test/runnable/testdstress.d @@ -1,10 +1,4 @@ // PERMUTE_ARGS: -/* -TEST_OUTPUT: ---- -runnable/testdstress.d(666): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. ---- -*/ module run.module_01; @@ -663,7 +657,7 @@ void test30() assert(status30 == 1); - delete m; // _d_callfinalizer + destroy(m); // _d_callfinalizer } catch (Error e) // FinalizeError { diff --git a/gcc/testsuite/gdc.test/runnable/testptrref.d b/gcc/testsuite/gdc.test/runnable/testptrref.d index c616d57..7255595 100644 --- a/gcc/testsuite/gdc.test/runnable/testptrref.d +++ b/gcc/testsuite/gdc.test/runnable/testptrref.d @@ -21,7 +21,7 @@ version(CRuntime_Microsoft) void[] function(string name) nothrow @nogc); dataSection = findImageSection(".data"); } - + void[] tlsRange; static this() { @@ -30,7 +30,7 @@ version(CRuntime_Microsoft) void[] function() nothrow @nogc); tlsRange = initTLSRanges(); } - + version = ptrref_supported; } else version(Win32) @@ -126,7 +126,7 @@ bool findDataPtr(const(void)* ptr) void* addr = dataSection.ptr + *p; else void* addr = *p; - + if (addr == ptr) return true; } @@ -158,7 +158,7 @@ void testRefPtr() assert(!findTlsPtr(cast(size_t*)&tlsStr)); // length assert(findTlsPtr(cast(size_t*)&tlsStr + 1)); // ptr - + // monitor is manually managed assert(!findDataPtr(cast(size_t*)cast(void*)Class.classinfo + 1)); assert(!findDataPtr(cast(size_t*)cast(void*)Class.classinfo + 1)); @@ -167,7 +167,7 @@ void testRefPtr() assert(!findTlsPtr(&arr)); assert(!findDataPtr(cast(size_t*)&arr + 1)); assert(!findTlsPtr(cast(size_t*)&arr + 1)); - + assert(findDataPtr(cast(size_t*)&strArr[0] + 1)); // ptr in _DATA! assert(findDataPtr(cast(size_t*)&strArr[1] + 1)); // ptr in _DATA! strArr[1] = "c"; diff --git a/gcc/testsuite/gdc.test/runnable/xpostblit.d b/gcc/testsuite/gdc.test/runnable/xpostblit.d index 8f8a59d..5889116 100644 --- a/gcc/testsuite/gdc.test/runnable/xpostblit.d +++ b/gcc/testsuite/gdc.test/runnable/xpostblit.d @@ -86,7 +86,7 @@ struct FieldThrow bool throwExcept; this(this) - { + { if (throwExcept) { throw new Exception(""); diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d index cd36bf2..e315889 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d @@ -469,7 +469,7 @@ extern (C++, std) static if (__traits(getTargetInfo, "cppStd") >= 201703) { // std::allocator no longer derives from __gnu_cxx::new_allocator, - // it derives from std::__new_allocator instead. + // it derives from std::__new_allocator instead. struct __new_allocator(T) { alias size_type = size_t; diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 251d78d..49f6ae2 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -dbd0c874a345438b8b4379a67525a933436d039a +55528bd1e963d858eaa63901fc818b957c349fbc 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/__builtins.di b/libphobos/libdruntime/__builtins.di index cd64881..e5c448e 100644 --- a/libphobos/libdruntime/__builtins.di +++ b/libphobos/libdruntime/__builtins.di @@ -38,3 +38,68 @@ alias __builtin_va_copy = core.stdc.stdarg.va_copy; /* dmd's ImportC rewrites __builtin_va_arg into an instantiation of va_arg */ alias va_arg = core.stdc.stdarg.va_arg; + +version (CRuntime_Microsoft) +{ + //https://docs.microsoft.com/en-us/cpp/cpp/int8-int16-int32-int64?view=msvc-170 + alias __int8 = byte; + alias __int16 = short; + alias __int32 = int; + alias __int64 = long; +} + +/*********** floating point *************/ + +/* https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html + */ + +version (DigitalMars) +{ + double __builtin_inf()() { return double.infinity; } + float __builtin_inff()() { return float.infinity; } + real __builtin_infl()() { return real.infinity; } + + alias __builtin_huge_val = __builtin_inf; + alias __builtin_huge_valf = __builtin_inff; + alias __builtin_huge_vall = __builtin_infl; + + import core.stdc.math; + + alias __builtin_fabs = core.stdc.math.fabs; + alias __builtin_fabsf = core.stdc.math.fabsf; + alias __builtin_fabsl = core.stdc.math.fabsl; + + ushort __builtin_bswap16()(ushort value) + { + import core.bitop; + return core.bitop.byteswap(value); + } + + uint __builtin_bswap32()(uint value) + { + import core.bitop; + return core.bitop.bswap(value); + } + + ulong __builtin_bswap64()(ulong value) + { + import core.bitop; + return core.bitop.bswap(value); + } + + // Stub these out to no-ops + int __builtin_constant_p(T)(T exp) { return 0; } // should be something like __traits(compiles, enum X = expr) + long __builtin_expect()(long exp, long c) { return exp; } + void* __builtin_assume_aligned()(const void* p, size_t align_, ...) { return cast(void*)p; } + + // https://releases.llvm.org/13.0.0/tools/clang/docs/LanguageExtensions.html#builtin-assume + void __builtin_assume(T)(lazy T arg) { } + + /* Header on macOS for arm64 references this. + * Don't need to implement it, it just needs to compile + */ + align (16) struct __uint128_t + { + ulong a, b; + } +} diff --git a/libphobos/libdruntime/core/attribute.d b/libphobos/libdruntime/core/attribute.d index b0b973f..69b20f0 100644 --- a/libphobos/libdruntime/core/attribute.d +++ b/libphobos/libdruntime/core/attribute.d @@ -241,3 +241,52 @@ version (UdaGNUAbiTag) struct gnuAbiTag this.tags = tags; } } + +/** + * Use this attribute to ensure that values of a `struct` or `union` type are + * not discarded. + * + * The value of an expression is considered to be discarded if + * + * $(UL + * $(LI + * the expression is the top-level expression in a statement or the + * left-hand expression in a comma expression, and + * ), + * $(LI + * the expression is not an assignment (`=`, `+=`, etc.), increment + * (`++`), or decrement (`--`) expression. + * ), + * ) + * + * If the declaration of a `struct` or `union` type has the `@mustuse` + * attribute, the compiler will emit an error any time a value of that type + * would be discarded. + * + * Currently, `@mustuse` is only recognized by the compiler when attached to + * `struct` and `union` declarations. To allow for future expansion, attaching + * `@mustuse` to a `class`, `interface`, `enum`, or function declaration is + * currently forbidden, and will result in a compile-time error. All other uses + * of `@mustuse` are ignored. + * + * Examples: + * --- + * @mustuse struct ErrorCode { int value; } + * + * extern(C) ErrorCode doSomething(); + * + * void main() + * { + * // error: would discard a value of type ErrorCode + * //doSomething(); + * + * ErrorCode result; + * // ok: value is assigned to a variable + * result = doSomething(); + * + * // ok: can ignore the value explicitly with a cast + * cast(void) doSomething(); + * } + * --- + */ +enum mustuse; diff --git a/libphobos/libdruntime/core/bitop.d b/libphobos/libdruntime/core/bitop.d index 40f2242..59445f0 100644 --- a/libphobos/libdruntime/core/bitop.d +++ b/libphobos/libdruntime/core/bitop.d @@ -758,19 +758,6 @@ version (DigitalMars) version (AnyX86) } -// @@@DEPRECATED_2.099@@@ -deprecated("volatileLoad has been moved to core.volatile. Use core.volatile.volatileLoad instead.") -{ - public import core.volatile : volatileLoad; -} - -// @@@DEPRECATED_2.099@@@ -deprecated("volatileStore has been moved to core.volatile. Use core.volatile.volatileStore instead.") -{ - public import core.volatile : volatileStore; -} - - /** * Reverses the order of bits in a 32-bit integer. */ diff --git a/libphobos/libdruntime/core/int128.d b/libphobos/libdruntime/core/int128.d index aad2cf2..2f628c0 100644 --- a/libphobos/libdruntime/core/int128.d +++ b/libphobos/libdruntime/core/int128.d @@ -801,6 +801,7 @@ unittest const Cm10_0 = inc(com(C10_0)); // Cent(0, -10); const Cm10_1 = inc(com(C10_1)); // Cent(-1, -11); const Cm10_3 = inc(com(C10_3)); // Cent(-3, -11); + const Cm20_0 = inc(com(C20_0)); // Cent(0, -20); enum Cs_3 = Cent(3, I.min); @@ -904,6 +905,7 @@ unittest assert(mul(C9_3, C10) == C90_30); assert(mul(Cs_3, C10) == C30); assert(mul(Cm10, Cm10) == C100); + assert(mul(C20_0, Cm1) == Cm20_0); assert( or(C4_8, C3_1) == C7_9); assert(and(C4_8, C7_9) == C4_8); diff --git a/libphobos/libdruntime/core/internal/array/appending.d b/libphobos/libdruntime/core/internal/array/appending.d index 1e58ddc..172263c 100644 --- a/libphobos/libdruntime/core/internal/array/appending.d +++ b/libphobos/libdruntime/core/internal/array/appending.d @@ -35,14 +35,14 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations. */ static if (isCopyingNothrow!T) // `nothrow` deduction doesn't work, so this is needed - ref Tarr _d_arrayappendcTX(return scope ref Tarr px, size_t n) @trusted pure nothrow + ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow { pragma(inline, false); mixin(_d_arrayappendcTXBody); } else - ref Tarr _d_arrayappendcTX(return scope ref Tarr px, size_t n) @trusted pure nothrow + ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow { pragma(inline, false); @@ -96,14 +96,14 @@ template _d_arrayappendTImpl(Tarr : T[], T) * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations. */ static if (isCopyingNothrow!T) - ref Tarr _d_arrayappendT(return scope ref Tarr x, scope Tarr y) @trusted pure nothrow + ref Tarr _d_arrayappendT(return ref scope Tarr x, scope Tarr y) @trusted pure nothrow { pragma(inline, false); mixin(_d_arrayappendTBody); } else - ref Tarr _d_arrayappendT(return scope ref Tarr x, scope Tarr y) @trusted pure + ref Tarr _d_arrayappendT(return ref scope Tarr x, scope Tarr y) @trusted pure { pragma(inline, false); diff --git a/libphobos/libdruntime/core/internal/array/comparison.d b/libphobos/libdruntime/core/internal/array/comparison.d index 1a68b9b..821f96e 100644 --- a/libphobos/libdruntime/core/internal/array/comparison.d +++ b/libphobos/libdruntime/core/internal/array/comparison.d @@ -60,24 +60,21 @@ int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted immutable len = lhs.length <= rhs.length ? lhs.length : rhs.length; foreach (const u; 0 .. len) { - static if (__traits(isFloating, T)) + auto a = lhs.ptr[u], b = rhs.ptr[u]; + static if (is(T : creal)) { - immutable a = lhs.ptr[u], b = rhs.ptr[u]; - static if (is(T == cfloat) || is(T == cdouble) - || is(T == creal)) - { - // Use rt.cmath2._Ccmp instead ? - auto r = (a.re > b.re) - (a.re < b.re); - if (!r) r = (a.im > b.im) - (a.im < b.im); - } - else - { - const r = (a > b) - (a < b); - } - if (r) return r; + // Use rt.cmath2._Ccmp instead ? + // Also: if NaN is present, numbers will appear equal. + auto r = (a.re > b.re) - (a.re < b.re); + if (!r) r = (a.im > b.im) - (a.im < b.im); + } + else + { + // This pattern for three-way comparison is better than conditional operators + // See e.g. https://godbolt.org/z/3j4vh1 + const r = (a > b) - (a < b); } - else if (lhs.ptr[u] != rhs.ptr[u]) - return lhs.ptr[u] < rhs.ptr[u] ? -1 : 1; + if (r) return r; } return (lhs.length > rhs.length) - (lhs.length < rhs.length); } @@ -117,8 +114,8 @@ if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) } else static if (__traits(compiles, at(s1, u) < at(s2, u))) { - if (at(s1, u) != at(s2, u)) - return at(s1, u) < at(s2, u) ? -1 : 1; + if (int result = (at(s1, u) > at(s2, u)) - (at(s1, u) < at(s2, u))) + return result; } else { diff --git a/libphobos/libdruntime/core/internal/convert.d b/libphobos/libdruntime/core/internal/convert.d index a876fcc..92eb243 100644 --- a/libphobos/libdruntime/core/internal/convert.d +++ b/libphobos/libdruntime/core/internal/convert.d @@ -741,28 +741,6 @@ const(ubyte)[] toUbyte(T)(const ref scope T val) if (is(T == __vector)) } } -// @@@DEPRECATED_2022-02@@@ -deprecated -@trusted pure nothrow @nogc -const(ubyte)[] toUbyte(T)(const ref return scope T val) if (__traits(isFloating, T) && is(T : creal)) -{ - if (__ctfe) - { - auto re = val.re; - auto im = val.im; - auto a = re.toUbyte(); - auto b = im.toUbyte(); - ubyte[] result = ctfe_alloc(a.length + b.length); - result[0 .. a.length] = a[0 .. a.length]; - result[a.length .. $] = b[0 .. b.length]; - return result; - } - else - { - return (cast(const(ubyte)*)&val)[0 .. T.sizeof]; - } -} - @trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == enum)) { diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index 091269a..3a7c8e0 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -2646,9 +2646,9 @@ T _d_newThrowable(T, Args...)(auto ref Args args) @trusted { debug(PRINTF) printf("_d_newThrowable(%s)\n", cast(char*) T.stringof); - import core.stdc.stdlib : malloc; + import core.memory : pureMalloc; auto init = __traits(initSymbol, T); - void* p = malloc(init.length); + void* p = pureMalloc(init.length); if (!p) { import core.exception : onOutOfMemoryError; diff --git a/libphobos/libdruntime/core/math.d b/libphobos/libdruntime/core/math.d index 4d46b67..30fc130 100644 --- a/libphobos/libdruntime/core/math.d +++ b/libphobos/libdruntime/core/math.d @@ -36,6 +36,7 @@ nothrow: * greater than long.max, the result is * indeterminate. */ +deprecated("rndtonl is to be removed by 2.100. Please use round instead") extern (C) real rndtonl(real x); pure: diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index 81d2d26..d1378af 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -285,7 +285,7 @@ struct Runtime * an appropriate calling context from which to begin the trace. * * Params: - * h = The new trace handler. Set to null to use the default handler. + * h = The new trace handler. Set to null to disable exception backtracing. */ extern(C) pragma(mangle, "rt_setTraceHandler") static @property void traceHandler(TraceHandler h); diff --git a/libphobos/libdruntime/core/stdc/stdio.d b/libphobos/libdruntime/core/stdc/stdio.d index c76b922..0dcdb6e 100644 --- a/libphobos/libdruntime/core/stdc/stdio.d +++ b/libphobos/libdruntime/core/stdc/stdio.d @@ -700,9 +700,8 @@ else version (Solaris) } else version (CRuntime_Bionic) { - import core.sys.posix.sys.types : off_t; /// - alias off_t fpos_t; + alias c_long fpos_t; // couldn't use off_t because of static if issue /// struct __sFILE @@ -745,12 +744,10 @@ else version (CRuntime_UClibc) import core.stdc.stddef : wchar_t; import core.sys.posix.sys.types : ssize_t, pthread_mutex_t; - alias long off_t; - /// struct fpos_t { - off_t __pos; + long __pos; // couldn't use off_t because of static if issue mbstate_t __state; int __mblen_pending; } @@ -759,7 +756,7 @@ else version (CRuntime_UClibc) { ssize_t function(void* __cookie, char* __buf, size_t __bufsize) read; ssize_t function(void* __cookie, const char* __buf, size_t __bufsize) write; - int function(void* __cookie, off_t* __pos, int __whence) seek; + int function(void* __cookie, long* __pos, int __whence) seek; int function(void* __cookie) close; } @@ -900,12 +897,14 @@ else version (CRuntime_Microsoft) extern shared void function() _fcloseallp; + FILE* __acrt_iob_func(int hnd); // VS2015+, reimplemented in msvc.d for VS2013- + /// - shared FILE* stdin; // = &__iob_func()[0]; + FILE* stdin()() { return __acrt_iob_func(0); } /// - shared FILE* stdout; // = &__iob_func()[1]; + FILE* stdout()() { return __acrt_iob_func(1); } /// - shared FILE* stderr; // = &__iob_func()[2]; + FILE* stderr()() { return __acrt_iob_func(2); } } else version (CRuntime_Glibc) { diff --git a/libphobos/libdruntime/core/sys/linux/config.d b/libphobos/libdruntime/core/sys/linux/config.d index 03d3e17..5d38244f 100644 --- a/libphobos/libdruntime/core/sys/linux/config.d +++ b/libphobos/libdruntime/core/sys/linux/config.d @@ -24,6 +24,9 @@ deprecated("use _DEFAULT_SOURCE") enum _SVID_SOURCE = true; } +deprecated("use _DEFAULT_SOURCE") enum __USE_MISC = _DEFAULT_SOURCE; +deprecated("use _ATFILE_SOURCE") enum __USE_ATFILE = _ATFILE_SOURCE; +deprecated("use _GNU_SOURCE") enum __USE_GNU = _GNU_SOURCE; diff --git a/libphobos/libdruntime/core/sys/linux/dlfcn.d b/libphobos/libdruntime/core/sys/linux/dlfcn.d index 4a12284..fbb8462 100644 --- a/libphobos/libdruntime/core/sys/linux/dlfcn.d +++ b/libphobos/libdruntime/core/sys/linux/dlfcn.d @@ -34,7 +34,7 @@ import core.sys.linux.config; version (X86_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -48,7 +48,7 @@ version (X86_Any) else version (HPPA_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/hppa/bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -62,7 +62,7 @@ else version (HPPA_Any) else version (MIPS_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/mips/bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -76,7 +76,7 @@ else version (MIPS_Any) else version (PPC_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -90,7 +90,7 @@ else version (PPC_Any) else version (ARM_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -104,7 +104,7 @@ else version (ARM_Any) else version (RISCV_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -118,7 +118,7 @@ else version (RISCV_Any) else version (SPARC_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -132,7 +132,7 @@ else version (SPARC_Any) else version (IBMZ_Any) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h - static if (__USE_GNU) + static if (_GNU_SOURCE) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { @@ -148,7 +148,7 @@ else // -static if (__USE_GNU) +static if (_GNU_SOURCE) { enum RTLD_NEXT = cast(void *)-1L; enum RTLD_DEFAULT = cast(void *)0; @@ -161,7 +161,7 @@ static if (__USE_GNU) // int dlclose(void* __handle); // POSIX // void* dlsym(void* __handle, const scope char* __name); // POSIX -static if (__USE_GNU) +static if (_GNU_SOURCE) { void* dlmopen(Lmid_t __nsid, const scope char* __file, int __mode); void* dlvsym(void* __handle, const scope char* __name, const scope char* __version); @@ -169,7 +169,7 @@ static if (__USE_GNU) // char* dlerror(); // POSIX -static if (__USE_GNU) +static if (_GNU_SOURCE) { int dladdr1(void* __address, Dl_info* __info, void** __extra_info, int __flags); diff --git a/libphobos/libdruntime/core/sys/linux/errno.d b/libphobos/libdruntime/core/sys/linux/errno.d index 02ae151..d7a39ac 100644 --- a/libphobos/libdruntime/core/sys/linux/errno.d +++ b/libphobos/libdruntime/core/sys/linux/errno.d @@ -13,7 +13,7 @@ nothrow: public import core.stdc.errno; import core.sys.linux.config; -static if (__USE_GNU) +static if (_GNU_SOURCE) { extern __gshared char* program_invocation_name, program_invocation_short_name; alias error_t = int; diff --git a/libphobos/libdruntime/core/sys/linux/netinet/in_.d b/libphobos/libdruntime/core/sys/linux/netinet/in_.d index 67bf654..1b428f5 100644 --- a/libphobos/libdruntime/core/sys/linux/netinet/in_.d +++ b/libphobos/libdruntime/core/sys/linux/netinet/in_.d @@ -115,7 +115,7 @@ version (linux_libc) enum IN6ADDR_ANY_INIT = in6_addr.init; enum IN6ADDR_LOOPBACK_INIT = in6_addr([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); - version (gnu_libc) static if (__USE_MISC) + version (gnu_libc) static if (_DEFAULT_SOURCE) { struct ip_mreq { @@ -174,13 +174,13 @@ version (linux_libc) extern(D) bool IN6_ARE_ADDR_EQUAL(in6_addr* a, in6_addr* b) pure @safe { return *a == *b; } - version (gnu_libc) static if (__USE_MISC) + version (gnu_libc) static if (_DEFAULT_SOURCE) { int bindresvport(int __sockfd, sockaddr_in* __sock_in); int bindresvport6(int __sockfd, sockaddr_in6* _); } - version (gnu_libc) static if (__USE_GNU) + version (gnu_libc) static if (_GNU_SOURCE) { struct in6_pktinfo { @@ -254,7 +254,7 @@ version (linux_libc) enum IP_DROP_SOURCE_MEMBERSHIP = 40; enum IP_MSFILTER = 41; - version (gnu_libc) static if (__USE_MISC) + version (gnu_libc) static if (_DEFAULT_SOURCE) { enum MCAST_JOIN_GROUP = 42; enum MCAST_BLOCK_SOURCE = 43; @@ -307,7 +307,7 @@ version (linux_libc) enum IP_DEFAULT_MULTICAST_LOOP = 1; enum IP_MAX_MEMBERSHIPS = 20; - version (gnu_libc) static if (__USE_MISC) + version (gnu_libc) static if (_DEFAULT_SOURCE) { struct ip_opts { diff --git a/libphobos/libdruntime/core/sys/linux/string.d b/libphobos/libdruntime/core/sys/linux/string.d index e3c94cf6..880faa4 100644 --- a/libphobos/libdruntime/core/sys/linux/string.d +++ b/libphobos/libdruntime/core/sys/linux/string.d @@ -16,7 +16,7 @@ nothrow: @nogc: @system: -static if (__USE_GNU) +static if (_GNU_SOURCE) { 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/sys/mman.d b/libphobos/libdruntime/core/sys/linux/sys/mman.d index a6548a7..649e2af 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/mman.d +++ b/libphobos/libdruntime/core/sys/linux/sys/mman.d @@ -37,7 +37,7 @@ version (PPC_Any) { enum PROT_SAO = 0x10; - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -60,7 +60,7 @@ version (PPC_Any) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/riscv/bits/mman.h else version (RISCV_Any) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -85,7 +85,7 @@ else version (RISCV_Any) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/s390/bits/mman.h else version (IBMZ_Any) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -101,7 +101,7 @@ else version (IBMZ_Any) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sh/bits/mman.h else version (SH) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x0100, MAP_DENYWRITE = 0x0800, @@ -117,7 +117,7 @@ else version (SH) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sparc/bits/mman.h else version (SPARC_Any) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x0200, MAP_DENYWRITE = 0x0800, @@ -141,9 +141,9 @@ else version (SPARC_Any) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86/bits/mman.h else version (X86_Any) { - static if (__USE_MISC) enum MAP_32BIT = 0x40; + static if (_DEFAULT_SOURCE) enum MAP_32BIT = 0x40; - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -159,7 +159,7 @@ else version (X86_Any) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/aarch64/bits/mman.h else version (AArch64) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -187,11 +187,11 @@ else version (Alpha) enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; - static if (__USE_MISC) + static if (_DEFAULT_SOURCE) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x10; - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, @@ -201,7 +201,7 @@ else version (Alpha) MAP_HUGE_MASK = 0x3f, } - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x01000, MAP_DENYWRITE = 0x02000, @@ -229,13 +229,13 @@ else version (Alpha) // MCL_FUTURE = 16384, // } - static if (__USE_GNU) enum + static if (_GNU_SOURCE) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, @@ -255,7 +255,7 @@ else version (Alpha) } // in core.sys.posix.sys.mman - // static if (__USE_XOPEN2K) enum + // static if (_XOPEN_SOURCE >= 600) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, @@ -267,7 +267,7 @@ else version (Alpha) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/arm/bits/mman.h else version (ARM) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -295,11 +295,11 @@ else version (HPPA_Any) enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; - static if (__USE_MISC) + static if (_DEFAULT_SOURCE) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x04; - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, @@ -310,7 +310,7 @@ else version (HPPA_Any) MAP_HUGE_MASK = 0x3f, } - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, @@ -336,13 +336,13 @@ else version (HPPA_Any) // MCL_FUTURE = 2, // } - static if (__USE_GNU) enum + static if (_GNU_SOURCE) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, @@ -375,7 +375,7 @@ else version (HPPA_Any) } // in core.sys.posix.sys.mman - // static if (__USE_XOPEN2K) enum + // static if (_XOPEN_SOURCE >= 600) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, @@ -387,7 +387,7 @@ else version (HPPA_Any) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/ia64/bits/mman.h else version (IA64) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_GROWSUP = 0x00200, @@ -404,7 +404,7 @@ else version (IA64) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/m68k/bits/mman.h else version (M68K) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, @@ -420,7 +420,7 @@ else version (M68K) // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/mips/bits/mman.h else version (MIPS_Any) { - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_NORESERVE = 0x0400, MAP_GROWSDOWN = 0x1000, @@ -460,11 +460,11 @@ else enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; - static if (__USE_MISC) + static if (_DEFAULT_SOURCE) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x10; - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, @@ -482,13 +482,13 @@ else // MS_INVALIDATE = 2, // } - static if (__USE_GNU) enum + static if (_GNU_SOURCE) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } - static if (__USE_MISC) enum + static if (_DEFAULT_SOURCE) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, @@ -508,7 +508,7 @@ else } // in core.sys.posix.sys.mman - // static if (__USE_XOPEN2K) enum + // static if (_XOPEN_SOURCE >= 600) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, @@ -530,12 +530,12 @@ else // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sparc/bits/mman.h version (SPARC_Any) { - static if (__USE_MISC) enum MAP_RENAME = MAP_ANONYMOUS; + static if (_DEFAULT_SOURCE) enum MAP_RENAME = MAP_ANONYMOUS; } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/mips/bits/mman.h else version (MIPS_Any) { - static if (__USE_MISC) enum MAP_RENAME = MAP_ANONYMOUS; + static if (_DEFAULT_SOURCE) enum MAP_RENAME = MAP_ANONYMOUS; } // http://sourceware.org/git/?p=glibc.git;a=blob;f=misc/sys/mman.h @@ -548,14 +548,14 @@ else version (MIPS_Any) // int munmap(void*, size_t); // int mprotect(void *__addr, size_t __len, int __prot); // int msync(void *__addr, size_t __len, int __flags); -static if (__USE_MISC) int madvise(void *__addr, size_t __len, int __advice); -// static if (__USE_XOPEN2K) int posix_madvise(void *__addr, size_t __len, int __advice); +static if (_DEFAULT_SOURCE) int madvise(void *__addr, size_t __len, int __advice); +// static if (_XOPEN_SOURCE >= 600) int posix_madvise(void *__addr, size_t __len, int __advice); // int mlock(const(void) *__addr, size_t __len); // int munlock(const(void) *__addr, size_t __len); // int mlockall(int __flags); // int munlockall(); -static if (__USE_MISC) int mincore(void *__start, size_t __len, ubyte *__vec); -static if (__USE_GNU) void *mremap(void *__addr, size_t __old_len, size_t __new_len, int __flags, ...); -static if (__USE_GNU) int remap_file_pages(void *__start, size_t __size, int __prot, size_t __pgoff, int __flags); +static if (_DEFAULT_SOURCE) int mincore(void *__start, size_t __len, ubyte *__vec); +static if (_GNU_SOURCE) void *mremap(void *__addr, size_t __old_len, size_t __new_len, int __flags, ...); +static if (_GNU_SOURCE) int remap_file_pages(void *__start, size_t __size, int __prot, size_t __pgoff, int __flags); // int shm_open(in char *__name, int __oflag, mode_t __mode); // int shm_unlink(in char *__name); diff --git a/libphobos/libdruntime/core/sys/posix/aio.d b/libphobos/libdruntime/core/sys/posix/aio.d index f4e0f12..a76846e 100644 --- a/libphobos/libdruntime/core/sys/posix/aio.d +++ b/libphobos/libdruntime/core/sys/posix/aio.d @@ -99,57 +99,7 @@ else version (CRuntime_Musl) } else version (CRuntime_UClibc) { - import core.sys.posix.config; - import core.sys.posix.sys.types; - - struct aiocb - { - int aio_fildes; - int aio_lio_opcode; - int aio_reqprio; - void* aio_buf; //volatile - size_t aio_nbytes; - sigevent aio_sigevent; - - aiocb* __next_prio; - int __abs_prio; - int __policy; - int __error_code; - ssize_t __return_value; - - static if (__USE_LARGEFILE64) - { - off_t aio_offset; - ubyte[off64_t.sizeof - off_t.sizeof] __pad; - } - else - { - off64_t aio_offset; - } - ubyte[32] __unused; - } - - static if (__USE_LARGEFILE64) - { - struct aiocb64 - { - int aio_fildes; - int aio_lio_opcode; - int aio_reqprio; - void* aio_buf; //volatile - size_t aio_nbytes; - sigevent aio_sigevent; - - aiocb* __next_prio; - int __abs_prio; - int __policy; - int __error_code; - ssize_t __return_value; - - off64_t aio_offset; - ubyte[32] __unused; - } - } + // UClibc does not implement aiocb. } else version (Darwin) { @@ -272,15 +222,6 @@ else version (CRuntime_Musl) AIO_ALLDONE } } -else version (CRuntime_UClibc) -{ - enum - { - AIO_CANCELED, - AIO_NOTCANCELED, - AIO_ALLDONE - } -} else version (Darwin) { enum @@ -328,15 +269,6 @@ else version (CRuntime_Musl) LIO_NOP } } -else version (CRuntime_UClibc) -{ - enum - { - LIO_READ, - LIO_WRITE, - LIO_NOP - } -} else version (Darwin) { enum @@ -382,14 +314,6 @@ else version (CRuntime_Musl) LIO_NOWAIT } } -else version (CRuntime_UClibc) -{ - enum - { - LIO_WAIT, - LIO_NOWAIT - } -} else version (Darwin) { enum @@ -456,37 +380,7 @@ else version (CRuntime_Bionic) } else version (CRuntime_UClibc) { - static if (__USE_LARGEFILE64) - { - int aio_read64(aiocb64* aiocbp); - int aio_write64(aiocb64* aiocbp); - int aio_fsync64(int op, aiocb64* aiocbp); - int aio_error64(const(aiocb64)* aiocbp); - ssize_t aio_return64(aiocb64* aiocbp); - int aio_suspend64(const(aiocb64*)* aiocb_list, int nitems, const(timespec)* timeout); - int aio_cancel64(int fd, aiocb64* aiocbp); - int lio_listio64(int mode, const(aiocb64*)* aiocb_list, int nitems, sigevent* sevp); - - alias aio_read = aio_read64; - alias aio_write = aio_write64; - alias aio_fsync = aio_fsync64; - alias aio_error = aio_error64; - alias aio_return = aio_return64; - alias aio_suspend = aio_suspend64; - alias aio_cancel = aio_cancel64; - alias lio_listio = lio_listio64; - } - else - { - int aio_read(aiocb* aiocbp); - int aio_write(aiocb* aiocbp); - int aio_fsync(int op, aiocb* aiocbp); - int aio_error(const(aiocb)* aiocbp); - ssize_t aio_return(aiocb* aiocbp); - int aio_suspend(const(aiocb*)* aiocb_list, int nitems, const(timespec)* timeout); - int aio_cancel(int fd, aiocb* aiocbp); - int lio_listio(int mode, const(aiocb*)* aiocb_list, int nitems, sigevent* sevp); - } + // UClibc does not implement aio.h } else version (OpenBSD) { @@ -507,27 +401,7 @@ else /* Functions outside/extending POSIX requirement. */ version (CRuntime_Glibc) { - static if (__USE_GNU) - { - /* To customize the implementation one can use the following struct. */ - struct aioinit - { - int aio_threads; - int aio_num; - int aio_locks; - int aio_usedba; - int aio_debug; - int aio_numusers; - int aio_idle_time; - int aio_reserved; - } - - void aio_init(const(aioinit)* init); - } -} -else version (CRuntime_UClibc) -{ - static if (__USE_GNU) + static if (_GNU_SOURCE) { /* To customize the implementation one can use the following struct. */ struct aioinit diff --git a/libphobos/libdruntime/core/sys/posix/config.d b/libphobos/libdruntime/core/sys/posix/config.d index 3b575fa..7bd0722 100644 --- a/libphobos/libdruntime/core/sys/posix/config.d +++ b/libphobos/libdruntime/core/sys/posix/config.d @@ -51,14 +51,24 @@ version (CRuntime_Glibc) enum __USE_LARGEFILE = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_LARGEFILE64 = __USE_FILE_OFFSET64 && !__REDIRECT; - enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; - enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; - enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; - enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; + deprecated("use _XOPEN_SOURCE >= 600") + { + enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; + enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; + } + deprecated("use _XOPEN_SOURCE >= 700") + { + enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; + enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; + } + deprecated("use _DEFAULT_SOURCE") enum __USE_MISC = _DEFAULT_SOURCE; + deprecated("use _ATFILE_SOURCE") enum __USE_ATFILE = _ATFILE_SOURCE; + deprecated("use _GNU_SOURCE") enum __USE_GNU = _GNU_SOURCE; + deprecated("use _REENTRANT") enum __USE_REENTRANT = _REENTRANT; version (D_LP64) @@ -68,6 +78,10 @@ version (CRuntime_Glibc) } else version (CRuntime_Musl) { + enum _GNU_SOURCE = false; + enum _DEFAULT_SOURCE = false; + enum _ATFILE_SOURCE = false; + // off_t is always 64 bits on Musl enum _FILE_OFFSET_BITS = 64; @@ -99,14 +113,24 @@ else version (CRuntime_UClibc) enum __USE_LARGEFILE = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_LARGEFILE64 = __USE_FILE_OFFSET64 && !__REDIRECT; - enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; - enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; - enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; - enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; + deprecated("use _XOPEN_SOURCE >= 600") + { + enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; + enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; + } + deprecated("use _XOPEN_SOURCE >= 700") + { + enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; + enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; + } + deprecated("use _DEFAULT_SOURCE") enum __USE_MISC = _DEFAULT_SOURCE; + deprecated("use _ATFILE_SOURCE") enum __USE_ATFILE = _ATFILE_SOURCE; + deprecated("use _GNU_SOURCE") enum __USE_GNU = _GNU_SOURCE; + deprecated("use _REENTRANT") enum __USE_REENTRANT = _REENTRANT; version (D_LP64) @@ -117,7 +141,11 @@ else version (CRuntime_UClibc) else version (CRuntime_Bionic) { enum _GNU_SOURCE = false; + enum _DEFAULT_SOURCE = false; + enum _ATFILE_SOURCE = false; + enum __USE_FILE_OFFSET64 = false; // see https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md + deprecated("use _GNU_SOURCE") enum __USE_GNU = _GNU_SOURCE; version (D_LP64) @@ -187,10 +215,16 @@ else version (Solaris) enum __USE_LARGEFILE = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_LARGEFILE64 = __USE_FILE_OFFSET64 && !__REDIRECT; - enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; - enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; - enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; - enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; + deprecated("use _XOPEN_SOURCE >= 600") + { + enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; + enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; + } + deprecated("use _XOPEN_SOURCE >= 700") + { + enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; + enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; + } version (D_LP64) enum __WORDSIZE = 64; diff --git a/libphobos/libdruntime/core/sys/posix/spawn.d b/libphobos/libdruntime/core/sys/posix/spawn.d index 86b1751..cfa3a40 100644 --- a/libphobos/libdruntime/core/sys/posix/spawn.d +++ b/libphobos/libdruntime/core/sys/posix/spawn.d @@ -100,8 +100,8 @@ version (linux) POSIX_SPAWN_SETSCHEDPARAM = 0x10, POSIX_SPAWN_SETSCHEDULER = 0x20 } - import core.sys.posix.config : __USE_GNU; - static if (__USE_GNU) + import core.sys.posix.config : _GNU_SOURCE; + static if (_GNU_SOURCE) { enum { @@ -140,8 +140,8 @@ version (linux) POSIX_SPAWN_SETSCHEDPARAM = 16, POSIX_SPAWN_SETSCHEDULER = 32 } - import core.sys.posix.config : __USE_GNU; - static if (__USE_GNU) + import core.sys.posix.config : _GNU_SOURCE; + static if (_GNU_SOURCE) { enum { @@ -196,8 +196,8 @@ version (linux) POSIX_SPAWN_SETSCHEDPARAM = 0x10, POSIX_SPAWN_SETSCHEDULER = 0x20 } - import core.sys.posix.config : __USE_GNU; - static if (__USE_GNU) + import core.sys.posix.config : _GNU_SOURCE; + static if (_GNU_SOURCE) { enum { diff --git a/libphobos/libdruntime/core/sys/posix/sys/ipc.d b/libphobos/libdruntime/core/sys/posix/sys/ipc.d index 18a6cbd..1718243 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/ipc.d +++ b/libphobos/libdruntime/core/sys/posix/sys/ipc.d @@ -83,7 +83,26 @@ version (linux) } else version (Darwin) { + align(4) struct ipc_perm + { + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + ushort _seq; + key_t _key; + } + + enum IPC_CREAT = 0x0200; // 01000 + enum IPC_EXCL = 0x0400; // 02000 + enum IPC_NOWAIT = 0x0800; // 04000 + + enum key_t IPC_PRIVATE = 0; + enum IPC_RMID = 0; + enum IPC_SET = 1; + enum IPC_STAT = 2; } else version (FreeBSD) { @@ -188,6 +207,46 @@ else version (DragonFlyBSD) enum IPC_SET = 1; enum IPC_STAT = 2; } +else version (Solaris) +{ + version (D_LP64) + { + struct ipc_perm + { + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + uint seq; + key_t key; + } + } + else + { + struct ipc_perm + { + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + uint seq; + key_t key; + int[4] pad; + } + } + + enum IPC_CREAT = 0x200; + enum IPC_EXCL = 0x400; + enum IPC_NOWAIT = 0x800; + + enum key_t IPC_PRIVATE = 0; + + enum IPC_RMID = 10; + enum IPC_SET = 11; + enum IPC_STAT = 12; +} else { static assert(false, "Unsupported platform"); @@ -203,7 +262,7 @@ version (CRuntime_Glibc) } else version (Darwin) { - + key_t ftok(const scope char*, int); } else version (FreeBSD) { @@ -221,6 +280,10 @@ else version (DragonFlyBSD) { key_t ftok(const scope char*, int); } +else version (Solaris) +{ + key_t ftok(const scope char*, int); +} else version (CRuntime_Bionic) { key_t ftok(const scope char*, int); diff --git a/libphobos/libdruntime/core/sys/posix/sys/mman.d b/libphobos/libdruntime/core/sys/posix/sys/mman.d index 33ce88f..430f215 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/mman.d +++ b/libphobos/libdruntime/core/sys/posix/sys/mman.d @@ -56,7 +56,7 @@ int posix_madvise(void*, size_t, int); version (CRuntime_Glibc) { - static if (__USE_XOPEN2K) + static if (_XOPEN_SOURCE >= 600) { int posix_madvise(void *__addr, size_t __len, int __advice); } @@ -303,7 +303,7 @@ else version (CRuntime_Musl) } else version (CRuntime_UClibc) { - static if (__USE_LARGEFILE64) void* mmap64(void*, size_t, int, int, int, off64_t); + static if (__USE_LARGEFILE64) void* mmap64(void*, size_t, int, int, int, off_t); static if (__USE_FILE_OFFSET64) alias mmap = mmap64; else diff --git a/libphobos/libdruntime/core/sys/posix/sys/shm.d b/libphobos/libdruntime/core/sys/posix/sys/shm.d index ce34141..d04e792 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/shm.d +++ b/libphobos/libdruntime/core/sys/posix/sys/shm.d @@ -259,6 +259,18 @@ else version (CRuntime_Musl) int shmdt(const scope void*); int shmget(key_t, size_t, int); } +else version (CRuntime_Bionic) +{ + enum SHMLBA = 4096; + + deprecated("Not useful on Android because it's disallowed by SELinux") + { + void* shmat(int, const scope void*, int); + int shmctl(int, int, shmid_ds*); + int shmdt(const scope void*); + int shmget(key_t, size_t, int); + } +} else version (CRuntime_UClibc) { int __getpagesize(); diff --git a/libphobos/libdruntime/core/sys/posix/sys/socket.d b/libphobos/libdruntime/core/sys/posix/sys/socket.d index 670ead7..c1309a6 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/socket.d +++ b/libphobos/libdruntime/core/sys/posix/sys/socket.d @@ -1038,9 +1038,9 @@ else version (OpenBSD) { ubyte ss_len; sa_family_t ss_family; - byte[6] __ss_pad1; + ubyte[6] __ss_pad1; long __ss_align; - byte[240] __ss_pad2; + ubyte[240] __ss_pad2; } struct msghdr @@ -1063,20 +1063,25 @@ else version (OpenBSD) enum : uint { - SCM_RIGHTS = 0x01 + SCM_RIGHTS = 0x01, + SCM_TIMESTAMP = 0x04 } private // { - extern (D) size_t _ALIGN(size_t p) { return (p + _ALIGNBYTES) & ~_ALIGNBYTES; } + enum _ALIGNBYTES = c_long.sizeof - 1; + extern (D) size_t _ALIGN(size_t p) pure nothrow @nogc + { + return (p + _ALIGNBYTES) & ~_ALIGNBYTES; + } } - extern (D) ubyte* CMSG_DATA(cmsghdr* cmsg) + extern (D) ubyte* CMSG_DATA(cmsghdr* cmsg) pure nothrow @nogc { return cast(ubyte*) cmsg + _ALIGN(cmsghdr.sizeof); } - extern (D) cmsghdr* CMSG_NXTHDR(msghdr* mhdr, cmsghdr* cmsg) + extern (D) cmsghdr* CMSG_NXTHDR(msghdr* mhdr, cmsghdr* cmsg) pure nothrow @nogc { if (cast(ubyte*) cmsg + _ALIGN(cmsg.cmsg_len) + _ALIGN(cmsghdr.sizeof) > cast(ubyte*) mhdr.msg_control + mhdr.msg_controllen) @@ -1085,11 +1090,24 @@ else version (OpenBSD) return cast(cmsghdr*) (cast(ubyte*) cmsg + _ALIGN(cmsg.cmsg_len)); } - extern (D) cmsghdr* CMSG_FIRSTHDR(msghdr* mhdr) + extern (D) cmsghdr* CMSG_FIRSTHDR(msghdr* mhdr) pure nothrow @nogc { return mhdr.msg_controllen >= cmsghdr.sizeof ? cast(cmsghdr*) mhdr.msg_control : null; } + extern (D) + { + size_t CMSG_LEN(size_t len) pure nothrow @nogc + { + return _ALIGN(cmsghdr.sizeof) + len; + } + } + + extern (D) size_t CMSG_SPACE(size_t len) pure nothrow @nogc + { + return _ALIGN(cmsghdr.sizeof) + _ALIGN(len); + } + struct linger { int l_onoff; diff --git a/libphobos/libdruntime/core/sys/posix/sys/stat.d b/libphobos/libdruntime/core/sys/posix/sys/stat.d index 51455a9..22f4df6 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/stat.d +++ b/libphobos/libdruntime/core/sys/posix/sys/stat.d @@ -89,7 +89,7 @@ version (linux) off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; - static if (__USE_MISC || __USE_XOPEN2K8) + static if (_DEFAULT_SOURCE || _XOPEN_SOURCE >= 700) { timespec st_atim; timespec st_mtim; @@ -136,7 +136,7 @@ version (linux) off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; - static if (__USE_MISC || __USE_XOPEN2K8) + static if (_DEFAULT_SOURCE || _XOPEN_SOURCE >= 700) { timespec st_atim; timespec st_mtim; @@ -218,7 +218,7 @@ version (linux) __blkcnt64_t st_blocks; } - static if ( __USE_MISC || __USE_XOPEN2K8) + static if ( _DEFAULT_SOURCE || _XOPEN_SOURCE >= 700) { __timespec st_atim; __timespec st_mtim; @@ -278,7 +278,7 @@ version (linux) c_long[3] st_pad2; off_t st_size; } - static if (__USE_MISC || __USE_XOPEN2K8) + static if (_DEFAULT_SOURCE || _XOPEN_SOURCE >= 700) { timespec st_atim; timespec st_mtim; @@ -339,7 +339,7 @@ version (linux) uint[3] st_pad2; off_t st_size; } - static if (__USE_MISC || __USE_XOPEN2K8) + static if (_DEFAULT_SOURCE || _XOPEN_SOURCE >= 700) { timespec st_atim; timespec st_mtim; @@ -491,7 +491,7 @@ version (linux) __blkcnt_t st_blocks; } - static if (__USE_MISC) + static if (_DEFAULT_SOURCE) { __timespec st_atim; __timespec st_mtim; @@ -573,7 +573,7 @@ version (linux) __blkcnt64_t st_blocks; } - static if ( __USE_MISC || __USE_XOPEN2K8) + static if ( _DEFAULT_SOURCE || _XOPEN_SOURCE >= 700) { __timespec st_atim; __timespec st_mtim; @@ -668,7 +668,7 @@ version (linux) __blkcnt64_t st_blocks; } - static if (__USE_MISC) + static if (_DEFAULT_SOURCE) { __timespec st_atim; __timespec st_mtim; @@ -753,7 +753,7 @@ version (linux) __blkcnt64_t st_blocks; } - static if (__USE_XOPEN2K8) + static if (_XOPEN_SOURCE >= 700) { __timespec st_atim; __timespec st_mtim; @@ -830,7 +830,7 @@ version (linux) __blkcnt_t st_blocks; else __blkcnt64_t st_blocks; - static if (__USE_XOPEN2K8) + static if (_XOPEN_SOURCE >= 700) { __timespec st_atim; __timespec st_mtim; @@ -894,7 +894,7 @@ version (linux) int __glibc_reserved0; __dev_t st_rdev; __off_t st_size; - static if (__USE_XOPEN2K8) + static if (_XOPEN_SOURCE >= 700) { __timespec st_atim; __timespec st_mtim; @@ -919,7 +919,7 @@ version (linux) __blkcnt_t st_blocks; c_long[3] __glibc_reserved; } - static if (__USE_XOPEN2K8) + static if (_XOPEN_SOURCE >= 700) static assert(stat_t.sizeof == 144); else static assert(stat_t.sizeof == 144); diff --git a/libphobos/libdruntime/core/sys/posix/sys/statvfs.d b/libphobos/libdruntime/core/sys/posix/sys/statvfs.d index 49c8450..df9030d 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/statvfs.d +++ b/libphobos/libdruntime/core/sys/posix/sys/statvfs.d @@ -44,7 +44,7 @@ version (CRuntime_Glibc) { } /* Definitions for the flag in `f_flag'. These definitions should be kept in sync with the definitions in . */ - static if (__USE_GNU) + static if (_GNU_SOURCE) { enum FFlag { diff --git a/libphobos/libdruntime/core/sys/posix/sys/types.d b/libphobos/libdruntime/core/sys/posix/sys/types.d index 02cf799..ec229dd 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/types.d +++ b/libphobos/libdruntime/core/sys/posix/sys/types.d @@ -322,7 +322,7 @@ else version (Darwin) alias uint fsfilcnt_t; alias c_long clock_t; alias uint id_t; - // key_t + alias int key_t; alias int suseconds_t; alias uint useconds_t; } diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 7bb6bec..cf7cf96 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -1885,8 +1885,8 @@ class TypeInfo_Struct : TypeInfo return false; else if (xopEquals) { - const dg = _memberFunc(p2, xopEquals); - return dg.xopEquals(p1); + const dg = _memberFunc(p1, xopEquals); + return dg.xopEquals(p2); } else if (p1 == p2) return true; diff --git a/libphobos/libdruntime/rt/util/typeinfo.d b/libphobos/libdruntime/rt/util/typeinfo.d index 26c24c4..7b55693 100644 --- a/libphobos/libdruntime/rt/util/typeinfo.d +++ b/libphobos/libdruntime/rt/util/typeinfo.d @@ -1,8 +1,8 @@ /** - * This module contains utilities for TypeInfo implementation. + * A few predefined implementations for primitive types and arrays thereof. Also a couple of helpers. * * Copyright: Copyright Kenji Hara 2014-. - * License: Boost License 1.0. + * License: Boost License 1.0. * Authors: Kenji Hara * Source: $(DRUNTIMESRC rt/util/_typeinfo.d) */ @@ -10,100 +10,74 @@ module rt.util.typeinfo; import rt.util.utility : d_cfloat, d_cdouble, d_creal, isComplex; static import core.internal.hash; -template Floating(T) -if (is(T == float) || is(T == double) || is(T == real)) +// Three-way compare for integrals: negative if `lhs < rhs`, positive if `lhs > rhs`, 0 otherwise. +pragma(inline, true) +private int cmp3(T)(const T lhs, const T rhs) +if (__traits(isIntegral, T)) { - pure nothrow @safe: - - bool equals(T f1, T f2) - { - return f1 == f2; - } - - int compare(T d1, T d2) - { - if (d1 != d1 || d2 != d2) // if either are NaN - { - if (d1 != d1) - { - if (d2 != d2) - return 0; - return -1; - } - return 1; - } - return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); - } + static if (T.sizeof < int.sizeof) + // Taking the difference will always fit in an int. + return int(lhs) - int(rhs); + else + return (lhs > rhs) - (lhs < rhs); +} - public alias hashOf = core.internal.hash.hashOf; +// Three-way compare for real fp types. NaN is smaller than all valid numbers. +// Code is small and fast, see https://godbolt.org/z/fzb877 +pragma(inline, true) +private int cmp3(T)(const T d1, const T d2) +if (is(T == float) || is(T == double) || is(T == real)) +{ + if (d2 != d2) + return d1 == d1; // 0 if both ar NaN, 1 if d1 is valid and d2 is NaN. + // If d1 is NaN, both comparisons are false so we get -1, as needed. + return (d1 > d2) - !(d1 >= d2); } -// @@@DEPRECATED_2.105@@@ -template Floating(T) +// Three-way compare for complex types. +pragma(inline, true) +private int cmp3(T)(const T f1, const T f2) if (isComplex!T) { - pure nothrow @safe: - - bool equals(T f1, T f2) - { - return f1.re == f2.re && f1.im == f2.im; - } - - int compare(T f1, T f2) - { - int result; - - if (f1.re < f2.re) - result = -1; - else if (f1.re > f2.re) - result = 1; - else if (f1.im < f2.im) - result = -1; - else if (f1.im > f2.im) - result = 1; - else - result = 0; + if (int result = cmp3(f1.re, f2.re)) return result; - } - - size_t hashOf(scope const T val) - { - return core.internal.hash.hashOf(val.re, core.internal.hash.hashOf(val.im)); - } + return cmp3(f1.im, f2.im); } -template Array(T) -if (is(T == float) || is(T == double) || is(T == real)) +unittest { - pure nothrow @safe: - - bool equals(T[] s1, T[] s2) - { - size_t len = s1.length; - if (len != s2.length) - return false; - for (size_t u = 0; u < len; u++) - { - if (!Floating!T.equals(s1[u], s2[u])) - return false; - } - return true; - } - - int compare(T[] s1, T[] s2) - { - size_t len = s1.length; - if (s2.length < len) - len = s2.length; - for (size_t u = 0; u < len; u++) - { - if (int c = Floating!T.compare(s1[u], s2[u])) - return c; - } - return (s1.length > s2.length) - (s1.length < s2.length); - } - - public alias hashOf = core.internal.hash.hashOf; + assert(cmp3(short.max, short.min) > 0); + assert(cmp3(42, 42) == 0); + assert(cmp3(int.max, int.min) > 0); + + double x, y; + assert(cmp3(x, y) == 0); + assert(cmp3(y, x) == 0); + x = 42; + assert(cmp3(x, y) > 0); + assert(cmp3(y, x) < 0); + y = 43; + assert(cmp3(x, y) < 0); + assert(cmp3(y, x) > 0); + y = 42; + assert(cmp3(x, y) == 0); + assert(cmp3(y, x) == 0); + + d_cdouble u, v; + assert(cmp3(u, v) == 0); + assert(cmp3(v, u) == 0); + u = d_cdouble(42, 42); + assert(cmp3(u, v) > 0); + assert(cmp3(v, u) < 0); + v = d_cdouble(43, 42); + assert(cmp3(u, v) < 0); + assert(cmp3(v, u) > 0); + v = d_cdouble(42, 43); + assert(cmp3(u, v) < 0); + assert(cmp3(v, u) > 0); + v = d_cdouble(42, 42); + assert(cmp3(u, v) == 0); + assert(cmp3(v, u) == 0); } // @@@DEPRECATED_2.105@@@ @@ -209,7 +183,7 @@ unittest }(); } -// Reduces to `T` if `cond` is `true` or `U` otherwise. +// Reduces to `T` if `cond` is `true` or `U` otherwise. Consider moving elsewhere if useful. private template Select(bool cond, T, U) { static if (cond) alias Select = T; @@ -238,57 +212,38 @@ if (T.sizeof == Base.sizeof && T.alignof == Base.alignof) static if (is(T == Base)) override size_t getHash(scope const void* p) { - static if (__traits(isFloating, T) || isComplex!T) - return Floating!T.hashOf(*cast(T*)p); - else - return hashOf(*cast(const T *)p); + return hashOf(*cast(const T *)p); } // `equals` is the same for `Base` and `T`, introduce it just once. static if (is(T == Base)) override bool equals(in void* p1, in void* p2) { - static if (__traits(isFloating, T) || isComplex!T) - return Floating!T.equals(*cast(T*)p1, *cast(T*)p2); - else - return *cast(T *)p1 == *cast(T *)p2; + return *cast(const T *)p1 == *cast(const T *)p2; } // `T` and `Base` may have different signedness, so this function is introduced conditionally. static if (is(T == Base) || (__traits(isIntegral, T) && T.max != Base.max)) override int compare(in void* p1, in void* p2) { - static if (__traits(isFloating, T) || isComplex!T) - { - return Floating!T.compare(*cast(T*)p1, *cast(T*)p2); - } - else static if (T.sizeof < int.sizeof) - { - // Taking the difference will always fit in an int. - return int(*cast(T *) p1) - int(*cast(T *) p2); - } - else - { - auto lhs = *cast(T *) p1, rhs = *cast(T *) p2; - return (lhs > rhs) - (lhs < rhs); - } + return cmp3(*cast(const T*) p1, *cast(const T*) p2); } static if (is(T == Base)) - override @property size_t tsize() nothrow pure + override @property size_t tsize() { return T.sizeof; } static if (is(T == Base)) - override @property size_t talign() nothrow pure + override @property size_t talign() { return T.alignof; } // Override initializer only if necessary. static if (is(T == Base) || T.init != Base.init) - override const(void)[] initializer() @trusted + override const(void)[] initializer() { static if (__traits(isZeroInit, T)) { @@ -311,7 +266,7 @@ if (T.sizeof == Base.sizeof && T.alignof == Base.alignof) } static if (is(T == Base) || RTInfo!T != RTInfo!Base) - override @property immutable(void)* rtInfo() nothrow pure const @safe + override @property immutable(void)* rtInfo() { return RTInfo!T; } @@ -377,52 +332,33 @@ private class TypeInfoArrayGeneric(T, Base = T) : Select!(is(T == Base), TypeInf static if (is(T == Base)) override size_t getHash(scope const void* p) @trusted const { - static if (__traits(isFloating, T) || isComplex!T) - return Array!T.hashOf(*cast(T[]*)p); - else - return hashOf(*cast(const T[]*) p); + return hashOf(*cast(const T[]*) p); } static if (is(T == Base)) override bool equals(in void* p1, in void* p2) const { - static if (__traits(isFloating, T) || isComplex!T) - { - return Array!T.equals(*cast(T[]*)p1, *cast(T[]*)p2); - } - else - { - import core.stdc.string; - auto s1 = *cast(T[]*)p1; - auto s2 = *cast(T[]*)p2; - return s1.length == s2.length && - memcmp(s1.ptr, s2.ptr, s1.length) == 0; - } + // Just reuse the builtin. + return *cast(const(T)[]*) p1 == *cast(const(T)[]*) p2; } static if (is(T == Base) || (__traits(isIntegral, T) && T.max != Base.max)) override int compare(in void* p1, in void* p2) const { - static if (__traits(isFloating, T) || isComplex!T) - { - return Array!T.compare(*cast(T[]*)p1, *cast(T[]*)p2); - } - else + // Can't reuse __cmp in object.d because that handles NaN differently. + // (Q: would it make sense to unify behaviors?) + // return __cmp(*cast(const T[]*) p1, *cast(const T[]*) p2); + auto lhs = *cast(const T[]*) p1; + auto rhs = *cast(const T[]*) p2; + size_t len = lhs.length; + if (rhs.length < len) + len = rhs.length; + for (size_t u = 0; u < len; u++) { - auto s1 = *cast(T[]*)p1; - auto s2 = *cast(T[]*)p2; - auto len = s1.length; - - if (s2.length < len) - len = s2.length; - for (size_t u = 0; u < len; u++) - { - if (int result = (s1[u] > s2[u]) - (s1[u] < s2[u])) - return result; - } - return (s1.length > s2.length) - (s1.length < s2.length); + if (int result = cmp3(lhs.ptr[u], rhs.ptr[u])) + return result; } - } + return cmp3(lhs.length, rhs.length); } override @property inout(TypeInfo) next() inout { @@ -692,52 +628,37 @@ unittest // typeof(null) class TypeInfo_n : TypeInfo { - override string toString() const @safe { return "typeof(null)"; } + const: pure: @nogc: nothrow: @safe: - override size_t getHash(scope const void* p) const - { - return 0; - } + override string toString() { return "typeof(null)"; } - override bool equals(in void* p1, in void* p2) const @trusted - { - return true; - } + override size_t getHash(scope const void*) { return 0; } - override int compare(in void* p1, in void* p2) const @trusted - { - return 0; - } + override bool equals(in void*, in void*) { return true; } - override @property size_t tsize() const - { - return typeof(null).sizeof; - } + override int compare(in void*, in void*) { return 0; } - override const(void)[] initializer() const @trusted - { - __gshared immutable void[typeof(null).sizeof] init; - return init; - } + override @property size_t tsize() { return typeof(null).sizeof; } - override void swap(void *p1, void *p2) const @trusted - { - } + override const(void)[] initializer() @trusted { return (cast(void *)null)[0 .. size_t.sizeof]; } - override @property immutable(void)* rtInfo() nothrow pure const @safe { return rtinfoNoPointers; } + override void swap(void*, void*) {} - unittest + override @property immutable(void)* rtInfo() { return rtinfoNoPointers; } +} + +unittest +{ + with (typeid(typeof(null))) { - with (typeid(typeof(null))) - { - assert(toString == "typeof(null)"); - assert(getHash(null) == 0); - assert(equals(null, null)); - assert(compare(null, null) == 0); - assert(tsize == typeof(null).sizeof); - assert(initializer == new ubyte[(void*).sizeof]); - assert(rtInfo == rtinfoNoPointers); - } + assert(toString == "typeof(null)"); + assert(getHash(null) == 0); + assert(equals(null, null)); + assert(compare(null, null) == 0); + assert(tsize == typeof(null).sizeof); + assert(initializer.ptr is null); + assert(initializer.length == typeof(null).sizeof); + assert(rtInfo == rtinfoNoPointers); } } diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 2babfbe..b5b939f 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -896b1d0e1e8b69bccac0e180ecd1b42a70f95d5b +1a3e80ec25afab6123cdcfe20186f36f006b68bb 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/internal.d b/libphobos/src/std/algorithm/internal.d index 3caeefe..6b45599 100644 --- a/libphobos/src/std/algorithm/internal.d +++ b/libphobos/src/std/algorithm/internal.d @@ -62,4 +62,6 @@ version (StdUnittest) } } +// Used instead of `&object.member` when `member` may be +// either a field or a @property function. package(std) T* addressOf(T)(ref T val) { return &val; } diff --git a/libphobos/src/std/bigint.d b/libphobos/src/std/bigint.d index bbb55c2..b2fcc07 100644 --- a/libphobos/src/std/bigint.d +++ b/libphobos/src/std/bigint.d @@ -414,17 +414,17 @@ public: /** * Implements assignment operators of the form `BigInt op= BigInt`. */ - BigInt opOpAssign(string op, T)(T y) pure nothrow @safe scope return + BigInt opOpAssign(string op, T)(T y) pure nothrow @safe return scope if ((op=="+" || op== "-" || op=="*" || op=="|" || op=="&" || op=="^" || op=="/" || op=="%") && is (T: BigInt)) { static if (op == "+") { - data = BigUint.addOrSub(data, y.data, sign != y.sign, &sign); + data = BigUint.addOrSub(data, y.data, sign != y.sign, sign); } else static if (op == "-") { - data = BigUint.addOrSub(data, y.data, sign == y.sign, &sign); + data = BigUint.addOrSub(data, y.data, sign == y.sign, sign); } else static if (op == "*") { @@ -2244,7 +2244,7 @@ void divMod(const BigInt dividend, const BigInt divisor, out BigInt quotient, ou BigUint.divMod(dividend.data, divisor.data, q, r); quotient.sign = dividend.sign != divisor.sign; quotient.data = q; - remainder.sign = dividend.sign; + remainder.sign = r.isZero() ? false : dividend.sign; remainder.data = r; } @@ -2291,6 +2291,14 @@ void divMod(const BigInt dividend, const BigInt divisor, out BigInt quotient, ou assert(q * d + r == -c); } +// https://issues.dlang.org/show_bug.cgi?id=22771 +@safe pure nothrow unittest +{ + BigInt quotient, remainder; + divMod(BigInt(-50), BigInt(1), quotient, remainder); + assert(remainder == 0); +} + // https://issues.dlang.org/show_bug.cgi?id=19740 @safe unittest { diff --git a/libphobos/src/std/container/rbtree.d b/libphobos/src/std/container/rbtree.d index 0b0a0b2..622dee4 100644 --- a/libphobos/src/std/container/rbtree.d +++ b/libphobos/src/std/container/rbtree.d @@ -111,7 +111,7 @@ struct RBNode(V) /** * Get the left child */ - @property inout(RBNode)* left() inout + @property inout(RBNode)* left() inout return scope { return _left; } @@ -119,7 +119,7 @@ struct RBNode(V) /** * Get the right child */ - @property inout(RBNode)* right() inout + @property inout(RBNode)* right() inout return scope { return _right; } @@ -127,7 +127,7 @@ struct RBNode(V) /** * Get the parent */ - @property inout(RBNode)* parent() inout + @property inout(RBNode)* parent() inout return scope { return _parent; } @@ -377,7 +377,7 @@ struct RBNode(V) * Returns the next highest valued node in the tree after this one, or end * if this was the highest-valued node. */ - Node remove(Node end) + Node remove(Node end) return { // // remove this node from the tree, fixing the color if necessary. @@ -558,7 +558,7 @@ struct RBNode(V) /** * Return the leftmost descendant of this node. */ - @property inout(RBNode)* leftmost() inout + @property inout(RBNode)* leftmost() inout return { inout(RBNode)* result = &this; while (result._left !is null) @@ -569,7 +569,7 @@ struct RBNode(V) /** * Return the rightmost descendant of this node */ - @property inout(RBNode)* rightmost() inout + @property inout(RBNode)* rightmost() inout return { inout(RBNode)* result = &this; while (result._right !is null) @@ -583,7 +583,7 @@ struct RBNode(V) * You should never call this on the marker node, as it is assumed that * there is a valid next node. */ - @property inout(RBNode)* next() inout + @property inout(RBNode)* next() inout return { inout(RBNode)* n = &this; if (n.right is null) @@ -602,7 +602,7 @@ struct RBNode(V) * You should never call this on the leftmost node of the tree as it is * assumed that there is a valid previous node. */ - @property inout(RBNode)* prev() inout + @property inout(RBNode)* prev() inout return { inout(RBNode)* n = &this; if (n.left is null) diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index a10f4da..8512a44 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -1642,7 +1642,7 @@ if (!isImplicitlyConvertible!(S, T) && Array-to-array conversion (except when target is a string type) converts each element in turn by using `to`. */ -private T toImpl(T, S)(S value) +private T toImpl(T, S)(scope S value) if (!isImplicitlyConvertible!(S, T) && !isSomeString!S && isDynamicArray!S && !isExactSomeString!T && isArray!T) diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index c974ada..a99c517 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -4635,7 +4635,7 @@ private struct DirIteratorImpl import std.path : chainPath; auto searchPattern = chainPath(directory, "*.*"); - static auto trustedFindFirstFileW(typeof(searchPattern) pattern, WIN32_FIND_DATAW* findinfo) @trusted + static auto trustedFindFirstFileW(typeof(searchPattern) pattern, scope WIN32_FIND_DATAW* findinfo) @trusted { return FindFirstFileW(pattern.tempCString!FSChar(), findinfo); } @@ -4653,7 +4653,7 @@ private struct DirIteratorImpl return toNext(true, &_findinfo); } - bool toNext(bool fetch, WIN32_FIND_DATAW* findinfo) @trusted + bool toNext(bool fetch, scope WIN32_FIND_DATAW* findinfo) @trusted { import core.stdc.wchar_ : wcscmp; @@ -5274,7 +5274,21 @@ Returns: */ string tempDir() @trusted { - import std.path : dirSeparator; + // We must check that the end of a path is not a separator, before adding another + // If we don't we end up with https://issues.dlang.org/show_bug.cgi?id=22738 + static string addSeparator(string input) + { + import std.path : dirSeparator; + import std.algorithm.searching : endsWith; + + // It is very rare a directory path will reach this point with a directory separator at the end + // However on OSX this can happen, so we must verify lest we break user code i.e. https://github.com/dlang/dub/pull/2208 + if (!input.endsWith(dirSeparator)) + return input ~ dirSeparator; + else + return input; + } + static string cache; if (cache is null) { @@ -5294,7 +5308,7 @@ string tempDir() @trusted static string findExistingDir(T...)(lazy T alternatives) { foreach (dir; alternatives) - if (!dir.empty && exists(dir)) return dir ~ dirSeparator; + if (!dir.empty && exists(dir)) return addSeparator(dir); return null; } @@ -5309,7 +5323,7 @@ string tempDir() @trusted if (cache is null) { - cache = getcwd() ~ dirSeparator; + cache = addSeparator(getcwd()); } } return cache; @@ -5338,6 +5352,9 @@ string tempDir() @trusted import std.algorithm.searching : endsWith; import std.path : dirSeparator; assert(tempDir.endsWith(dirSeparator)); + + // https://issues.dlang.org/show_bug.cgi?id=22738 + assert(!tempDir.endsWith(dirSeparator ~ dirSeparator)); } /** diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d index bc8d368..da698e0 100644 --- a/libphobos/src/std/functional.d +++ b/libphobos/src/std/functional.d @@ -68,6 +68,8 @@ import std.traits : isCallable, Parameters; import std.internal.attributes : betterC; +public import core.lifetime : forward; + private template needOpCallAlias(alias fun) { /* Determine whether or not unaryFun and binaryFun need to alias to fun or @@ -1845,10 +1847,3 @@ if (isCallable!(F)) static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD))); } } - -// forward used to be here but was moved to druntime -template forward(args...) -{ - import core.lifetime : fun = forward; - alias forward = fun!args; -} diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d index 6a93e0a..d5c4768 100644 --- a/libphobos/src/std/internal/math/biguintcore.d +++ b/libphobos/src/std/internal/math/biguintcore.d @@ -813,7 +813,7 @@ public: // If wantSub is false, return x + y, leaving sign unchanged. // If wantSub is true, return abs(x - y), negating sign if x cast(immutable) sub(x.data, y.data, &negative))(); - *sign ^= negative; + sign ^= negative; if (r.isZero()) { - *sign = false; + sign = false; } } else diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d index f8908cf..cd23232 100644 --- a/libphobos/src/std/socket.d +++ b/libphobos/src/std/socket.d @@ -787,13 +787,20 @@ class InternetHost assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com", ih.name); - assert(ih.getHostByAddr(ih.addrList[0])); - string getHostNameFromInt = ih.name.dup; + /* The following assert randomly fails in the test suite. + * https://issues.dlang.org/show_bug.cgi?id=22791 + * So just ignore it when it fails. + */ + //assert(ih.getHostByAddr(ih.addrList[0])); + if (ih.getHostByAddr(ih.addrList[0])) + { + string getHostNameFromInt = ih.name.dup; - assert(ih.getHostByAddr(ia.toAddrString())); - string getHostNameFromStr = ih.name.dup; + assert(ih.getHostByAddr(ia.toAddrString())); + string getHostNameFromStr = ih.name.dup; - assert(getHostNameFromInt == getHostNameFromStr); + assert(getHostNameFromInt == getHostNameFromStr); + } } diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 658fd38..5e35a6b 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -262,6 +262,8 @@ private enum isHashable(T) = __traits(compiles, private enum hasPostblit(T) = __traits(hasPostblit, T); +private enum isInout(T) = is(T == inout); + /** * A [tagged union](https://en.wikipedia.org/wiki/Tagged_union) that can hold a * single value from any of a specified set of types. @@ -419,6 +421,7 @@ public: ( allSatisfy!(isCopyable, Map!(InoutOf, Types)) && !anySatisfy!(hasPostblit, Map!(InoutOf, Types)) + && allSatisfy!(isInout, Map!(InoutOf, Types)) ) { /// Constructs a `SumType` that's a copy of another `SumType`. @@ -1492,6 +1495,23 @@ version (D_BetterC) {} else immutable SumType!(int*) si = ∋ } +// Immutable member type with copy constructor +// https://issues.dlang.org/show_bug.cgi?id=22572 +@safe unittest +{ + static struct CopyConstruct + { + this(ref inout CopyConstruct other) inout {} + } + + static immutable struct Value + { + CopyConstruct c; + } + + SumType!Value s; +} + /// True if `T` is an instance of the `SumType` template, otherwise false. private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...); diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index 28edb9b..ea8f8bd 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -2798,13 +2798,24 @@ struct Nullable(T) } } - this (ref return scope inout Nullable!T rhs) inout + static if (__traits(hasPostblit, T)) { - _isNull = rhs._isNull; - if (!_isNull) - _value.payload = rhs._value.payload; - else - _value = DontCallDestructorT.init; + this(this) + { + if (!_isNull) + _value.payload.__xpostblit(); + } + } + else static if (__traits(hasCopyConstructor, T)) + { + this(ref return scope inout Nullable!T rhs) inout + { + _isNull = rhs._isNull; + if (!_isNull) + _value.payload = rhs._value.payload; + else + _value = DontCallDestructorT.init; + } } /** @@ -9630,13 +9641,28 @@ unittest { int b; @disable this(this); - this (ref return scope inout S rhs) inout + this(ref return scope inout S rhs) inout { this.b = rhs.b + 1; } } Nullable!S s1 = S(1); + assert(s1.get().b == 2); + Nullable!S s2 = s1; + assert(s2.get().b == 3); +} + +@safe unittest +{ + static struct S + { + int b; + this(this) { ++b; } + } + + Nullable!S s1 = S(1); + assert(s1.get().b == 2); Nullable!S s2 = s1; - assert(s2.get().b > s1.get().b); + assert(s2.get().b == 3); } diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 192b6fd..9780b1b 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -5363,7 +5363,7 @@ pure @safe unittest pure @safe unittest { import std.range : stride; - static bool testAll(Matcher, Range)(scope ref Matcher m, ref Range r) + static bool testAll(Matcher, Range)(ref Matcher m, ref Range r) @safe { bool t = m.test(r); auto save = r.idx; diff --git a/libphobos/src/std/zip.d b/libphobos/src/std/zip.d index 4d7422b..72d1287 100644 --- a/libphobos/src/std/zip.d +++ b/libphobos/src/std/zip.d @@ -222,14 +222,6 @@ final class ArchiveMember @property @safe pure nothrow @nogc uint expandedSize() const { return _expandedSize; } /** - * Should be 0. - * - * Returns: The number of the disk where this member can be found. - */ - deprecated("Multidisk not supported; will be removed in 2.099.0") - @property @safe pure nothrow @nogc ushort diskNumber() const { return 0; } - - /** * Data of member in compressed form. * * Returns: The file data in compressed form. @@ -452,13 +444,6 @@ public: private bool _isZip64; static const ushort zip64ExtractVersion = 45; - deprecated("Use digitalSignatureLength instead; will be removed in 2.098.0") - static const int digiSignLength = 6; - deprecated("Use zip64EndOfCentralDirLocatorLength instead; will be removed in 2.098.0") - static const int eocd64LocLength = 20; - deprecated("Use zip64EndOfCentralDirLength instead; will be removed in 2.098.0") - static const int eocd64Length = 56; - private Segment[] _segs; /** @@ -469,29 +454,11 @@ public: @property @safe @nogc pure nothrow ubyte[] data() { return _data; } /** - * 0 since multi-disk zip archives are not supported. - * - * Returns: Number of this disk. - */ - deprecated("Multidisk not supported; will be removed in 2.099.0") - @property @safe @nogc pure nothrow uint diskNumber() const { return 0; } - - /** - * 0 since multi-disk zip archives are not supported. - * - * Returns: Number of the disk, where the central directory starts. - */ - deprecated("Multidisk not supported; will be removed in 2.099.0") - @property @safe @nogc pure nothrow uint diskStartDir() const { return 0; } - - /** * Number of ArchiveMembers in the directory. * * Returns: The number of files in this archive. */ - deprecated("Use totalEntries instead; will be removed in 2.099.0") - @property @safe @nogc pure nothrow uint numEntries() const { return cast(uint) _directory.length; } - @property @safe @nogc pure nothrow uint totalEntries() const { return cast(uint) _directory.length; } /// ditto + @property @safe @nogc pure nothrow uint totalEntries() const { return cast(uint) _directory.length; } /** * True when the archive is in Zip64 format. Set this to true to force building a Zip64 archive. diff --git a/libphobos/testsuite/libphobos.betterc/test19933.d b/libphobos/testsuite/libphobos.betterc/test19933.d new file mode 100644 index 0000000..a0faadd --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test19933.d @@ -0,0 +1,11 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=19933 +// https://issues.dlang.org/show_bug.cgi?id=18816 + +import core.stdc.stdio; + +extern(C) int main() +{ + fprintf(stderr, "Hello\n"); + return 0; +} diff --git a/libphobos/testsuite/libphobos.hash/test_hash.d b/libphobos/testsuite/libphobos.hash/test_hash.d index d0a8e5fb..0ad2443 100644 --- a/libphobos/testsuite/libphobos.hash/test_hash.d +++ b/libphobos/testsuite/libphobos.hash/test_hash.d @@ -277,7 +277,7 @@ void issue22076() static struct S1 { S0 a; - inout(S0)* b() inout nothrow { return &a; } + inout(S0)* b() inout return nothrow { return &a; } alias b this; } -- 2.7.4