From patchwork Wed Aug 3 11:04:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1663283 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=oFkuWGS9; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LyTYb2D69z9sB4 for ; Wed, 3 Aug 2022 21:05:54 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5E31E3857C4A for ; Wed, 3 Aug 2022 11:05:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5E31E3857C4A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1659524749; bh=5rV2PXfePj4+9Vk5NSUm68y02NUeWJNHx9FA2XcSu9I=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=oFkuWGS9ru3+0o9wPtEjd7g5OSVibtFXsJGkusJ8zYV8ApQJo8DRT31oywE1ffPat WSgytbLmi8mB5RHlNePolBAT+wpB/T1e1pvZYIC0vN7+S+DperkIrRWygG6LJ9EDpZ xjCWM6hDhDSU3mCbQgvCbdrubJuy/sZ/TD3+AyBU= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [IPv6:2001:67c:2050:0:465::102]) by sourceware.org (Postfix) with ESMTPS id 53EF73858C20 for ; Wed, 3 Aug 2022 11:05:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 53EF73858C20 Received: from smtp202.mailbox.org (smtp202.mailbox.org [IPv6:2001:67c:2050:b231:465::202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4LyTXT4gv8z9sWt; Wed, 3 Aug 2022 13:04:57 +0200 (CEST) To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd d7772a2369, phobos 5748ca43f. Date: Wed, 3 Aug 2022 13:04:51 +0200 Message-Id: <20220803110451.2375766-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4LyTXT4gv8z9sWt X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Iain Buclaw via Gcc-patches From: Iain Buclaw Reply-To: Iain Buclaw Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Hi, This patch merges the D front-end with upstream dmd d7772a2369, and standard library with phobos 5748ca43f, bumping the version to 2.100.1. In upstream dmd, the D compiler and D runtime library have been merged together into one repository. Both dmd and libdruntime now track that. D front-end changes: - Deprecated `scope(failure)' blocks that contain `return' statements. - Deprecated using integers for `version' or `debug' conditions. - Deprecated returning a discarded void value from a function. - `new' can now allocate an associative array. D runtime changes: - Added avx512f detection to core.cpuid module. Phobos changes: - Changed std.experimental.logger.core.sharedLog to return shared(Logger). Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd d7772a2369. * dmd/VERSION: Bump version to v2.100.1. * d-codegen.cc (get_frameinfo): Check whether decision to generate closure changed since semantic finished. * d-lang.cc (d_handle_option): Remove handling of -fdebug=level and -fversion=level. * decl.cc (DeclVisitor::visit (VarDeclaration *)): Generate evaluation of noreturn variable initializers before throw. * expr.cc (ExprVisitor::visit (AssignExp *)): Don't generate assignment for noreturn types, only evaluate for side effects. * lang.opt (fdebug=): Undocument -fdebug=level. (fversion=): Undocument -fversion=level. libphobos/ChangeLog: * configure: Regenerate. * configure.ac (libtool_VERSION): Update to 4:0:0. * libdruntime/MERGE: Merge upstream druntime d7772a2369. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/internal/array/duplication.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 5748ca43f. * testsuite/libphobos.gc/nocollect.d: --- gcc/d/d-codegen.cc | 7 + gcc/d/d-lang.cc | 20 - gcc/d/decl.cc | 7 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/arrayop.d | 4 +- gcc/d/dmd/chkformat.d | 494 +++++++++++++----- gcc/d/dmd/clone.d | 4 + gcc/d/dmd/constfold.d | 123 +---- gcc/d/dmd/cparse.d | 2 +- gcc/d/dmd/dcast.d | 14 +- gcc/d/dmd/declaration.h | 1 + gcc/d/dmd/dinterpret.d | 11 +- gcc/d/dmd/dmodule.d | 8 +- gcc/d/dmd/dsymbol.d | 26 + gcc/d/dmd/dsymbolsem.d | 7 +- gcc/d/dmd/dtemplate.d | 2 +- gcc/d/dmd/entity.d | 21 +- gcc/d/dmd/escape.d | 33 +- gcc/d/dmd/expressionsem.d | 113 ++-- gcc/d/dmd/file_manager.d | 6 + gcc/d/dmd/func.d | 62 ++- gcc/d/dmd/impcnvtab.d | 55 ++ gcc/d/dmd/initsem.d | 39 +- gcc/d/dmd/lexer.d | 2 +- gcc/d/dmd/mustuse.d | 2 +- gcc/d/dmd/optimize.d | 2 +- gcc/d/dmd/parse.d | 32 +- gcc/d/dmd/semantic3.d | 10 +- gcc/d/dmd/statementsem.d | 50 +- gcc/d/dmd/transitivevisitor.d | 6 + gcc/d/dmd/typesem.d | 13 +- gcc/d/expr.cc | 11 + gcc/d/lang.opt | 4 +- .../gdc.test/compilable/backendfloatoptim.d | 10 + .../gdc.test/compilable/cppmangle3.d | 4 - .../gdc.test/compilable/must_use_initialize.d | 16 + gcc/testsuite/gdc.test/compilable/noreturn1.d | 28 + gcc/testsuite/gdc.test/compilable/test20832.d | 12 + gcc/testsuite/gdc.test/compilable/test21177.d | 65 ++- gcc/testsuite/gdc.test/compilable/test21432.d | 25 + gcc/testsuite/gdc.test/compilable/test22390.d | 8 + gcc/testsuite/gdc.test/compilable/test23082.d | 17 + gcc/testsuite/gdc.test/compilable/test23166.d | 22 + gcc/testsuite/gdc.test/compilable/test23172.d | 33 ++ gcc/testsuite/gdc.test/compilable/test23235.d | 20 + gcc/testsuite/gdc.test/compilable/test23256.d | 6 + gcc/testsuite/gdc.test/compilable/test23262.d | 17 + .../gdc.test/compilable/testgotoskips.d | 17 + .../fail_compilation/attributediagnostic.d | 39 +- .../gdc.test/fail_compilation/chkformat.d | 18 + .../gdc.test/fail_compilation/diag10319.d | 20 +- .../gdc.test/fail_compilation/diag11198.d | 14 +- .../gdc.test/fail_compilation/diag12829.d | 10 +- .../gdc.test/fail_compilation/fail118.d | 20 +- .../gdc.test/fail_compilation/fail20547.d | 15 - .../gdc.test/fail_compilation/fail22134.d | 17 + .../gdc.test/fail_compilation/fail23181.d | 16 + .../gdc.test/fail_compilation/fail261.d | 5 +- .../gdc.test/fail_compilation/fail58.d | 8 +- .../gdc.test/fail_compilation/fail6889.d | 2 +- .../gdc.test/fail_compilation/fail7848.d | 8 +- .../gdc.test/fail_compilation/ice11856_1.d | 7 +- .../fail_compilation/misc_parser_err_cov1.d | 3 +- .../gdc.test/fail_compilation/newaa.d | 19 + .../gdc.test/fail_compilation/nogc3.d | 8 +- .../gdc.test/fail_compilation/retscope.d | 4 +- .../gdc.test/fail_compilation/test13786.d | 12 +- .../gdc.test/fail_compilation/test16193.d | 4 +- .../gdc.test/fail_compilation/test21443.d | 21 + .../gdc.test/fail_compilation/test21912.d | 16 +- .../gdc.test/fail_compilation/test21939.d | 5 +- .../gdc.test/fail_compilation/test23022.d | 15 + .../gdc.test/fail_compilation/test23112.d | 30 ++ .../gdc.test/fail_compilation/test23170.d | 12 + .../gdc.test/fail_compilation/test23216.d | 24 + gcc/testsuite/gdc.test/runnable/closure.d | 8 +- gcc/testsuite/gdc.test/runnable/evalorder.d | 26 + gcc/testsuite/gdc.test/runnable/lexer.d | 8 +- gcc/testsuite/gdc.test/runnable/noreturn1.d | 32 ++ gcc/testsuite/gdc.test/runnable/test11.d | 37 -- gcc/testsuite/gdc.test/runnable/test18973.d | 25 + gcc/testsuite/gdc.test/runnable/test19.d | 15 - gcc/testsuite/gdc.test/runnable/test20734.d | 7 + gcc/testsuite/gdc.test/runnable/test23181.d | 27 + gcc/testsuite/gdc.test/runnable/test8.d | 39 ++ gcc/testsuite/gdc.test/runnable/version.d | 23 +- gcc/testsuite/gdc.test/runnable/warning1.d | 9 - libphobos/configure | 2 +- libphobos/configure.ac | 2 +- libphobos/libdruntime/MERGE | 4 +- libphobos/libdruntime/Makefile.am | 16 +- libphobos/libdruntime/Makefile.in | 19 +- libphobos/libdruntime/core/cpuid.d | 16 + libphobos/libdruntime/core/int128.d | 2 - .../core/internal/array/appending.d | 28 +- .../core/internal/array/duplication.d | 346 ++++++++++++ libphobos/libdruntime/core/internal/dassert.d | 2 +- libphobos/libdruntime/core/runtime.d | 2 +- libphobos/libdruntime/core/stdc/errno.d | 2 +- libphobos/libdruntime/core/stdc/stdio.d | 53 +- libphobos/libdruntime/core/stdc/wchar_.d | 90 +++- .../core/sys/darwin/mach/getsect.d | 1 - .../core/sys/dragonflybsd/string.d | 1 - .../libdruntime/core/sys/linux/sys/time.d | 1 - .../libdruntime/core/sys/linux/sys/xattr.d | 1 - libphobos/libdruntime/core/sys/linux/tipc.d | 1 - libphobos/libdruntime/core/sys/posix/signal.d | 79 +-- libphobos/libdruntime/core/sys/posix/spawn.d | 2 +- libphobos/libdruntime/core/sys/posix/stdio.d | 2 +- .../libdruntime/core/sys/posix/sys/select.d | 1 - libphobos/libdruntime/core/sys/posix/time.d | 66 ++- .../libdruntime/core/sys/posix/ucontext.d | 1 - .../core/sys/solaris/sys/priocntl.d | 1 - .../core/sys/solaris/sys/procset.d | 1 - .../libdruntime/core/sys/windows/cguid.d | 1 - .../libdruntime/core/sys/windows/ntsecpkg.d | 1 - .../libdruntime/core/sys/windows/olectlid.d | 1 - .../libdruntime/core/sys/windows/shlguid.d | 1 - libphobos/libdruntime/core/sys/windows/sspi.d | 1 - libphobos/libdruntime/object.d | 340 +----------- libphobos/libdruntime/rt/dylib_fixes.c | 1 - libphobos/src/MERGE | 2 +- libphobos/src/etc/c/curl.d | 18 +- libphobos/src/std/algorithm/comparison.d | 2 +- libphobos/src/std/algorithm/iteration.d | 15 +- libphobos/src/std/algorithm/searching.d | 12 + libphobos/src/std/conv.d | 19 +- libphobos/src/std/experimental/checkedint.d | 2 +- libphobos/src/std/experimental/logger/core.d | 176 +++++-- .../src/std/experimental/logger/filelogger.d | 2 +- .../src/std/experimental/logger/multilogger.d | 2 +- libphobos/src/std/file.d | 2 +- libphobos/src/std/format/internal/write.d | 6 +- libphobos/src/std/format/package.d | 24 + libphobos/src/std/math/package.d | 1 + libphobos/src/std/math/rounding.d | 28 +- libphobos/src/std/random.d | 67 ++- libphobos/src/std/stdio.d | 17 +- libphobos/src/std/sumtype.d | 148 +++--- libphobos/src/std/typecons.d | 20 +- libphobos/src/std/uni/package.d | 8 +- libphobos/testsuite/libphobos.gc/nocollect.d | 2 +- 143 files changed, 2497 insertions(+), 1287 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/backendfloatoptim.d create mode 100644 gcc/testsuite/gdc.test/compilable/must_use_initialize.d create mode 100644 gcc/testsuite/gdc.test/compilable/test20832.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21432.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22390.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23082.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23166.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23172.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23235.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23256.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23262.d create mode 100644 gcc/testsuite/gdc.test/compilable/testgotoskips.d delete mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail20547.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22134.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail23181.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/newaa.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test21443.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test23022.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test23112.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test23170.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test23216.d create mode 100644 gcc/testsuite/gdc.test/runnable/test18973.d create mode 100644 gcc/testsuite/gdc.test/runnable/test23181.d create mode 100644 libphobos/libdruntime/core/internal/array/duplication.d diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2d90899b37f..3fd4bee58f6 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2826,8 +2826,15 @@ get_frameinfo (FuncDeclaration *fd) DECL_LANG_FRAMEINFO (fds) = ffi; + const bool requiresClosure = fd->requiresClosure; if (fd->needsClosure ()) { + /* This can shift due to templates being expanded that access alias + symbols, give it a decent error for now. */ + if (requiresClosure != fd->requiresClosure + && (fd->nrvo_var || global.params.betterC)) + fd->checkClosure (); + /* Set-up a closure frame, this will be allocated on the heap. */ FRAMEINFO_CREATES_FRAME (ffi) = 1; FRAMEINFO_IS_CLOSURE (ffi) = 1; diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 6e4350f54cc..04147edee32 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -456,16 +456,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fdebug_: - if (ISDIGIT (arg[0])) - { - int level = integral_argument (arg); - if (level != -1) - { - global.params.debuglevel = level; - break; - } - } - if (Identifier::isValidIdentifier (CONST_CAST (char *, arg))) { if (!global.params.debugids) @@ -713,16 +703,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fversion_: - if (ISDIGIT (arg[0])) - { - int level = integral_argument (arg); - if (level != -1) - { - global.params.versionlevel = level; - break; - } - } - if (Identifier::isValidIdentifier (CONST_CAST (char *, arg))) { if (!global.params.versionids) diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 3caa465dd1e..58cea4dec3f 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -646,9 +646,12 @@ public: if (!d->isDataseg () && !d->isMember () && d->_init && !d->_init->isVoidInitializer ()) { + /* Evaluate RHS for side effects first. */ + Expression *ie = initializerToExpression (d->_init); + add_stmt (build_expr (ie)); + Expression *e = d->type->defaultInitLiteral (d->loc); - tree exp = build_expr (e); - add_stmt (exp); + add_stmt (build_expr (e)); } return; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 8324c1cc88c..c358b69e3fc 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -56589f0f4d724c1c8022c57509a243f16a04228a +d7772a236983ec37b92d21b28bad3cd2de57b945 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 5ea2ba0d8ec..83a14f57e16 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.100.0 +v2.100.1 diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index 16cbe620bc5..272e751cb51 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -111,8 +111,8 @@ bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false) * evaluation order as the actual array operations have no * side-effect. * References: - * https://github.com/dlang/druntime/blob/master/src/object.d#L3944 - * https://github.com/dlang/druntime/blob/master/src/core/internal/array/operations.d + * https://github.com/dlang/dmd/blob/cdfadf8a18f474e6a1b8352af2541efe3e3467cc/druntime/src/object.d#L4694 + * https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/array/operations.d */ Expression arrayOp(BinExp e, Scope* sc) { diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index a3f3bc4f141..e118d7014f9 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -62,7 +62,7 @@ import dmd.target; bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list) { //printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr); - size_t n, gnu_m_count; // index in args / number of Format.GNU_m + size_t n; // index in args for (size_t i = 0; i < format.length;) { if (format[i] != '%') @@ -79,6 +79,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre if (fmt == Format.percent) continue; // "%%", no arguments + if (fmt == Format.GNU_m) + continue; // "%m", no arguments if (isVa_list) { @@ -88,14 +90,11 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre continue; } - if (fmt == Format.GNU_m) - ++gnu_m_count; - Expression getNextArg(ref bool skip) { if (n == args.length) { - if (args.length < (n + 1) - gnu_m_count) + if (args.length < (n + 1)) deprecation(loc, "more format specifiers than %d arguments", cast(int)n); else skip = true; @@ -207,7 +206,6 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre errorMsg(null, e, "ptrdiff_t", t); break; - case Format.GNU_a: // Format.GNU_a is only for scanf case Format.lg: case Format.g: // double if (t.ty != Tfloat64 && t.ty != Timaginary64) @@ -289,8 +287,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre break; case Format.GNU_m: - break; // not assert(0) because it may go through it if there are extra arguments - + case Format.POSIX_ms: + case Format.POSIX_mls: case Format.percent: assert(0); } @@ -481,8 +479,6 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres errorMsg(null, e, "real*", t); break; - case Format.GNU_a: - case Format.GNU_m: case Format.c: case Format.s: // pointer to char string if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8))) @@ -500,10 +496,23 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres errorMsg(null, e, "void**", t); break; + case Format.POSIX_ms: // pointer to pointer to char string + Type tnext2 = tnext ? tnext.nextOf() : null; + if (!(t.ty == Tpointer && tnext.ty == Tpointer && (tnext2.ty == Tchar || tnext2.ty == Tint8 || tnext2.ty == Tuns8))) + errorMsg(null, e, "char**", t); + break; + + case Format.POSIX_mls: // pointer to pointer to wchar_t string + Type tnext2 = tnext ? tnext.nextOf() : null; + if (!(t.ty == Tpointer && tnext.ty == Tpointer && tnext2.ty.isSomeChar && tnext2.size() == target.c.wchar_tsize)) + errorMsg(null, e, "wchar_t**", t); + break; + case Format.error: deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); break; + case Format.GNU_m: case Format.percent: assert(0); } @@ -567,35 +576,97 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx, return error(); } - /* Read the scanset - * A scanset can be anything, so we just check that it is paired + /* Read the specifier */ - if (format[i] == '[') + Format specifier; + Modifier flags = Modifier.none; + switch (format[i]) { - while (i < length) - { - if (format[i] == ']') - break; + case 'm': + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/scanf.html + // POSIX.1-2017 C Extension (CX) + flags = Modifier.m; ++i; - } + if (i == length) + return error(); + if (format[i] == 'l') + { + ++i; + if (i == length) + return error(); + flags = Modifier.ml; + } - // no `]` found - if (i == length) - return error(); + // Check valid conversion types for %m. + if (format[i] == 'c' || format[i] == 's') + specifier = flags == Modifier.ml ? Format.POSIX_mls : + Format.POSIX_ms; + else if (format[i] == 'C' || format[i] == 'S') + specifier = flags == Modifier.m ? Format.POSIX_mls : + Format.error; + else if (format[i] == '[') + goto case '['; + else + specifier = Format.error; + ++i; + break; - ++i; - // no specifier after `]` - // it could be mixed with the one above, but then idx won't have the right index - if (i == length) - return error(); - } + case 'l': + // Look for wchar_t scanset %l[..] + immutable j = i + 1; + if (j < length && format[j] == '[') + { + i = j; + flags = Modifier.l; + goto case '['; + } + goto default; - /* Read the specifier - */ - char genSpec; - Format specifier = parseGenericFormatSpecifier(format, i, genSpec); - if (specifier == Format.error) - return error(); + case '[': + // Read the scanset + i++; + if (i == length) + return error(); + // If the conversion specifier begins with `[]` or `[^]`, the right + // bracket character is not the terminator, but in the scanlist. + if (format[i] == '^') + { + i++; + if (i == length) + return error(); + } + if (format[i] == ']') + { + i++; + if (i == length) + return error(); + } + // A scanset can be anything, so we just check that it is paired + while (i < length) + { + if (format[i] == ']') + break; + ++i; + } + // no `]` found + if (i == length) + return error(); + + specifier = flags == Modifier.none ? Format.s : + flags == Modifier.l ? Format.ls : + flags == Modifier.m ? Format.POSIX_ms : + flags == Modifier.ml ? Format.POSIX_mls : + Format.error; + ++i; + break; + + default: + char genSpec; + specifier = parseGenericFormatSpecifier(format, i, genSpec); + if (specifier == Format.error) + return error(); + break; + } idx = i; return specifier; // success @@ -613,11 +684,13 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx, * even if `Format.error` is returned * widthStar = set if * for width * precisionStar = set if * for precision + * useGNUExts = true if parsing GNU format extensions * Returns: * Format */ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, - out bool widthStar, out bool precisionStar) nothrow pure @safe + out bool widthStar, out bool precisionStar, bool useGNUExts = + findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @safe { auto i = idx; assert(format[i] == '%'); @@ -730,14 +803,33 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, /* Read the specifier */ char genSpec; - Format specifier = parseGenericFormatSpecifier(format, i, genSpec); - if (specifier == Format.error) - return error(); + Format specifier; + switch (format[i]) + { + case 'm': + // https://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html + if (useGNUExts) + { + specifier = Format.GNU_m; + genSpec = format[i]; + ++i; + break; + } + goto default; + + default: + specifier = parseGenericFormatSpecifier(format, i, genSpec); + if (specifier == Format.error) + return error(); + break; + } switch (genSpec) { case 'c': case 's': + case 'C': + case 'S': if (hash || zero) return error(); break; @@ -748,6 +840,11 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, return error(); break; + case 'm': + if (hash || zero || flags) + return error(); + break; + case 'n': if (hash || zero || precision || width || flags) return error(); @@ -761,6 +858,22 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, return specifier; // success } +/* Different kinds of conversion modifiers. */ +enum Modifier +{ + none, + h, // short + hh, // char + j, // intmax_t + l, // wint_t/wchar_t + ll, // long long int + L, // long double + m, // char** + ml, // wchar_t** + t, // ptrdiff_t + z // size_t +} + /* Different kinds of formatting specifications, variations we don't care about are merged. (Like we don't care about the difference between f, e, g, a, etc.) @@ -799,8 +912,9 @@ enum Format jn, // pointer to intmax_t zn, // pointer to size_t tn, // pointer to ptrdiff_t - GNU_a, // GNU ext. : address to a string with no maximum size (scanf) - GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf) + GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) + POSIX_ms, // POSIX ext. : dynamically allocated char string (scanf) + POSIX_mls, // POSIX ext. : dynamically allocated wchar_t string (scanf) percent, // %% (i.e. no argument) error, // invalid format specification } @@ -820,38 +934,48 @@ enum Format * Format */ Format parseGenericFormatSpecifier(scope const char[] format, - ref size_t idx, out char genSpecifier, bool useGNUExts = - findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @trusted + ref size_t idx, out char genSpecifier) nothrow pure @safe { const length = format.length; /* Read the `length modifier` */ const lm = format[idx]; - bool lm1; // if jztL - bool lm2; // if `hh` or `ll` - if (lm == 'j' || - lm == 'z' || - lm == 't' || - lm == 'L') + Modifier flags; + switch (lm) { - ++idx; - if (idx == length) - return Format.error; - lm1 = true; - } - else if (lm == 'h' || lm == 'l') - { - ++idx; - if (idx == length) - return Format.error; - lm2 = lm == format[idx]; - if (lm2) - { + case 'j': + case 'z': + case 't': + case 'L': + flags = lm == 'j' ? Modifier.j : + lm == 'z' ? Modifier.z : + lm == 't' ? Modifier.t : + Modifier.L; ++idx; if (idx == length) return Format.error; - } + break; + + case 'h': + case 'l': + ++idx; + if (idx == length) + return Format.error; + if (lm == format[idx]) + { + flags = lm == 'h' ? Modifier.hh : Modifier.ll; + ++idx; + if (idx == length) + return Format.error; + } + else + flags = lm == 'h' ? Modifier.h : Modifier.l; + break; + + default: + flags = Modifier.none; + break; } /* Read the `specifier` @@ -863,103 +987,88 @@ Format parseGenericFormatSpecifier(scope const char[] format, { case 'd': case 'i': - if (lm == 'L') - specifier = Format.error; - else - specifier = lm == 'h' && lm2 ? Format.hhd : - lm == 'h' ? Format.hd : - lm == 'l' && lm2 ? Format.lld : - lm == 'l' ? Format.ld : - lm == 'j' ? Format.jd : - lm == 'z' ? Format.zd : - lm == 't' ? Format.td : - Format.d; + specifier = flags == Modifier.none ? Format.d : + flags == Modifier.hh ? Format.hhd : + flags == Modifier.h ? Format.hd : + flags == Modifier.ll ? Format.lld : + flags == Modifier.l ? Format.ld : + flags == Modifier.j ? Format.jd : + flags == Modifier.z ? Format.zd : + flags == Modifier.t ? Format.td : + Format.error; break; case 'u': case 'o': case 'x': case 'X': - if (lm == 'L') - specifier = Format.error; - else - specifier = lm == 'h' && lm2 ? Format.hhu : - lm == 'h' ? Format.hu : - lm == 'l' && lm2 ? Format.llu : - lm == 'l' ? Format.lu : - lm == 'j' ? Format.ju : - lm == 'z' ? Format.zd : - lm == 't' ? Format.td : - Format.u; + specifier = flags == Modifier.none ? Format.u : + flags == Modifier.hh ? Format.hhu : + flags == Modifier.h ? Format.hu : + flags == Modifier.ll ? Format.llu : + flags == Modifier.l ? Format.lu : + flags == Modifier.j ? Format.ju : + flags == Modifier.z ? Format.zd : + flags == Modifier.t ? Format.td : + Format.error; break; - case 'a': - if (useGNUExts) - { - // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html - specifier = Format.GNU_a; - break; - } - goto case; - case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': - if (lm == 'L') - specifier = Format.Lg; - else if (lm1 || lm2 || lm == 'h') - specifier = Format.error; - else - specifier = lm == 'l' ? Format.lg : Format.g; + specifier = flags == Modifier.none ? Format.g : + flags == Modifier.L ? Format.Lg : + flags == Modifier.l ? Format.lg : + Format.error; break; case 'c': - if (lm1 || lm2 || lm == 'h') - specifier = Format.error; - else - specifier = lm == 'l' ? Format.lc : Format.c; + specifier = flags == Modifier.none ? Format.c : + flags == Modifier.l ? Format.lc : + Format.error; break; case 's': - if (lm1 || lm2 || lm == 'h') - specifier = Format.error; - else - specifier = lm == 'l' ? Format.ls : Format.s; + specifier = flags == Modifier.none ? Format.s : + flags == Modifier.l ? Format.ls : + Format.error; break; case 'p': - if (lm1 || lm2 || lm == 'h' || lm == 'l') - specifier = Format.error; - else - specifier = Format.p; + specifier = flags == Modifier.none ? Format.p : + Format.error; break; case 'n': - if (lm == 'L') - specifier = Format.error; - else - specifier = lm == 'l' && lm2 ? Format.lln : - lm == 'l' ? Format.ln : - lm == 'h' && lm2 ? Format.hhn : - lm == 'h' ? Format.hn : - lm == 'j' ? Format.jn : - lm == 'z' ? Format.zn : - lm == 't' ? Format.tn : - Format.n; + specifier = flags == Modifier.none ? Format.n : + flags == Modifier.ll ? Format.lln : + flags == Modifier.l ? Format.ln : + flags == Modifier.hh ? Format.hhn : + flags == Modifier.h ? Format.hn : + flags == Modifier.j ? Format.jn : + flags == Modifier.z ? Format.zn : + flags == Modifier.t ? Format.tn : + Format.error; break; - case 'm': - if (useGNUExts) - { - // https://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html - specifier = Format.GNU_m; - break; - } - goto default; + case 'C': + // POSIX.1-2017 X/Open System Interfaces (XSI) + // %C format is equivalent to %lc + specifier = flags == Modifier.none ? Format.lc : + Format.error; + break; + + case 'S': + // POSIX.1-2017 X/Open System Interfaces (XSI) + // %S format is equivalent to %ls + specifier = flags == Modifier.none ? Format.ls : + Format.error; + break; default: specifier = Format.error; @@ -1126,10 +1235,13 @@ unittest assert(idx == 2); idx = 0; - Format g = parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar); - assert(g == Format.g || g == Format.GNU_a); + assert(parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar) == Format.g); assert(idx == 2); + idx = 0; + assert(parsePrintfFormatSpecifier("%La", idx, widthStar, precisionStar) == Format.Lg); + assert(idx == 3); + idx = 0; assert(parsePrintfFormatSpecifier("%A", idx, widthStar, precisionStar) == Format.g); assert(idx == 2); @@ -1296,8 +1408,7 @@ unittest assert(idx == 2); idx = 0; - g = parseScanfFormatSpecifier("%a", idx, asterisk); - assert(g == Format.g || g == Format.GNU_a); + assert(parseScanfFormatSpecifier("%a", idx, asterisk) == Format.g); assert(idx == 2); idx = 0; @@ -1322,15 +1433,25 @@ unittest // scansets idx = 0; - assert(parseScanfFormatSpecifier("%[a-zA-Z]s", idx, asterisk) == Format.s); - assert(idx == 10); + assert(parseScanfFormatSpecifier("%[a-zA-Z]", idx, asterisk) == Format.s); + assert(idx == 9); assert(!asterisk); idx = 0; - assert(parseScanfFormatSpecifier("%*25[a-z]hhd", idx, asterisk) == Format.hhd); - assert(idx == 12); + assert(parseScanfFormatSpecifier("%*25l[a-z]", idx, asterisk) == Format.ls); + assert(idx == 10); assert(asterisk); + idx = 0; + assert(parseScanfFormatSpecifier("%[]]", idx, asterisk) == Format.s); + assert(idx == 4); + assert(!asterisk); + + idx = 0; + assert(parseScanfFormatSpecifier("%[^]]", idx, asterisk) == Format.s); + assert(idx == 5); + assert(!asterisk); + // Too short formats foreach (s; ["%", "% ", "%#", "%0", "%*", "%1", "%19", "%j", "%z", "%t", "%l", "%h", "%ll", "%hh", "%K"]) @@ -1354,11 +1475,108 @@ unittest } // Invalid scansets - foreach (s; ["%[]", "%[s", "%[0-9lld", "%[", "%[a-z]"]) + foreach (s; ["%[]", "%[^", "%[^]", "%[s", "%[0-9lld", "%[", "%l[^]"]) + { + idx = 0; + assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); + assert(idx == s.length); + } + + // Posix extensions + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%m", "%ma", "%md", "%ml", "%mm", "%mlb", "%mlj", "%mlr", "%mlz", + "%LC", "%lC", "%llC", "%jC", "%tC", "%hC", "%hhC", "%zC", + "%LS", "%lS", "%llS", "%jS", "%tS", "%hS", "%hhS", "%zS"]) { idx = 0; assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); assert(idx == s.length); } + idx = 0; + assert(parseScanfFormatSpecifier("%mc", idx, asterisk) == Format.POSIX_ms); + assert(idx == 3); + + idx = 0; + assert(parseScanfFormatSpecifier("%ms", idx, asterisk) == Format.POSIX_ms); + assert(idx == 3); + + idx = 0; + assert(parseScanfFormatSpecifier("%m[0-9]", idx, asterisk) == Format.POSIX_ms); + assert(idx == 7); + + idx = 0; + assert(parseScanfFormatSpecifier("%mlc", idx, asterisk) == Format.POSIX_mls); + assert(idx == 4); + + idx = 0; + assert(parseScanfFormatSpecifier("%mls", idx, asterisk) == Format.POSIX_mls); + assert(idx == 4); + + idx = 0; + assert(parseScanfFormatSpecifier("%ml[^0-9]", idx, asterisk) == Format.POSIX_mls); + assert(idx == 9); + + idx = 0; + assert(parseScanfFormatSpecifier("%mC", idx, asterisk) == Format.POSIX_mls); + assert(idx == 3); + + idx = 0; + assert(parseScanfFormatSpecifier("%mS", idx, asterisk) == Format.POSIX_mls); + assert(idx == 3); + + idx = 0; + assert(parsePrintfFormatSpecifier("%C", idx, widthStar, precisionStar) == Format.lc); + assert(idx == 2); + + idx = 0; + assert(parseScanfFormatSpecifier("%C", idx, asterisk) == Format.lc); + assert(idx == 2); + + idx = 0; + assert(parsePrintfFormatSpecifier("%S", idx, widthStar, precisionStar) == Format.ls); + assert(idx == 2); + + idx = 0; + assert(parseScanfFormatSpecifier("%S", idx, asterisk) == Format.ls); + assert(idx == 2); + + // GNU extensions: explicitly toggle ISO/GNU flag. + // ISO printf() + bool useGNUExts = false; + { + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%#m", "%+m", "%-m", "% m", "%0m"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); + assert(idx == s.length); + } + foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); + assert(idx == 2); + } + } + + // GNU printf() + useGNUExts = true; + { + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%#m", "%+m", "%-m", "% m", "%0m"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); + assert(idx == s.length); + } + + // valid cases, all parsed as `%m` + foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.GNU_m); + assert(idx == 2); + } + } } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index cf4ccbb955c..1a26eaa434b 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -1121,6 +1121,10 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) if (!dtor) return null; + // Don't try to call `@disable`d dtors + if (dtor.storage_class & STC.disable) + return null; + // Generate shim only when ABI incompatible on target platform if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD) return dtor; diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index d90542f3fd8..f4e44e812c8 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -234,99 +234,9 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2) UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2) { - UnionExp ue = void; - if (type.isreal()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type); - } - else if (type.isimaginary()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type); - } - else if (type.iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - auto c1 = complex_t(CTFloat.zero); - real_t r1 = CTFloat.zero; - real_t i1 = CTFloat.zero; - auto c2 = complex_t(CTFloat.zero); - real_t r2 = CTFloat.zero; - real_t i2 = CTFloat.zero; - auto v = complex_t(CTFloat.zero); - int x; - if (e1.type.isreal()) - { - r1 = e1.toReal(); - x = 0; - } - else if (e1.type.isimaginary()) - { - i1 = e1.toImaginary(); - x = 3; - } - else - { - c1 = e1.toComplex(); - x = 6; - } - if (e2.type.isreal()) - { - r2 = e2.toReal(); - } - else if (e2.type.isimaginary()) - { - i2 = e2.toImaginary(); - x += 1; - } - else - { - c2 = e2.toComplex(); - x += 2; - } - switch (x) - { - case 0 + 0: - v = complex_t(r1 - r2); - break; - case 0 + 1: - v = complex_t(r1, -i2); - break; - case 0 + 2: - v = complex_t(r1 - creall(c2), -cimagl(c2)); - break; - case 3 + 0: - v = complex_t(-r2, i1); - break; - case 3 + 1: - v = complex_t(CTFloat.zero, i1 - i2); - break; - case 3 + 2: - v = complex_t(-creall(c2), i1 - cimagl(c2)); - break; - case 6 + 0: - v = complex_t(creall(c1) - r2, cimagl(c1)); - break; - case 6 + 1: - v = complex_t(creall(c1), cimagl(c1) - i2); - break; - case 6 + 2: - v = c1 - c2; - break; - default: - assert(0); - } - emplaceExp!(ComplexExp)(&ue, loc, v, type); - } - else if (SymOffExp soe = e1.isSymOffExp()) - { - emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger()); - ue.exp().type = type; - } - else - { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type); - } + // Compute e1-e2 as e1+(-e2) + UnionExp neg = Neg(e2.type, e2); + UnionExp ue = Add(loc, type, e1, neg.exp()); return ue; } @@ -1213,6 +1123,10 @@ UnionExp ArrayLength(Type type, Expression e1) Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim; emplaceExp!(UnionExp)(&ue, e); } + else if (e1.isNullExp()) + { + emplaceExp!(IntegerExp)(&ue, loc, 0, type); + } else cantExp(ue); return ue; @@ -1505,17 +1419,11 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) Type t2 = e2.type.toBasetype(); //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars()); - if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral)) - { - e = e2; - t = t1; - goto L2; - } - else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_) + + /* e is the non-null operand, t is the type of the null operand + */ + UnionExp catNull(Expression e, Type t) { - e = e1; - t = t2; - L2: Type tn = e.type.toBasetype(); if (tn.ty.isSomeChar) { @@ -1545,6 +1453,15 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } + + if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral)) + { + return catNull(e2, t1); + } + else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_) + { + return catNull(e1, t2); + } else if (e1.op == EXP.null_ && e2.op == EXP.null_) { if (type == e1.type) diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index a3bebb7365a..2679a63245c 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1675,7 +1675,7 @@ final class CParser(AST) : Parser!AST auto stags = applySpecifier(stag, specifier); symbols.push(stags); - if (tt.tok == TOK.enum_) + if (0 && tt.tok == TOK.enum_) // C11 proscribes enums with no members, but we allow it { if (!tt.members) error(tt.loc, "`enum %s` has no members", stag.toChars()); diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 12051d92215..afd19f3d0f5 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1106,9 +1106,14 @@ MATCH implicitConvTo(Expression e, Type t) MATCH visitCond(CondExp e) { - auto result = visit(e); - if (result != MATCH.nomatch) - return result; + e.econd = e.econd.optimize(WANTvalue); + const opt = e.econd.toBool(); + if (opt.isPresent()) + { + auto result = visit(e); + if (result != MATCH.nomatch) + return result; + } MATCH m1 = e.e1.implicitConvTo(t); MATCH m2 = e.e2.implicitConvTo(t); @@ -2942,6 +2947,9 @@ Lagain: t1 = Type.basic[ty1]; t2 = Type.basic[ty2]; + + if (!(t1 && t2)) + return null; e1 = e1.castTo(sc, t1); e2 = e2.castTo(sc, t2); return Lret(Type.basic[ty]); diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 2c7d381e797..c8f6c2aab36 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -684,6 +684,7 @@ public: const char *kind() const override; bool isUnique(); bool needsClosure(); + bool checkClosure(); bool hasNestedFrameRefs(); ParameterList getParameterList(); diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 5841a252454..890c3b6fef2 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -2352,6 +2352,7 @@ public: if (ExpInitializer ie = v._init.isExpInitializer()) { result = interpretRegion(ie.exp, istate, goal); + return; } else if (v._init.isVoidInitializer()) { @@ -2359,12 +2360,16 @@ public: // There is no AssignExp for void initializers, // so set it here. setValue(v, result); + return; } - else + else if (v._init.isArrayInitializer()) { - e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); - result = CTFEExp.cantexp; + result = v._init.initializerToExpression(v.type); + if (result !is null) + return; } + e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); + result = CTFEExp.cantexp; } else if (v.type.size() == 0) { diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 0be938ffdf5..5e802dab8cc 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -619,7 +619,7 @@ extern (C++) final class Module : Package else { // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module - bool isPackageMod = (strcmp(toChars(), "package") != 0) && (strcmp(srcfile.name(), package_d) == 0 || (strcmp(srcfile.name(), package_di) == 0)); + bool isPackageMod = (strcmp(toChars(), "package") != 0) && isPackageFileName(srcfile); if (isPackageMod) .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars()); else @@ -824,8 +824,7 @@ extern (C++) final class Module : Package const(char)* srcname = srcfile.toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); - isPackageFile = (strcmp(srcfile.name(), package_d) == 0 || - strcmp(srcfile.name(), package_di) == 0); + isPackageFile = isPackageFileName(srcfile); const(char)[] buf = cast(const(char)[]) this.src; bool needsReencoding = true; @@ -1032,8 +1031,7 @@ extern (C++) final class Module : Package } assert(dst); Module m = ppack ? ppack.isModule() : null; - if (m && (strcmp(m.srcfile.name(), package_d) != 0 && - strcmp(m.srcfile.name(), package_di) != 0)) + if (m && !isPackageFileName(m.srcfile)) { .error(md.loc, "package name '%s' conflicts with usage as a module name in file %s", ppack.toPrettyChars(), m.srcfile.toChars()); } diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 2b608f6974c..c940ff06c67 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -2441,6 +2441,15 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) auto sd = s.isScopeDsymbol(); // new declaration auto sd2 = s2.isScopeDsymbol(); // existing declaration + static if (log) void print(EnumDeclaration sd) + { + printf("members: %p\n", sd.members); + printf("symtab: %p\n", sd.symtab); + printf("endlinnum: %d\n", sd.endlinnum); + printf("type: %s\n", sd.type.toChars()); + printf("memtype: %s\n", sd.memtype.toChars()); + } + if (!sd2) { /* Look in tag table @@ -2473,6 +2482,23 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) { sd2.members = sd.members; // transfer definition to sd2 sd.members = null; + if (auto ed2 = sd2.isEnumDeclaration()) + { + auto ed = sd.isEnumDeclaration(); + if (ed.memtype != ed2.memtype) + return null; // conflict + + // transfer ed's members to sd2 + ed2.members.foreachDsymbol( (s) + { + if (auto em = s.isEnumMember()) + em.ed = ed2; + }); + + ed2.type = ed.type; + ed2.memtype = ed.memtype; + ed2.added = false; + } return sd2; } else diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 11a51f10e99..7f57cbe12ca 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2023,7 +2023,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(EnumDeclaration ed) { //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); - //printf("EnumDeclaration::semantic() %p %s\n", this, ed.toChars()); + //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); if (ed.semanticRun >= PASS.semanticdone) return; // semantic() already completed if (ed.semanticRun == PASS.semantic) @@ -4442,7 +4442,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor invd.semanticRun < PASS.semantic && !ad.isUnionDeclaration() // users are on their own with union fields ) + { + invd.fixupInvariantIdent(ad.invs.length); ad.invs.push(invd); + } if (!invd.type) invd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, invd.storage_class); @@ -5713,6 +5716,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) { + //printf("addEnumMembers(ed: %p)\n", ed); if (ed.added) return; ed.added = true; @@ -5736,6 +5740,7 @@ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) em.ed = ed; if (isCEnum) { + //printf("adding EnumMember %s to %p\n", em.toChars(), ed); em.addMember(sc, ed); // add em to ed's symbol table em.addMember(sc, sds); // add em to symbol table that ed is in em.parent = ed; // restore it after previous addMember() changed it diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index c0a8e9f4664..02f12e42570 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -7323,7 +7323,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol errors = true; } L1: - //printf("\tnested inside %s\n", enclosing.toChars()); + //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars()); nested |= 1; } } diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d index ef2fdef02f4..c29d4999f26 100644 --- a/gcc/d/dmd/entity.d +++ b/gcc/d/dmd/entity.d @@ -17,18 +17,27 @@ import core.stdc.ctype; nothrow: -public int HtmlNamedEntity(const(char)* p, size_t length) +/********************************** + * See if `name` is an HTML Named Entity + * Params: + * name = name of the entity + * Returns: + * code point corresponding to the named entity + * ~0 for not recognized as a named entity + */ +public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe { - int tableIndex = tolower(*p) - 'a'; - if (tableIndex >= 0 && tableIndex < 26) + const firstC = tolower(name[0]); + if (firstC >= 'a' && firstC <= 'z') { - foreach (entity; namesTable[tableIndex]) + // Linear search (use hash table instead?) + foreach (entity; namesTable[firstC - 'a']) { - if (entity.name == p[0 .. length]) + if (entity.name == name) return entity.value; } } - return -1; + return ~0; } private: diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 0646f57c5cd..fb5e092d25b 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -351,7 +351,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC { unsafeAssign!"scope variable"(v); } - else if (v.storage_class & STC.variadic && p == sc.func) + else if (v.isTypesafeVariadicParameter && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -649,7 +649,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) Dsymbol p = v.toParent2(); if (va && !vaIsRef && !va.isScope() && !v.isScope() && - (va.storage_class & v.storage_class & (STC.maybescope | STC.variadic)) == STC.maybescope && + !v.isTypesafeVariadicParameter && !va.isTypesafeVariadicParameter && + (va.storage_class & v.storage_class & STC.maybescope) && p == fd) { /* Add v to va's list of dependencies @@ -663,7 +664,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) !(v.storage_class & STC.return_) && v.isParameter() && fd.flags & FUNCFLAG.returnInprocess && - p == fd) + p == fd && + !v.isTypesafeVariadicParameter) { if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars()); inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope` @@ -735,7 +737,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1); } - else if (v.storage_class & STC.variadic && p == fd) + else if (v.isTypesafeVariadicParameter && p == fd) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -1022,7 +1024,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) continue; } } - else if (v.storage_class & STC.variadic && p == sc.func) + else if (v.isTypesafeVariadicParameter && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -1194,7 +1196,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) v.isParameter() && !v.doNotInferReturn && sc.func.flags & FUNCFLAG.returnInprocess && - p == sc.func) + p == sc.func && + !v.isTypesafeVariadicParameter) { inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return' continue; @@ -1250,7 +1253,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } } } - else if (v.storage_class & STC.variadic && p == sc.func) + else if (v.isTypesafeVariadicParameter && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -1627,7 +1630,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re { if (tb.ty == Tsarray) return; - if (v.storage_class & STC.variadic) + if (v.isTypesafeVariadicParameter) { er.byvalue.push(v); return; @@ -1943,7 +1946,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR VarDeclaration v = ve.var.isVarDeclaration(); if (tb.ty == Tarray || tb.ty == Tsarray) { - if (v && v.storage_class & STC.variadic) + if (v && v.isTypesafeVariadicParameter) { er.pushRef(v, retRefTransition); return; @@ -2586,3 +2589,15 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g return sc.setUnsafeDIP1000(gag, e.loc, "cannot take address of `scope` variable `%s` since `scope` applies to first indirection only", v); } + +/**************************** + * Determine if `v` is a typesafe variadic parameter. + * Params: + * v = variable to check + * Returns: + * true if `v` is a variadic parameter + */ +bool isTypesafeVariadicParameter(VarDeclaration v) +{ + return !!(v.storage_class & STC.variadic); +} diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 35ba5fa83ed..30baabdad52 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -3463,8 +3463,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.arguments && exp.newtype.isTypeSArray()) { auto ts = exp.newtype.isTypeSArray(); - edim = ts.dim; - exp.newtype = ts.next; + // check `new Value[Key]` + ts.dim = ts.dim.expressionSemantic(sc); + if (ts.dim.op == EXP.type) + { + exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type); + } + else + { + edim = ts.dim; + exp.newtype = ts.next; + } } ClassDeclaration cdthis = null; @@ -3518,18 +3527,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { return setError(); } - //https://issues.dlang.org/show_bug.cgi?id=20547 - //exp.arguments are the "parameters" to [], not to a real function - //so the errors that come from preFunctionParameters are misleading - if (originalNewtype.ty == Tsarray) - { - if (preFunctionParameters(sc, exp.arguments, false)) - { - exp.error("cannot create a `%s` with `new`", originalNewtype.toChars()); - return setError(); - } - } - else if (preFunctionParameters(sc, exp.arguments)) + if (preFunctionParameters(sc, exp.arguments)) { return setError(); } @@ -3885,6 +3883,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.type.pointerTo(); } + else if (tb.ty == Taarray) + { + // e.g. `new Alias(args)` + if (nargs) + { + exp.error("`new` cannot take arguments for an associative array"); + return setError(); + } + } else { exp.error("cannot create a `%s` with `new`", exp.type.toChars()); @@ -5019,7 +5026,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } - if (tf.trust <= TRUST.system && sc.setUnsafe()) + if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc, + "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1)) { exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); @@ -7588,11 +7596,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Check for unsafe casts - if (!isSafeCast(ex, t1b, tob) && - (!sc.func && sc.stc & STC.safe || sc.setUnsafe())) + if (!isSafeCast(ex, t1b, tob)) { - exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); - return setError(); + // This is an ad-hoc fix for https://issues.dlang.org/show_bug.cgi?id=19646 + // Should be replaced by a more general @system variables implementation + if (!sc.func && sc.stc & STC.safe) + { + exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); + return setError(); + } + + if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to)) + { + return setError(); + } } // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built @@ -8900,6 +8917,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) || e2x.checkSharedAccess(sc)) return setError(); + + if (e2x.type.isTypeNoreturn() && !e2x.isAssertExp() && !e2x.isThrowExp() && !e2x.isCallExp()) + { + auto msg = new StringExp(e2x.loc, "Accessed expression of type `noreturn`"); + msg.type = Type.tstring; + e2x = new AssertExp(e2x.loc, IntegerExp.literal!0, msg); + e2x.type = Type.tnoreturn; + return setResult(e2x); + } exp.e2 = e2x; } @@ -9896,9 +9922,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ae.e2.type.nextOf && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf); + /* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal, + * then we do want to make a temporary for it and call its destructor. + */ const isArraySetCtor = (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && - ae.e2.isLvalue && (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) && ae.e1.type.nextOf && ae.e1.type.nextOf.equivalent(ae.e2.type); @@ -10302,6 +10330,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // `__appendtmp*` will be destroyed together with the array `exp.e1`. auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); vd.storage_class |= STC.nodtor; + // Be more explicit that this "declaration" is local to the expression + vd.storage_class |= STC.exptemp; } auto ale = new ArrayLengthExp(exp.loc, value1); @@ -11870,6 +11900,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars()); + // https://issues.dlang.org/show_bug.cgi?id=22390 + // Equality comparison between array of noreturns simply lowers to length equality comparison + if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn()) + { + Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length); + Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length); + auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2); + result = e.expressionSemantic(sc); + return; + } + if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays")) return setError(); @@ -12638,7 +12679,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) e = new CommaExp(exp.loc, eleft, e); e.type = Type.tvoid; // ambiguous type? } - return e; + return e.expressionSemantic(sc); } if (auto o = s.isOverloadSet()) { @@ -13131,26 +13172,24 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) { //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars()); - if (v) + if (v is null) + return true; + + if (!v.canTakeAddressOf()) + { + exp.error("cannot take address of `%s`", exp.toChars()); + return false; + } + if (sc.func && !sc.intypeof && !v.isDataseg()) { - if (!v.canTakeAddressOf()) + v.storage_class &= ~STC.maybescope; + v.doNotInferScope = true; + if (global.params.useDIP1000 != FeatureState.enabled && + !(v.storage_class & STC.temp) && + sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func)) { - exp.error("cannot take address of `%s`", exp.toChars()); return false; } - if (sc.func && !sc.intypeof && !v.isDataseg()) - { - const(char)* p = v.isParameter() ? "parameter" : "local"; - v.storage_class &= ~STC.maybescope; - v.doNotInferScope = true; - if (global.params.useDIP1000 != FeatureState.enabled && - !(v.storage_class & STC.temp) && - sc.setUnsafe()) - { - exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); - return false; - } - } } return true; } diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index 9fe40bf0603..0ea73036a78 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -20,6 +20,12 @@ import dmd.identifier; enum package_d = "package." ~ mars_ext; enum package_di = "package." ~ hdr_ext; +/// Returns: whether a file with `name` is a special "package.d" module +bool isPackageFileName(scope FileName fileName) nothrow +{ + return FileName.equals(fileName.name, package_d) || FileName.equals(fileName.name, package_di); +} + final class FileManager { private StringTable!(const(ubyte)[]) files; diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 83bc2eab1fe..7475cb4f9f5 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -867,6 +867,8 @@ extern (C++) class FuncDeclaration : Declaration auto f = s.isFuncDeclaration(); if (!f) return 0; + if (f.storage_class & STC.disable) + return 0; if (t.equals(f.type)) { fd = f; @@ -2048,9 +2050,11 @@ extern (C++) class FuncDeclaration : Declaration } if (!found) { - //printf("\tadding sibling %s\n", fdthis.toPrettyChars()); + //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars()); if (!sc.intypeof && !(sc.flags & SCOPE.compile)) + { siblingCallers.push(fdthis); + } } } @@ -2164,7 +2168,6 @@ extern (C++) class FuncDeclaration : Declaration return false; Lyes: - //printf("\tneeds closure\n"); return true; } @@ -2176,14 +2179,21 @@ extern (C++) class FuncDeclaration : Declaration * Returns: * true if any errors occur. */ - extern (D) final bool checkClosure() + extern (C++) final bool checkClosure() { + //printf("checkClosure() %s\n", toChars()); if (!needsClosure()) return false; if (setGC()) { - error("is `@nogc` yet allocates closures with the GC"); + error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars()); + if (global.gag) // need not report supplemental errors + return true; + } + else if (global.params.betterC) + { + error("is `-betterC` yet allocates closure for `%s()` with the GC", toChars()); if (global.gag) // need not report supplemental errors return true; } @@ -2216,7 +2226,7 @@ extern (C++) class FuncDeclaration : Declaration break LcheckAncestorsOfANestedRef; } a.push(f); - .errorSupplemental(f.loc, "%s closes over variable %s at %s", + .errorSupplemental(f.loc, "`%s` closes over variable `%s` at %s", f.toPrettyChars(), v.toChars(), v.loc.toChars()); break LcheckAncestorsOfANestedRef; } @@ -3293,7 +3303,8 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); - printCandidates(loc, td, sc.isDeprecated()); + if (!global.gag || global.params.showGaggedErrors) + printCandidates(loc, td, sc.isDeprecated()); return null; } /* This case used to happen when several ctors are mixed in an agregate. @@ -3331,7 +3342,8 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, { .error(loc, "none of the overloads of `%s` are callable using a %sobject", fd.ident.toChars(), thisBuf.peekChars()); - printCandidates(loc, fd, sc.isDeprecated()); + if (!global.gag || global.params.showGaggedErrors) + printCandidates(loc, fd, sc.isDeprecated()); return null; } @@ -3361,18 +3373,23 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, { .error(loc, "none of the overloads of `%s` are callable using argument types `%s`", fd.toChars(), fargsBuf.peekChars()); - printCandidates(loc, fd, sc.isDeprecated()); + if (!global.gag || global.params.showGaggedErrors) + printCandidates(loc, fd, sc.isDeprecated()); return null; } .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), tf.modToChars(), fargsBuf.peekChars()); + // re-resolve to check for supplemental message - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); - if (failMessage) - errorSupplemental(loc, failMessage); + if (!global.gag || global.params.showGaggedErrors) + { + const(char)* failMessage; + functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); + if (failMessage) + errorSupplemental(loc, failMessage); + } return null; } @@ -4220,6 +4237,7 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody) { + // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list. super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); this.fbody = fbody; } @@ -4256,6 +4274,15 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration { v.visit(this); } + + extern (D) void fixupInvariantIdent(size_t offset) + { + OutBuffer idBuf; + idBuf.writestring("__invariant"); + idBuf.print(offset); + + ident = Identifier.idPool(idBuf[]); + } } @@ -4447,12 +4474,15 @@ void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool depr errorFunc(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : ""); } - else if (FuncDeclaration fd2 = cast(FuncDeclaration) s.arg0) + else if (s.arg0.dyncast() == DYNCAST.dsymbol) { - if (maxDepth > 0) + if (FuncDeclaration fd2 = (cast(Dsymbol) s.arg0).isFuncDeclaration()) { - errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars()); - errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation); + if (maxDepth > 0) + { + errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars()); + errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation); + } } } } diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d index ab46f5eebbd..832c331c314 100644 --- a/gcc/d/dmd/impcnvtab.d +++ b/gcc/d/dmd/impcnvtab.d @@ -64,6 +64,57 @@ enum ImpCnvTab impCnvTab = generateImpCnvTab(); ImpCnvTab generateImpCnvTab() { + TY[TMAX] typeTYs = + [ + Tarray, + Tsarray, + Taarray, + Tpointer, + Treference, + Tfunction, + Tident, + Tclass, + Tstruct, + Tenum, + Tdelegate, + Tnone, + Tvoid, + Tint8, + Tuns8, + Tint16, + Tuns16, + Tint32, + Tuns32, + Tint64, + Tuns64, + Tfloat32, + Tfloat64, + Tfloat80, + Timaginary32, + Timaginary64, + Timaginary80, + Tcomplex32, + Tcomplex64, + Tcomplex80, + Tbool, + Tchar, + Twchar, + Tdchar, + Terror, + Tinstance, + Ttypeof, + Ttuple, + Tslice, + Treturn, + Tnull, + Tvector, + Tint128, + Tuns128, + Ttraits, + Tmixin, + Tnoreturn, + Ttag, + ]; ImpCnvTab impCnvTab; // Set conversion tables @@ -375,5 +426,9 @@ ImpCnvTab generateImpCnvTab() X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80); + // "No type is implicitly convertible to noreturn, but noreturn is implicitly convertible to every other type" + foreach(convertToTy; typeTYs) + X(Tnoreturn, convertToTy, convertToTy, convertToTy, convertToTy); + return impCnvTab; } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index a1963dabcdc..a5767127104 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -567,18 +567,40 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = e.optimize(WANTvalue); } } + + // Look for the case of statically initializing an array with a single member. + // Recursively strip static array / enum layers until a compatible element is found, + // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found + // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]] + // int[2] = new Object => null + Expression sarrayRepeat(Type tb) { - // Look for the case of statically initializing an array - // with a single member. - auto tba = tb.isTypeSArray(); - if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next)) + auto tsa = tb.isTypeSArray(); + if (!tsa) + return null; + + // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars()); + Expression elem = null; + if (i.exp.implicitConvTo(tb.nextOf())) + elem = i.exp.implicitCastTo(sc, tb.nextOf()); + else if (auto ae = sarrayRepeat(tb.nextOf().toBasetype())) + elem = ae; + else + return null; + + auto arrayElements = new Expressions(cast(size_t) tsa.dim.toInteger()); + foreach (ref e; *arrayElements) + e = elem; + return new ArrayLiteralExp(i.exp.loc, tb, elem, arrayElements); + } + + if (auto sa = sarrayRepeat(tb)) { - /* If the variable is not actually used in compile time, array creation is - * redundant. So delay it until invocation of toExpression() or toDt(). - */ - t = tb.nextOf(); + // printf("sa = %s\n", sa.toChars()); + i.exp = sa; } + { auto tta = t.isTypeSArray(); if (i.exp.implicitConvTo(t)) { @@ -595,6 +617,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { + auto tba = tb.isTypeSArray(); // Look for mismatch of compile-time known length to emit // better diagnostic message, as same as AssignExp::semantic. if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index ef918e275d0..11afcdd9f0b 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -1326,7 +1326,7 @@ class Lexer switch (*p) { case ';': - c = HtmlNamedEntity(idstart, p - idstart); + c = HtmlNamedEntity(idstart[0 .. p - idstart]); if (c == ~0) { error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index 4eb422805db..369d60e208a 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -98,7 +98,7 @@ void checkMustUseReserved(Dsymbol sym) */ private bool isAssignment(Expression e) { - if (e.isAssignExp || e.isBinAssignExp) + if (e.isAssignExp || e.isBinAssignExp || e.isConstructExp || e.isBlitExp) return true; if (auto ce = e.isCallExp()) { diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 2b7b9ac1013..be28d082405 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -1120,7 +1120,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) e.e1 = ci; } } - if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray) + if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray || e.e1.op == EXP.null_) { ret = ArrayLength(e.type, e.e1).copy(); } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 4e3fd533c18..a2c364e7e15 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2186,7 +2186,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) s = new AST.DebugSymbol(token.loc, token.ident); else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`debug = ` is deprecated, use debug identifiers instead"); + s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue); + } else { error("identifier or integer expected, not `%s`", token.toChars()); @@ -2215,7 +2221,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) id = token.ident; else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`debug( )` is deprecated, use debug identifiers instead"); + level = cast(uint)token.unsvalue; + } else error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars()); loc = token.loc; @@ -2235,7 +2247,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) s = new AST.VersionSymbol(token.loc, token.ident); else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`version = ` is deprecated, use version identifiers instead"); s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue); + } else { error("identifier or integer expected, not `%s`", token.toChars()); @@ -2269,7 +2286,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) id = token.ident; else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`version( )` is deprecated, use version identifiers instead"); + level = cast(uint)token.unsvalue; + } else if (token.value == TOK.unittest_) id = Identifier.idPool(Token.toString(TOK.unittest_)); else if (token.value == TOK.assert_) @@ -9312,13 +9335,10 @@ LagainStc: { AST.TypeAArray taa = cast(AST.TypeAArray)t; AST.Type index = taa.index; + // `new Type[expr]` is a static array auto edim = AST.typeToExpression(index); - if (!edim) - { - error("cannot create a `%s` with `new`", t.toChars); - return new AST.NullExp(loc); - } - t = new AST.TypeSArray(taa.next, edim); + if (edim) + t = new AST.TypeSArray(taa.next, edim); } else if (token.value == TOK.leftParenthesis && t.ty != Tsarray) { diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index c5d7667fefc..6f377700efc 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -470,14 +470,6 @@ private extern(C++) final class Semantic3Visitor : Visitor if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) { stc |= STC.variadic; - auto vtypeb = vtype.toBasetype(); - if (vtypeb.ty == Tarray || vtypeb.ty == Tclass) - { - /* Since it'll be pointing into the stack for the array - * contents, it needs to be `scope` - */ - stc |= STC.scope_; - } } if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_)) @@ -1379,7 +1371,7 @@ private extern(C++) final class Semantic3Visitor : Visitor funcdecl.flags &= ~FUNCFLAG.semantic3Errors; if (funcdecl.type.ty == Terror) funcdecl.errors = true; - //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars()); + //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars()); //fflush(stdout); } diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index f23b9882ae0..e5e57535b37 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -733,9 +733,26 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor { assert(oaggr.type); - fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars()); - if (isAggregate(fs.aggr.type)) - fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`"); + fs.error("invalid `%s` aggregate `%s` of type `%s`", + Token.toChars(fs.op), oaggr.toChars(), oaggr.type.toPrettyChars()); + + if (auto ad = isAggregate(fs.aggr.type)) + { + if (fs.op == TOK.foreach_reverse_) + { + fs.loc.errorSupplemental("`foreach_reverse` works with bidirectional ranges"~ + " (implementing `back` and `popBack`), aggregates implementing" ~ + " `opApplyReverse`, or the result of an aggregate's `.tupleof` property"); + fs.loc.errorSupplemental("https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange"); + } + else + { + fs.loc.errorSupplemental("`foreach` works with input ranges"~ + " (implementing `front` and `popFront`), aggregates implementing" ~ + " `opApply`, or the result of an aggregate's `.tupleof` property"); + fs.loc.errorSupplemental("https://dlang.org/phobos/std_range_primitives.html#isInputRange"); + } + } return setError(); } @@ -2828,10 +2845,20 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor rs.error("`return` statements cannot be in contracts"); errors = true; } - if (sc.os && sc.os.tok != TOK.onScopeFailure) + if (sc.os) { - rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); - errors = true; + // @@@DEPRECATED_2.112@@@ + // Deprecated in 2.100, transform into an error in 2.112 + if (sc.os.tok == TOK.onScopeFailure) + { + rs.deprecation("`return` statements cannot be in `scope(failure)` bodies."); + deprecationSupplemental(rs.loc, "Use try-catch blocks for this purpose"); + } + else + { + rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); + errors = true; + } } if (sc.tf) { @@ -2913,6 +2940,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor rs.exp.type = texp; } + // @@@DEPRECATED_2.111@@@ + const olderrors = global.startGagging(); + // uncomment to turn deprecation into an error when + // deprecation cycle is over + if (discardValue(rs.exp)) + { + //errors = true; + } + if (global.endGagging(olderrors)) + rs.exp.deprecation("`%s` has no effect", rs.exp.toChars()); + /* Replace: * return exp; * with: diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 25dee7f4185..5791a885068 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -862,6 +862,12 @@ package mixin template ParseVisitMethods(AST) visitFuncBody(d); } + override void visit(AST.CtorDeclaration d) + { + //printf("Visiting CtorDeclaration\n"); + visitFuncBody(d); + } + override void visit(AST.StaticCtorDeclaration d) { //printf("Visiting StaticCtorDeclaration\n"); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 0469b927316..b1f1b1fa167 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1272,6 +1272,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) errors = true; } + const bool isTypesafeVariadic = i + 1 == dim && + tf.parameterList.varargs == VarArg.typesafe && + (t.isTypeDArray() || t.isTypeClass()); + if (isTypesafeVariadic) + { + /* typesafe variadic arguments are constructed on the stack, so must be `scope` + */ + fparam.storageClass |= STC.scope_ | STC.scopeinferred; + } + if (fparam.storageClass & STC.return_) { if (fparam.isReference()) @@ -1300,8 +1310,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } } - if (i + 1 == dim && tf.parameterList.varargs == VarArg.typesafe && - (t.isTypeDArray() || t.isTypeClass())) + if (isTypesafeVariadic) { /* This is because they can be constructed on the stack * https://dlang.org/spec/function.html#typesafe_variadic_functions diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 1bb10a835d2..40c2689a3b9 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -873,6 +873,17 @@ public: gcc_unreachable (); } + /* Look for exp = noreturn; */ + if (e->e2->type->isTypeNoreturn ()) + { + /* If the RHS is a `noreturn' expression, there is no point generating + any code for the assignment, just evaluate side effects. */ + tree t1 = build_expr (e->e1); + tree t2 = build_expr (e->e2); + this->result_ = compound_expr (t1, t2); + return; + } + /* Look for array[] = n; */ if (e->e1->op == EXP::slice) { diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index bd9c61d540d..da652396468 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -249,7 +249,7 @@ Compile in debug code. fdebug= D Joined RejectNegative --fdebug= Compile in debug code, code <= , or code identified by . +-fdebug= Compile in debug code identified by . fdoc D @@ -466,7 +466,7 @@ Compile in unittest code. fversion= D Joined RejectNegative --fversion= Compile in version code >= or identified by . +-fversion= Compile in version code identified by . fweak-templates D Var(flag_weak_templates) Init(1) diff --git a/gcc/testsuite/gdc.test/compilable/backendfloatoptim.d b/gcc/testsuite/gdc.test/compilable/backendfloatoptim.d new file mode 100644 index 00000000000..7ec9f614ef8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/backendfloatoptim.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -O -inline + +//https://issues.dlang.org/show_bug.cgi?id=20143 +real fun(int x) { return 0.0; } + +double bug() +{ + // value passed to fun is irrelevant + return 0.0 / fun(420); +} diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle3.d b/gcc/testsuite/gdc.test/compilable/cppmangle3.d index 93e49c72c18..82c68f7a3a5 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle3.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle3.d @@ -45,16 +45,12 @@ alias Alias(T) = T; static assert(is(Alias!(__traits(parent, Foo.bar)) == Foo)); extern(C++, "std"): -debug = 456; debug = def; -version = 456; version = def; extern(C++, "std") { - debug = 456; debug = def; - version = 456; version = def; } diff --git a/gcc/testsuite/gdc.test/compilable/must_use_initialize.d b/gcc/testsuite/gdc.test/compilable/must_use_initialize.d new file mode 100644 index 00000000000..8caec434bdc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/must_use_initialize.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=23236 +// can't initialize a @mustuse member in constructor + +import core.attribute; + +@mustuse struct MyError { } + +struct S +{ + MyError lastError; + + this(int x) + { + this.lastError = MyError(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/noreturn1.d b/gcc/testsuite/gdc.test/compilable/noreturn1.d index 5bba9baa72a..e648a56d896 100644 --- a/gcc/testsuite/gdc.test/compilable/noreturn1.d +++ b/gcc/testsuite/gdc.test/compilable/noreturn1.d @@ -122,3 +122,31 @@ noreturn testdg(noreturn delegate() dg) { dg(); } + +noreturn func() +{ + while(1) + { + } +} +alias AliasSeq(T...) = T; +alias Types = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, + long, ulong, char, wchar, dchar, float, double, + real); +void noreturnImplicit() +{ + /* + Testing both ways because, although the underlying table + is symmetrical the code that calls into it may be buggy. + */ + { + int x = 2 + func(); + int y = func() + 2; + } + foreach(T; Types) + { + T value; + auto x = value + throw new Exception("Hello"); + auto y = (throw new Exception("wow")) + value; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test20832.d b/gcc/testsuite/gdc.test/compilable/test20832.d new file mode 100644 index 00000000000..25617a9a398 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test20832.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: -preview=dip1000 +// https://issues.dlang.org/show_bug.cgi?id=20823 + +void boo(T)( scope void delegate(T[] data) fun) {} +void goo(T)(/+scope+/ void delegate(T[] data) fun) {} + +void main() +{ + void Execute(int[] data) {} + goo(&Execute); + boo(&Execute); +} diff --git a/gcc/testsuite/gdc.test/compilable/test21177.d b/gcc/testsuite/gdc.test/compilable/test21177.d index b3b613bc0e9..b485304c188 100644 --- a/gcc/testsuite/gdc.test/compilable/test21177.d +++ b/gcc/testsuite/gdc.test/compilable/test21177.d @@ -4,15 +4,19 @@ DISABLED: win TEST_OUTPUT: --- compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(111): 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*` +compilable/test21177.d(154): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(155): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(202): Deprecation: format specifier `"%m"` is invalid +compilable/test21177.d(203): Deprecation: argument `d` for format specification `"%mc"` must be `char**`, not `int` +compilable/test21177.d(204): Deprecation: argument `c` for format specification `"%ms"` must be `char**`, not `char*` +compilable/test21177.d(205): Deprecation: format specifier `"%ml"` is invalid +compilable/test21177.d(206): Deprecation: argument `d` for format specification `"%mlc"` must be `wchar_t**`, not `int` +compilable/test21177.d(207): Deprecation: argument `c` for format specification `"%mls"` must be `wchar_t**`, not `char*` --- */ @@ -27,50 +31,45 @@ void main() #line 100 printf("%m this is a string in errno"); printf("%s %m", "str".ptr, 2); - printf("%a", 2.); + printf("%m %a", 2.); printf("%m %m %s"); + printf("%m"); printf("%*m"); - + pragma(msg, "compilable/test21177.d(111): Deprecation: more format specifiers than 0 arguments"); + } + else + { + pragma(msg, "compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments"); + printf("%m"); + } + { char* a, b; - sscanf("salut poilu", "%a %m", a, b); + sscanf("salut poilu", "%ms %m[^\n]", &a, &b); assert(!strcmp(a, b)); free(a); free(b); - char* t, p; - sscanf("Tomate Patate", "%ms %as", t, p); + char* t; wchar_t* p; + sscanf("Tomate Patate", "%mc %mlc", &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"); + sscanf("152", "%mc"); + sscanf("153", "%ml"); + sscanf("154", "%mls"); + sscanf("155", "%mlc"); #line 200 - printf("%m"); - char* c; + int d; sscanf("204", "%m", c); - sscanf("205", "%ms", c); - sscanf("206", "%a", c); - sscanf("207", "%as", c); - + sscanf("205", "%mc", d); + sscanf("206", "%ms", c); + sscanf("207", "%ml", d); + sscanf("208", "%mlc", d); + sscanf("209", "%mls", c); } } diff --git a/gcc/testsuite/gdc.test/compilable/test21432.d b/gcc/testsuite/gdc.test/compilable/test21432.d new file mode 100644 index 00000000000..2c83e246116 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21432.d @@ -0,0 +1,25 @@ +// https://issues.dlang.org/show_bug.cgi?id=21432 +auto issue21432() +{ + enum int[] a = []; + return a; +} + +enum test21432a = issue21432; + +/////////////////////// + +double issue21432b(double r) +{ + enum double[4] poly = [ + 0x1.ffffffffffdbdp-2, + 0x1.555555555543cp-3, + 0x1.55555cf172b91p-5, + 0x1.1111167a4d017p-7, + ]; + + immutable r2 = r * r; + return r + r2 * (poly[0] + r * poly[1]) + r2 * r2 * (poly[2] + r * poly[3]); +} + +enum test21432b = issue21432b(-0x1p-1); diff --git a/gcc/testsuite/gdc.test/compilable/test22390.d b/gcc/testsuite/gdc.test/compilable/test22390.d new file mode 100644 index 00000000000..f045416c4c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22390.d @@ -0,0 +1,8 @@ +// https://issues.dlang.org/show_bug.cgi?id=22390 + +int main() +{ + noreturn[] empty; + assert(empty == empty); + return 0; +} diff --git a/gcc/testsuite/gdc.test/compilable/test23082.d b/gcc/testsuite/gdc.test/compilable/test23082.d new file mode 100644 index 00000000000..9df4e4e7774 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23082.d @@ -0,0 +1,17 @@ +// https://issues.dlang.org/show_bug.cgi?id=23082 + +/* +TEST_OUTPUT: +--- +bar +--- +*/ + +void foo()() {} +alias bar = foo; +void bar() { } + +void main() +{ + pragma(msg, __traits(parent, main).bar.stringof); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23166.d b/gcc/testsuite/gdc.test/compilable/test23166.d new file mode 100644 index 00000000000..66da4cd6963 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23166.d @@ -0,0 +1,22 @@ +// REQUIRED_ARGS: -inline + +// https://issues.dlang.org/show_bug.cgi?id=23166 + +// seg fault with -inline + +bool __equals(scope const char[] lhs, scope const char[] rhs) +{ + if (lhs.length != rhs.length) + return false; + + { + import core.stdc.string : memcmp; + return lhs.length == 0; + } + return true; +} + +int test(string type) +{ + return __equals(type, "as-is"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23172.d b/gcc/testsuite/gdc.test/compilable/test23172.d new file mode 100644 index 00000000000..18b6d4ce8c5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23172.d @@ -0,0 +1,33 @@ +// https://issues.dlang.org/show_bug.cgi?id=23172 + +enum E : ubyte { // `ubyte` is needed to trigger the bug + A, + B, +} + +struct S { + E e; +} + +void compiles(bool b, S s) { + E e = b ? E.A : s.e; +} + +void errors(bool b, const ref S s) { + E e = b ? E.A : s.e; +} + +// from https://issues.dlang.org/show_bug.cgi?id=23188 + +enum Status : byte +{ + A, B, C +} + +Status foo() +{ + Status t = Status.A; + const Status s = t; + + return (s == Status.A) ? Status.B : s; // <-- here +} diff --git a/gcc/testsuite/gdc.test/compilable/test23235.d b/gcc/testsuite/gdc.test/compilable/test23235.d new file mode 100644 index 00000000000..99772adeba4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23235.d @@ -0,0 +1,20 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23235 + */ + +@safe: + +void awkk(string[] ppp...) +{ +} + +void bark(string[] foo...) { + awkk(foo); +} + +void cack(string[] bar...) { + bark(bar); +} + +void test() { + cack("abc", "def"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23256.d b/gcc/testsuite/gdc.test/compilable/test23256.d new file mode 100644 index 00000000000..1e5720128ca --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23256.d @@ -0,0 +1,6 @@ +/* REQUIRED_ARGS: -os=windows + */ + +// https://issues.dlang.org/show_bug.cgi?id=23256 + +void test23256() { } diff --git a/gcc/testsuite/gdc.test/compilable/test23262.d b/gcc/testsuite/gdc.test/compilable/test23262.d new file mode 100644 index 00000000000..96da2721b1b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23262.d @@ -0,0 +1,17 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23262 + */ + +struct T() +{ + string[] tags; + + this(string[] tags...) + { + this.tags = tags; // don't infer `return` attribute for `tags` + } +} + +void test() +{ + T!() t; +} diff --git a/gcc/testsuite/gdc.test/compilable/testgotoskips.d b/gcc/testsuite/gdc.test/compilable/testgotoskips.d new file mode 100644 index 00000000000..659b5f776a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testgotoskips.d @@ -0,0 +1,17 @@ +/* + Tests to defend against false positives from the goto skips over decl errors +*/ +// https://issues.dlang.org/show_bug.cgi?id=23271 +class A { + private static A[] active; + private void test() { + foreach(a; active) { + if(a is this) + goto label; + } + // used to say Error: `goto` skips declaration of variable `s.A.test.__appendtmp4` at s.d(...) + active ~= this; + label: + return; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d index 1fdf5a5a722..8360e1ac484 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d @@ -1,12 +1,20 @@ /* TEST_OUTPUT: --- -fail_compilation/attributediagnostic.d(16): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1` -fail_compilation/attributediagnostic.d(18): which calls `attributediagnostic.layer0` -fail_compilation/attributediagnostic.d(20): which calls `attributediagnostic.system` -fail_compilation/attributediagnostic.d(22): which was inferred `@system` because of: -fail_compilation/attributediagnostic.d(22): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not -fail_compilation/attributediagnostic.d(17): `attributediagnostic.layer1` is declared here +fail_compilation/attributediagnostic.d(24): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1` +fail_compilation/attributediagnostic.d(26): which calls `attributediagnostic.layer0` +fail_compilation/attributediagnostic.d(28): which calls `attributediagnostic.system` +fail_compilation/attributediagnostic.d(30): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(30): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not +fail_compilation/attributediagnostic.d(25): `attributediagnostic.layer1` is declared here +fail_compilation/attributediagnostic.d(46): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system1` +fail_compilation/attributediagnostic.d(35): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(35): cast from `uint` to `int*` not allowed in safe code +fail_compilation/attributediagnostic.d(33): `attributediagnostic.system1` is declared here +fail_compilation/attributediagnostic.d(47): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system2` +fail_compilation/attributediagnostic.d(41): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(41): `@safe` function `system2` cannot call `@system` `fsys` +fail_compilation/attributediagnostic.d(39): `attributediagnostic.system2` is declared here --- */ @@ -19,5 +27,22 @@ auto layer0() { system(); } auto system() { - asm {} + asm {} +} + +auto system1() +{ + int* x = cast(int*) 0xDEADBEEF; +} + +auto fsys = function void() @system {}; +auto system2() +{ + fsys(); +} + +void main() @safe +{ + system1(); + system2(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/chkformat.d b/gcc/testsuite/gdc.test/fail_compilation/chkformat.d index e9ed2415d7c..fa8915e5fa9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/chkformat.d +++ b/gcc/testsuite/gdc.test/fail_compilation/chkformat.d @@ -169,3 +169,21 @@ void test409() { char* p; printf("%llu", p); } void test410() { char* p; printf("%lld", p); } void test411() { char* p; printf("%ju", p); } void test412() { char* p; printf("%jd", p); } + +/* https://issues.dlang.org/show_bug.cgi?id=23247 +TEST_OUTPUT: +--- +fail_compilation/chkformat.d(501): Deprecation: argument `p` for format specification `"%a"` must be `double`, not `char*` +fail_compilation/chkformat.d(502): Deprecation: argument `p` for format specification `"%La"` must be `real`, not `char*` +fail_compilation/chkformat.d(503): Deprecation: argument `p` for format specification `"%a"` must be `float*`, not `char*` +fail_compilation/chkformat.d(504): Deprecation: argument `p` for format specification `"%la"` must be `double*`, not `char*` +fail_compilation/chkformat.d(505): Deprecation: argument `p` for format specification `"%La"` must be `real*`, not `char*` +--- +*/ +#line 500 + +void test501() { char* p; printf("%a", p); } +void test502() { char* p; printf("%La", p); } +void test503() { char* p; scanf("%a", p); } +void test504() { char* p; scanf("%la", p); } +void test505() { char* p; scanf("%La", p); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d index 416d56310e1..7b2eca79b80 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d @@ -1,15 +1,17 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10319.d(27): Error: `pure` function `D main` cannot call impure function `diag10319.foo` -fail_compilation/diag10319.d(27): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` -fail_compilation/diag10319.d(16): `diag10319.foo` is declared here -fail_compilation/diag10319.d(28): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` -fail_compilation/diag10319.d(28): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` -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: function `D main` may throw but is marked as `nothrow` +fail_compilation/diag10319.d(29): Error: `pure` function `D main` cannot call impure function `diag10319.foo` +fail_compilation/diag10319.d(29): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` +fail_compilation/diag10319.d(18): `diag10319.foo` is declared here +fail_compilation/diag10319.d(30): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` +fail_compilation/diag10319.d(30): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` +fail_compilation/diag10319.d(23): which was inferred `@system` because of: +fail_compilation/diag10319.d(23): cannot take address of local `x` in `@safe` function `bar` +fail_compilation/diag10319.d(20): `diag10319.bar!int.bar` is declared here +fail_compilation/diag10319.d(29): Error: function `diag10319.foo` is not `nothrow` +fail_compilation/diag10319.d(30): Error: function `diag10319.bar!int.bar` is not `nothrow` +fail_compilation/diag10319.d(27): Error: function `D main` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d index 279d62a5496..1be0f1e85a2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d @@ -1,12 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11198.d(15): Error: version `blah` declaration must be at module level -fail_compilation/diag11198.d(16): Error: debug `blah` declaration must be at module level -fail_compilation/diag11198.d(17): Error: version `1` level declaration must be at module level -fail_compilation/diag11198.d(18): Error: debug `2` level declaration must be at module level -fail_compilation/diag11198.d(19): Error: identifier or integer expected, not `""` -fail_compilation/diag11198.d(20): Error: identifier or integer expected, not `""` +fail_compilation/diag11198.d(17): Error: version `blah` declaration must be at module level +fail_compilation/diag11198.d(18): Error: debug `blah` declaration must be at module level +fail_compilation/diag11198.d(19): Deprecation: `version = ` is deprecated, use version identifiers instead +fail_compilation/diag11198.d(19): Error: version `1` level declaration must be at module level +fail_compilation/diag11198.d(20): Deprecation: `debug = ` is deprecated, use debug identifiers instead +fail_compilation/diag11198.d(20): Error: debug `2` level declaration must be at module level +fail_compilation/diag11198.d(21): Error: identifier or integer expected, not `""` +fail_compilation/diag11198.d(22): Error: identifier or integer expected, not `""` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d index f6e764bd98d..1d37a1ecbfe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/diag12829.d(12): Error: function `diag12829.test1` is `@nogc` yet allocates closures with the GC -fail_compilation/diag12829.d(15): diag12829.test1.__lambda2 closes over variable x at fail_compilation/diag12829.d(14) -fail_compilation/diag12829.d(19): diag12829.test1.bar closes over variable x at fail_compilation/diag12829.d(14) -fail_compilation/diag12829.d(26): Error: function `diag12829.test2` is `@nogc` yet allocates closures with the GC -fail_compilation/diag12829.d(31): diag12829.test2.S.foo closes over variable x at fail_compilation/diag12829.d(28) +fail_compilation/diag12829.d(12): Error: function `diag12829.test1` is `@nogc` yet allocates closure for `test1()` with the GC +fail_compilation/diag12829.d(15): `diag12829.test1.__lambda2` closes over variable `x` at fail_compilation/diag12829.d(14) +fail_compilation/diag12829.d(19): `diag12829.test1.bar` closes over variable `x` at fail_compilation/diag12829.d(14) +fail_compilation/diag12829.d(26): Error: function `diag12829.test2` is `@nogc` yet allocates closure for `test2()` with the GC +fail_compilation/diag12829.d(31): `diag12829.test2.S.foo` closes over variable `x` at fail_compilation/diag12829.d(28) --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail118.d b/gcc/testsuite/gdc.test/fail_compilation/fail118.d index 3df797d6b8f..a526b908acd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail118.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail118.d @@ -1,15 +1,17 @@ /* TEST_OUTPUT: --- -fail_compilation/fail118.d(43): Error: invalid `foreach` aggregate `Iter` of type `Iter` -fail_compilation/fail118.d(43): maybe define `opApply()`, range primitives, or use `.tupleof` -fail_compilation/fail118.d(44): Error: invalid `foreach` aggregate `Iter` of type `Iter` -fail_compilation/fail118.d(44): maybe define `opApply()`, range primitives, or use `.tupleof` -fail_compilation/fail118.d(47): Error: invalid `foreach` aggregate `s` of type `S*` -fail_compilation/fail118.d(49): Error: undefined identifier `unknown` -fail_compilation/fail118.d(37): Error: undefined identifier `doesNotExist` -fail_compilation/fail118.d(51): Error: template instance `fail118.error!()` error instantiating -fail_compilation/fail118.d(51): Error: invalid `foreach` aggregate `error()` of type `void` +fail_compilation/fail118.d(45): Error: invalid `foreach` aggregate `Iter` of type `Iter` +fail_compilation/fail118.d(45): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/fail118.d(45): https://dlang.org/phobos/std_range_primitives.html#isInputRange +fail_compilation/fail118.d(46): Error: invalid `foreach` aggregate `Iter` of type `Iter` +fail_compilation/fail118.d(46): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/fail118.d(46): https://dlang.org/phobos/std_range_primitives.html#isInputRange +fail_compilation/fail118.d(49): Error: invalid `foreach` aggregate `s` of type `S*` +fail_compilation/fail118.d(51): Error: undefined identifier `unknown` +fail_compilation/fail118.d(39): Error: undefined identifier `doesNotExist` +fail_compilation/fail118.d(53): Error: template instance `fail118.error!()` error instantiating +fail_compilation/fail118.d(53): Error: invalid `foreach` aggregate `error()` of type `void` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20547.d b/gcc/testsuite/gdc.test/fail_compilation/fail20547.d deleted file mode 100644 index c14977d0f12..00000000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20547.d +++ /dev/null @@ -1,15 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail20547.d(12): Error: cannot create a `string[string]` with `new` -fail_compilation/fail20547.d(14): Error: cannot create a `string[string]` with `new` ---- -*/ - -void main() -{ - //https://issues.dlang.org/show_bug.cgi?id=11790 - string[string] crash = new string[string]; - //https://issues.dlang.org/show_bug.cgi?id=20547 - int[string] c = new typeof(crash); -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22134.d b/gcc/testsuite/gdc.test/fail_compilation/fail22134.d new file mode 100644 index 00000000000..5a4933ef325 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22134.d @@ -0,0 +1,17 @@ +// https://issues.dlang.org/show_bug.cgi?id=22134 +/* REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/fail22134.d(12): Deprecation: `this.arr[i]` has no effect +--- +*/ +struct StackBuffer +{ + auto opIndex(size_t i) + { + return arr[i]; + } + +private: + void[] arr; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23181.d b/gcc/testsuite/gdc.test/fail_compilation/fail23181.d new file mode 100644 index 00000000000..519244c1cdf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23181.d @@ -0,0 +1,16 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23181 +TEST_OUTPUT: +--- +$p:druntime/import/core/lifetime.d$($n$): Error: struct `fail23181.fail23181.NoPostblit` is not copyable because it has a disabled postblit +$p:druntime/import/core/internal/array/construction.d$($n$): Error: template instance `core.lifetime.copyEmplace!(NoPostblit, NoPostblit)` error instantiating +fail_compilation/fail23181.d(15): instantiated from here: `_d_arraysetctor!(NoPostblit[], NoPostblit)` +--- +*/ +void fail23181() +{ + struct NoPostblit + { + @disable this(this); + } + NoPostblit[4] noblit23181 = NoPostblit(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail261.d b/gcc/testsuite/gdc.test/fail_compilation/fail261.d index 85da957290c..d807dc8f3aa 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail261.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail261.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail261.d(19): Error: invalid `foreach` aggregate `range` of type `MyRange` -fail_compilation/fail261.d(19): maybe define `opApply()`, range primitives, or use `.tupleof` +fail_compilation/fail261.d(20): Error: invalid `foreach` aggregate `range` of type `MyRange` +fail_compilation/fail261.d(20): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/fail261.d(20): https://dlang.org/phobos/std_range_primitives.html#isInputRange --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail58.d b/gcc/testsuite/gdc.test/fail_compilation/fail58.d index 15570554fac..89b2351acfe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail58.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail58.d @@ -7,7 +7,7 @@ fail_compilation/fail58.d(30): Error: function `fail58.SomeFunc(dchar[] pText, o fail_compilation/fail58.d(30): cannot pass argument `""` of type `string` to parameter `dchar[] pText` --- */ -debug(1) import std.stdio; +debug import std.stdio; const int anything = -1000; // Line #2 dchar[] SomeFunc( dchar[] pText, out int pStopPosn) { @@ -15,7 +15,7 @@ dchar[] SomeFunc( dchar[] pText, out int pStopPosn) pStopPosn = 0; else pStopPosn = -1; - debug(1) writefln("DEBUG: using '%s' we get %d", pText, pStopPosn); + debug writefln("DEBUG: using '%s' we get %d", pText, pStopPosn); return pText.dup; } @@ -24,12 +24,12 @@ int main(char[][] pArgs) int sp; SomeFunc("123", sp); - debug(1) writefln("DEBUG: got %d", sp); + debug writefln("DEBUG: got %d", sp); assert(sp == -1); SomeFunc("", sp); // if (sp != 0){} // Line #22 - debug(1) writefln("DEBUG: got %d", sp); + debug writefln("DEBUG: got %d", sp); assert(sp == -1); return 0; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d index aa189770903..ee84a84ce79 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d @@ -55,7 +55,7 @@ L1: scope(failure) { L2: goto L1; } // OK goto L2; // NG - scope(failure) { return; } // OK + foreach (i; 0..1) { diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d index e8371c4f7fe..001c7d75443 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d @@ -9,12 +9,12 @@ 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: 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(32): Error: `pure` function `fail7848.C.__invariant0` cannot call impure function `fail7848.func` +fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant0` 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: `@nogc` function `fail7848.C.__invariant0` 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: function `fail7848.C.__invariant1` may throw but is marked as `nothrow` +fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant0` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d index d2a1d1dbcc5..24e39da85bb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d @@ -1,8 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11856_1.d(13): Error: none of the overloads of template `ice11856_1.g` are callable using argument types `!()(A)` -fail_compilation/ice11856_1.d(11): Candidate is: `g(T)(T x)` +fail_compilation/ice11856_1.d(16): Error: none of the overloads of template `ice11856_1.g` are callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(14): Candidate is: `g(T)(T x)` + with `T = A` + must satisfy the following constraint: +` is(typeof(x.f()))` --- */ struct A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d index 22cf39241f8..b50a616ac97 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d @@ -10,7 +10,6 @@ fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)` fail_compilation/misc_parser_err_cov1.d(32): Error: `type identifier : specialization` expected following `is` fail_compilation/misc_parser_err_cov1.d(33): Error: semicolon expected following auto declaration, not `auto` fail_compilation/misc_parser_err_cov1.d(33): Error: found `+` when expecting `(` following `mixin` -fail_compilation/misc_parser_err_cov1.d(34): Error: cannot create a `char[float]` with `new` fail_compilation/misc_parser_err_cov1.d(35): Error: `key:value` expected for associative array literal fail_compilation/misc_parser_err_cov1.d(36): Error: basic type expected, not `;` fail_compilation/misc_parser_err_cov1.d(36): Error: `{ members }` expected for anonymous class @@ -44,7 +43,7 @@ void main() auto tt = __traits(` is deprecated, use debug identifiers instead +fail_compilation/test13786.d(18): Deprecation: `version = ` is deprecated, use version identifiers instead +fail_compilation/test13786.d(16): Error: debug `123` level declaration must be at module level +fail_compilation/test13786.d(17): Error: debug `abc` declaration must be at module level +fail_compilation/test13786.d(18): Error: version `123` level declaration must be at module level +fail_compilation/test13786.d(19): Error: version `abc` declaration must be at module level +fail_compilation/test13786.d(22): Error: template instance `test13786.T!()` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16193.d b/gcc/testsuite/gdc.test/fail_compilation/test16193.d index 053f5832c77..6c80471c77b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16193.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16193.d @@ -2,8 +2,8 @@ REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test16193.d(38): Error: function `test16193.abc` is `@nogc` yet allocates closures with the GC -fail_compilation/test16193.d(40): test16193.abc.__foreachbody2 closes over variable x at fail_compilation/test16193.d(39) +fail_compilation/test16193.d(38): Error: function `test16193.abc` is `@nogc` yet allocates closure for `abc()` with the GC +fail_compilation/test16193.d(40): `test16193.abc.__foreachbody2` closes over variable `x` at fail_compilation/test16193.d(39) --- */ //fail_compilation/test16193.d(22): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21443.d b/gcc/testsuite/gdc.test/fail_compilation/test21443.d new file mode 100644 index 00000000000..2d99524da35 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test21443.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=21443 +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/test21443.d(14): Deprecation: `return` statements cannot be in `scope(failure)` bodies. +fail_compilation/test21443.d(14): Use try-catch blocks for this purpose +--- +*/ + +ulong get () @safe nothrow +{ + scope (failure) return 10; + throw new Error(""); +} + +void main () @safe +{ + assert(get() == 10); // passes +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21912.d b/gcc/testsuite/gdc.test/fail_compilation/test21912.d index 925210bf875..9b07eba0df6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21912.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21912.d @@ -2,14 +2,14 @@ PERMUTE_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test21912.d(24): Error: function `test21912.escapeParam` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(26): test21912.escapeParam.__lambda2 closes over variable i at fail_compilation/test21912.d(24) -fail_compilation/test21912.d(29): Error: function `test21912.escapeAssign` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(31): test21912.escapeAssign.__lambda3 closes over variable i at fail_compilation/test21912.d(29) -fail_compilation/test21912.d(40): Error: function `test21912.escapeAssignRef` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(42): test21912.escapeAssignRef.__lambda3 closes over variable i at fail_compilation/test21912.d(40) -fail_compilation/test21912.d(51): Error: function `test21912.escapeParamInferred` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(53): test21912.escapeParamInferred.__lambda2 closes over variable i at fail_compilation/test21912.d(51) +fail_compilation/test21912.d(24): Error: function `test21912.escapeParam` is `@nogc` yet allocates closure for `escapeParam()` with the GC +fail_compilation/test21912.d(26): `test21912.escapeParam.__lambda2` closes over variable `i` at fail_compilation/test21912.d(24) +fail_compilation/test21912.d(29): Error: function `test21912.escapeAssign` is `@nogc` yet allocates closure for `escapeAssign()` with the GC +fail_compilation/test21912.d(31): `test21912.escapeAssign.__lambda3` closes over variable `i` at fail_compilation/test21912.d(29) +fail_compilation/test21912.d(40): Error: function `test21912.escapeAssignRef` is `@nogc` yet allocates closure for `escapeAssignRef()` with the GC +fail_compilation/test21912.d(42): `test21912.escapeAssignRef.__lambda3` closes over variable `i` at fail_compilation/test21912.d(40) +fail_compilation/test21912.d(51): Error: function `test21912.escapeParamInferred` is `@nogc` yet allocates closure for `escapeParamInferred()` with the GC +fail_compilation/test21912.d(53): `test21912.escapeParamInferred.__lambda2` closes over variable `i` at fail_compilation/test21912.d(51) --- */ @nogc: diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21939.d b/gcc/testsuite/gdc.test/fail_compilation/test21939.d index 8f30bac97af..e513dc248c6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21939.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21939.d @@ -2,8 +2,9 @@ /* TEST_OUTPUT: --- -fail_compilation/test21939.d(10): Error: invalid `foreach` aggregate `Object` of type `Object` -fail_compilation/test21939.d(10): maybe define `opApply()`, range primitives, or use `.tupleof` +fail_compilation/test21939.d(11): Error: invalid `foreach` aggregate `Object` of type `Object` +fail_compilation/test21939.d(11): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/test21939.d(11): https://dlang.org/phobos/std_range_primitives.html#isInputRange --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23022.d b/gcc/testsuite/gdc.test/fail_compilation/test23022.d new file mode 100644 index 00000000000..8c4eca9c563 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23022.d @@ -0,0 +1,15 @@ +/* +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/test23022.d(14): Error: scope parameter `p` may not be returned +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23022 +// Typesafe variadic parameter should not infer return + +auto ir(string[] p...) +{ + return p; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23112.d b/gcc/testsuite/gdc.test/fail_compilation/test23112.d new file mode 100644 index 00000000000..325d89bd6c2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23112.d @@ -0,0 +1,30 @@ +/* REQUIRED_ARGS: -betterC +TEST_OUTPUT: +--- +fail_compilation/test23112.d(106): Error: function `test23112.bar` is `@nogc` yet allocates closure for `bar()` with the GC +fail_compilation/test23112.d(108): `test23112.bar.f` closes over variable `a` at fail_compilation/test23112.d(106) +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23112 + +#line 100 + +struct Forward(alias F) +{ + auto call()() { return F(); } +} + +auto bar(int a) nothrow @safe +{ + auto f() + { + return a; + } + return Forward!f(); +} + +extern(C) void main() +{ + assert(bar(3).call() == 3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23170.d b/gcc/testsuite/gdc.test/fail_compilation/test23170.d new file mode 100644 index 00000000000..eb79cd81565 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23170.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test23170.d(10): Error: array literal in `@nogc` delegate `test23170.__lambda5` may cause a GC allocation +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=23170 + +@nogc: +enum lambda = () => badAlias([1, 2, 3]); +alias badAlias = (int[] array) => id(array); +int[] id(int[] array) { return array; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23216.d b/gcc/testsuite/gdc.test/fail_compilation/test23216.d new file mode 100644 index 00000000000..d7c12ed3207 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23216.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test23216.d(23): Error: invalid `foreach_reverse` aggregate `r` of type `Range` +fail_compilation/test23216.d(23): `foreach_reverse` works with bidirectional ranges (implementing `back` and `popBack`), aggregates implementing `opApplyReverse`, or the result of an aggregate's `.tupleof` property +fail_compilation/test23216.d(23): https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23216 +// Better Error Message For foreach_reverse Without Bidirectional Range + +struct Range +{ + bool empty = true; + int front = 0; + void popFront() { } +} + +void main() +{ + Range r; + foreach_reverse (word; r) { } +} diff --git a/gcc/testsuite/gdc.test/runnable/closure.d b/gcc/testsuite/gdc.test/runnable/closure.d index af304c1f38a..1382f2d35ce 100644 --- a/gcc/testsuite/gdc.test/runnable/closure.d +++ b/gcc/testsuite/gdc.test/runnable/closure.d @@ -922,7 +922,10 @@ void test14730() // This is questionable case. Currently it works without any errors, // but not sure it's really intentional - +// It showed up again in https://issues.dlang.org/show_bug.cgi?id=23112 +// where it's an @safe issue so it's a bug. +static if (0) +{ struct S14730x(alias f) { auto foo()() { return f(0); } @@ -947,6 +950,7 @@ void test14730x() // *after* the semantic3 completion of makeS() function. assert(s.foo() == 10); } +} /************************************/ @@ -981,7 +985,7 @@ int main() test9685b(); test12406(); test14730(); - test14730x(); + //test14730x(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/evalorder.d b/gcc/testsuite/gdc.test/runnable/evalorder.d index 6805ee2e649..f93aef541ce 100644 --- a/gcc/testsuite/gdc.test/runnable/evalorder.d +++ b/gcc/testsuite/gdc.test/runnable/evalorder.d @@ -46,6 +46,12 @@ int mul11ret3(T)(ref T s) return 3; } +auto cat11ret3(T)(ref T s) +{ + s ~= 11; + return [3]; +} + void add() { static int test1(int val) { val += add8ret3(val); return val; } @@ -147,6 +153,25 @@ void shr() static assert(test(0x80) == 0x40); } +void cat() +{ + static auto test1(int[] val) { val ~= cat11ret3(val); return val; } + assert(test1([1]) == [1, 11, 3]); + static assert(test1([1]) == [1, 11, 3]); + + static auto test2(int[] val) { val = val ~ cat11ret3(val); return val; } + // FIXME: assert(test2([1]) == [1, 3]); + static assert(test2([1]) == [1, 3]); + + static auto test3(int[] val) { (val ~= 7) ~= cat11ret3(val); return val; } + assert(test3([2]) == [2, 7, 11, 3]); + static assert(test3([2]) == [2, 7, 11, 3]); + + static auto test4(int[] val) { (val ~= cat11ret3(val)) ~= 7; return val; } + assert(test4([2]) == [2, 11, 3, 7]); + static assert(test4([2]) == [2, 11, 3, 7]); +} + void ldc_github_1617() { add(); @@ -156,6 +181,7 @@ void ldc_github_1617() addptr(); lhsCast(); shr(); + cat(); } /******************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/lexer.d b/gcc/testsuite/gdc.test/runnable/lexer.d index ee2fef8f23f..6e31c07f9cb 100644 --- a/gcc/testsuite/gdc.test/runnable/lexer.d +++ b/gcc/testsuite/gdc.test/runnable/lexer.d @@ -1,5 +1,11 @@ // REQUIRED_ARGS: - +/* +TEST_OUTPUT: +--- +runnable/lexer.d(81): Deprecation: `version( )` is deprecated, use version identifiers instead +runnable/lexer.d(82): Deprecation: `debug( )` is deprecated, use debug identifiers instead +--- +*/ /*********************************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/noreturn1.d b/gcc/testsuite/gdc.test/runnable/noreturn1.d index 7d15b54a213..5ed46c16250 100644 --- a/gcc/testsuite/gdc.test/runnable/noreturn1.d +++ b/gcc/testsuite/gdc.test/runnable/noreturn1.d @@ -261,6 +261,37 @@ void testThrowDtor() /*****************************************/ +noreturn func() +{ + throw new Exception("B"); +} + +// https://issues.dlang.org/show_bug.cgi?id=23120 +void test23120() +{ + string a; + try + { + noreturn q = throw new Exception ("A"); + } + catch(Exception e) + { + a ~= e.msg; + } + + try + { + noreturn z = func(); + } + catch(Exception e) + { + a ~= e.msg; + } + + assert(a == "AB"); +} + +/*****************************************/ int main() { test1(); @@ -269,5 +300,6 @@ int main() testThrowExpression(); testThrowSideEffect(); testThrowDtor(); + test23120(); return 0; } diff --git a/gcc/testsuite/gdc.test/runnable/test11.d b/gcc/testsuite/gdc.test/runnable/test11.d index 6735a817c5e..333b6005827 100644 --- a/gcc/testsuite/gdc.test/runnable/test11.d +++ b/gcc/testsuite/gdc.test/runnable/test11.d @@ -1193,41 +1193,6 @@ void test63() printf("%.*s\n", cast(int)s.length, s.ptr); } - -/**************************************/ - -debug = 3; - -void test64() -{ - debug(5) - { - assert(0); - } - debug(3) - { - int x = 3; - } - assert(x == 3); -} - -/**************************************/ - -version = 3; - -void test65() -{ - version(5) - { - assert(0); - } - version(3) - { - int x = 3; - } - assert(x == 3); -} - /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=8809 @@ -1381,8 +1346,6 @@ int main(string[] argv) test61(); test62(); test63(); - test64(); - test65(); test8809(); test9734(); diff --git a/gcc/testsuite/gdc.test/runnable/test18973.d b/gcc/testsuite/gdc.test/runnable/test18973.d new file mode 100644 index 00000000000..29fcfa75774 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test18973.d @@ -0,0 +1,25 @@ +// This is a runnable test as we are testing a linker error + +// https://issues.dlang.org/show_bug.cgi?id=18973 +struct X { + @disable size_t toHash() const; + @disable string toString() const; + @disable bool opEquals(const ref X) const; + @disable int opCmp(const ref X) const; +} + +// https://issues.dlang.org/show_bug.cgi?id=9161 +public struct dummy +{ + static auto opCall(C)(in C[] name) + { + return name; + } + + @disable ~this(); //comment this out to avoid error +} + +void main() +{ + assert(dummy("ABCDE") == "ABCDE"); +} diff --git a/gcc/testsuite/gdc.test/runnable/test19.d b/gcc/testsuite/gdc.test/runnable/test19.d index 372d32f71e3..eda6172abc0 100644 --- a/gcc/testsuite/gdc.test/runnable/test19.d +++ b/gcc/testsuite/gdc.test/runnable/test19.d @@ -59,22 +59,7 @@ void test2() void test3() { debug printf("debug\n"); - debug(1) printf("debug(1)\n"); - debug(2) printf("debug(2)\n"); - debug(3) printf("debug(3)\n"); debug(bar) printf("debug(bar)\n"); - debug(10) assert(0); - - debug(1) - { - int d1 = 3; - - printf("debug(1) { }\n"); - } - debug(2) - { - printf("debug(2): d1 = %d\n", d1); - } } /* ================================ */ diff --git a/gcc/testsuite/gdc.test/runnable/test20734.d b/gcc/testsuite/gdc.test/runnable/test20734.d index 264602bccc5..b3c5916ada5 100644 --- a/gcc/testsuite/gdc.test/runnable/test20734.d +++ b/gcc/testsuite/gdc.test/runnable/test20734.d @@ -16,6 +16,7 @@ extern(C) int main() nothrow @nogc @safe { takeScopeSlice([ S(1), S(2) ]); // @nogc => no GC allocation (() @trusted { assert(numDtor == 2); })(); // stack-allocated array literal properly destructed + assert23100([]); return 0; } @@ -26,3 +27,9 @@ void test23098() @safe { f23098([10, 20]); } + +// https://issues.dlang.org/show_bug.cgi?id=23100 +void assert23100(scope int[] d) @safe nothrow @nogc +{ + assert(!d); +} diff --git a/gcc/testsuite/gdc.test/runnable/test23181.d b/gcc/testsuite/gdc.test/runnable/test23181.d new file mode 100644 index 00000000000..b961690a2bc --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23181.d @@ -0,0 +1,27 @@ +// https://issues.dlang.org/show_bug.cgi?id=23181 +void main() +{ + int count; + struct HasDtor + { + ~this() { ++count; } + } + + // array[] = elem() + // -> creates temporary to construct array and calls destructor. + { + count = 0; + HasDtor[4] dtor1 = HasDtor(); + assert(count == 1); + } + assert(count == 5); + + // array[] = array[elem()] + // -> constructs array using direct emplacement. + { + count = 0; + HasDtor[2] dtor2 = [HasDtor(), HasDtor()]; + assert(count == 0); + } + assert(count == 2); +} diff --git a/gcc/testsuite/gdc.test/runnable/test8.d b/gcc/testsuite/gdc.test/runnable/test8.d index 7d66eb6c623..d65ba0eb7ad 100644 --- a/gcc/testsuite/gdc.test/runnable/test8.d +++ b/gcc/testsuite/gdc.test/runnable/test8.d @@ -591,6 +591,44 @@ void test34() assert(b[i][j] == 16); } +/***********************************/ +// https://issues.dlang.org/show_bug.cgi?id=19178 + +float[3][4] arr2f = 10; +Int3_4[1] arr3i = 20; +short[3][4][1][1] arr4s = 30; + +enum Int3 : int[3] { + a = [0, 1, 2], +} + +enum Int3_4 : Int3[4] { + b = Int3[4].init, +} + +struct S35 +{ + int[3][3] arr = [2, 1]; +} + +void test35() +{ + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 3; j++) + { + // printf("[%d %d]: %f %d %d\n", i, j, arr2f[i][j], arr3i[0][i][j], arr4s[0][0][i][j]); + assert(arr2f[i][j] == 10); + assert(arr3i[0][i][j] == 20); + assert(arr4s[0][0][i][j] == 30); + } + } + + S35 t = S35.init; + assert(t.arr[0] == [2, 2, 2]); + assert(t.arr[1] == [1, 1, 1]); + assert(t.arr[2] == [0, 0, 0]); +} /***********************************/ string itoa(int i) @@ -868,6 +906,7 @@ int main() test32(); test33(); test34(); + test35(); test36(); test37(); test38(); diff --git a/gcc/testsuite/gdc.test/runnable/version.d b/gcc/testsuite/gdc.test/runnable/version.d index 1186e4c6a36..e225d5e4be3 100644 --- a/gcc/testsuite/gdc.test/runnable/version.d +++ b/gcc/testsuite/gdc.test/runnable/version.d @@ -1,10 +1,9 @@ /* PERMUTE_ARGS: -REQUIRED_ARGS: -version=3 -version=foo +REQUIRED_ARGS: -version=foo RUN_OUTPUT: --- i = 2 -i = 2 --- */ @@ -15,20 +14,6 @@ extern(C) int printf(const char*, ...); void test1() { int i = 3; - - version(2) - { - i = 2; - } - else - { - i = 0; - } - printf("i = %d\n", i); - assert(i == 2); - - i = 3; - version(foo) { i = 2; @@ -47,10 +32,6 @@ version(foo) { version = bar; } -else -{ - version = 4; -} void test2() { @@ -59,8 +40,6 @@ void test2() } else assert(0); - - version(4) assert(0); } /*******************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/warning1.d b/gcc/testsuite/gdc.test/runnable/warning1.d index 537088e97cc..01ac20c0baf 100644 --- a/gcc/testsuite/gdc.test/runnable/warning1.d +++ b/gcc/testsuite/gdc.test/runnable/warning1.d @@ -133,15 +133,6 @@ void test6518() } } -/******************************************/ -// https://issues.dlang.org/show_bug.cgi?id=7232 - -bool test7232() -{ - scope(failure) return false; - return true; -} - /***************************************************/ struct S9332 diff --git a/libphobos/configure b/libphobos/configure index 9da06f087d0..69d2d440d69 100755 --- a/libphobos/configure +++ b/libphobos/configure @@ -15554,7 +15554,7 @@ SPEC_PHOBOS_DEPS="$LIBS" # Libdruntime / phobos soname version -libtool_VERSION=3:0:0 +libtool_VERSION=4:0:0 # Set default flags (after DRUNTIME_WERROR!) diff --git a/libphobos/configure.ac b/libphobos/configure.ac index 31209ba2920..8bdf7332b86 100644 --- a/libphobos/configure.ac +++ b/libphobos/configure.ac @@ -253,7 +253,7 @@ SPEC_PHOBOS_DEPS="$LIBS" AC_SUBST(SPEC_PHOBOS_DEPS) # Libdruntime / phobos soname version -libtool_VERSION=3:0:0 +libtool_VERSION=4:0:0 AC_SUBST(libtool_VERSION) # Set default flags (after DRUNTIME_WERROR!) diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 6e25a9d6f92..c358b69e3fc 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -651389b52243dcadb338dd0c14dd27e7850cda8d +d7772a236983ec37b92d21b28bad3cd2de57b945 The first line of this file holds the git revision number of the last -merge done from the dlang/druntime repository. +merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 56b332d4efa..2e1e91da79f 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -174,14 +174,14 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/internal/array/appending.d core/internal/array/capacity.d \ core/internal/array/casting.d core/internal/array/comparison.d \ core/internal/array/concatenation.d core/internal/array/construction.d \ - core/internal/array/equality.d core/internal/array/operations.d \ - core/internal/array/utils.d core/internal/atomic.d \ - core/internal/attributes.d core/internal/container/array.d \ - core/internal/container/common.d core/internal/container/hashtab.d \ - core/internal/container/treap.d core/internal/convert.d \ - core/internal/dassert.d core/internal/destruction.d \ - core/internal/entrypoint.d core/internal/gc/bits.d \ - core/internal/gc/impl/conservative/gc.d \ + core/internal/array/duplication.d core/internal/array/equality.d \ + core/internal/array/operations.d core/internal/array/utils.d \ + core/internal/atomic.d core/internal/attributes.d \ + core/internal/container/array.d core/internal/container/common.d \ + core/internal/container/hashtab.d core/internal/container/treap.d \ + core/internal/convert.d core/internal/dassert.d \ + core/internal/destruction.d core/internal/entrypoint.d \ + core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \ core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \ core/internal/gc/os.d core/internal/gc/pooltable.d \ core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 24865fb258a..de6656c552b 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -196,6 +196,7 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \ core/internal/array/comparison.lo \ core/internal/array/concatenation.lo \ core/internal/array/construction.lo \ + core/internal/array/duplication.lo \ core/internal/array/equality.lo \ core/internal/array/operations.lo core/internal/array/utils.lo \ core/internal/atomic.lo core/internal/attributes.lo \ @@ -841,14 +842,14 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/internal/array/appending.d core/internal/array/capacity.d \ core/internal/array/casting.d core/internal/array/comparison.d \ core/internal/array/concatenation.d core/internal/array/construction.d \ - core/internal/array/equality.d core/internal/array/operations.d \ - core/internal/array/utils.d core/internal/atomic.d \ - core/internal/attributes.d core/internal/container/array.d \ - core/internal/container/common.d core/internal/container/hashtab.d \ - core/internal/container/treap.d core/internal/convert.d \ - core/internal/dassert.d core/internal/destruction.d \ - core/internal/entrypoint.d core/internal/gc/bits.d \ - core/internal/gc/impl/conservative/gc.d \ + core/internal/array/duplication.d core/internal/array/equality.d \ + core/internal/array/operations.d core/internal/array/utils.d \ + core/internal/atomic.d core/internal/attributes.d \ + core/internal/container/array.d core/internal/container/common.d \ + core/internal/container/hashtab.d core/internal/container/treap.d \ + core/internal/convert.d core/internal/dassert.d \ + core/internal/destruction.d core/internal/entrypoint.d \ + core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \ core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \ core/internal/gc/os.d core/internal/gc/pooltable.d \ core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \ @@ -1208,6 +1209,8 @@ core/internal/array/concatenation.lo: \ core/internal/array/$(am__dirstamp) core/internal/array/construction.lo: \ core/internal/array/$(am__dirstamp) +core/internal/array/duplication.lo: \ + core/internal/array/$(am__dirstamp) core/internal/array/equality.lo: core/internal/array/$(am__dirstamp) core/internal/array/operations.lo: \ core/internal/array/$(am__dirstamp) diff --git a/libphobos/libdruntime/core/cpuid.d b/libphobos/libdruntime/core/cpuid.d index e31f776d7ee..1c2ac067704 100644 --- a/libphobos/libdruntime/core/cpuid.d +++ b/libphobos/libdruntime/core/cpuid.d @@ -170,6 +170,8 @@ public: bool hle() {return _hle;} /// Is RTM (restricted transactional memory) supported bool rtm() {return _rtm;} + /// Is AVX512F supported + bool avx512f() {return _avx512f;} /// Is rdseed supported bool hasRdseed() {return _hasRdseed;} /// Is SHA supported @@ -279,6 +281,7 @@ private immutable bool _avx2; bool _hle; bool _rtm; + bool _avx512f; bool _hasRdseed; bool _hasSha; bool _amd3dnow; @@ -389,6 +392,7 @@ CpuFeatures* getCpuFeatures() @nogc nothrow enum : uint { FSGSBASE_BIT = 1 << 0, + SGX_BIT = 1 << 2, BMI1_BIT = 1 << 3, HLE_BIT = 1 << 4, AVX2_BIT = 1 << 5, @@ -397,8 +401,19 @@ CpuFeatures* getCpuFeatures() @nogc nothrow ERMS_BIT = 1 << 9, INVPCID_BIT = 1 << 10, RTM_BIT = 1 << 11, + AVX512F_BIT = 1 << 16, + AVX512DQ_BIT = 1 << 17, RDSEED_BIT = 1 << 18, + ADX_BIT = 1 << 19, + AVX512IFMA_BIT = 1 << 21, + CLFLUSHOPT_BIT = 1 << 23, + CLWB_BIT = 1 << 24, + AVX512PF_BIT = 1 << 26, + AVX512ER_BIT = 1 << 27, + AVX512CD_BIT = 1 << 28, SHA_BIT = 1 << 29, + AVX512BW_BIT = 1 << 30, + AVX512VL_BIT = 1 << 31, } // feature flags XFEATURES_ENABLED_MASK enum : ulong @@ -1122,6 +1137,7 @@ shared static this() _avx2 = avx && (cf.extfeatures & AVX2_BIT) != 0; _hle = (cf.extfeatures & HLE_BIT) != 0; _rtm = (cf.extfeatures & RTM_BIT) != 0; + _avx512f = (cf.extfeatures & AVX512F_BIT) != 0; _hasRdseed = (cf.extfeatures&RDSEED_BIT)!=0; _hasSha = (cf.extfeatures&SHA_BIT)!=0; _amd3dnow = (cf.amdfeatures&AMD_3DNOW_BIT)!=0; diff --git a/libphobos/libdruntime/core/int128.d b/libphobos/libdruntime/core/int128.d index e4326fd54c3..46eb9b27556 100644 --- a/libphobos/libdruntime/core/int128.d +++ b/libphobos/libdruntime/core/int128.d @@ -943,5 +943,3 @@ unittest assert(rol(C7_9, 1) == rol1(C7_9)); assert(ror(C7_9, 1) == ror1(C7_9)); } - - diff --git a/libphobos/libdruntime/core/internal/array/appending.d b/libphobos/libdruntime/core/internal/array/appending.d index d416efe1c50..616d27cfe83 100644 --- a/libphobos/libdruntime/core/internal/array/appending.d +++ b/libphobos/libdruntime/core/internal/array/appending.d @@ -30,26 +30,14 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) * Returns: * The new value of `px` * Bugs: - * This function template was ported from a much older runtime hook that bypassed safety, - * purity, and throwabilty checks. To prevent breaking existing code, this function template - * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations. + * This function template was ported from a much older runtime hook that bypassed safety, + * purity, and throwabilty checks. To prevent breaking existing code, this function template + * is temporarily declared `@trusted 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 ref scope Tarr px, size_t n) @trusted pure nothrow - { - pragma(inline, false); - - mixin(_d_arrayappendcTXBody); - } - else - ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow - { - pragma(inline, false); - - mixin(_d_arrayappendcTXBody); - } - - private enum _d_arrayappendcTXBody = q{ + ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow + { + // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718 + pragma(inline, false); version (D_TypeInfo) { auto ti = typeid(Tarr); @@ -64,7 +52,7 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) } else assert(0, "Cannot append arrays if compiling without support for runtime type information!"); - }; + } /** * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl). diff --git a/libphobos/libdruntime/core/internal/array/duplication.d b/libphobos/libdruntime/core/internal/array/duplication.d new file mode 100644 index 00000000000..41dfab6f349 --- /dev/null +++ b/libphobos/libdruntime/core/internal/array/duplication.d @@ -0,0 +1,346 @@ +/** +The `.dup` and `.idup` properties for Associative Arrays and Dynamic Arrays + +Copyright: Copyright Digital Mars 2000 - 2022. +License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + (See accompanying file LICENSE) +Source: $(DRUNTIMESRC core/internal/_array/_duplication.d) +*/ +module core.internal.array.duplication; + +private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow; + +U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)) +{ + if (__ctfe) + return _dupCtfe!(T, U)(a); + + import core.stdc.string : memcpy; + auto arr = _d_newarrayU(typeid(T[]), a.length); + memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length); + return *cast(U[]*) &arr; +} + +U[] _dupCtfe(T, U)(scope T[] a) +{ + static if (is(T : void)) + assert(0, "Cannot dup a void[] array at compile time."); + else + { + U[] res; + foreach (ref e; a) + res ~= e; + return res; + } +} + +U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T)) +{ + // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch + // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`. + if (__ctfe) + return _dupCtfe!(T, U)(a); + + import core.lifetime: copyEmplace; + U[] res = () @trusted { + auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length); + size_t i; + scope (failure) + { + import core.internal.lifetime: emplaceInitializer; + // Initialize all remaining elements to not destruct garbage + foreach (j; i .. a.length) + emplaceInitializer(cast() arr[j]); + } + for (; i < a.length; i++) + { + copyEmplace(a.ptr[i], arr[i]); + } + return cast(U[])(arr[0..a.length]); + } (); + + return res; +} + +// https://issues.dlang.org/show_bug.cgi?id=22107 +@safe unittest +{ + static int i; + @safe struct S + { + this(this) { i++; } + } + + void fun(scope S[] values...) @safe + { + values.dup; + } +} + +@safe unittest +{ + static struct S1 { int* p; } + static struct S2 { @disable this(); } + static struct S3 { @disable this(this); } + + int dg1() pure nothrow @safe + { + { + char[] m; + string i; + m = m.dup; + i = i.idup; + m = i.dup; + i = m.idup; + } + { + S1[] m; + immutable(S1)[] i; + m = m.dup; + i = i.idup; + static assert(!is(typeof(m.idup))); + static assert(!is(typeof(i.dup))); + } + { + S3[] m; + immutable(S3)[] i; + static assert(!is(typeof(m.dup))); + static assert(!is(typeof(i.idup))); + } + { + shared(S1)[] m; + m = m.dup; + static assert(!is(typeof(m.idup))); + } + { + int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0); + } + return 1; + } + + int dg2() pure nothrow @safe + { + { + S2[] m = [S2.init, S2.init]; + immutable(S2)[] i = [S2.init, S2.init]; + m = m.dup; + m = i.dup; + i = m.idup; + i = i.idup; + } + return 2; + } + + enum a = dg1(); + enum b = dg2(); + assert(dg1() == a); + assert(dg2() == b); +} + +@system unittest +{ + static struct Sunpure { this(this) @safe nothrow {} } + static struct Sthrow { this(this) @safe pure {} } + static struct Sunsafe { this(this) @system pure nothrow {} } + static struct Snocopy { @disable this(this); } + + [].dup!Sunpure; + [].dup!Sthrow; + cast(void) [].dup!Sunsafe; + static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); + static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); + static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); + static assert(!__traits(compiles, () { [].dup!Snocopy; })); + + [].idup!Sunpure; + [].idup!Sthrow; + [].idup!Sunsafe; + static assert(!__traits(compiles, () pure { [].idup!Sunpure; })); + static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; })); + static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); + static assert(!__traits(compiles, () { [].idup!Snocopy; })); +} + +@safe unittest +{ + // test that the copy-constructor is called with .dup + static struct ArrElem + { + int a; + this(int a) + { + this.a = a; + } + this(ref const ArrElem) + { + a = 2; + } + this(ref ArrElem) immutable + { + a = 3; + } + } + + auto arr = [ArrElem(1), ArrElem(1)]; + + ArrElem[] b = arr.dup; + assert(b[0].a == 2 && b[1].a == 2); + + immutable ArrElem[] c = arr.idup; + assert(c[0].a == 3 && c[1].a == 3); +} + +@system unittest +{ + static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} } + static struct Sthrow { this(ref const typeof(this)) @safe pure {} } + static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} } + [].dup!Sunpure; + [].dup!Sthrow; + cast(void) [].dup!Sunsafe; + static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); + static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); + static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); + + // for idup to work on structs that have copy constructors, it is necessary + // that the struct defines a copy constructor that creates immutable objects + static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} } + static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} } + static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} } + [].idup!ISunpure; + [].idup!ISthrow; + [].idup!ISunsafe; + static assert(!__traits(compiles, () pure { [].idup!ISunpure; })); + static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; })); + static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; })); +} + +@safe unittest +{ + static int*[] pureFoo() pure { return null; } + { char[] s; immutable x = s.dup; } + { immutable x = (cast(int*[])null).dup; } + { immutable x = pureFoo(); } + { immutable x = pureFoo().dup; } +} + +@safe unittest +{ + auto a = [1, 2, 3]; + auto b = a.dup; + debug(SENTINEL) {} else + assert(b.capacity >= 3); +} + +@system unittest +{ + // Bugzilla 12580 + void[] m = [0]; + shared(void)[] s = [cast(shared)1]; + immutable(void)[] i = [cast(immutable)2]; + + s = s.dup; + static assert(is(typeof(s.dup) == shared(void)[])); + + m = i.dup; + i = m.dup; + i = i.idup; + i = m.idup; + i = s.idup; + i = s.dup; + static assert(!__traits(compiles, m = s.dup)); +} + +@safe unittest +{ + // Bugzilla 13809 + static struct S + { + this(this) {} + ~this() {} + } + + S[] arr; + auto a = arr.dup; +} + +@system unittest +{ + // Bugzilla 16504 + static struct S + { + __gshared int* gp; + int* p; + // postblit and hence .dup could escape + this(this) { gp = p; } + } + + int p; + scope S[1] arr = [S(&p)]; + auto a = arr.dup; // dup does escape +} + +// https://issues.dlang.org/show_bug.cgi?id=21983 +// dup/idup destroys partially constructed arrays on failure +@safe unittest +{ + static struct SImpl(bool postblit) + { + int num; + long l = 0xDEADBEEF; + + static if (postblit) + { + this(this) + { + if (this.num == 3) + throw new Exception(""); + } + } + else + { + this(scope ref const SImpl other) + { + if (other.num == 3) + throw new Exception(""); + + this.num = other.num; + this.l = other.l; + } + } + + ~this() @trusted + { + if (l != 0xDEADBEEF) + { + import core.stdc.stdio; + printf("Unexpected value: %lld\n", l); + fflush(stdout); + assert(false); + } + } + } + + alias Postblit = SImpl!true; + alias Copy = SImpl!false; + + static int test(S)() + { + S[4] arr = [ S(1), S(2), S(3), S(4) ]; + try + { + arr.dup(); + assert(false); + } + catch (Exception) + { + return 1; + } + } + + static assert(test!Postblit()); + assert(test!Postblit()); + + static assert(test!Copy()); + assert(test!Copy()); +} diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d index 2c51b8641ae..07486c216f0 100644 --- a/libphobos/libdruntime/core/internal/dassert.d +++ b/libphobos/libdruntime/core/internal/dassert.d @@ -14,7 +14,7 @@ * * Copyright: D Language Foundation 2018 - 2020 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/internal/dassert.d, _dassert.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/dassert.d, _dassert.d) * Documentation: https://dlang.org/phobos/core_internal_dassert.html */ module core.internal.dassert; diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index d1378afca91..75e671cb34b 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -4,7 +4,7 @@ * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly - * Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/runtime.d, _runtime.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/runtime.d, _runtime.d) * Documentation: https://dlang.org/phobos/core_runtime.html */ diff --git a/libphobos/libdruntime/core/stdc/errno.d b/libphobos/libdruntime/core/stdc/errno.d index 24b4138153d..c992a5ff0de 100644 --- a/libphobos/libdruntime/core/stdc/errno.d +++ b/libphobos/libdruntime/core/stdc/errno.d @@ -8,7 +8,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Alex Rønne Petersen - * Source: https://github.com/dlang/druntime/blob/master/src/core/stdc/errno.d + * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/errno.d * Standards: ISO/IEC 9899:1999 (E) */ diff --git a/libphobos/libdruntime/core/stdc/stdio.d b/libphobos/libdruntime/core/stdc/stdio.d index 2e8381180db..fc98350e139 100644 --- a/libphobos/libdruntime/core/stdc/stdio.d +++ b/libphobos/libdruntime/core/stdc/stdio.d @@ -9,7 +9,7 @@ * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen - * Source: https://github.com/dlang/druntime/blob/master/src/core/stdc/stdio.d + * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/stdio.d * Standards: ISO/IEC 9899:1999 (E) */ @@ -1286,6 +1286,57 @@ version (MinGW) /// alias __mingw_scanf scanf; } +else version (CRuntime_Glibc) +{ + /// + pragma(printf) + int fprintf(FILE* stream, scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_fscanf(FILE* stream, scope const char* format, scope ...); + /// + alias fscanf = __isoc99_fscanf; + /// + pragma(printf) + int sprintf(scope char* s, scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_sscanf(scope const char* s, scope const char* format, scope ...); + /// + alias sscanf = __isoc99_sscanf; + /// + pragma(printf) + int vfprintf(FILE* stream, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vfscanf(FILE* stream, scope const char* format, va_list arg); + /// + alias vfscanf = __isoc99_vfscanf; + /// + pragma(printf) + int vsprintf(scope char* s, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vsscanf(scope const char* s, scope const char* format, va_list arg); + /// + alias vsscanf = __isoc99_vsscanf; + /// + pragma(printf) + int vprintf(scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vscanf(scope const char* format, va_list arg); + /// + alias vscanf = __isoc99_vscanf; + /// + pragma(printf) + int printf(scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_scanf(scope const char* format, scope ...); + /// + alias scanf = __isoc99_scanf; +} else { /// diff --git a/libphobos/libdruntime/core/stdc/wchar_.d b/libphobos/libdruntime/core/stdc/wchar_.d index e8fb94b11e6..d0870290854 100644 --- a/libphobos/libdruntime/core/stdc/wchar_.d +++ b/libphobos/libdruntime/core/stdc/wchar_.d @@ -127,30 +127,72 @@ alias wchar_t wint_t; /// enum wchar_t WEOF = 0xFFFF; -/// -int fwprintf(FILE* stream, const scope wchar_t* format, scope const ...); -/// -int fwscanf(FILE* stream, const scope wchar_t* format, scope ...); -/// -int swprintf(wchar_t* s, size_t n, const scope wchar_t* format, scope const ...); -/// -int swscanf(const scope wchar_t* s, const scope wchar_t* format, scope ...); -/// -int vfwprintf(FILE* stream, const scope wchar_t* format, va_list arg); -/// -int vfwscanf(FILE* stream, const scope wchar_t* format, va_list arg); -/// -int vswprintf(wchar_t* s, size_t n, const scope wchar_t* format, va_list arg); -/// -int vswscanf(const scope wchar_t* s, const scope wchar_t* format, va_list arg); -/// -int vwprintf(const scope wchar_t* format, va_list arg); -/// -int vwscanf(const scope wchar_t* format, va_list arg); -/// -int wprintf(const scope wchar_t* format, scope const ...); -/// -int wscanf(const scope wchar_t* format, scope ...); +version (CRuntime_Glibc) +{ + /// + int fwprintf(FILE* stream, const scope wchar_t* format, scope const ...); + /// + int __isoc99_fwscanf(FILE* stream, const scope wchar_t* format, scope ...); + /// + alias fwscanf = __isoc99_fwscanf; + /// + int swprintf(wchar_t* s, size_t n, const scope wchar_t* format, scope const ...); + /// + int __isoc99_swscanf(const scope wchar_t* s, const scope wchar_t* format, scope ...); + /// + alias swscanf = __isoc99_swscanf; + /// + int vfwprintf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + int __isoc99_vfwscanf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + alias vfwscanf = __isoc99_vfwscanf; + /// + int vswprintf(wchar_t* s, size_t n, const scope wchar_t* format, va_list arg); + /// + int __isoc99_vswscanf(const scope wchar_t* s, const scope wchar_t* format, va_list arg); + /// + alias vswscanf = __isoc99_vswscanf; + /// + int vwprintf(const scope wchar_t* format, va_list arg); + /// + int __isoc99_vwscanf(const scope wchar_t* format, va_list arg); + /// + alias vwscanf = __isoc99_vwscanf; + /// + int wprintf(const scope wchar_t* format, scope const ...); + /// + int __isoc99_wscanf(const scope wchar_t* format, scope ...); + /// + alias wscanf = __isoc99_wscanf; +} +else +{ + /// + int fwprintf(FILE* stream, const scope wchar_t* format, scope const ...); + /// + int fwscanf(FILE* stream, const scope wchar_t* format, scope ...); + /// + int swprintf(wchar_t* s, size_t n, const scope wchar_t* format, scope const ...); + /// + int swscanf(const scope wchar_t* s, const scope wchar_t* format, scope ...); + /// + int vfwprintf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + int vfwscanf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + int vswprintf(wchar_t* s, size_t n, const scope wchar_t* format, va_list arg); + /// + int vswscanf(const scope wchar_t* s, const scope wchar_t* format, va_list arg); + /// + int vwprintf(const scope wchar_t* format, va_list arg); + /// + int vwscanf(const scope wchar_t* format, va_list arg); + /// + int wprintf(const scope wchar_t* format, scope const ...); + /// + int wscanf(const scope wchar_t* format, scope ...); +} // No unsafe pointer manipulation. @trusted diff --git a/libphobos/libdruntime/core/sys/darwin/mach/getsect.d b/libphobos/libdruntime/core/sys/darwin/mach/getsect.d index fd1a8e4ea36..dc42a2dc450 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/getsect.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/getsect.d @@ -468,4 +468,3 @@ const(section)* getsectbynamefromheaderwithswap_64( const scope char* section, int fSwap ); - diff --git a/libphobos/libdruntime/core/sys/dragonflybsd/string.d b/libphobos/libdruntime/core/sys/dragonflybsd/string.d index 4b8422748b6..1a85ba606a1 100644 --- a/libphobos/libdruntime/core/sys/dragonflybsd/string.d +++ b/libphobos/libdruntime/core/sys/dragonflybsd/string.d @@ -19,4 +19,3 @@ static if (__BSD_VISIBLE) { 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/time.d b/libphobos/libdruntime/core/sys/linux/sys/time.d index 6ea626ed390..4b56229687c 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/time.d +++ b/libphobos/libdruntime/core/sys/linux/sys/time.d @@ -65,4 +65,3 @@ extern (D) pure @safe @nogc nothrow { } } - diff --git a/libphobos/libdruntime/core/sys/linux/sys/xattr.d b/libphobos/libdruntime/core/sys/linux/sys/xattr.d index 2f8d3f376f9..6446ff8b9a3 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/xattr.d +++ b/libphobos/libdruntime/core/sys/linux/sys/xattr.d @@ -66,4 +66,3 @@ ssize_t flistxattr (int __fd, char *list, size_t size); int removexattr (const scope char *path, const scope char *name); int lremovexattr (const scope char *path, const scope char *name); int fremovexattr (int fd, const scope char *name); - diff --git a/libphobos/libdruntime/core/sys/linux/tipc.d b/libphobos/libdruntime/core/sys/linux/tipc.d index 3246e62ec04..4d5d886269a 100644 --- a/libphobos/libdruntime/core/sys/linux/tipc.d +++ b/libphobos/libdruntime/core/sys/linux/tipc.d @@ -208,4 +208,3 @@ enum: int TIPC_DEST_DROPPABLE = 129, TIPC_CONN_TIMEOUT = 130, } - diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d index 68aee980ef3..542e83a1679 100644 --- a/libphobos/libdruntime/core/sys/posix/signal.d +++ b/libphobos/libdruntime/core/sys/posix/signal.d @@ -14,7 +14,7 @@ module core.sys.posix.signal; import core.sys.posix.config; public import core.stdc.signal; public import core.sys.posix.sys.types; // for pid_t -//public import core.sys.posix.time; // for timespec, now defined here +public import core.sys.posix.time; // for timespec version (OSX) version = Darwin; @@ -2804,83 +2804,6 @@ else static assert(false, "Unsupported platform"); } -// -// Timer (TMR) -// -/* -NOTE: This should actually be defined in core.sys.posix.time. - It is defined here instead to break a circular import. - -struct timespec -{ - time_t tv_sec; - int tv_nsec; -} -*/ - -version (linux) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (Darwin) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (FreeBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (NetBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (OpenBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (DragonFlyBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (Solaris) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } - - alias timespec timestruc_t; -} -else -{ - static assert(false, "Unsupported platform"); -} - // // Realtime Signals (RTS) // diff --git a/libphobos/libdruntime/core/sys/posix/spawn.d b/libphobos/libdruntime/core/sys/posix/spawn.d index cfa3a40057c..206496261b0 100644 --- a/libphobos/libdruntime/core/sys/posix/spawn.d +++ b/libphobos/libdruntime/core/sys/posix/spawn.d @@ -4,7 +4,7 @@ * Copyright: Copyright (C) 2018 by The D Language Foundation, All Rights Reserved * Authors: Petar Kirov * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/sys/posix/spawn.d, _spawn.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/sys/posix/spawn.d, _spawn.d) * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ module core.sys.posix.spawn; diff --git a/libphobos/libdruntime/core/sys/posix/stdio.d b/libphobos/libdruntime/core/sys/posix/stdio.d index 077838d50aa..d0d3d60ff46 100644 --- a/libphobos/libdruntime/core/sys/posix/stdio.d +++ b/libphobos/libdruntime/core/sys/posix/stdio.d @@ -487,7 +487,7 @@ else version (CRuntime_Musl) version (HaveMemstream) { - FILE* fmemopen(const scope void* buf, in size_t size, const scope char* mode); + FILE* fmemopen(const scope void* buf, size_t size, const scope char* mode); FILE* open_memstream(char** ptr, size_t* sizeloc); version (CRuntime_UClibc) {} else FILE* open_wmemstream(wchar_t** ptr, size_t* sizeloc); diff --git a/libphobos/libdruntime/core/sys/posix/sys/select.d b/libphobos/libdruntime/core/sys/posix/sys/select.d index 2a659c30dc0..925976d3e33 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/select.d +++ b/libphobos/libdruntime/core/sys/posix/sys/select.d @@ -608,4 +608,3 @@ pure unittest assert(!FD_ISSET(i, &fd)); } } - diff --git a/libphobos/libdruntime/core/sys/posix/time.d b/libphobos/libdruntime/core/sys/posix/time.d index a9be87c8597..ff3a3c46cd0 100644 --- a/libphobos/libdruntime/core/sys/posix/time.d +++ b/libphobos/libdruntime/core/sys/posix/time.d @@ -167,9 +167,6 @@ else CLOCK_PROCESS_CPUTIME_ID (TMR|CPT) CLOCK_THREAD_CPUTIME_ID (TMR|TCT) -NOTE: timespec must be defined in core.sys.posix.signal to break - a circular import. - struct timespec { time_t tv_sec; @@ -199,6 +196,69 @@ int timer_getoverrun(timer_t); int timer_settime(timer_t, int, const scope itimerspec*, itimerspec*); */ +version (linux) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (Darwin) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (FreeBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (NetBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (OpenBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (DragonFlyBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (Solaris) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } + + alias timespec timestruc_t; +} +else +{ + static assert(false, "Unsupported platform"); +} + version (CRuntime_Glibc) { enum CLOCK_PROCESS_CPUTIME_ID = 2; diff --git a/libphobos/libdruntime/core/sys/posix/ucontext.d b/libphobos/libdruntime/core/sys/posix/ucontext.d index 20297f50b90..e8c2f87bbd3 100644 --- a/libphobos/libdruntime/core/sys/posix/ucontext.d +++ b/libphobos/libdruntime/core/sys/posix/ucontext.d @@ -1628,4 +1628,3 @@ version (Solaris) int addrtosymstr(uintptr_t, char*, int); int printstack(int); } - diff --git a/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d b/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d index bfbf3ee2abc..c56be3b00f8 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d @@ -113,4 +113,3 @@ struct pcadmin_t id_t pc_cid; caddr_t pc_cladmin; } - diff --git a/libphobos/libdruntime/core/sys/solaris/sys/procset.d b/libphobos/libdruntime/core/sys/solaris/sys/procset.d index 43fa9978af3..8bd91157007 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/procset.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/procset.d @@ -50,4 +50,3 @@ void setprocset(ref procset_t psp, idop_t op, idtype_t ltype, id_t lid, idtype_t psp.p_ridtype = rtype; psp.p_rid = rid; } - diff --git a/libphobos/libdruntime/core/sys/windows/cguid.d b/libphobos/libdruntime/core/sys/windows/cguid.d index 0afbc42e8b0..d0a8fb9f087 100644 --- a/libphobos/libdruntime/core/sys/windows/cguid.d +++ b/libphobos/libdruntime/core/sys/windows/cguid.d @@ -10,4 +10,3 @@ module core.sys.windows.cguid; version (Windows): import core.sys.windows.basetyps; - diff --git a/libphobos/libdruntime/core/sys/windows/ntsecpkg.d b/libphobos/libdruntime/core/sys/windows/ntsecpkg.d index d4c93d7b573..d8c5e95edbd 100644 --- a/libphobos/libdruntime/core/sys/windows/ntsecpkg.d +++ b/libphobos/libdruntime/core/sys/windows/ntsecpkg.d @@ -444,4 +444,3 @@ alias NTSTATUS function(ULONG, PULONG, PSECPKG_FUNCTION_TABLE *, PULONG) SpLsaModeInitializeFn; alias NTSTATUS function(ULONG, PULONG, PSECPKG_USER_FUNCTION_TABLE *, PULONG) SpUserModeInitializeFn; - diff --git a/libphobos/libdruntime/core/sys/windows/olectlid.d b/libphobos/libdruntime/core/sys/windows/olectlid.d index 8bbe657134b..b58c14ae1fe 100644 --- a/libphobos/libdruntime/core/sys/windows/olectlid.d +++ b/libphobos/libdruntime/core/sys/windows/olectlid.d @@ -10,4 +10,3 @@ module core.sys.windows.olectlid; version (Windows): import core.sys.windows.basetyps; - diff --git a/libphobos/libdruntime/core/sys/windows/shlguid.d b/libphobos/libdruntime/core/sys/windows/shlguid.d index 1c0c98fc070..e0c1af1045a 100644 --- a/libphobos/libdruntime/core/sys/windows/shlguid.d +++ b/libphobos/libdruntime/core/sys/windows/shlguid.d @@ -16,4 +16,3 @@ import core.sys.windows.basetyps, core.sys.windows.w32api; // I think this is just a helper macro for other win32 headers? //MACRO #define DEFINE_SHLGUID(n,l,w1,w2) DEFINE_GUID(n,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) - diff --git a/libphobos/libdruntime/core/sys/windows/sspi.d b/libphobos/libdruntime/core/sys/windows/sspi.d index 07a259622d2..21e982daa81 100644 --- a/libphobos/libdruntime/core/sys/windows/sspi.d +++ b/libphobos/libdruntime/core/sys/windows/sspi.d @@ -380,4 +380,3 @@ version (Unicode) { alias QUERY_SECURITY_PACKAGE_INFO_FN_A QUERY_SECURITY_PACKAGE_INFO_FN; alias INIT_SECURITY_INTERFACE_A INIT_SECURITY_INTERFACE; } - diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index fe65c0973e1..8ef6548981f 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -3765,6 +3765,7 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, if (!is(const(T) : T)) { import core.internal.traits : Unconst; + import core.internal.array.duplication : _dup; static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~ " to "~Unconst!T.stringof~" in dup."); @@ -3786,6 +3787,7 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, @property T[] dup(T)(const(T)[] a) if (is(const(T) : T)) { + import core.internal.array.duplication : _dup; return _dup!(const(T), T)(a); } @@ -3793,6 +3795,7 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, /// Provide the .idup array property. @property immutable(T)[] idup(T)(T[] a) { + import core.internal.array.duplication : _dup; static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~ " to immutable in idup."); return _dup!(T, immutable(T))(a); @@ -3813,73 +3816,6 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, assert(s == "abc"); } -private U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)) -{ - if (__ctfe) - return _dupCtfe!(T, U)(a); - - import core.stdc.string : memcpy; - auto arr = _d_newarrayU(typeid(T[]), a.length); - memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length); - return *cast(U[]*) &arr; -} - -private U[] _dupCtfe(T, U)(scope T[] a) -{ - static if (is(T : void)) - assert(0, "Cannot dup a void[] array at compile time."); - else - { - U[] res; - foreach (ref e; a) - res ~= e; - return res; - } -} - -private U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T)) -{ - // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch - // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`. - if (__ctfe) - return _dupCtfe!(T, U)(a); - - import core.lifetime: copyEmplace; - U[] res = () @trusted { - auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length); - size_t i; - scope (failure) - { - import core.internal.lifetime: emplaceInitializer; - // Initialize all remaining elements to not destruct garbage - foreach (j; i .. a.length) - emplaceInitializer(cast() arr[j]); - } - for (; i < a.length; i++) - { - copyEmplace(a.ptr[i], arr[i]); - } - return cast(U[])(arr[0..a.length]); - } (); - - return res; -} - -// https://issues.dlang.org/show_bug.cgi?id=22107 -@safe unittest -{ - static int i; - @safe struct S - { - this(this) { i++; } - } - - void fun(scope S[] values...) @safe - { - values.dup; - } -} - // HACK: This is a lie. `_d_arraysetcapacity` is neither `nothrow` nor `pure`, but this lie is // necessary for now to prevent breaking code. private extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow; @@ -4067,8 +4003,6 @@ auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow @system assert(is(typeof(b3) == immutable(int[]))); } -private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow; - private void _doPostblit(T)(T[] arr) { // infer static postblit type, run postblit if any @@ -4085,274 +4019,6 @@ private void _doPostblit(T)(T[] arr) } } -@safe unittest -{ - static struct S1 { int* p; } - static struct S2 { @disable this(); } - static struct S3 { @disable this(this); } - - int dg1() pure nothrow @safe - { - { - char[] m; - string i; - m = m.dup; - i = i.idup; - m = i.dup; - i = m.idup; - } - { - S1[] m; - immutable(S1)[] i; - m = m.dup; - i = i.idup; - static assert(!is(typeof(m.idup))); - static assert(!is(typeof(i.dup))); - } - { - S3[] m; - immutable(S3)[] i; - static assert(!is(typeof(m.dup))); - static assert(!is(typeof(i.idup))); - } - { - shared(S1)[] m; - m = m.dup; - static assert(!is(typeof(m.idup))); - } - { - int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0); - } - return 1; - } - - int dg2() pure nothrow @safe - { - { - S2[] m = [S2.init, S2.init]; - immutable(S2)[] i = [S2.init, S2.init]; - m = m.dup; - m = i.dup; - i = m.idup; - i = i.idup; - } - return 2; - } - - enum a = dg1(); - enum b = dg2(); - assert(dg1() == a); - assert(dg2() == b); -} - -@system unittest -{ - static struct Sunpure { this(this) @safe nothrow {} } - static struct Sthrow { this(this) @safe pure {} } - static struct Sunsafe { this(this) @system pure nothrow {} } - static struct Snocopy { @disable this(this); } - - [].dup!Sunpure; - [].dup!Sthrow; - cast(void) [].dup!Sunsafe; - static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); - static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); - static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); - static assert(!__traits(compiles, () { [].dup!Snocopy; })); - - [].idup!Sunpure; - [].idup!Sthrow; - [].idup!Sunsafe; - static assert(!__traits(compiles, () pure { [].idup!Sunpure; })); - static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; })); - static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); - static assert(!__traits(compiles, () { [].idup!Snocopy; })); -} - -@safe unittest -{ - // test that the copy-constructor is called with .dup - static struct ArrElem - { - int a; - this(int a) - { - this.a = a; - } - this(ref const ArrElem) - { - a = 2; - } - this(ref ArrElem) immutable - { - a = 3; - } - } - - auto arr = [ArrElem(1), ArrElem(1)]; - - ArrElem[] b = arr.dup; - assert(b[0].a == 2 && b[1].a == 2); - - immutable ArrElem[] c = arr.idup; - assert(c[0].a == 3 && c[1].a == 3); -} - -@system unittest -{ - static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} } - static struct Sthrow { this(ref const typeof(this)) @safe pure {} } - static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} } - [].dup!Sunpure; - [].dup!Sthrow; - cast(void) [].dup!Sunsafe; - static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); - static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); - static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); - - // for idup to work on structs that have copy constructors, it is necessary - // that the struct defines a copy constructor that creates immutable objects - static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} } - static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} } - static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} } - [].idup!ISunpure; - [].idup!ISthrow; - [].idup!ISunsafe; - static assert(!__traits(compiles, () pure { [].idup!ISunpure; })); - static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; })); - static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; })); -} - -@safe unittest -{ - static int*[] pureFoo() pure { return null; } - { char[] s; immutable x = s.dup; } - { immutable x = (cast(int*[])null).dup; } - { immutable x = pureFoo(); } - { immutable x = pureFoo().dup; } -} - -@safe unittest -{ - auto a = [1, 2, 3]; - auto b = a.dup; - debug(SENTINEL) {} else - assert(b.capacity >= 3); -} - -@system unittest -{ - // Bugzilla 12580 - void[] m = [0]; - shared(void)[] s = [cast(shared)1]; - immutable(void)[] i = [cast(immutable)2]; - - s = s.dup; - static assert(is(typeof(s.dup) == shared(void)[])); - - m = i.dup; - i = m.dup; - i = i.idup; - i = m.idup; - i = s.idup; - i = s.dup; - static assert(!__traits(compiles, m = s.dup)); -} - -@safe unittest -{ - // Bugzilla 13809 - static struct S - { - this(this) {} - ~this() {} - } - - S[] arr; - auto a = arr.dup; -} - -@system unittest -{ - // Bugzilla 16504 - static struct S - { - __gshared int* gp; - int* p; - // postblit and hence .dup could escape - this(this) { gp = p; } - } - - int p; - scope S[1] arr = [S(&p)]; - auto a = arr.dup; // dup does escape -} - -// https://issues.dlang.org/show_bug.cgi?id=21983 -// dup/idup destroys partially constructed arrays on failure -@safe unittest -{ - static struct SImpl(bool postblit) - { - int num; - long l = 0xDEADBEEF; - - static if (postblit) - { - this(this) - { - if (this.num == 3) - throw new Exception(""); - } - } - else - { - this(scope ref const SImpl other) - { - if (other.num == 3) - throw new Exception(""); - - this.num = other.num; - this.l = other.l; - } - } - - ~this() @trusted - { - if (l != 0xDEADBEEF) - { - import core.stdc.stdio; - printf("Unexpected value: %lld\n", l); - fflush(stdout); - assert(false); - } - } - } - - alias Postblit = SImpl!true; - alias Copy = SImpl!false; - - static int test(S)() - { - S[4] arr = [ S(1), S(2), S(3), S(4) ]; - try - { - arr.dup(); - assert(false); - } - catch (Exception) - { - return 1; - } - } - - static assert(test!Postblit()); - assert(test!Postblit()); - - static assert(test!Copy()); - assert(test!Copy()); -} - /** Destroys the given object and optionally resets to initial state. It's used to _destroy an object, calling its destructor or finalizer so it no longer diff --git a/libphobos/libdruntime/rt/dylib_fixes.c b/libphobos/libdruntime/rt/dylib_fixes.c index e484fed7fb1..c1391b8538f 100644 --- a/libphobos/libdruntime/rt/dylib_fixes.c +++ b/libphobos/libdruntime/rt/dylib_fixes.c @@ -25,4 +25,3 @@ __attribute__((destructor)) static void finalizer () { rt_term(); } - diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 744e5ad5e78..1f0cfbf3e29 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -1516ecad932d88a1618163384e6f69009d125391 +5748ca43fd5c3e31ce7a8511f542b67e5d5a3dc6 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/etc/c/curl.d b/libphobos/src/etc/c/curl.d index 0c5b727944c..e6a10435d2b 100644 --- a/libphobos/src/etc/c/curl.d +++ b/libphobos/src/etc/c/curl.d @@ -1372,9 +1372,9 @@ alias curl_TimeCond = int; /** curl_strequal() and curl_strnequal() are subject for removal in a future libcurl, see lib/README.curlx for details */ extern (C) { -int curl_strequal(in const(char) *s1, in const(char) *s2); +int curl_strequal(scope const(char) *s1, scope const(char) *s2); /// ditto -int curl_strnequal(in const(char) *s1, in const(char) *s2, size_t n); +int curl_strnequal(scope const(char) *s1, scope const(char) *s2, size_t n); } enum CurlForm { nothing, /********** the first one is unused ************/ @@ -1464,7 +1464,7 @@ CURLFORMcode curl_formadd(curl_httppost **httppost, curl_httppost **last_post,. * Should return the buffer length passed to it as the argument "len" on * success. */ -alias curl_formget_callback = size_t function(void *arg, in const(char) *buf, size_t len); +alias curl_formget_callback = size_t function(void *arg, const(char) *buf, size_t len); /** * Name: curl_formget() @@ -1494,7 +1494,7 @@ void curl_formfree(curl_httppost *form); * Returns a malloc()'ed string that MUST be curl_free()ed after usage is * complete. DEPRECATED - see lib/README.curlx */ -char * curl_getenv(in const(char) *variable); +char * curl_getenv(scope const(char) *variable); /** * Name: curl_version() @@ -1514,10 +1514,10 @@ char * curl_version(); * %XX versions). This function returns a new allocated string or NULL if an * error occurred. */ -char * curl_easy_escape(CURL *handle, in const(char) *string, int length); +char * curl_easy_escape(CURL *handle, scope const(char) *string, int length); /** the previous version: */ -char * curl_escape(in const(char) *string, int length); +char * curl_escape(scope const(char) *string, int length); /** @@ -1531,10 +1531,10 @@ char * curl_escape(in const(char) *string, int length); * Conversion Note: On non-ASCII platforms the ASCII %XX codes are * converted into the host encoding. */ -char * curl_easy_unescape(CURL *handle, in const(char) *string, int length, int *outlength); +char * curl_easy_unescape(CURL *handle, scope const(char) *string, int length, int *outlength); /** the previous version */ -char * curl_unescape(in const(char) *string, int length); +char * curl_unescape(scope const(char) *string, int length); /** * Name: curl_free() @@ -1608,7 +1608,7 @@ struct curl_slist * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ -curl_slist * curl_slist_append(curl_slist *, in const(char) *); +curl_slist * curl_slist_append(curl_slist *, const(char) *); /** * Name: curl_slist_free_all() diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d index 2fcc2bacd5c..b810fbb9258 100644 --- a/libphobos/src/std/algorithm/comparison.d +++ b/libphobos/src/std/algorithm/comparison.d @@ -1027,7 +1027,7 @@ template equal(alias pred = "a == b") } } - private bool equalLoop(Rs...)(Rs rs) + private bool equalLoop(Rs...)(ref Rs rs) { for (; !rs[0].empty; rs[0].popFront) static foreach (r; rs[1 .. $]) diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index af665c41197..300a8978fe5 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -1263,19 +1263,22 @@ public: // filter /** -Implements the higher order filter function. The predicate is passed to -$(REF unaryFun, std,functional), and can either accept a string, or any callable -that can be executed via `pred(element)`. +`filter!(predicate)(range)` returns a new range containing only elements `x` in `range` for +which `predicate(x)` returns `true`. + +The predicate is passed to $(REF unaryFun, std,functional), and can be either a string, or +any callable that can be executed via `pred(element)`. Params: predicate = Function to apply to each element of range Returns: - `filter!(predicate)(range)` returns a new range containing only elements `x` in `range` for - which `predicate(x)` returns `true`. + An input range that contains the filtered elements. If `range` is at least a forward range, the return value of `filter` + will also be a forward range. See_Also: - $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function)) + $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function)), + $(REF filterBidirectional, std,algorithm,iteration) */ template filter(alias predicate) if (is(typeof(unaryFun!predicate))) diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index 55a14385e8a..daa4b99045e 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -2512,6 +2512,8 @@ RandomAccessRange find(RandomAccessRange, alias pred, InputRange)( Convenience function. Like find, but only returns whether or not the search was successful. +For more information about `pred` see $(LREF find). + See_Also: $(REF among, std,algorithm,comparison) for checking a value against multiple possibilities. +/ @@ -2622,6 +2624,8 @@ Advances `r` until it finds the first two adjacent elements `a`, `b` that satisfy `pred(a, b)`. Performs $(BIGOH r.length) evaluations of `pred`. +For more information about `pred` see $(LREF find). + Params: pred = The predicate to satisfy. r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to @@ -2698,6 +2702,8 @@ Advances `seq` by calling `seq.popFront` until either `find!(pred)(choices, seq.front)` is `true`, or `seq` becomes empty. Performs $(BIGOH seq.length * choices.length) evaluations of `pred`. +For more information about `pred` see $(LREF find). + Params: pred = The predicate to use for determining a match. seq = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to @@ -2758,6 +2764,8 @@ if (isInputRange!InputRange && isForwardRange!ForwardRange) * Similarly, the haystack is positioned so as `pred` evaluates to `false` for * `haystack.front`. * + * For more information about `pred` see $(LREF find). + * Params: * haystack = The * $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search @@ -2882,6 +2890,8 @@ $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and the type of `result[0]` and `result[1]` is the same as $(REF takeExactly, std,range). +For more information about `pred` see $(LREF find). + Params: pred = Predicate to use for comparing needle against haystack. haystack = The range to search. @@ -4595,6 +4605,8 @@ $(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one of) the given needle(s) or, if no needles are given, if its front element fulfils predicate `pred`. +For more information about `pred` see $(LREF find). + Params: pred = Predicate to use in comparing the elements of the haystack and the diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 8f6c3bf568e..9164e079865 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -3419,17 +3419,20 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum } } + Target result = cast(Target) (sign ? -ldval : ldval); + // if overflow occurred - enforce(ldval != real.infinity, new ConvException("Range error")); + import std.math : isFinite; + enforce(isFinite(result), new ConvException("Range error")); advanceSource(); static if (doCount) { - return tuple!("data", "count")(cast (Target) (sign ? -ldval : ldval), count); + return tuple!("data", "count")(result, count); } else { - return cast (Target) (sign ? -ldval : ldval); + return result; } } @@ -3785,6 +3788,16 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum assertThrown!ConvException(parse!double(s)); } +@safe unittest // https://issues.dlang.org/show_bug.cgi?id=22637 +{ + import std.exception : assertThrown, assertNotThrown; + auto src = "9991232549867999698999493543521458974414359998784641646846435132132543645435456345634541999999999999999" + ~ "9999999943321231321311999231345312413646846354354354399999934153465464654646464654134135354199999999996515734999" + ~ "9999999320135273486741354354731567431324134999999999999999999999999999999999999999999999135411.9"; + assertThrown!ConvException(parse!double(src)); + static if (real.max_10_exp > 310) assertNotThrown!ConvException(parse!real(src)); +} + /** Parsing one character off a range returns the first element and calls `popFront`. diff --git a/libphobos/src/std/experimental/checkedint.d b/libphobos/src/std/experimental/checkedint.d index 9237341d418..2be5a2ea150 100644 --- a/libphobos/src/std/experimental/checkedint.d +++ b/libphobos/src/std/experimental/checkedint.d @@ -1,6 +1,6 @@ /** - * This module is now deprecated, use $(MREF std, experimental) + * This module is now deprecated, use $(MREF std, checkedint) * instead. * * Copyright: Copyright The D Language Foundation 2005 - 2015. diff --git a/libphobos/src/std/experimental/logger/core.d b/libphobos/src/std/experimental/logger/core.d index d899db70793..f3c69324ba1 100644 --- a/libphobos/src/std/experimental/logger/core.d +++ b/libphobos/src/std/experimental/logger/core.d @@ -4,6 +4,7 @@ Source: $(PHOBOSSRC std/experimental/logger/core.d) */ module std.experimental.logger.core; +import core.atomic : atomicLoad, atomicOp, atomicStore, MemoryOrder; import core.sync.mutex : Mutex; import std.datetime.date : DateTime; import std.datetime.systime : Clock, SysTime; @@ -555,14 +556,14 @@ abstract class Logger Params: lv = `LogLevel` to use for this `Logger` instance. */ - this(LogLevel lv) @safe + this(this This)(LogLevel lv) { this.logLevel_ = lv; this.fatalHandler_ = delegate() { throw new Error("A fatal log message was logged"); }; - this.mutex = new Mutex(); + this.mutex = new typeof(mutex)(); } /** A custom logger must implement this method in order to work in a @@ -661,7 +662,7 @@ abstract class Logger /// Ditto @property final void logLevel(const LogLevel lv) @safe @nogc { - synchronized (mutex) this.logLevel_ = lv; + atomicStore(this.logLevel_, lv); } /** This `delegate` is called in case a log message with @@ -1403,28 +1404,28 @@ abstract class Logger // Thread Global -private __gshared Logger stdSharedDefaultLogger; +private shared Logger stdSharedDefaultLogger; private shared Logger stdSharedLogger; private shared LogLevel stdLoggerGlobalLogLevel = LogLevel.all; /* This method returns the global default Logger. * Marked @trusted because of excessive reliance on __gshared data */ -private @property Logger defaultSharedLoggerImpl() @trusted +private @property shared(Logger) defaultSharedLoggerImpl() @trusted { import core.lifetime : emplace; import std.stdio : stderr; __gshared align(__traits(classInstanceAlignment, FileLogger)) - void[__traits(classInstanceSize, FileLogger)] _buffer; + void[__traits(classInstanceSize, FileLogger)] _buffer = void; import std.concurrency : initOnce; initOnce!stdSharedDefaultLogger({ auto buffer = cast(ubyte[]) _buffer; - return emplace!FileLogger(buffer, stderr, LogLevel.info); + return cast(shared) emplace!(FileLogger)(buffer, stderr, LogLevel.info); }()); - return stdSharedDefaultLogger; + return atomicLoad(stdSharedDefaultLogger); } /** This property sets and gets the default `Logger`. Unless set to another @@ -1452,19 +1453,12 @@ if (sharedLog !is myLogger) sharedLog = new myLogger; ------------- */ -@property Logger sharedLog() @safe +@property shared(Logger) sharedLog() @safe { - static auto trustedLoad(ref shared Logger logger) @trusted - { - import core.atomic : atomicLoad, MemoryOrder; - return cast() atomicLoad!(MemoryOrder.acq)(logger); - //FIXME: Casting shared away here. Not good. See issue 16232. - } - // If we have set up our own logger use that - if (auto logger = trustedLoad(stdSharedLogger)) + if (auto logger = atomicLoad!(MemoryOrder.seq)(stdSharedLogger)) { - return logger; + return atomicLoad(logger); } else { @@ -1474,10 +1468,9 @@ if (sharedLog !is myLogger) } /// Ditto -@property void sharedLog(Logger logger) @trusted +@property void sharedLog(shared(Logger) logger) @safe { - import core.atomic : atomicStore, MemoryOrder; - atomicStore!(MemoryOrder.rel)(stdSharedLogger, cast(shared) logger); + atomicStore!(MemoryOrder.seq)(stdSharedLogger, atomicLoad(logger)); } /** This methods get and set the global `LogLevel`. @@ -1523,9 +1516,12 @@ class StdForwardLogger : Logger this.fatalHandler = delegate() {}; } - override protected void writeLogMsg(ref LogEntry payload) + override protected void writeLogMsg(ref LogEntry payload) @trusted { - sharedLog.forwardMsg(payload); + synchronized (sharedLog.mutex) + { + (cast() sharedLog).forwardMsg(payload); + } } } @@ -1535,6 +1531,40 @@ class StdForwardLogger : Logger auto nl1 = new StdForwardLogger(LogLevel.all); } +@safe unittest +{ + import core.thread : Thread, msecs; + + static class RaceLogger : Logger + { + int value; + this() @safe shared + { + super(LogLevel.init); + } + override void writeLogMsg(ref LogEntry payload) @safe + { + import core.thread : Thread, msecs; + if (payload.msg == "foo") + { + value = 42; + () @trusted { Thread.sleep(100.msecs); }(); + assert(value == 42, "Another thread changed the value"); + } + else + { + () @trusted { Thread.sleep(50.msecs); } (); + value = 13; + } + } + } + + sharedLog = new shared RaceLogger; + scope(exit) { sharedLog = null; } + () @trusted { new Thread(() { log("foo"); }).start(); }(); + log("bar"); +} + /** This `LogLevel` is unqiue to every thread. The thread local `Logger` will use this `LogLevel` to filter log calls @@ -1561,7 +1591,7 @@ private @property Logger stdThreadLocalLogImpl() @trusted } /** This function returns a thread unique `Logger`, that by default -propergates all data logged to it to the `sharedLog`. +propagates all data logged to it to the `sharedLog`. These properties can be used to set and get this `Logger`. Every modification to this `Logger` will only be visible in the thread the @@ -1671,10 +1701,12 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto oldunspecificLogger = sharedLog; scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); } - sharedLog = tl1; + () @trusted { + sharedLog = cast(shared) tl1; + }(); log(); assert(tl1.line == __LINE__ - 1); @@ -1793,22 +1825,34 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); - auto oldunspecificLogger = sharedLog; + Logger oldunspecificLogger; + () @trusted { + oldunspecificLogger = cast() sharedLog; + }(); assert(oldunspecificLogger.logLevel == LogLevel.info, to!string(oldunspecificLogger.logLevel)); assert(l.logLevel == LogLevel.all); - sharedLog = l; + + () @trusted { + sharedLog = cast(shared) l; + }(); + assert(globalLogLevel == LogLevel.all, to!string(globalLogLevel)); scope(exit) { - sharedLog = oldunspecificLogger; + () @trusted { + sharedLog = atomicLoad(cast(shared) oldunspecificLogger); + }(); } - assert(sharedLog.logLevel == LogLevel.all); + () @trusted { + assert((cast() sharedLog).logLevel == LogLevel.all); + }(); + assert(stdThreadLocalLog.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); @@ -1880,13 +1924,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile"; FileLogger l = new FileLogger(filename); auto oldunspecificLogger = sharedLog; - sharedLog = l; + + sharedLog = cast(shared) l; scope(exit) { remove(filename); assert(!exists(filename)); - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -1923,7 +1968,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe scope(exit) { remove(filename); - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -1931,8 +1976,11 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe string written = "this should be written to file"; auto l = new FileLogger(filename); - sharedLog = l; - sharedLog.logLevel = LogLevel.critical; + sharedLog = cast(shared) l; + + () @trusted { + (cast() sharedLog).logLevel = LogLevel.critical; + }(); log(LogLevel.error, false, notWritten); log(LogLevel.critical, true, written); @@ -1974,11 +2022,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto mem = new TestLogger; mem.fatalHandler = delegate() {}; - sharedLog = mem; + + () @trusted { + sharedLog = cast(shared) mem; + }(); scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2221,11 +2272,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto mem = new TestLogger; mem.fatalHandler = delegate() {}; - sharedLog = mem; + + () @trusted { + sharedLog = cast(shared) mem; + }(); scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2477,10 +2531,13 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe stdThreadLocalLog.logLevel = LogLevel.all; - sharedLog = mem; + () @trusted { + sharedLog = cast(shared) mem; + }(); + scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2707,12 +2764,15 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } auto tl = new TestLogger(LogLevel.info); - sharedLog = tl; + + () @trusted { + sharedLog = cast(shared) tl; + }(); trace("trace"); assert(tl.msg.indexOf("trace") == -1); @@ -2730,7 +2790,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2738,7 +2798,10 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto tl = new TestLogger(LogLevel.info); logger.insertLogger("required", tl); - sharedLog = logger; + + () @trusted { + sharedLog = cast(shared) logger; + }(); trace("trace"); assert(tl.msg.indexOf("trace") == -1); @@ -2774,14 +2837,12 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe // Workaround for atomics not allowed in @safe code private auto trustedLoad(T)(ref shared T value) @trusted { - import core.atomic : atomicLoad, MemoryOrder; return atomicLoad!(MemoryOrder.acq)(value); } // ditto private void trustedStore(T)(ref shared T dst, ref T src) @trusted { - import core.atomic : atomicStore, MemoryOrder; atomicStore!(MemoryOrder.rel)(dst, src); } @@ -2789,7 +2850,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted // to shared logger @system unittest { - import core.atomic, core.thread, std.concurrency; + import core.thread, std.concurrency; static shared logged_count = 0; @@ -2826,10 +2887,13 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted auto oldSharedLog = sharedLog; scope(exit) { - sharedLog = oldSharedLog; + sharedLog = atomicLoad(oldSharedLog); } - sharedLog = new IgnoredLog; + () @trusted { + sharedLog = cast(shared) new IgnoredLog; + }(); + Thread[] spawned; foreach (i; 0 .. 4) @@ -2849,7 +2913,9 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted @safe unittest { - auto dl = cast(FileLogger) sharedLog; + auto dl = () @trusted { + return cast(FileLogger) cast() sharedLog; + }(); assert(dl !is null); assert(dl.logLevel == LogLevel.info); assert(globalLogLevel == LogLevel.all); @@ -2946,7 +3012,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted auto oldShared = sharedLog; scope(exit) { - sharedLog = oldShared; + sharedLog = atomicLoad(oldShared); if (exists(fn)) { remove(fn); @@ -2956,7 +3022,11 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted auto ts = [ "Test log 1", "Test log 2", "Test log 3"]; auto fl = new FileLogger(fn); - sharedLog = fl; + + () @trusted { + sharedLog = cast(shared) fl; + }(); + assert(exists(fn)); foreach (t; ts) diff --git a/libphobos/src/std/experimental/logger/filelogger.d b/libphobos/src/std/experimental/logger/filelogger.d index 5112e520bc0..457012e21b5 100644 --- a/libphobos/src/std/experimental/logger/filelogger.d +++ b/libphobos/src/std/experimental/logger/filelogger.d @@ -259,7 +259,7 @@ class FileLogger : Logger file.close(); } -@safe unittest +@system unittest { auto dl = cast(FileLogger) sharedLog; assert(dl !is null); diff --git a/libphobos/src/std/experimental/logger/multilogger.d b/libphobos/src/std/experimental/logger/multilogger.d index 9acd23a59cd..35936901964 100644 --- a/libphobos/src/std/experimental/logger/multilogger.d +++ b/libphobos/src/std/experimental/logger/multilogger.d @@ -187,7 +187,7 @@ class MultiLogger : Logger assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg); } -@safe unittest +@system unittest { auto dl = cast(FileLogger) sharedLog; assert(dl !is null); diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index b8b4a8ce6c6..d6cac41ef04 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -1510,7 +1510,7 @@ private ushort bitmapcount, reserved; attrgroup_t commonattr, volattr, dirattr, fileattr, forkattr; } - extern(C) int setattrlist(in char* path, scope ref attrlist attrs, + extern(C) int setattrlist(scope const(char)* path, scope ref attrlist attrs, scope void* attrbuf, size_t attrBufSize, c_ulong options) nothrow @nogc @system; } diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d index f1d69643495..2fd6ff72990 100644 --- a/libphobos/src/std/format/internal/write.d +++ b/libphobos/src/std/format/internal/write.d @@ -1337,7 +1337,7 @@ if (is(StringTypeOf!T) && !is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToSt /* Static-size arrays are formatted as dynamic arrays. */ -void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref const(T) obj, +void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref T obj, scope const ref FormatSpec!Char f) if (is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { @@ -1782,13 +1782,13 @@ void formatChar(Writer)(ref Writer w, in dchar c, in char quote) Associative arrays are formatted by using `':'` and $(D ", ") as separators, and enclosed by `'['` and `']'`. */ -void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f) +void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f) if (is(AssocArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { import std.format : enforceFmt, formatValue; import std.range.primitives : put; - AssocArrayTypeOf!(const(T)) val = obj; + AssocArrayTypeOf!T val = obj; const spec = f.spec; enforceFmt(spec == 's' || spec == '(', diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d index 76d68f6cff6..3f6f33adf6e 100644 --- a/libphobos/src/std/format/package.d +++ b/libphobos/src/std/format/package.d @@ -1356,6 +1356,30 @@ if (isSomeChar!Char) assert(result == " 1"); } +// https://issues.dlang.org/show_bug.cgi?id=23245 +@safe unittest +{ + static struct S + { + string toString() { return "S"; } + } + + S[1] s; + assert(format("%s", s) == "[S]"); +} + +// https://issues.dlang.org/show_bug.cgi?id=23246 +@safe unittest +{ + static struct S + { + string toString() { return "S"; } + } + + S[int] s = [0 : S()]; + assert(format("%s", s) == "[0:S]"); +} + /// ditto typeof(fmt) format(alias fmt, Args...)(Args args) if (isSomeString!(typeof(fmt))) diff --git a/libphobos/src/std/math/package.d b/libphobos/src/std/math/package.d index 7443b0dea2e..19982ec216a 100644 --- a/libphobos/src/std/math/package.d +++ b/libphobos/src/std/math/package.d @@ -383,6 +383,7 @@ template floatTraits(T) enum ushort EXPBIAS = 0x3FE0; enum uint EXPMASK_INT = 0x7FF0_0000; enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only + enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF; enum realFormat = RealFormat.ieeeDouble; version (LittleEndian) { diff --git a/libphobos/src/std/math/rounding.d b/libphobos/src/std/math/rounding.d index 5c8d708c489..7dbe89b2dee 100644 --- a/libphobos/src/std/math/rounding.d +++ b/libphobos/src/std/math/rounding.d @@ -908,7 +908,9 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc // Other kinds of extractors for real formats. static if (F.realFormat == RealFormat.ieeeSingle) - int vi; + uint vi; + else static if (F.realFormat == RealFormat.ieeeDouble) + ulong vi; } floatBits y = void; y.rv = x; @@ -919,15 +921,14 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc static if (F.realFormat == RealFormat.ieeeSingle) { int exp = ((y.vi >> (T.mant_dig - 1)) & 0xff) - 0x7f; + enum mantissa_mask = F.MANTISSAMASK_INT; + enum sign_shift = 31; } else static if (F.realFormat == RealFormat.ieeeDouble) { - int exp = ((y.vu[F.EXPPOS_SHORT] >> 4) & 0x7ff) - 0x3ff; - - version (LittleEndian) - int pos = 0; - else - int pos = 3; + long exp = ((y.vi >> (T.mant_dig - 1)) & 0x7ff) - 0x3ff; + enum mantissa_mask = F.MANTISSAMASK_LONG; + enum sign_shift = 63; } else static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeExtended53) @@ -959,18 +960,21 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc return 0.0; } - static if (F.realFormat == RealFormat.ieeeSingle) + static if (F.realFormat == RealFormat.ieeeSingle || + F.realFormat == RealFormat.ieeeDouble) { if (exp < (T.mant_dig - 1)) { // Clear all bits representing the fraction part. - const uint fraction_mask = F.MANTISSAMASK_INT >> exp; + // Note: the fraction mask represents the floating point number 0.999999... + // i.e: `2.0 ^^ (exp - T.mant_dig + 1) * (fraction_mask + 1) == 1.0` + const fraction_mask = mantissa_mask >> exp; if ((y.vi & fraction_mask) != 0) { - // If 'x' is negative, then first substract 1.0 from the value. - if (y.vi < 0) - y.vi += 0x00800000 >> exp; + // If 'x' is negative, then first substract (1.0 - T.epsilon) from the value. + if (y.vi >> sign_shift) + y.vi += fraction_mask; y.vi &= ~fraction_mask; } } diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d index 106e51ceedb..b2206ce56ba 100644 --- a/libphobos/src/std/random.d +++ b/libphobos/src/std/random.d @@ -2762,7 +2762,7 @@ Returns: return a `ref` to the $(D range element), otherwise it will return a copy. */ -auto ref choice(Range, RandomGen = Random)(auto ref Range range, ref RandomGen urng) +auto ref choice(Range, RandomGen = Random)(Range range, ref RandomGen urng) if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen) { assert(range.length > 0, @@ -2772,7 +2772,22 @@ if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen) } /// ditto -auto ref choice(Range)(auto ref Range range) +auto ref choice(Range)(Range range) +{ + return choice(range, rndGen); +} + +/// ditto +auto ref choice(Range, RandomGen = Random)(ref Range range, ref RandomGen urng) +if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen) +{ + assert(range.length > 0, + __PRETTY_FUNCTION__ ~ ": invalid Range supplied. Range cannot be empty"); + return range[uniform(size_t(0), $, urng)]; +} + +/// ditto +auto ref choice(Range)(ref Range range) { return choice(range, rndGen); } @@ -2827,6 +2842,39 @@ auto ref choice(Range)(auto ref Range range) "Choice did not return a valid element from the given Range"); } +@safe unittest // issue 18631 +{ + auto rng = MinstdRand0(42); + const a = [0,1,2]; + const(int[]) b = [0, 1, 2]; + auto x = choice(a); + auto y = choice(b); + auto z = choice(cast(const)[1, 2, 3]); + auto x1 = choice(a, rng); + auto y1 = choice(b, rng); + auto z1 = choice(cast(const)[1, 2, 3], rng); +} + +@safe unittest // Ref range (issue 18631 PR) +{ + struct TestRange + { + int x; + ref int front() return {return x;} + ref int back() return {return x;} + void popFront() {} + void popBack() {} + bool empty = false; + TestRange save() {return this;} + size_t length = 10; + alias opDollar = length; + ref int opIndex(size_t i) return {return x;} + } + + TestRange r = TestRange(10); + int* s = &choice(r); +} + /** Shuffles elements of `r` using `gen` as a shuffler. `r` must be a random-access range with length. If no RNG is specified, `rndGen` @@ -3008,8 +3056,16 @@ if (isRandomAccessRange!Range) } /** -Rolls a dice with relative probabilities stored in $(D -proportions). Returns the index in `proportions` that was chosen. +Get a random index into a list of weights corresponding to each index + +Similar to rolling a die with relative probabilities stored in `proportions`. +Returns the index in `proportions` that was chosen. + +Note: + Usually, dice are 'fair', meaning that each side has equal probability + to come up, in which case `1 + uniform(0, 6)` can simply be used. + In future Phobos versions, this function might get renamed to something like + `weightedChoice` to avoid confusion. Params: rnd = (optional) random number generator to use; if not @@ -3055,6 +3111,9 @@ if (isNumeric!Num) /// @safe unittest { + auto d6 = 1 + dice(1, 1, 1, 1, 1, 1); // fair dice roll + auto d6b = 1 + dice(2, 1, 1, 1, 1, 1); // double the chance to roll '1' + auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions auto y = dice(50, 50); // y is 0 or 1 in equal proportions auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time, diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index 8614dc96901..a1fe962906b 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -1132,10 +1132,9 @@ each item is inferred from the size and type of the input array, respectively. Returns: The slice of `buffer` containing the data that was actually read. This will be shorter than `buffer` if EOF was reached before the buffer -could be filled. +could be filled. If the buffer is empty, it will be returned. -Throws: `Exception` if `buffer` is empty. - `ErrnoException` if the file is not opened or the call to `fread` fails. +Throws: `ErrnoException` if the file is not opened or the call to `fread` fails. `rawRead` always reads in binary mode on Windows. */ @@ -1144,7 +1143,7 @@ Throws: `Exception` if `buffer` is empty. import std.exception : enforce, errnoEnforce; if (!buffer.length) - throw new Exception("rawRead must take a non-empty buffer"); + return buffer; enforce(isOpen, "Attempting to read from an unopened file"); version (Windows) { @@ -1211,6 +1210,16 @@ Throws: `Exception` if `buffer` is empty. } } + // https://issues.dlang.org/show_bug.cgi?id=13893 + @system unittest + { + import std.exception : assertNotThrown; + + File f; + ubyte[0] u; + assertNotThrown(f.rawRead(u)); + } + /** Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/fwrite.html, fwrite) for the file handle. The number of items to write and the size of each diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 1d375ef4d7e..160665c6a31 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -1941,79 +1941,8 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) auto ref matchImpl(SumTypes...)(auto ref SumTypes args) if (allSatisfy!(isSumType, SumTypes) && args.length > 0) { - enum typeCount(SumType) = SumType.Types.length; alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes)); - - /* A TagTuple represents a single possible set of tags that `args` - * could have at runtime. - * - * Because D does not allow a struct to be the controlling expression - * of a switch statement, we cannot dispatch on the TagTuple directly. - * Instead, we must map each TagTuple to a unique integer and generate - * a case label for each of those integers. - * - * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses - * the same technique that's used to map index tuples to memory offsets - * in a multidimensional static array. - * - * For example, when `args` consists of two SumTypes with two member - * types each, the TagTuples corresponding to each case label are: - * - * case 0: TagTuple([0, 0]) - * case 1: TagTuple([1, 0]) - * case 2: TagTuple([0, 1]) - * case 3: TagTuple([1, 1]) - * - * When there is only one argument, the caseId is equal to that - * argument's tag. - */ - static struct TagTuple - { - size_t[SumTypes.length] tags; - alias tags this; - - invariant - { - static foreach (i; 0 .. tags.length) - { - assert(tags[i] < SumTypes[i].Types.length, "Invalid tag"); - } - } - - this(ref const(SumTypes) args) - { - static foreach (i; 0 .. tags.length) - { - tags[i] = args[i].tag; - } - } - - static TagTuple fromCaseId(size_t caseId) - { - TagTuple result; - - // Most-significant to least-significant - static foreach_reverse (i; 0 .. result.length) - { - result[i] = caseId / stride!i; - caseId %= stride!i; - } - - return result; - } - - size_t toCaseId() - { - size_t result; - - static foreach (i; 0 .. tags.length) - { - result += tags[i] * stride!i; - } - - return result; - } - } + alias TagTuple = .TagTuple!(SumTypes); /* * A list of arguments to be passed to a handler needed for the case @@ -2149,6 +2078,81 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) } } +private enum typeCount(SumType) = SumType.Types.length; + +/* A TagTuple represents a single possible set of tags that `args` + * could have at runtime. + * + * Because D does not allow a struct to be the controlling expression + * of a switch statement, we cannot dispatch on the TagTuple directly. + * Instead, we must map each TagTuple to a unique integer and generate + * a case label for each of those integers. + * + * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses + * the same technique that's used to map index tuples to memory offsets + * in a multidimensional static array. + * + * For example, when `args` consists of two SumTypes with two member + * types each, the TagTuples corresponding to each case label are: + * + * case 0: TagTuple([0, 0]) + * case 1: TagTuple([1, 0]) + * case 2: TagTuple([0, 1]) + * case 3: TagTuple([1, 1]) + * + * When there is only one argument, the caseId is equal to that + * argument's tag. + */ +private struct TagTuple(SumTypes...) +{ + size_t[SumTypes.length] tags; + alias tags this; + + alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes)); + + invariant + { + static foreach (i; 0 .. tags.length) + { + assert(tags[i] < SumTypes[i].Types.length, "Invalid tag"); + } + } + + this(ref const(SumTypes) args) + { + static foreach (i; 0 .. tags.length) + { + tags[i] = args[i].tag; + } + } + + static TagTuple fromCaseId(size_t caseId) + { + TagTuple result; + + // Most-significant to least-significant + static foreach_reverse (i; 0 .. result.length) + { + result[i] = caseId / stride!i; + caseId %= stride!i; + } + + return result; + } + + size_t toCaseId() + { + size_t result; + + static foreach (i; 0 .. tags.length) + { + result += tags[i] * stride!i; + } + + return result; + } +} + // Matching @safe unittest { diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index 8a3e22f74a9..4ecfb1051d1 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -4905,8 +4905,14 @@ if (is(Interface == interface) && is(BaseClass == class)) // - try default first // - only on a failure run & return fallback enum fallback = q{ - scope (failure) return fallback.%1$s(args); - return default_.%1$s(args); + try + { + return default_.%1$s(args); + } + catch (Exception) + { + return fallback.%1$s(args); + } }.format(__traits(identifier, func)); } @@ -6589,15 +6595,11 @@ if (!is(T == class) && !(is(T == interface))) private enum enableGCScan = hasIndirections!T; } - // TODO remove pure when https://issues.dlang.org/show_bug.cgi?id=15862 has been fixed extern(C) private pure nothrow @nogc static { pragma(mangle, "free") void pureFree( void *ptr ); static if (enableGCScan) - { - pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null ); - pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p ); - } + import core.memory : GC; } /// `RefCounted` storage implementation. @@ -6637,7 +6639,7 @@ if (!is(T == class) && !(is(T == interface))) { import std.internal.memory : enforceCalloc; _store = cast(Impl*) enforceCalloc(1, Impl.sizeof); - pureGcAddRange(&_store._payload, T.sizeof); + GC.addRange(&_store._payload, T.sizeof); } else { @@ -6650,7 +6652,7 @@ if (!is(T == class) && !(is(T == interface))) { static if (enableGCScan) { - pureGcRemoveRange(&this._store._payload); + GC.removeRange(&this._store._payload); } pureFree(_store); _store = null; diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 98735ac1a88..e12a70cfe80 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -7032,9 +7032,7 @@ template genericDecodeGrapheme(bool getValue) case RI: if (isRegionalIndicator(ch)) mixin(eat); - else - goto L_End_Extend; - break; + goto L_End_Extend; case L: if (isHangL(ch)) mixin(eat); @@ -7166,6 +7164,10 @@ if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar)) s = "\u11A8\u0308\uAC01"; assert(equal(decodeGrapheme(s)[], "\u11A8\u0308")); assert(equal(decodeGrapheme(s)[], "\uAC01")); + + // Two Union Jacks of the Great Britain + s = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + assert(equal(decodeGrapheme(s)[], "\U0001F1EC\U0001F1E7")); } /++ diff --git a/libphobos/testsuite/libphobos.gc/nocollect.d b/libphobos/testsuite/libphobos.gc/nocollect.d index 5df1483a284..64ed2221134 100644 --- a/libphobos/testsuite/libphobos.gc/nocollect.d +++ b/libphobos/testsuite/libphobos.gc/nocollect.d @@ -12,4 +12,4 @@ void main() stats = GC.profileStats(); assert(stats.numCollections == 0); -} \ No newline at end of file +}