From patchwork Mon Dec 11 10:07:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 81888 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9058A3858433 for ; Mon, 11 Dec 2023 10:07:46 +0000 (GMT) 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 [80.241.56.152]) by sourceware.org (Postfix) with ESMTPS id 8F2223858D37 for ; Mon, 11 Dec 2023 10:07:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8F2223858D37 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=gdcproject.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gdcproject.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8F2223858D37 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=80.241.56.152 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702289242; cv=none; b=UHpwAPf0+YAgTA/+YFDeXEet2pODLcfjwbo1VkoyYZ9VO8XRjx0hnTtw43BpW67oqYJu8W3FPojCCmPLDj+dKBqDSzvilWzO5pubuagMNuPh/KAnJgET8+jr7WXvZqv55N2EfZdObCvcPdvWJYHfftgqQIFOvPKu6kNlHdXulrY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702289242; c=relaxed/simple; bh=3pMV7Qkjv+jj/K8uS+v5g5qxDn+2X06VodkGFLSxn2Y=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=PmJc3qc8a8K03mi0FDDWF/qv6F8cKkxhKRZq/XtSoJAgc5x3rfzjV/f8aO7D2BLvz6O6nAgR+bMHuDfveoxYC7frL1BSHQh1QwetqS2Uihn3BbcxKeGLKJvXoOiWhIX/QFsc9SGlIjX6wOfPDiHnaEjz1Fo89VsRNToe32z5mdI= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp202.mailbox.org (smtp202.mailbox.org [10.196.197.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4SpcqN3Mvzz9t31; Mon, 11 Dec 2023 11:07:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gdcproject.org; s=MBO0001; t=1702289232; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=9gy44vS1GzzKCaP2IsYgZ/SiuPvLKURr9fC6TViAMCA=; b=QNl6eyrZiCt7tBdDi1kr/X5yUepTRDs1jDMHAirIGlbSGtj5Z3KVcVhXsFGTHVZmp2l9zW xac9Vr/Pg4uG2bBnLe/CZfWvses00XNCpUjWKrw7k+c2zgxc45JIv97s1edkzp7j3lpv6B b7RDRE1WVz5mgaU+tWjQbFlOOgfIiOjwz0YIzw0qIppNnUPigKO1wK/8cNxZv21V27g5qt eJPt9X7zT/X+/Nq+yprTdECiLGRAoqt+Z9nSjlnYUAhrKqYUktmyCJG4AUW7lf5EpoLGIM 0VK6i5d1zSgNuqzXHE/RqjPktMsOL3aqHsC8DFeBSVJrYejpy4+961MY3HuP1g== From: Iain Buclaw To: gcc-patches@gcc.gnu.org Cc: Iain Buclaw Subject: [committed] d: Merge upstream dmd, druntime 2bbf64907c, phobos b64bfbf91 Date: Mon, 11 Dec 2023 11:07:10 +0100 Message-Id: <20231211100710.348988-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, KAM_SOMETLD_ARE_BAD_TLD, KAM_STOCKGEN, PDS_OTHER_BAD_TLD, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE, URI_TRY_3LD 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.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Hi, This patch merges the D front-end and runtime library with upstream dmd 2bbf64907c, and the standard library with phobos b64bfbf91. Synchronizing with the upstream release of v2.106.0. D front-end changes: - Import dmd v2.106.0. D runtime changes: - Import druntime v2.106.0. Phobos changes: - Import phobos v2.106.0. Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * Make-lang.in (D_FRONTEND_OBJS): Rename d/common-string.o to d/common-smallbuffer.o. * dmd/MERGE: Merge upstream dmd 2bbf64907c. * dmd/VERSION: Bump version to v2.106.0. * modules.cc (layout_moduleinfo_fields): Update for new front-end interface. (layout_moduleinfo): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 2bbf64907c. * src/MERGE: Merge upstream phobos b64bfbf91. --- gcc/d/Make-lang.in | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/aggregate.d | 10 - gcc/d/dmd/aggregate.h | 1 - gcc/d/dmd/attrib.d | 67 ------ gcc/d/dmd/attrib.h | 9 - gcc/d/dmd/canthrow.d | 2 +- gcc/d/dmd/common/README.md | 2 +- gcc/d/dmd/common/file.d | 15 +- gcc/d/dmd/common/{string.d => smallbuffer.d} | 49 ++-- gcc/d/dmd/cparse.d | 8 + gcc/d/dmd/dcast.d | 12 +- gcc/d/dmd/denum.d | 7 - gcc/d/dmd/dimport.d | 16 -- gcc/d/dmd/dmodule.d | 36 ++- gcc/d/dmd/dsymbol.d | 172 -------------- gcc/d/dmd/dsymbol.h | 5 +- gcc/d/dmd/dsymbolsem.d | 214 +++++++++++++++++ gcc/d/dmd/dtemplate.d | 7 +- gcc/d/dmd/enum.h | 1 - gcc/d/dmd/escape.d | 2 +- gcc/d/dmd/expressionsem.d | 2 +- gcc/d/dmd/hdrgen.d | 27 +++ gcc/d/dmd/import.h | 1 - gcc/d/dmd/initsem.d | 20 +- gcc/d/dmd/module.h | 1 + gcc/d/dmd/nspace.d | 14 -- gcc/d/dmd/nspace.h | 1 - gcc/d/dmd/parse.d | 12 +- gcc/d/dmd/root/file.d | 2 +- gcc/d/dmd/root/filename.d | 4 +- gcc/d/dmd/root/speller.d | 2 +- gcc/d/dmd/root/string.d | 2 +- gcc/d/dmd/typesem.d | 58 +++++ gcc/d/modules.cc | 4 +- .../fail_compilation/misc_parser_err_cov1.d | 2 +- gcc/testsuite/gdc.test/runnable/dbitfields.d | 34 +++ libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/cpuid.d | 7 +- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/searching.d | 218 +++++++----------- libphobos/src/std/conv.d | 5 +- libphobos/src/std/range/package.d | 24 +- libphobos/src/std/uni/package.d | 12 + 45 files changed, 579 insertions(+), 518 deletions(-) rename gcc/d/dmd/common/{string.d => smallbuffer.d} (82%) diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index b3007a96bd0..a0d4d7cbeb4 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -95,7 +95,7 @@ D_FRONTEND_OBJS = \ d/common-bitfields.o \ d/common-file.o \ d/common-outbuffer.o \ - d/common-string.o \ + d/common-smallbuffer.o \ d/compiler.o \ d/cond.o \ d/constfold.o \ diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index aa0062c10eb..5edcee1c84d 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -ff57fec51558013b25cadb7e83da9f4675915d56 +2bbf64907cbbb483d003e0a8fcf8b502e4883799 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 41fdc654b14..8c95cd04f80 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.106.0-rc.1 +v2.106.0 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 307bb0171c4..352ca88f470 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -178,16 +178,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol return sc2; } - override final void setScope(Scope* sc) - { - // Might need a scope to resolve forward references. The check for - // semanticRun prevents unnecessary setting of _scope during deferred - // setScope phases for aggregates which already finished semantic(). - // See https://issues.dlang.org/show_bug.cgi?id=16607 - if (semanticRun < PASS.semanticdone) - ScopeDsymbol.setScope(sc); - } - /*************************************** * Returns: * The total number of fields minus the number of hidden fields. diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index cd8f1a15fbd..98fa6bd1bb0 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -113,7 +113,6 @@ public: Sizeok sizeok; // set when structsize contains valid data virtual Scope *newScope(Scope *sc); - void setScope(Scope *sc) override final; virtual void finalizeSize() = 0; uinteger_t size(const Loc &loc) override final; bool fill(const Loc &loc, Expressions &elements, bool ctorinit); diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 251e2e88ca5..faf04890e8e 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -123,19 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return sc; } - override void setScope(Scope* sc) - { - Dsymbols* d = include(sc); - //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.setScope(sc2) ); - if (sc2 != sc) - sc2.pop(); - } - } - override void importAll(Scope* sc) { Dsymbols* d = include(sc); @@ -338,14 +325,6 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration return scx; } - override void setScope(Scope* sc) - { - //printf("DeprecatedDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol.setScope(sc); // for forward reference - return AttribDeclaration.setScope(sc); - } - override void accept(Visitor v) { v.visit(this); @@ -433,13 +412,6 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration sc.aligndecl, sc.inlining); } - override void setScope(Scope* sc) - { - if (decl) - Dsymbol.setScope(sc); // for forward reference - return AttribDeclaration.setScope(sc); - } - override const(char)* toChars() const { return toString().ptr; @@ -703,13 +675,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); } - override void setScope(Scope* sc) - { - if (decl) - Dsymbol.setScope(sc); - return AttribDeclaration.setScope(sc); - } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) { //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); @@ -913,11 +878,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration } } - override void setScope(Scope* sc) - { - include(sc).foreachDsymbol( s => s.setScope(sc) ); - } - override void accept(Visitor v) { v.visit(this); @@ -983,13 +943,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration } } - override void setScope(Scope* sc) - { - // do not evaluate condition before semantic pass - // But do set the scope, in case we need it for forward referencing - Dsymbol.setScope(sc); - } - override void importAll(Scope* sc) { // do not evaluate condition before semantic pass @@ -1104,13 +1057,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration // change this to give semantics to documentation comments on static foreach declarations } - override void setScope(Scope* sc) - { - // do not evaluate condition before semantic pass - // But do set the scope, in case we need it for forward referencing - Dsymbol.setScope(sc); - } - override void importAll(Scope* sc) { // do not evaluate aggregate before semantic pass @@ -1209,11 +1155,6 @@ extern (C++) final class MixinDeclaration : AttribDeclaration return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps)); } - override void setScope(Scope* sc) - { - Dsymbol.setScope(sc); - } - override const(char)* kind() const { return "mixin"; @@ -1264,14 +1205,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration return sc2; } - override void setScope(Scope* sc) - { - //printf("UserAttributeDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol.setScope(sc); // for forward reference of UDAs - return AttribDeclaration.setScope(sc); - } - extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2) { Expressions* udas; diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index efea9af950c..98c5e521977 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -26,7 +26,6 @@ public: virtual Dsymbols *include(Scope *sc); virtual Scope *newScope(Scope *sc); - void setScope(Scope *sc) override; void importAll(Scope *sc) override; void addComment(const utf8_t *comment) override; const char *kind() const override; @@ -61,7 +60,6 @@ public: DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void setScope(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -84,7 +82,6 @@ public: CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void setScope(Scope *sc) override; const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -135,7 +132,6 @@ public: unsigned anonalignsize; // size of anonymous struct for alignment purposes AnonDeclaration *syntaxCopy(Dsymbol *s) override; - void setScope(Scope *sc) override; void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; AnonDeclaration *isAnonDeclaration() override { return this; } @@ -163,7 +159,6 @@ public: bool oneMember(Dsymbol **ps, Identifier *ident) override final; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override final; - void setScope(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -176,7 +171,6 @@ public: StaticIfDeclaration *syntaxCopy(Dsymbol *s) override; Dsymbols *include(Scope *sc) override; - void setScope(Scope *sc) override; void importAll(Scope *sc) override; StaticIfDeclaration *isStaticIfDeclaration() override { return this; } const char *kind() const override; @@ -196,7 +190,6 @@ public: bool oneMember(Dsymbol **ps, Identifier *ident) override; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override; - void setScope(Scope *sc) override; void importAll(Scope *sc) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } @@ -223,7 +216,6 @@ public: d_bool compiled; MixinDeclaration *syntaxCopy(Dsymbol *s) override; - void setScope(Scope *sc) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -239,7 +231,6 @@ public: UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void setScope(Scope *sc) override; Expressions *getAttributes(); const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 67305922df6..5a608a9986d 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -22,7 +22,6 @@ import dmd.declaration; import dmd.dsymbol; import dmd.errorsink; import dmd.expression; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.init; @@ -81,6 +80,7 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink) if (!f.isDtorDeclaration()) errorSupplementalInferredAttr(f, 10, false, STC.nothrow_); + import dmd.expressionsem : checkOverriddenDtor; f.checkOverriddenDtor(null, e.loc, dd => dd.type.toTypeFunction().isnothrow, "not nothrow"); } else if (func) diff --git a/gcc/d/dmd/common/README.md b/gcc/d/dmd/common/README.md index 853fd4ff502..ad507c75bd4 100644 --- a/gcc/d/dmd/common/README.md +++ b/gcc/d/dmd/common/README.md @@ -5,4 +5,4 @@ | [bitfields.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields | | [file.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management | | [outbuffer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data | -| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/string.d) | Common string functions including filename manipulation | +| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/smallbuffer.d) | Common string functions including filename manipulation | diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d index 076f357e50b..704110f50bd 100644 --- a/gcc/d/dmd/common/file.d +++ b/gcc/d/dmd/common/file.d @@ -17,13 +17,13 @@ module dmd.common.file; import core.stdc.errno : errno; import core.stdc.stdio : fprintf, remove, rename, stderr; import core.stdc.stdlib : exit; -import core.stdc.string : strerror; +import core.stdc.string : strerror, strlen; import core.sys.windows.winbase; import core.sys.windows.winnt; import core.sys.posix.fcntl; import core.sys.posix.unistd; -import dmd.common.string; +import dmd.common.smallbuffer; nothrow: @@ -129,7 +129,8 @@ struct FileMapping(Datum) enum openFlags = CREATE_ALWAYS; } - handle = filename.asDString.extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null)); + handle = filename[0 .. strlen(filename)]. + extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null)); if (handle == invalidHandle) { static if (is(Datum == const)) @@ -312,7 +313,7 @@ struct FileMapping(Datum) else version(Windows) { import core.sys.windows.winbase; - if (deleteme.asDString.extendedPathThen!(p => DeleteFileW(p.ptr)) == 0) + if (deleteme[0 .. strlen(deleteme)].extendedPathThen!(p => DeleteFileW(p.ptr)) == 0) { fprintf(stderr, "DeleteFileW error %d\n", GetLastError()); return false; @@ -447,8 +448,8 @@ struct FileMapping(Datum) else version(Windows) { import core.sys.windows.winbase; - auto r = oldname.asDString.extendedPathThen!( - p1 => filename.asDString.extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING)) + auto r = oldname[0 .. strlen(oldname)].extendedPathThen!( + p1 => filename[0 .. strlen(filename)].extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING)) ); if (r == 0) { @@ -483,7 +484,7 @@ extern(D) static bool writeFile(const(char)* name, const void[] data) nothrow else version (Windows) { DWORD numwritten; // here because of the gotos - const nameStr = name.asDString; + const nameStr = name[0 .. strlen(name)]; // work around Windows file path length limitation // (see documentation for extendedPathThen). HANDLE h = nameStr.extendedPathThen! diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/smallbuffer.d similarity index 82% rename from gcc/d/dmd/common/string.d rename to gcc/d/dmd/common/smallbuffer.d index 9453a3474da..ec0eaae647f 100644 --- a/gcc/d/dmd/common/string.d +++ b/gcc/d/dmd/common/smallbuffer.d @@ -4,11 +4,11 @@ * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d, common/_string.d) - * Documentation: https://dlang.org/phobos/dmd_common_string.html - * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/string.d + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/smallbuffer.d, common/_smallbuffer.d) + * Documentation: https://dlang.org/phobos/dmd_common_smallbuffer.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/smallbuffer */ -module dmd.common.string; +module dmd.common.smallbuffer; nothrow: @@ -106,34 +106,12 @@ unittest assert(b[] !is buf[]); } -/** -Converts a zero-terminated C string to a D slice. Takes linear time and allocates no memory. - -Params: -stringz = the C string to be converted - -Returns: -a slice comprehending the string. The terminating 0 is not part of the slice. -*/ -auto asDString(C)(C* stringz) pure @nogc nothrow -{ - import core.stdc.string : strlen; - return stringz[0 .. strlen(stringz)]; -} - -/// -unittest -{ - const char* p = "123".ptr; - assert(p.asDString == "123"); -} - /** (Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by `buffer` containing the converted string. The terminating zero is not part of the returned slice, but is guaranteed to follow it. */ -version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow +version(Windows) wchar[] toWStringz(scope const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow { import core.sys.windows.winnls : MultiByteToWideChar; import dmd.common.file : CodePage; @@ -141,16 +119,17 @@ version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar if (narrow is null) return null; - const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); - if (requiredLength < cast(int) buffer.length) + size_t length; + int i; + while (1) { - buffer[requiredLength] = 0; - return buffer[0 .. requiredLength]; + // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar + length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); + if (length < buffer.length) + break; + buffer.create(length + 1); + assert(++i == 1); // ensure loop should only execute once or twice } - - buffer.create(requiredLength + 1); - const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, requiredLength); - assert(length == requiredLength); buffer[length] = 0; return buffer[0 .. length]; } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index ed5f1f8b9a2..89a594823ae 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1890,6 +1890,14 @@ final class CParser(AST) : Parser!AST if (specifier.alignExps) error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2 + if (specifier.vector_size) + { + auto length = new AST.IntegerExp(token.loc, specifier.vector_size / dt.size(), AST.Type.tuns32); + auto tsa = new AST.TypeSArray(dt, length); + dt = new AST.TypeVector(tsa); + specifier.vector_size = 0; // used it up + } + bool isalias = true; if (auto ts = dt.isTypeStruct()) { diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 14c67f062a3..bb86b080be6 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -68,7 +68,6 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) Expression visit(Expression e) { // printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); - if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t)) { // no need for an extra cast when matching is exact @@ -802,8 +801,8 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t) return result; } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) - { + else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer)) + { // Tpointer because ImportC eagerly converts Tsarray to Tpointer result = MATCH.exact; // Convert array literal to vector type TypeVector tv = tb.isTypeVector(); @@ -1487,6 +1486,10 @@ MATCH cimplicitConvTo(Expression e, Type t) if (tb.equals(typeb)) return MATCH.exact; + + if (tb.isTypeVector() || typeb.isTypeVector()) + return implicitConvTo(e, t); // permissive checking doesn't apply to vectors + if ((typeb.isintegral() || typeb.isfloating()) && (tb.isintegral() || tb.isfloating())) return MATCH.convert; @@ -2298,9 +2301,10 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) ae.type = tp; } } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) + else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer)) { // Convert array literal to vector type + // The Tpointer case comes from C eagerly converting Tsarray to Tpointer TypeVector tv = tb.isTypeVector(); TypeSArray tbase = tv.basetype.isTypeSArray(); assert(tbase.ty == Tsarray); diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 797f6ee0a2d..5713be1e99e 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -83,13 +83,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return ed; } - override void setScope(Scope* sc) - { - if (semanticRun > PASS.initial) - return; - ScopeDsymbol.setScope(sc); - } - override bool oneMember(Dsymbol* ps, Identifier ident) { if (isAnonymous()) diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 0132e49cbed..5c01a9f5889 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -305,22 +305,6 @@ extern (C++) final class Import : Dsymbol return this; } - override void setScope(Scope* sc) - { - Dsymbol.setScope(sc); - if (aliasdecls.length) - { - if (!mod) - importAll(sc); - - sc = sc.push(mod); - sc.visibility = visibility; - foreach (ad; aliasdecls) - ad.setScope(sc); - sc = sc.pop(); - } - } - override bool overloadInsert(Dsymbol s) { /* Allow multiple imports with the same package base, but disallow diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 5f5de6390fb..d096e437cf9 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -33,6 +33,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.file_manager; +import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; @@ -969,7 +970,7 @@ extern (C++) final class Module : Package * If this works out well, it can be extended to all modules * before any semantic() on any of them. */ - setScope(sc); // remember module scope for semantic + this.setScope(sc); // remember module scope for semantic for (size_t i = 0; i < members.length; i++) { Dsymbol s = (*members)[i]; @@ -1576,3 +1577,36 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) return buf; } + +/******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ +extern(C++) FuncDeclaration findGetMembers(ScopeDsymbol dsym) +{ + import dmd.opover : search_function; + Dsymbol s = search_function(dsym, Id.getmembers); + FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; + version (none) + { + // Finish + __gshared TypeFunction tfgetmembers; + if (!tfgetmembers) + { + Scope sc; + sc.eSink = global.errorSink; + auto parameters = new Parameters(); + Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); + parameters.push(p); + Type tret = null; + TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d); + tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction(); + } + if (fdx) + fdx = fdx.overloadExactMatch(tfgetmembers); + } + if (fdx && fdx.isVirtual()) + fdx = null; + return fdx; +} diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index a52745fcc0e..8f5a292a284 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -31,7 +31,6 @@ import dmd.dmodule; import dmd.dversion; import dmd.dscope; import dmd.dstruct; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; @@ -44,11 +43,9 @@ import dmd.lexer; import dmd.location; import dmd.mtype; import dmd.nspace; -import dmd.opover; import dmd.root.aav; import dmd.root.rmem; import dmd.rootobject; -import dmd.root.speller; import dmd.root.string; import dmd.statement; import dmd.staticassert; @@ -386,40 +383,6 @@ extern (C++) class Dsymbol : ASTNode return '`' ~ cstr.toDString() ~ "`\0"; } - final bool checkDeprecated(const ref Loc loc, Scope* sc) - { - if (global.params.useDeprecated == DiagnosticReporting.off) - return false; - if (!this.isDeprecated()) - return false; - // Don't complain if we're inside a deprecated symbol's scope - if (sc.isDeprecated()) - return false; - // Don't complain if we're inside a template constraint - // https://issues.dlang.org/show_bug.cgi?id=21831 - if (sc.flags & SCOPE.constraint) - return false; - - const(char)* message = null; - for (Dsymbol p = this; p; p = p.parent) - { - message = p.depdecl ? p.depdecl.getMessage() : null; - if (message) - break; - } - if (message) - deprecation(loc, "%s `%s` is deprecated - %s", kind, toPrettyChars, message); - else - deprecation(loc, "%s `%s` is deprecated", kind, toPrettyChars); - - if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) - ti.printInstantiationTrace(Classification.deprecation); - else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null) - ti.printInstantiationTrace(Classification.deprecation); - - return true; - } - /********************************** * Determine which Module a Dsymbol is in. */ @@ -749,113 +712,10 @@ extern (C++) class Dsymbol : ASTNode return toAlias(); } - /************************************* - * Set scope for future semantic analysis so we can - * deal better with forward references. - */ - void setScope(Scope* sc) - { - //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc); - if (!sc.nofree) - sc.setNoFree(); // may need it even after semantic() finishes - _scope = sc; - if (sc.depdecl) - depdecl = sc.depdecl; - if (!userAttribDecl) - userAttribDecl = sc.userAttribDecl; - } - void importAll(Scope* sc) { } - extern (D) final Dsymbol search_correct(Identifier ident) - { - /*************************************************** - * Search for symbol with correct spelling. - */ - extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost) - { - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - if (!seed.length) - return null; - Identifier id = Identifier.lookup(seed); - if (!id) - return null; - cost = 0; // all the same cost - Dsymbol s = this; - Module.clearCache(); - return s.search(Loc.initial, id, IgnoreErrors); - } - - if (global.gag) - return null; // don't do it for speculative compiles; too time consuming - // search for exact name first - if (auto s = this.search(Loc.initial, ident, IgnoreErrors)) - return s; - return speller!symbol_search_fp(ident.toString()); - } - - /*************************************** - * Search for identifier id as a member of `this`. - * `id` may be a template instance. - * - * Params: - * loc = location to print the error messages - * sc = the scope where the symbol is located - * id = the id of the symbol - * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` - * - * Returns: - * symbol found, NULL if not - */ - extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags) - { - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); - Dsymbol s = toAlias(); - Dsymbol sm; - if (Declaration d = s.isDeclaration()) - { - if (d.inuse) - { - .error(loc, "circular reference to `%s`", d.toPrettyChars()); - return null; - } - } - switch (id.dyncast()) - { - case DYNCAST.identifier: - sm = s.search(loc, cast(Identifier)id, flags); - break; - case DYNCAST.dsymbol: - { - // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol st = cast(Dsymbol)id; - TemplateInstance ti = st.isTemplateInstance(); - sm = s.search(loc, ti.name); - if (!sm) - return null; - sm = sm.toAlias(); - TemplateDeclaration td = sm.isTemplateDeclaration(); - if (!td) - return null; // error but handled later - ti.tempdecl = td; - if (!ti.semanticRun) - ti.dsymbolSemantic(sc); - sm = ti.toAlias(); - break; - } - case DYNCAST.type: - case DYNCAST.expression: - default: - assert(0); - } - return sm; - } - bool overloadInsert(Dsymbol s) { //printf("Dsymbol::overloadInsert('%s')\n", s.toChars()); @@ -1468,38 +1328,6 @@ public: return "ScopeDsymbol"; } - /******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - final FuncDeclaration findGetMembers() - { - Dsymbol s = search_function(this, Id.getmembers); - FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; - version (none) - { - // Finish - __gshared TypeFunction tfgetmembers; - if (!tfgetmembers) - { - Scope sc; - sc.eSink = global.errorSink; - auto parameters = new Parameters(); - Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); - parameters.push(p); - Type tret = null; - TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d); - tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction(); - } - if (fdx) - fdx = fdx.overloadExactMatch(tfgetmembers); - } - if (fdx && fdx.isVirtual()) - fdx = null; - return fdx; - } - /******************************** * Insert Dsymbol in table. * Params: diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index e0c2046bf90..15c997027da 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -205,7 +205,6 @@ public: const char *locToChars(); bool equals(const RootObject * const o) const override; bool isAnonymous() const; - bool checkDeprecated(const Loc &loc, Scope *sc); Module *getModule(); bool isCsymbol(); Module *getAccessModule(); @@ -228,7 +227,6 @@ public: virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); - virtual void setScope(Scope *sc); virtual void importAll(Scope *sc); virtual bool overloadInsert(Dsymbol *s); virtual uinteger_t size(const Loc &loc); @@ -342,7 +340,6 @@ public: bool isforwardRef() override final; static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2); const char *kind() const override; - FuncDeclaration *findGetMembers(); virtual Dsymbol *symtabInsert(Dsymbol *s); virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); bool hasStaticCtorOrDtor() override; @@ -431,3 +428,5 @@ public: void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds); Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); +bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc); +void setScope(Dsymbol *d, Scope *sc); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 430377ff874..060abfe1896 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -212,6 +212,39 @@ const(char)* getMessage(DeprecatedDeclaration dd) return dd.msgstr; } +bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc) +{ + if (global.params.useDeprecated == DiagnosticReporting.off) + return false; + if (!d.isDeprecated()) + return false; + // Don't complain if we're inside a deprecated symbol's scope + if (sc.isDeprecated()) + return false; + // Don't complain if we're inside a template constraint + // https://issues.dlang.org/show_bug.cgi?id=21831 + if (sc.flags & SCOPE.constraint) + return false; + + const(char)* message = null; + for (Dsymbol p = d; p; p = p.parent) + { + message = p.depdecl ? p.depdecl.getMessage() : null; + if (message) + break; + } + if (message) + deprecation(loc, "%s `%s` is deprecated - %s", d.kind, d.toPrettyChars, message); + else + deprecation(loc, "%s `%s` is deprecated", d.kind, d.toPrettyChars); + + if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) + ti.printInstantiationTrace(Classification.deprecation); + else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null) + ti.printInstantiationTrace(Classification.deprecation); + + return true; +} // Returns true if a contract can appear without a function body. package bool allowsContractWithoutBody(FuncDeclaration funcdecl) @@ -7811,6 +7844,37 @@ extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int f return v.result; } +Dsymbol search_correct(Dsymbol d, Identifier ident) +{ + /*************************************************** + * Search for symbol with correct spelling. + */ + Dsymbol symbol_search_fp(const(char)[] seed, out int cost) + { + /* If not in the lexer's string table, it certainly isn't in the symbol table. + * Doing this first is a lot faster. + */ + if (!seed.length) + return null; + Identifier id = Identifier.lookup(seed); + if (!id) + return null; + cost = 0; // all the same cost + Dsymbol s = d; + Module.clearCache(); + return s.search(Loc.initial, id, IgnoreErrors); + } + + if (global.gag) + return null; // don't do it for speculative compiles; too time consuming + // search for exact name first + if (auto s = d.search(Loc.initial, ident, IgnoreErrors)) + return s; + + import dmd.root.speller : speller; + return speller!symbol_search_fp(ident.toString()); +} + private extern(C++) class SearchVisitor : Visitor { alias visit = Visitor.visit; @@ -8407,3 +8471,153 @@ private extern(C++) class SearchVisitor : Visitor return setResult(s); } } +/************************************* + * Set scope for future semantic analysis so we can + * deal better with forward references. + * + * Params: + * d = dsymbol for which the scope is set + * sc = scope that is used to set the value + */ +extern(C++) void setScope(Dsymbol d, Scope* sc) +{ + scope setScopeVisitor = new SetScopeVisitor(sc); + d.accept(setScopeVisitor); +} + +private extern(C++) class SetScopeVisitor : Visitor +{ + alias visit = typeof(super).visit; + Scope* sc; + + this(Scope* sc) + { + this.sc = sc; + } + + override void visit(Dsymbol d) + { + //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", d, d.toChars(), sc, sc.stc); + if (!sc.nofree) + sc.setNoFree(); // may need it even after semantic() finishes + d._scope = sc; + if (sc.depdecl) + d.depdecl = sc.depdecl; + if (!d.userAttribDecl) + d.userAttribDecl = sc.userAttribDecl; + } + + override void visit(Import i) + { + visit(cast(Dsymbol)i); + if (i.aliasdecls.length) + { + if (!i.mod) + i.importAll(sc); + + sc = sc.push(i.mod); + sc.visibility = i.visibility; + foreach (ad; i.aliasdecls) + ad.setScope(sc); + sc = sc.pop(); + } + } + + override void visit(Nspace ns) + { + visit(cast(Dsymbol)ns); + if (ns.members) + { + assert(sc); + sc = sc.push(ns); + sc.linkage = LINK.cpp; // namespaces default to C++ linkage + sc.parent = ns; + ns.members.foreachDsymbol(s => s.setScope(sc)); + sc.pop(); + } + } + + override void visit(EnumDeclaration ed) + { + if (ed.semanticRun > PASS.initial) + return; + visit(cast(Dsymbol)ed); + } + + override void visit(AggregateDeclaration ad) + { + // Might need a scope to resolve forward references. The check for + // semanticRun prevents unnecessary setting of _scope during deferred + // setScope phases for aggregates which already finished semantic(). + // See https://issues.dlang.org/show_bug.cgi?id=16607 + if (ad.semanticRun < PASS.semanticdone) + visit(cast(Dsymbol)ad); + } + + override void visit(AttribDeclaration atr) + { + Dsymbols* d = atr.include(sc); + //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); + if (d) + { + Scope* sc2 = atr.newScope(sc); + d.foreachDsymbol( s => s.setScope(sc2) ); + if (sc2 != sc) + sc2.pop(); + } + } + + override void visit(DeprecatedDeclaration dd) + { + //printf("DeprecatedDeclaration::setScope() %p\n", this); + if (dd.decl) + visit(cast(Dsymbol)dd); // for forward reference + visit(cast(AttribDeclaration)dd); + } + + override void visit(CPPMangleDeclaration cppmd) + { + if (cppmd.decl) + visit(cast(Dsymbol)cppmd); // for forward reference + visit(cast(AttribDeclaration)cppmd); + } + + override void visit(AnonDeclaration anond) + { + if (anond.decl) + visit(cast(Dsymbol)anond); // for forward reference + visit(cast(AttribDeclaration)anond); + } + + override void visit(ConditionalDeclaration condd) + { + condd.include(sc).foreachDsymbol( s => s.setScope(sc) ); + } + + override void visit(StaticIfDeclaration sid) + { + // do not evaluate condition before semantic pass + // But do set the scope, in case we need it for forward referencing + visit(cast(Dsymbol)sid); // for forward reference + } + + override void visit(StaticForeachDeclaration sfd) + { + // do not evaluate condition before semantic pass + // But do set the scope, in case we need it for forward referencing + visit(cast(Dsymbol)sfd); // for forward reference + } + + override void visit(MixinDeclaration md) + { + visit(cast(Dsymbol)md); + } + + override void visit(UserAttributeDeclaration uad) + { + //printf("UserAttributeDeclaration::setScope() %p\n", this); + if (uad.decl) + visit(cast(Dsymbol)uad); + visit(cast(AttribDeclaration)uad); + } +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 037e0d01196..326d66364b8 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -7515,7 +7515,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("\t-. mi = %s\n", mi.toPrettyChars()); - assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module"); + if (memberOf) // already appended to some module + { + assert(mi.isRoot(), "can only re-append to a root module"); + if (memberOf.isRoot()) + return null; // no need to move to another root module + } Dsymbols* a = mi.members; a.push(this); diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index e17e8cf5b0a..5f91ead9e17 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -46,7 +46,6 @@ public: bool inuse(bool v); EnumDeclaration *syntaxCopy(Dsymbol *s) override; - void setScope(Scope *sc) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; Type *getType() override; const char *kind() const override; diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index e25fc84234e..f928b08503a 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -2343,7 +2343,7 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) VarDeclaration[10] tmp = void; size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.length : 0); - import dmd.common.string : SmallBuffer; + import dmd.common.smallbuffer : SmallBuffer; auto sb = SmallBuffer!VarDeclaration(dim, tmp[]); VarDeclaration[] array = sb[]; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index e6b90183b51..1664bf22dca 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -4387,7 +4387,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0); if (!e) { - error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars()); + error(cle.loc, "cannot convert initializer `%s` to expression", toChars(init)); return setError(); } result = e; diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index ac2dda3e89f..0944ade4c28 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -1968,6 +1968,10 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, v._init.initializerToBuffer(buf, &hgs); } + const commentIt = hgs.importcHdr && isSpecialCName(v.ident); + if (commentIt) + buf.writestring("/+"); + if (anywritten) { buf.writestring(", "); @@ -2000,8 +2004,31 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, buf.writestring(" = "); vinit(v); } + if (commentIt) + buf.writestring("+/"); } +/************************************* + * The names __DATE__, __TIME__,__EOF__, __VENDOR__, __TIMESTAMP__, __VERSION__ + * are special to the D lexer and cannot be used as D source variable names. + * Params: + * id = name to check + * Returns: + * true if special C name + */ +private bool isSpecialCName(Identifier id) +{ + auto s = id.toString(); + if (s.length >= 7 && s[0] == '_' && s[1] == '_' && + (id == Id.DATE || + id == Id.TIME || + id == Id.EOFX || + id == Id.VENDOR || + id == Id.TIMESTAMP || + id == Id.VERSIONX)) + return true; + return false; +} /********************************************* * Print expression to buffer. diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index aeb3621f1eb..624cd7406a3 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -43,7 +43,6 @@ public: Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees void importAll(Scope *sc) override; Dsymbol *toAlias() override; - void setScope(Scope* sc) override; bool overloadInsert(Dsymbol *s) override; Import *isImport() override { return this; } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 76c2d8916b0..6d31f956c8e 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -199,7 +199,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ uint length; const(uint) amax = 0x80000000; bool errors = false; - //printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i); + //printf("ArrayInitializer::semantic(%s), ai: %s\n", t.toChars(), toChars(i)); if (i.sem) // if semantic() already run { return i; @@ -600,7 +600,17 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Initializer visitC(CInitializer ci) { - //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), ci.toChars()); + //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), toChars(ci)); + static if (0) + if (auto ts = tx.isTypeStruct()) + { + import dmd.common.outbuffer; + OutBuffer buf; + HdrGenStage hgs; + toCBuffer(ts.sym, buf, hgs); + printf("%s\n", buf.peekChars()); + } + /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer */ t = t.toBasetype(); @@ -794,6 +804,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ for (size_t index = 0; index < ci.initializerList.length; ) { CInitializer cprev; + size_t indexprev; L1: DesigInit di = ci.initializerList[index]; Designators* dlist = di.designatorList; @@ -827,6 +838,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ /* The peeling didn't work, so unpeel it */ ci = cprev; + index = indexprev; di = ci.initializerList[index]; goto L2; } @@ -837,12 +849,14 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { if (fieldi == nfields) break; - if (index == 0 && ci.initializerList.length == 1 && di.initializer.isCInitializer()) + if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer()) { /* Try peeling off this set of { } and see if it works */ cprev = ci; ci = di.initializer.isCInitializer(); + indexprev = index; + index = 0; goto L1; } diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 92efc1656da..cab0b0a4c1b 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -169,3 +169,4 @@ struct ModuleDeclaration }; extern void getLocalClasses(Module* mod, Array& aclasses); +FuncDeclaration *findGetMembers(ScopeDsymbol *dsym); diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d index a49e0bf0cc2..22c6e63a465 100644 --- a/gcc/d/dmd/nspace.d +++ b/gcc/d/dmd/nspace.d @@ -85,20 +85,6 @@ extern (C++) final class Nspace : ScopeDsymbol return ns; } - override void setScope(Scope* sc) - { - ScopeDsymbol.setScope(sc); - if (members) - { - assert(sc); - sc = sc.push(this); - sc.linkage = LINK.cpp; // namespaces default to C++ linkage - sc.parent = this; - members.foreachDsymbol(s => s.setScope(sc)); - sc.pop(); - } - } - override bool hasPointers() { //printf("Nspace::hasPointers() %s\n", toChars()); diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index 7d30402c595..701cc935eb5 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -21,7 +21,6 @@ class Nspace final : public ScopeDsymbol public: Expression *identExp; Nspace *syntaxCopy(Dsymbol *s) override; - void setScope(Scope *sc) override; bool hasPointers() override; void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index f9d174ab14f..b6f30b93f47 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -8428,7 +8428,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.TemplateParameters* tpl = null; nextToken(); - if (token.value == TOK.leftParenthesis) + if (token.value != TOK.leftParenthesis) + { + error("expected `(` following `is`, not `%s`", token.toChars()); + goto Lerr; + } + else { nextToken(); if (token.value == TOK.identifier && peekNext() == TOK.leftParenthesis) @@ -8476,11 +8481,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else check(TOK.rightParenthesis); } - else - { - error("`type identifier : specialization` expected following `is`"); - goto Lerr; - } e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl); break; } diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index 1fb105682ea..fdf13d4e8b0 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -24,7 +24,7 @@ import dmd.root.rmem; import dmd.root.string; import dmd.common.file; -import dmd.common.string; +import dmd.common.smallbuffer; nothrow: diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 631c08c44d2..8f31f212048 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -37,7 +37,7 @@ version (Windows) import core.sys.windows.windef; import core.sys.windows.winnls; - import dmd.common.string : extendedPathThen; + import dmd.common.smallbuffer : extendedPathThen; extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc; extern (Windows) void SetLastError(DWORD) nothrow @nogc; @@ -1177,7 +1177,7 @@ version(Windows) */ private auto toWStringzThen(alias F)(const(char)[] str) nothrow { - import dmd.common.string : SmallBuffer, toWStringz; + import dmd.common.smallbuffer : SmallBuffer, toWStringz; if (!str.length) return F(""w.ptr); diff --git a/gcc/d/dmd/root/speller.d b/gcc/d/dmd/root/speller.d index b646bdda0cc..7ad08b7216e 100644 --- a/gcc/d/dmd/root/speller.d +++ b/gcc/d/dmd/root/speller.d @@ -42,7 +42,7 @@ private: import core.stdc.stdlib; import core.stdc.string; -import dmd.common.string : SmallBuffer; +import dmd.common.smallbuffer : SmallBuffer; enum isSearchFunction(alias fun) = is(searchFunctionType!fun); alias searchFunctionType(alias fun) = typeof(() {int x; return fun("", x);}()); diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d index 8b204ab4cad..5ee81a9b63d 100644 --- a/gcc/d/dmd/root/string.d +++ b/gcc/d/dmd/root/string.d @@ -69,7 +69,7 @@ The return value of `T` auto toCStringThen(alias dg)(const(char)[] src) nothrow { import dmd.root.rmem : mem; - import dmd.common.string : SmallBuffer; + import dmd.common.smallbuffer : SmallBuffer; const len = src.length + 1; char[512] small = void; diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 8795002cd15..2063a954b99 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -372,6 +372,64 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb pt = t.merge(); } +/*************************************** + * Search for identifier id as a member of `this`. + * `id` may be a template instance. + * + * Params: + * loc = location to print the error messages + * sc = the scope where the symbol is located + * id = the id of the symbol + * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` + * + * Returns: + * symbol found, NULL if not + */ +private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); + Dsymbol s = dsym.toAlias(); + Dsymbol sm; + if (Declaration d = s.isDeclaration()) + { + if (d.inuse) + { + .error(loc, "circular reference to `%s`", d.toPrettyChars()); + return null; + } + } + switch (id.dyncast()) + { + case DYNCAST.identifier: + sm = s.search(loc, cast(Identifier)id, flags); + break; + case DYNCAST.dsymbol: + { + // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol st = cast(Dsymbol)id; + TemplateInstance ti = st.isTemplateInstance(); + sm = s.search(loc, ti.name); + if (!sm) + return null; + sm = sm.toAlias(); + TemplateDeclaration td = sm.isTemplateDeclaration(); + if (!td) + return null; // error but handled later + ti.tempdecl = td; + if (!ti.semanticRun) + ti.dsymbolSemantic(sc); + sm = ti.toAlias(); + break; + } + case DYNCAST.type: + case DYNCAST.expression: + default: + assert(0); + } + return sm; +} + /****************************************** * We've mistakenly parsed `t` as a type. * Redo `t` as an Expression only if there are no type modifiers. diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index e3c1ef9f82e..250743e8dbe 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -503,7 +503,7 @@ layout_moduleinfo_fields (Module *decl, tree type) if (decl->sshareddtor) layout_moduleinfo_field (ptr_type_node, type, offset); - if (decl->findGetMembers ()) + if (findGetMembers (decl)) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->sictor) @@ -571,7 +571,7 @@ layout_moduleinfo (Module *decl) aimports_dim--; } - sgetmembers = decl->findGetMembers (); + sgetmembers = findGetMembers (decl); size_t flags = 0; if (decl->sctor) 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 9de436b0119..a170b77b88c 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 @@ -7,7 +7,7 @@ fail_compilation/misc_parser_err_cov1.d(30): Error: basic type expected, not `)` fail_compilation/misc_parser_err_cov1.d(31): Error: `__traits(identifier, args...)` expected fail_compilation/misc_parser_err_cov1.d(31): Error: semicolon expected following auto declaration, not `o` 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(32): Error: expected `(` following `is`, not `;` 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(35): Error: `key:value` expected for associative array literal diff --git a/gcc/testsuite/gdc.test/runnable/dbitfields.d b/gcc/testsuite/gdc.test/runnable/dbitfields.d index 0d1877a7bfd..aa154c7bbb2 100644 --- a/gcc/testsuite/gdc.test/runnable/dbitfields.d +++ b/gcc/testsuite/gdc.test/runnable/dbitfields.d @@ -173,6 +173,39 @@ static assert(test7u() == 1); static assert(test7s() == -1); static assert(test7s2() == -2); +/******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24257 + +struct S24257 +{ + uint : 15; + bool done : 1; +} + +bool advance() +{ + S24257 n; + n.done = false; + n.done = true; + return n.done; +} + +bool retard() +{ + S24257 n; + n.done = true; + n.done = false; + return n.done; +} + +static assert(advance() == true); + +void test24257() +{ + assert(advance() == true); + assert(retard() == false); +} + /******************************************/ int main() @@ -184,6 +217,7 @@ int main() test5(); test6(); test7(); + test24257(); return 0; } diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index aa0062c10eb..5edcee1c84d 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -ff57fec51558013b25cadb7e83da9f4675915d56 +2bbf64907cbbb483d003e0a8fcf8b502e4883799 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/core/cpuid.d b/libphobos/libdruntime/core/cpuid.d index 9c5735728b5..62edbac34f3 100644 --- a/libphobos/libdruntime/core/cpuid.d +++ b/libphobos/libdruntime/core/cpuid.d @@ -628,16 +628,17 @@ void getAMDcacheinfo() if (max_extended_cpuid >= 0x8000_0006) { // AMD K6-III or K6-2+ or later. - ubyte numcores = 1; + uint numcores = 1; if (max_extended_cpuid >= 0x8000_0008) { + // read the number of physical cores (minus 1) from the 8 lowest ECX bits version (GNU_OR_LDC) asm pure nothrow @nogc { "cpuid" : "=a" (dummy), "=c" (numcores) : "a" (0x8000_0008) : "ebx", "edx"; } else asm pure nothrow @nogc { mov EAX, 0x8000_0008; cpuid; - mov numcores, CL; + mov numcores, ECX; } - ++numcores; + numcores = (numcores & 0xFF) + 1; if (numcores>cpuFeatures.maxCores) cpuFeatures.maxCores = numcores; } diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 1b20d58c1e2..3c0e1b28d31 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -17bafda797296e04f40f16a9660e5a9685392db4 +b64bfbf911fcd1675ae9792545649c9d45bb907e The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index 68979057f54..4526aa22bc0 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -2895,94 +2895,100 @@ if (isForwardRange!R1 && ifTestable!(typeof(haystack.front), unaryFun!pred)) assert(findSkip!isWhite(s) == 2); } +private struct FindSplitResult(ubyte emptyRangeIndex, Types...) +{ + this(Types vals) + { + asTuple = typeof(asTuple)(vals); + } + void opAssign(typeof(asTuple) rhs) + { + asTuple = rhs; + } + Tuple!Types asTuple; + alias asTuple this; + + static if (hasConstEmptyMember!(typeof(asTuple[emptyRangeIndex]))) + { + bool opCast(T : bool)() const => !asTuple[emptyRangeIndex].empty; + } + else + { + bool opCast(T : bool)() => !asTuple[emptyRangeIndex].empty; + } +} + /** These functions find the first occurrence of `needle` in `haystack` and then split `haystack` as follows. -`findSplit` returns a tuple `result` containing $(I three) ranges. `result[0]` -is the portion of `haystack` before `needle`, `result[1]` is the portion of -`haystack` that matches `needle`, and `result[2]` is the portion of `haystack` -after the match. If `needle` was not found, `result[0]` comprehends `haystack` +$(PANEL +`findSplit` returns a tuple `result` containing $(I three) ranges. +$(UL +$(LI `result[0]` is the portion of `haystack` before `needle`) +$(LI `result[1]` is the portion of +`haystack` that matches `needle`) +$(LI `result[2]` is the portion of `haystack` +after the match.) +) +If `needle` was not found, `result[0]` comprehends `haystack` entirely and `result[1]` and `result[2]` are empty. -`findSplitBefore` returns a tuple `result` containing two ranges. `result[0]` is -the portion of `haystack` before `needle`, and `result[1]` is the balance of -`haystack` starting with the match. If `needle` was not found, `result[0]` +`findSplitBefore` returns a tuple `result` containing two ranges. +$(UL +$(LI `result[0]` is the portion of `haystack` before `needle`) +$(LI `result[1]` is the balance of `haystack` starting with the match.) +) +If `needle` was not found, `result[0]` comprehends `haystack` entirely and `result[1]` is empty. `findSplitAfter` returns a tuple `result` containing two ranges. -`result[0]` is the portion of `haystack` up to and including the -match, and `result[1]` is the balance of `haystack` starting -after the match. If `needle` was not found, `result[0]` is empty +$(UL +$(LI `result[0]` is the portion of `haystack` up to and including the +match) +$(LI `result[1]` is the balance of `haystack` starting +after the match.) +) +If `needle` was not found, `result[0]` is empty and `result[1]` is `haystack`. - +) +$(P In all cases, the concatenation of the returned ranges spans the entire `haystack`. If `haystack` is a random-access range, all three components of the tuple have the same type as `haystack`. Otherwise, `haystack` must be a $(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). +the type of `result[0]` (and `result[1]` for `findSplit`) is the same as +the result of $(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. - needle = What to look for. + pred = Predicate to compare 2 elements. + haystack = The forward range to search. + needle = The forward range to look for. Returns: -A sub-type of `Tuple!()` of the split portions of `haystack` (see above for -details). This sub-type of `Tuple!()` has `opCast` defined for `bool`. This -`opCast` returns `true` when the separating `needle` was found -and `false` otherwise. +A sub-type of $(REF Tuple, std, typecons) of the split portions of `haystack` (see above for +details). This sub-type of `Tuple` defines `opCast!bool`, which +returns `true` when the separating `needle` was found and `false` otherwise. See_Also: $(LREF find) */ auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2) { - static struct Result(S1, S2) if (isForwardRange!S1 && - isForwardRange!S2) - { - this(S1 pre, S1 separator, S2 post) - { - asTuple = typeof(asTuple)(pre, separator, post); - } - void opAssign(typeof(asTuple) rhs) - { - asTuple = rhs; - } - Tuple!(S1, S1, S2) asTuple; - static if (hasConstEmptyMember!(typeof(asTuple[1]))) - { - bool opCast(T : bool)() const - { - return !asTuple[1].empty; - } - } - else - { - bool opCast(T : bool)() - { - return !asTuple[1].empty; - } - } - alias asTuple this; - } - static if (isSomeString!R1 && isSomeString!R2 || (isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && hasLength!R2)) { auto balance = find!pred(haystack, needle); immutable pos1 = haystack.length - balance.length; immutable pos2 = balance.empty ? pos1 : pos1 + needle.length; - return Result!(typeof(haystack[0 .. pos1]), - typeof(haystack[pos2 .. haystack.length]))(haystack[0 .. pos1], - haystack[pos1 .. pos2], - haystack[pos2 .. haystack.length]); + alias Slice = typeof(haystack[0 .. pos1]); + return FindSplitResult!(1, Slice, Slice, Slice)( + haystack[0 .. pos1], haystack[pos1 .. pos2], haystack[pos2 .. haystack.length]); } else { @@ -3011,10 +3017,11 @@ if (isForwardRange!R1 && isForwardRange!R2) { pos1 = pos2; } - return Result!(typeof(takeExactly(original, pos1)), - typeof(h))(takeExactly(original, pos1), - takeExactly(haystack, pos2 - pos1), - h); + return FindSplitResult!(1, + typeof(takeExactly(original, pos1)), + typeof(takeExactly(original, pos1)), typeof(h))( + takeExactly(original, pos1), + takeExactly(haystack, pos2 - pos1), h); } } @@ -3022,43 +3029,14 @@ if (isForwardRange!R1 && isForwardRange!R2) auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2) { - static struct Result(S1, S2) if (isForwardRange!S1 && - isForwardRange!S2) - { - this(S1 pre, S2 post) - { - asTuple = typeof(asTuple)(pre, post); - } - void opAssign(typeof(asTuple) rhs) - { - asTuple = rhs; - } - Tuple!(S1, S2) asTuple; - static if (hasConstEmptyMember!(typeof(asTuple[1]))) - { - bool opCast(T : bool)() const - { - return !asTuple[1].empty; - } - } - else - { - bool opCast(T : bool)() - { - return !asTuple[1].empty; - } - } - alias asTuple this; - } - static if (isSomeString!R1 && isSomeString!R2 || (isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2)) { auto balance = find!pred(haystack, needle); immutable pos = haystack.length - balance.length; - return Result!(typeof(haystack[0 .. pos]), - typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos], - haystack[pos .. haystack.length]); + return FindSplitResult!(1, + typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))( + haystack[0 .. pos], haystack[pos .. haystack.length]); } else { @@ -3088,9 +3066,9 @@ if (isForwardRange!R1 && isForwardRange!R2) pos1 = pos2; haystack = h; } - return Result!(typeof(takeExactly(original, pos1)), - typeof(haystack))(takeExactly(original, pos1), - haystack); + return FindSplitResult!(1, + typeof(takeExactly(original, pos1)), typeof(haystack))( + takeExactly(original, pos1), haystack); } } @@ -3098,47 +3076,19 @@ if (isForwardRange!R1 && isForwardRange!R2) auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2) { - static struct Result(S1, S2) if (isForwardRange!S1 && - isForwardRange!S2) - { - this(S1 pre, S2 post) - { - asTuple = typeof(asTuple)(pre, post); - } - void opAssign(typeof(asTuple) rhs) - { - asTuple = rhs; - } - Tuple!(S1, S2) asTuple; - static if (hasConstEmptyMember!(typeof(asTuple[1]))) - { - bool opCast(T : bool)() const - { - return !asTuple[0].empty; - } - } - else - { - bool opCast(T : bool)() - { - return !asTuple[0].empty; - } - } - alias asTuple this; - } - static if (isSomeString!R1 && isSomeString!R2 || isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2) { auto balance = find!pred(haystack, needle); immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length; - return Result!(typeof(haystack[0 .. pos]), - typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos], - haystack[pos .. haystack.length]); + return FindSplitResult!(0, + typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))( + haystack[0 .. pos], haystack[pos .. haystack.length]); } else { import std.range : takeExactly; + alias Res = FindSplitResult!(0, typeof(takeExactly(haystack, 0)), typeof(haystack)); auto original = haystack.save; auto h = haystack.save; auto n = needle.save; @@ -3148,9 +3098,7 @@ if (isForwardRange!R1 && isForwardRange!R2) if (h.empty) { // Failed search - return Result!(typeof(takeExactly(original, 0)), - typeof(original))(takeExactly(original, 0), - original); + return Res(takeExactly(original, 0), original); } if (binaryFun!pred(h.front, n.front)) { @@ -3166,9 +3114,7 @@ if (isForwardRange!R1 && isForwardRange!R2) pos2 = ++pos1; } } - return Result!(typeof(takeExactly(original, pos2)), - typeof(h))(takeExactly(original, pos2), - h); + return Res(takeExactly(original, pos2), h); } } @@ -3185,12 +3131,12 @@ if (isForwardRange!R1 && isForwardRange!R2) } else assert(0); - // works with const aswell - if (const split = "dlang-rocks".findSplit("-")) + // findSplitBefore returns 2 ranges + if (const split = [2, 3, 2, 3, 4, 1].findSplitBefore!"a > b"([2, 2])) { - assert(split[0] == "dlang"); - assert(split[1] == "-"); - assert(split[2] == "rocks"); + assert(split[0] == [2, 3, 2]); + // [3, 4] each greater than [2, 2] + assert(split[1] == [3, 4, 1]); } else assert(0); } diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 4248e4b9d44..3a533814894 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -4848,8 +4848,9 @@ private S textImpl(S, U...)(U args) static foreach (arg; args) { static if ( - isSomeChar!(typeof(arg)) || isSomeString!(typeof(arg)) || - ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) ) + isSomeChar!(typeof(arg)) + || isSomeString!(typeof(arg)) + || ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) ) ) app.put(arg); else static if ( diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d index 1b4f233d94a..c985015a7af 100644 --- a/libphobos/src/std/range/package.d +++ b/libphobos/src/std/range/package.d @@ -1025,7 +1025,18 @@ if (Ranges.length > 0 && } else { - @property bool empty() => frontIndex >= backIndex; + @property bool empty() + { + if (frontIndex == 0) + { + // special handling: we might be in Range.init state! + // For instance, `format!"%s"` uses Range.init to ensure + // that formatting is possible. + // In that case, we must still behave in an internally consistent way. + return source[0].empty; + } + return frontIndex >= backIndex; + } } static if (allSatisfy!(isForwardRange, R)) @@ -1705,6 +1716,17 @@ pure @safe nothrow @nogc unittest } } +/// https://issues.dlang.org/show_bug.cgi?id=24243 +pure @safe nothrow unittest +{ + import std.algorithm.iteration : filter; + + auto range = chain([2], [3].filter!"a"); + + // This might happen in format!"%s"(range), for instance. + assert(typeof(range).init.empty); +} + /** Choose one of two ranges at runtime depending on a Boolean condition. diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 9903d6c28c3..fec7e5f78ac 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -7706,6 +7706,12 @@ public: return this.tupleof == other.tupleof; } + // Define a default toHash to allow AA usage + size_t toHash() const @trusted + { + return hashOf(slen_, hashOf(small_)); + } + /++ True if this object contains valid extended grapheme cluster. Decoding primitives of this module always return a valid `Grapheme`. @@ -7907,6 +7913,12 @@ static assert(Grapheme.sizeof == size_t.sizeof*4); assert(equal(h[], iota(cast(int)'A', cast(int)'Z'+1))); } +// ensure Grapheme can be used as an AA key. +@safe unittest +{ + int[Grapheme] aa; +} + /++ $(P Does basic case-insensitive comparison of `r1` and `r2`. This function uses simpler comparison rule thus achieving better performance