From patchwork Tue Nov 21 14:08:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1866847 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gdcproject.org header.i=@gdcproject.org header.a=rsa-sha256 header.s=MBO0001 header.b=IwqHEU3G; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SZR8j4nBfz1yRV for ; Wed, 22 Nov 2023 01:09:57 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D41B33858407 for ; Tue, 21 Nov 2023 14:09:51 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [IPv6:2001:67c:2050:0:465::201]) by sourceware.org (Postfix) with ESMTPS id BD7023858D37 for ; Tue, 21 Nov 2023 14:09:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BD7023858D37 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 BD7023858D37 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:67c:2050:0:465::201 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700575749; cv=none; b=ihaeXhM6RDq8p+PKhQqcT9pEDWWb1SRbZDBgzJIr0n+tm6eELeAZLDp92Zidwe7b1E+h7VzeW1BkLd00UiPiaAeL3o2751kV9Zojj3gh9SmRyM1a7XucHdEpjWSHnZrsg/Rrj6Cy6XZGMko+dyHOh4+Bz/nKaY5un9mg8wzBo0c= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700575749; c=relaxed/simple; bh=hkwK5xK48Me1jk4J4oHWiR+7gNNwWzZYnIGatoVap4I=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=vdPv09pC5e1ETIvrga54GHM/5W7kjajxm25sFwEJmZauwTyPIIC5WIRQAQyCCZ17Ryk2ENs1iOAWtZlEUL3a9080QEHiF/VQGOo34bdNhRcDZ7vFkSsNIXSN7M2/fJ+PECMz8eD/bCXGDarU9vq0ht6p/yPDOthROgVpsYi7cZ8= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (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-201.mailbox.org (Postfix) with ESMTPS id 4SZR7Z3hzYz9stf; Tue, 21 Nov 2023 15:08:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gdcproject.org; s=MBO0001; t=1700575738; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eg/nAYhmwJYtlaT4GUqRNbaZUCW6J4uApxaoln8ITGU=; b=IwqHEU3GvU5m/gg2g8TGVLYIYh9kWPeUMSdEhhFz3hGDdRzDM8ZUamG79SQ3xkh3HqhUae n7DVKpAuHuLtYA1mlYdj23zDH1ryveMKXD41cY8sfs7B9aUViwqPzB/8ckO7d/D+peIogR dQx5R5qZQmt8NPg6s7QnoIgDWdXhxC+SbBemnAc6jhcvppR/x58kUNXatzHey/Q4tbvwcG FQEGnGqUaPlr78BGYRwnOI+FpZYfvBsaOE6W5ILgn1bg9myMMdzq2bLD7/EnBNJZO1JsdX ymPMfhoRMDZ/dn90nTM3BKDGDsYrSUJBsGhHbq7Ib6AvTSFouxkzgXJ8k6CGRQ== From: Iain Buclaw To: gcc-patches@gcc.gnu.org Cc: Iain Buclaw Subject: [committed] d: Merge upstream dmd ff57fec515, druntime ff57fec515, phobos 17bafda79. Date: Tue, 21 Nov 2023 15:08:27 +0100 Message-Id: <20231121140827.109435-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4SZR7Z3hzYz9stf X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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+incoming=patchwork.ozlabs.org@gcc.gnu.org This patch merges the D front-end and runtime library with upstream dmd ff57fec515, and the standard library with phobos 17bafda79. Synchronizing with the upstream release candidate of v2.106.0. D front-end changes: - Import dmd v2.106.0-rc.1. - New'ing multi-dimensional arrays are now are converted to a single template call `_d_newarraymTX'. D runtime changes: - Import druntime v2.106.0-rc.1. Phobos changes: - Import phobos v2.106.0-rc.1. Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd ff57fec515. * dmd/VERSION: Bump version to v2.106.0-rc.1. * expr.cc (ExprVisitor::visit (CatAssignExp *)): Update for new front-end interface. (ExprVisitor::visit (NewExp *)): Likewise. * runtime.def (NEWARRAYMTX): Remove. (NEWARRAYMITX): Remove. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime ff57fec515. * src/MERGE: Merge upstream phobos 17bafda79. gcc/testsuite/ChangeLog: * gdc.dg/asm1.d: Adjust expected diagnostic. --- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/aggregate.d | 2 +- gcc/d/dmd/aggregate.h | 2 - gcc/d/dmd/astenums.d | 1 + gcc/d/dmd/attrib.d | 111 +- gcc/d/dmd/attrib.h | 7 - gcc/d/dmd/common/outbuffer.d | 6 +- gcc/d/dmd/cparse.d | 7 + gcc/d/dmd/ctfeexpr.d | 55 +- gcc/d/dmd/dcast.d | 7 + gcc/d/dmd/dclass.d | 67 +- gcc/d/dmd/declaration.d | 12 - gcc/d/dmd/declaration.h | 1 - gcc/d/dmd/denum.d | 32 - gcc/d/dmd/dimport.d | 40 - gcc/d/dmd/dmodule.d | 65 +- gcc/d/dmd/dscope.d | 22 +- gcc/d/dmd/dstruct.d | 17 - gcc/d/dmd/dsymbol.d | 475 +-------- gcc/d/dmd/dsymbol.h | 16 +- gcc/d/dmd/dsymbolsem.d | 986 +++++++++++++++++- gcc/d/dmd/dtemplate.d | 7 +- gcc/d/dmd/dtoh.d | 1 + gcc/d/dmd/dversion.d | 75 -- gcc/d/dmd/enum.h | 2 - gcc/d/dmd/escape.d | 22 +- gcc/d/dmd/expression.d | 4 +- gcc/d/dmd/expression.h | 4 +- gcc/d/dmd/expressionsem.d | 160 +-- gcc/d/dmd/func.d | 61 +- gcc/d/dmd/hdrgen.d | 21 +- gcc/d/dmd/id.d | 3 +- gcc/d/dmd/import.h | 2 - gcc/d/dmd/importc.d | 1 + gcc/d/dmd/init.d | 29 + gcc/d/dmd/init.h | 10 + gcc/d/dmd/initsem.d | 19 + gcc/d/dmd/lambdacomp.d | 1 + gcc/d/dmd/module.h | 2 - gcc/d/dmd/nogc.d | 16 +- gcc/d/dmd/nspace.d | 43 - gcc/d/dmd/nspace.h | 2 - gcc/d/dmd/opover.d | 1 + gcc/d/dmd/optimize.d | 12 +- gcc/d/dmd/parse.d | 67 +- gcc/d/dmd/parsetimevisitor.d | 1 + gcc/d/dmd/scope.h | 5 + gcc/d/dmd/semantic3.d | 2 +- gcc/d/dmd/statementsem.d | 4 +- gcc/d/dmd/staticassert.d | 5 - gcc/d/dmd/staticassert.h | 1 - gcc/d/dmd/traits.d | 82 +- gcc/d/dmd/typesem.d | 2 +- gcc/d/dmd/version.h | 2 - gcc/d/dmd/visitor.h | 2 + gcc/d/expr.cc | 99 +- gcc/d/runtime.def | 7 - gcc/testsuite/gdc.dg/asm1.d | 2 +- .../gdc.test/compilable/issue16020.d | 7 +- gcc/testsuite/gdc.test/compilable/nogc.d | 9 + .../gdc.test/fail_compilation/b20011.d | 8 +- .../gdc.test/fail_compilation/const_ctor.d | 26 + .../gdc.test/fail_compilation/ctor_attr.d | 29 + .../gdc.test/fail_compilation/diag10415.d | 2 +- .../gdc.test/fail_compilation/diag10862.d | 4 +- .../gdc.test/fail_compilation/diag10926.d | 2 +- .../gdc.test/fail_compilation/diag14102.d | 8 +- .../gdc.test/fail_compilation/diag4596.d | 4 +- .../gdc.test/fail_compilation/diag8101b.d | 2 +- .../fail_compilation/dip1000_deprecation.d | 56 - .../gdc.test/fail_compilation/fail10299.d | 2 +- .../gdc.test/fail_compilation/fail13116.d | 4 +- .../gdc.test/fail_compilation/fail13336a.d | 2 +- .../gdc.test/fail_compilation/fail13336b.d | 4 +- .../gdc.test/fail_compilation/fail17491.d | 16 +- .../gdc.test/fail_compilation/fail21243.d | 18 +- .../gdc.test/fail_compilation/fail217.d | 2 +- .../gdc.test/fail_compilation/fail24224.d | 22 + .../gdc.test/fail_compilation/fail6795.d | 12 +- .../gdc.test/fail_compilation/fail7424d.d | 2 +- .../gdc.test/fail_compilation/fail7424e.d | 2 +- .../gdc.test/fail_compilation/fail7424f.d | 2 +- .../gdc.test/fail_compilation/fail7424i.d | 2 +- .../gdc.test/fail_compilation/fail7603a.d | 2 +- .../gdc.test/fail_compilation/fail7603b.d | 2 +- .../gdc.test/fail_compilation/fail7603c.d | 2 +- .../gdc.test/fail_compilation/fail9537.d | 2 +- .../gdc.test/fail_compilation/fail9773.d | 2 +- .../gdc.test/fail_compilation/fail9891.d | 2 +- .../gdc.test/fail_compilation/fail_arrayop2.d | 12 +- .../gdc.test/fail_compilation/fail_scope.d | 8 +- .../gdc.test/fail_compilation/ice10419.d | 2 +- .../gdc.test/fail_compilation/ice12841.d | 4 +- .../gdc.test/fail_compilation/ice13459.d | 2 +- .../gdc.test/fail_compilation/ice20264.d | 2 +- .../gdc.test/fail_compilation/ice9284.d | 2 +- .../fail_compilation/immutable_ctor.d | 19 + .../gdc.test/fail_compilation/issue16020.d | 8 +- .../gdc.test/fail_compilation/issue20704.d | 8 +- .../gdc.test/fail_compilation/test16381.d | 2 +- .../gdc.test/fail_compilation/test22048.d | 2 +- .../gdc.test/fail_compilation/test24157.d | 4 +- .../gdc.test/fail_compilation/test24159.d | 14 + .../fail_compilation/testrvaluecpctor.d | 4 +- .../gdc.test/fail_compilation/tolvalue.d | 48 + .../gdc.test/fail_compilation/vector_cast.d | 13 + gcc/testsuite/gdc.test/runnable/staticaa.d | 15 +- gcc/testsuite/gdc.test/runnable/test24184.d | 30 + libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/cpuid.d | 23 +- .../core/internal/array/appending.d | 83 +- .../core/internal/array/construction.d | 108 ++ libphobos/libdruntime/core/internal/atomic.d | 5 +- .../core/internal/gc/impl/conservative/gc.d | 6 +- libphobos/libdruntime/core/internal/newaa.d | 31 +- libphobos/libdruntime/core/stdc/fenv.d | 8 +- libphobos/libdruntime/core/stdc/stdarg.d | 6 + libphobos/libdruntime/core/sync/event.d | 12 +- libphobos/libdruntime/core/sys/elf/package.d | 2 + .../libdruntime/core/sys/linux/sys/auxv.d | 17 + .../libdruntime/core/sys/linux/sys/mman.d | 1 + libphobos/libdruntime/core/thread/fiber.d | 44 +- libphobos/libdruntime/core/vararg.d | 7 + libphobos/libdruntime/object.d | 14 +- libphobos/libdruntime/rt/aaA.d | 25 +- libphobos/libdruntime/rt/lifetime.d | 92 -- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/iteration.d | 58 +- libphobos/src/std/algorithm/searching.d | 210 ++-- libphobos/src/std/array.d | 4 +- libphobos/src/std/logger/package.d | 2 +- libphobos/src/std/math/hardware.d | 58 ++ 133 files changed, 2264 insertions(+), 1728 deletions(-) create mode 100644 gcc/testsuite/gdc.test/fail_compilation/const_ctor.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d delete mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24224.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24159.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/tolvalue.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/vector_cast.d create mode 100644 gcc/testsuite/gdc.test/runnable/test24184.d diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 0cf9b5fd4a8..aa0062c10eb 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -65a3da148c0c700a6c928f0e13799b2a7d34fcbe +ff57fec51558013b25cadb7e83da9f4675915d56 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 b272d4bbe5c..41fdc654b14 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.106.0-beta.1 +v2.106.0-rc.1 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index d42ef951085..307bb0171c4 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -663,7 +663,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol */ extern (D) final Dsymbol searchCtor() { - auto s = search(Loc.initial, Id.ctor); + auto s = this.search(Loc.initial, Id.ctor); if (s) { if (!(s.isCtorDeclaration() || diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 58a0126de1a..cd8f1a15fbd 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -167,7 +167,6 @@ private: public: static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject); StructDeclaration *syntaxCopy(Dsymbol *s) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; const char *kind() const override; void finalizeSize() override final; bool isPOD(); @@ -285,7 +284,6 @@ public: virtual bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isBaseInfoComplete(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; void finalizeSize() override; bool hasMonitor(); bool isFuncHidden(FuncDeclaration *fd); diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 77f36f304a5..6a9c0104a72 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -383,6 +383,7 @@ enum STMT : ubyte enum InitKind : ubyte { void_, + default_, error, struct_, array, diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 49fc3082ba8..251e2e88ca5 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -32,7 +32,7 @@ import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem : dsymbolSemantic; +import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.expressionsem; @@ -123,18 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return sc; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - Dsymbols* d = include(sc); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.addMember(sc2, sds) ); - if (sc2 != sc) - sc2.pop(); - } - } - override void setScope(Scope* sc) { Dsymbols* d = include(sc); @@ -295,34 +283,6 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration return t; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - Dsymbols* d = include(sc); - if (d) - { - Scope* sc2 = newScope(sc); - - d.foreachDsymbol( (s) - { - //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); - // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol) - if (auto decl = s.isDeclaration()) - { - decl.storage_class |= stc & STC.local; - if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? - { - sdecl.stc |= stc & STC.local; - } - } - s.addMember(sc2, sds); - }); - - if (sc2 != sc) - sc2.pop(); - } - - } - override inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return this; @@ -640,37 +600,6 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining); } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - if (pkg_identifiers) - { - Dsymbol tmp; - Package.resolve(pkg_identifiers, &tmp, null); - visibility.pkg = tmp ? tmp.isPackage() : null; - pkg_identifiers = null; - } - if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module) - { - Module m = sc._module; - - // https://issues.dlang.org/show_bug.cgi?id=17441 - // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if - // each package's .isModule() properites are equal. - // - // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null. - // This breaks package declarations of the package in question if they are declared in - // the same package.d file, which _do_ have a module associated with them, and hence a non-null - // isModule() - if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident)) - { - Package pkg = m.parent ? m.parent.isPackage() : null; - if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg)) - .error(loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", kind(), toPrettyChars(false), m.toPrettyChars(true)); - } - } - return AttribDeclaration.addMember(sc, sds); - } - override const(char)* kind() const { return "visibility attribute"; @@ -1054,23 +983,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration } } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); - /* This is deferred until the condition evaluated later (by the include() call), - * so that expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this.scopesym = sds; - } - override void setScope(Scope* sc) { // do not evaluate condition before semantic pass @@ -1186,12 +1098,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration return d; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - // used only for caching the enclosing symbol - this.scopesym = sds; - } - override void addComment(const(char)* comment) { // do nothing @@ -1266,15 +1172,6 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration return sc.push(sym); } - /*************************************** - * Lazily initializes the scope to forward to. - */ - override void addMember(Scope* sc, ScopeDsymbol sds) - { - sym.parent = sds; - return super.addMember(sc, sym); - } - override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return this; @@ -1312,12 +1209,6 @@ extern (C++) final class MixinDeclaration : AttribDeclaration return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps)); } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); - this.scopesym = sds; - } - override void setScope(Scope* sc) { Dsymbol.setScope(sc); diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index f47a1f6f836..efea9af950c 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 addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; void addComment(const utf8_t *comment) override; @@ -49,7 +48,6 @@ public: StorageClassDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; bool oneMember(Dsymbol **ps, Identifier *ident) override final; - void addMember(Scope *sc, ScopeDsymbol *sds) override; StorageClassDeclaration *isStorageClassDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -110,7 +108,6 @@ public: VisibilityDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; const char *kind() const override; const char *toPrettyChars(bool unused) override; VisibilityDeclaration *isVisibilityDeclaration() override { return this; } @@ -179,7 +176,6 @@ public: StaticIfDeclaration *syntaxCopy(Dsymbol *s) override; Dsymbols *include(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; StaticIfDeclaration *isStaticIfDeclaration() override { return this; } @@ -199,7 +195,6 @@ public: StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; Dsymbols *include(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void addComment(const utf8_t *comment) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; @@ -213,7 +208,6 @@ public: ForwardingScopeDsymbol *sym; Scope *newScope(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } }; @@ -229,7 +223,6 @@ public: d_bool compiled; MixinDeclaration *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index b8ad7851e4d..4e7a82fb565 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -281,7 +281,7 @@ struct OutBuffer write(&v, v.sizeof); } - /// NOT zero-terminated + /// Buffer will NOT be zero-terminated extern (C++) void writestring(const(char)* s) pure nothrow @system { if (!s) @@ -302,14 +302,14 @@ struct OutBuffer write(s); } - /// NOT zero-terminated, followed by newline + /// Buffer will NOT be zero-terminated, followed by newline void writestringln(const(char)[] s) pure nothrow @safe { writestring(s); writenl(); } - /** Write string to buffer, ensure it is zero terminated + /** Write C string AND null byte */ void writeStringz(const(char)* s) pure nothrow @system { diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index f0c834972d6..ed5f1f8b9a2 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -2168,6 +2168,7 @@ final class CParser(AST) : Parser!AST * C11 Initialization * initializer: * assignment-expression + * { } // C23 6.7.10 addition * { initializer-list } * { initializer-list , } * @@ -2198,6 +2199,12 @@ final class CParser(AST) : Parser!AST nextToken(); const loc = token.loc; + if (token.value == TOK.rightCurly) // { } + { + nextToken(); + return new AST.DefaultInitializer(loc); + } + /* Collect one or more `designation (opt) initializer` * into ci.initializerList, but lazily create ci */ diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index c93269fb321..43efc05b5d3 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -28,6 +28,7 @@ import dmd.func; import dmd.globals; import dmd.location; import dmd.mtype; +import dmd.root.bitarray; import dmd.root.complex; import dmd.root.ctfloat; import dmd.root.port; @@ -43,14 +44,14 @@ import dmd.visitor; extern (D) struct UnionExp { // yes, default constructor does nothing - extern (D) this(Expression e) + extern (D) this(Expression e) nothrow { memcpy(&this, cast(void*)e, e.size); } /* Extract pointer to Expression */ - extern (D) Expression exp() return + extern (D) Expression exp() return nothrow { return cast(Expression)&u; } @@ -109,7 +110,7 @@ void emplaceExp(T : Expression, Args...)(void* p, Args args) (cast(T)p).__ctor(args); } -void emplaceExp(T : UnionExp)(T* p, Expression e) +void emplaceExp(T : UnionExp)(T* p, Expression e) nothrow { memcpy(p, cast(void*)e, e.size); } @@ -134,7 +135,7 @@ void generateUncaughtError(ThrownExceptionExp tee) * Returns: * index of the field, or -1 if not found */ -int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe +int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe nothrow { foreach (i, field; sd.fields) { @@ -145,7 +146,7 @@ int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pur } // True if 'e' is CTFEExp::cantexp, or an exception -bool exceptionOrCantInterpret(const Expression e) @safe +bool exceptionOrCantInterpret(const Expression e) @safe nothrow { return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext); } @@ -153,7 +154,7 @@ bool exceptionOrCantInterpret(const Expression e) @safe /************** Aggregate literals (AA/string/array/struct) ******************/ // Given expr, which evaluates to an array/AA/string literal, // return true if it needs to be copied -bool needToCopyLiteral(const Expression expr) +bool needToCopyLiteral(const Expression expr) nothrow { Expression e = cast()expr; for (;;) @@ -593,7 +594,7 @@ TypeAArray toBuiltinAAType(Type t) /************** TypeInfo operations ************************************/ // Return true if type is TypeInfo_Class -bool isTypeInfo_Class(const Type type) +bool isTypeInfo_Class(const Type type) nothrow { auto tc = cast()type.isTypeClass(); return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null)); @@ -741,14 +742,14 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres Expression agg2 = getAggregateFromPointer(e2, &ofs2); if (agg1 == agg2) { - Type pointee = (cast(TypePointer)agg1.type).next; + Type pointee = agg1.type.nextOf(); const sz = pointee.size(); emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ && agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr) { - Type pointee = (cast(TypePointer)agg1.type).next; + Type pointee = agg1.type.nextOf(); const sz = pointee.size(); emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } @@ -794,14 +795,14 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type goto Lcant; } dinteger_t ofs2 = e2.toInteger(); - Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next; + Type pointee = agg1.type.toBasetype().nextOf(); dinteger_t sz = pointee.size(); sinteger_t indx; dinteger_t len; - if (agg1.op == EXP.symbolOffset) + if (auto soe = agg1.isSymOffExp()) { indx = ofs1 / sz; - len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger(); + len = soe.var.type.isTypeSArray().dim.toInteger(); } else { @@ -836,9 +837,9 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars()); goto Lcant; } - if (eptr.type.toBasetype().ty == Tsarray) + if (auto tsa = eptr.type.toBasetype().isTypeSArray()) { - dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger(); + dinteger_t dim = tsa.dim.toInteger(); // Create a CTFE pointer &agg1[indx .. indx+dim] auto se = ctfeEmplaceExp!SliceExp(loc, agg1, ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t), @@ -978,7 +979,7 @@ bool isCtfeComparable(Expression e) } /// Map EXP comparison ops -private bool numCmp(N)(EXP op, N n1, N n2) +private bool numCmp(N)(EXP op, N n1, N n2) nothrow { switch (op) { @@ -997,25 +998,25 @@ private bool numCmp(N)(EXP op, N n1, N n2) } /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool specificCmp(EXP op, int rawCmp) @safe +bool specificCmp(EXP op, int rawCmp) @safe nothrow { return numCmp!int(op, rawCmp, 0); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe +bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe nothrow { return numCmp!dinteger_t(op, n1, n2); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe +bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe nothrow { return numCmp!sinteger_t(op, n1, n2); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool realCmp(EXP op, real_t r1, real_t r2) @safe +bool realCmp(EXP op, real_t r1, real_t r2) @safe nothrow { // Don't rely on compiler, handle NAN arguments separately if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered @@ -1105,7 +1106,7 @@ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte /* Given a delegate expression e, return .funcptr. * If e is NullExp, return NULL. */ -private FuncDeclaration funcptrOf(Expression e) @safe +private FuncDeclaration funcptrOf(Expression e) @safe nothrow { assert(e.type.ty == Tdelegate); if (auto de = e.isDelegateExp()) @@ -1116,7 +1117,7 @@ private FuncDeclaration funcptrOf(Expression e) @safe return null; } -private bool isArray(const Expression e) @safe +private bool isArray(const Expression e) @safe nothrow { return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_; } @@ -1270,8 +1271,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide size_t dim = es1.keys.length; if (es2.keys.length != dim) return 1; - bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim); - memset(used, 0, bool.sizeof * dim); + BitArray used; + used.length = dim; foreach (size_t i; 0 .. dim) { Expression k1 = (*es1.keys)[i]; @@ -1290,11 +1291,9 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } if (!v2 || ctfeRawCmp(loc, v1, v2, identity)) { - mem.xfree(used); return 1; } } - mem.xfree(used); return 0; } else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_) @@ -2000,9 +1999,8 @@ void showCtfeExpr(Expression e, int level = 0) UnionExp voidInitLiteral(Type t, VarDeclaration var) { UnionExp ue; - if (t.ty == Tsarray) + if (auto tsa = t.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)t; Expression elem = voidInitLiteral(tsa.next, var).copy(); // For aggregate value types (structs, static arrays) we must // create an a separate copy for each element. @@ -2019,9 +2017,8 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var) ArrayLiteralExp ae = ue.exp().isArrayLiteralExp(); ae.ownedByCtfe = OwnedBy.ctfe; } - else if (t.ty == Tstruct) + else if (auto ts = t.isTypeStruct()) { - TypeStruct ts = cast(TypeStruct)t; auto exps = new Expressions(ts.sym.fields.length); foreach (size_t i; 0 .. ts.sym.fields.length) { diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index eb3890bb58f..14c67f062a3 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1631,6 +1631,13 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } else if (tob.ty == Tvector && t1b.ty != Tvector) { + if (t1b.ty == Tsarray) + { + // Casting static array to vector with same size, e.g. `cast(int4) int[4]` + if (t1b.size(e.loc) != tob.size(e.loc)) + goto Lfail; + return new VectorExp(e.loc, e, tob).expressionSemantic(sc); + } //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); TypeVector tv = tob.isTypeVector(); Expression result = new CastExp(e.loc, e, tv.elementType()); diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index bae942cbd97..72b85cfc64e 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -180,7 +180,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration int cppDtorVtblIndex = -1; /// to prevent recursive attempts - private bool inuse; + bool inuse; ThreeState isabstract; @@ -367,7 +367,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration baseok = Baseok.none; } - extern (D) private void classError(const(char)* fmt, const(char)* arg) + extern (D) final void classError(const(char)* fmt, const(char)* arg) { .error(loc, fmt, kind, toPrettyChars, arg); } @@ -468,67 +468,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration return baseok >= Baseok.done; } - override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags); - //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); - if (_scope && baseok < Baseok.semanticdone) - { - if (!inuse) - { - // must semantic on base class/interfaces - inuse = true; - dsymbolSemantic(this, null); - inuse = false; - } - } - - if (!members || !symtab) // opaque or addMember is not yet done - { - // .stringof is always defined (but may be hidden by some other symbol) - if (ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone) - classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); - //*(char*)0=0; - return null; - } - - auto s = ScopeDsymbol.search(loc, ident, flags); - - // don't search imports of base classes - if (flags & SearchImportsOnly) - return s; - - if (s) - return s; - - // Search bases classes in depth-first, left to right order - foreach (b; (*baseclasses)[]) - { - if (!b.sym) - continue; - - if (!b.sym.symtab) - { - classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars()); - continue; - } - - import dmd.access : symbolIsVisible; - - s = b.sym.search(loc, ident, flags); - if (!s) - continue; - else if (s == this) // happens if s is nested in this and derives from this - s = null; - else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s)) - s = null; - else - break; - } - - return s; - } - /************************************ * Search base classes in depth-first, left-to-right order for * a class or interface named 'ident'. @@ -675,7 +614,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration final bool isFuncHidden(FuncDeclaration fd) { //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars()); - Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); + Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); if (!s) { //printf("not found\n"); diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 76a31f4caf7..0e125fdd001 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -421,18 +421,6 @@ extern (C++) abstract class Declaration : Dsymbol return Modifiable.yes; } - override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - Dsymbol s = Dsymbol.search(loc, ident, flags); - if (!s && type) - { - s = type.toDsymbol(_scope); - if (s) - s = s.search(loc, ident, flags); - } - return s; - } - final bool isStatic() const pure nothrow @nogc @safe { return (storage_class & STC.static_) != 0; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 8cd295f1e06..a65fb4467e5 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -124,7 +124,6 @@ public: const char *kind() const override; uinteger_t size(const Loc &loc) override final; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; bool isStatic() const { return (storage_class & STCstatic) != 0; } LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index f33b5fd543e..797f6ee0a2d 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -83,25 +83,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return ed; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - version (none) - { - printf("EnumDeclaration::addMember() %s\n", toChars()); - for (size_t i = 0; i < members.length; i++) - { - EnumMember em = (*members)[i].isEnumMember(); - printf(" member %s\n", em.toChars()); - } - } - if (!isAnonymous()) - { - ScopeDsymbol.addMember(sc, sds); - } - - addEnumMembersToSymtab(this, sc, sds); - } - override void setScope(Scope* sc) { if (semanticRun > PASS.initial) @@ -126,19 +107,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return "enum"; } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars()); - if (_scope) - { - // Try one last time to resolve this enum - dsymbolSemantic(this, _scope); - } - - Dsymbol s = ScopeDsymbol.search(loc, ident, flags); - return s; - } - // is Dsymbol deprecated? override bool isDeprecated() const { diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index d74c8603420..0132e49cbed 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -305,33 +305,6 @@ extern (C++) final class Import : Dsymbol return this; } - /***************************** - * Add import to sd's symbol table. - */ - override void addMember(Scope* sc, ScopeDsymbol sd) - { - //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc); - if (names.length == 0) - return Dsymbol.addMember(sc, sd); - if (aliasId) - Dsymbol.addMember(sc, sd); - /* Instead of adding the import to sd's symbol table, - * add each of the alias=name pairs - */ - for (size_t i = 0; i < names.length; i++) - { - Identifier name = names[i]; - Identifier _alias = aliases[i]; - if (!_alias) - _alias = name; - auto tname = new TypeIdentifier(loc, name); - auto ad = new AliasDeclaration(loc, _alias, tname); - ad._import = this; - ad.addMember(sc, sd); - aliasdecls.push(ad); - } - } - override void setScope(Scope* sc) { Dsymbol.setScope(sc); @@ -348,19 +321,6 @@ extern (C++) final class Import : Dsymbol } } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); - if (!pkg) - { - load(null); - mod.importAll(null); - mod.dsymbolSemantic(null); - } - // Forward it to the package/module - return pkg.search(loc, ident, flags); - } - 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 e6dde181fab..5f5de6390fb 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -268,22 +268,6 @@ extern (C++) class Package : ScopeDsymbol return isAncestorPackageOf(pkg.parent.isPackage()); } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); - flags &= ~SearchLocalsOnly; // searching an import is always transitive - if (!isModule() && mod) - { - // Prefer full package name. - Dsymbol s = symtab ? symtab.lookup(ident) : null; - if (s) - return s; - //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); - return mod.search(loc, ident, flags); - } - return ScopeDsymbol.search(loc, ident, flags); - } - override void accept(Visitor v) { v.visit(this); @@ -414,10 +398,10 @@ extern (C++) final class Module : Package return rootimports == ThreeState.yes; } - private Identifier searchCacheIdent; - private Dsymbol searchCacheSymbol; // cached value of search - private int searchCacheFlags; // cached flags - private bool insearch; + Identifier searchCacheIdent; + Dsymbol searchCacheSymbol; // cached value of search + int searchCacheFlags; // cached flags + bool insearch; /** * A root module is one that will be compiled all the way to @@ -1036,47 +1020,6 @@ extern (C++) final class Module : Package } } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - /* Since modules can be circularly referenced, - * need to stop infinite recursive searches. - * This is done with the cache. - */ - //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); - if (insearch) - return null; - - /* Qualified module searches always search their imports, - * even if SearchLocalsOnly - */ - if (!(flags & SearchUnqualifiedModule)) - flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); - - if (searchCacheIdent == ident && searchCacheFlags == flags) - { - //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", - // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); - return searchCacheSymbol; - } - - uint errors = global.errors; - - insearch = true; - Dsymbol s = ScopeDsymbol.search(loc, ident, flags); - insearch = false; - - if (errors == global.errors) - { - // https://issues.dlang.org/show_bug.cgi?id=10752 - // Can cache the result only when it does not cause - // access error so the side-effect should be reproduced in later search. - searchCacheIdent = ident; - searchCacheSymbol = s; - searchCacheFlags = flags; - } - return s; - } - override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) { if (insearch) // don't follow import cycles diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 3853512005c..d68bcdaad40 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -66,13 +66,15 @@ enum SCOPE fullinst = 0x10000, /// fully instantiate templates ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block + dip1000 = 0x40000, /// dip1000 errors enabled for this scope + dip25 = 0x80000, /// dip25 errors enabled for this scope } /// Flags that are carried along with a scope push() private enum PersistentFlags = SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility | - SCOPE.Cfile | SCOPE.ctfeBlock; + SCOPE.Cfile | SCOPE.ctfeBlock | SCOPE.dip1000 | SCOPE.dip25; extern (C++) struct Scope { @@ -176,6 +178,10 @@ extern (C++) struct Scope m = m.parent; m.addMember(null, sc.scopesym); m.parent = null; // got changed by addMember() + if (global.params.useDIP1000 == FeatureState.enabled) + sc.flags |= SCOPE.dip1000; + if (global.params.useDIP25 == FeatureState.enabled) + sc.flags |= SCOPE.dip25; if (_module.filetype == FileType.c) sc.flags |= SCOPE.Cfile; // Create the module scope underneath the global scope @@ -344,7 +350,7 @@ extern (C++) struct Scope * Returns: * symbol if found, null if not */ - extern (D) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) + extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) { version (LOGSEARCH) { @@ -821,4 +827,16 @@ extern (C++) struct Scope { return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0; } + + /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled) + extern (D) FeatureState useDIP1000() + { + return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled; + } + + /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled) + extern (D) FeatureState useDIP25() + { + return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled; + } } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index f77a263a894..36e847c3f88 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -263,23 +263,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration return sd; } - override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); - if (_scope && !symtab) - dsymbolSemantic(this, _scope); - - if (!members || !symtab) // opaque or semantic() is not yet called - { - // .stringof is always defined (but may be hidden by some other symbol) - if(ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone) - .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars()); - return null; - } - - return ScopeDsymbol.search(loc, ident, flags); - } - override const(char)* kind() const { return "struct"; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 914213c1e57..a52745fcc0e 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -35,7 +35,6 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; @@ -750,67 +749,6 @@ extern (C++) class Dsymbol : ASTNode return toAlias(); } - void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab); - parent = sds; - if (isAnonymous()) // no name, so can't add it to symbol table - return; - - if (!sds.symtabInsert(this)) // if name is already defined - { - if (isAliasDeclaration() && !_scope) - setScope(sc); - Dsymbol s2 = sds.symtabLookup(this,ident); - /* https://issues.dlang.org/show_bug.cgi?id=17434 - * - * If we are trying to add an import to the symbol table - * that has already been introduced, then keep the one with - * larger visibility. This is fine for imports because if - * we have multiple imports of the same file, if a single one - * is public then the symbol is reachable. - */ - if (auto i1 = isImport()) - { - if (auto i2 = s2.isImport()) - { - if (sc.explicitVisibility && sc.visibility > i2.visibility) - sds.symtab.update(this); - } - } - - // If using C tag/prototype/forward declaration rules - if (sc.flags & SCOPE.Cfile && !this.isImport()) - { - if (handleTagSymbols(*sc, this, s2, sds)) - return; - if (handleSymbolRedeclarations(*sc, this, s2, sds)) - return; - - sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading - errors = true; - return; - } - - if (!s2.overloadInsert(this)) - { - sds.multiplyDefined(Loc.initial, this, s2); - errors = true; - } - } - if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) - { - if (ident == Id.__sizeof || - !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof)) - { - .error(loc, "%s `%s` `.%s` property cannot be redefined", kind, toPrettyChars, ident.toChars()); - errors = true; - } - } - } - /************************************* * Set scope for future semantic analysis so we can * deal better with forward references. @@ -831,21 +769,6 @@ extern (C++) class Dsymbol : ASTNode { } - /********************************************* - * Search for ident as member of s. - * Params: - * loc = location to print for error messages - * ident = identifier to search for - * flags = IgnoreXXXX - * Returns: - * null if not found - */ - Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) - { - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); - return null; - } - extern (D) final Dsymbol search_correct(Identifier ident) { /*************************************************** @@ -870,7 +793,7 @@ extern (C++) class Dsymbol : ASTNode if (global.gag) return null; // don't do it for speculative compiles; too time consuming // search for exact name first - if (auto s = search(Loc.initial, ident, IgnoreErrors)) + if (auto s = this.search(Loc.initial, ident, IgnoreErrors)) return s; return speller!symbol_search_fp(ident.toString()); } @@ -1339,12 +1262,12 @@ extern (C++) class ScopeDsymbol : Dsymbol Dsymbols* members; // all Dsymbol's in this scope DsymbolTable symtab; // members[] sorted into table uint endlinnum; // the linnumber of the statement after the scope (0 if unknown) - -private: /// symbols whose members have been imported, i.e. imported modules and template mixins Dsymbols* importedScopes; Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import +private: + import dmd.root.bitarray; BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages @@ -1373,166 +1296,7 @@ public: return sds; } - /***************************************** - * This function is #1 on the list of functions that eat cpu time. - * Be very, very careful about slowing it down. - */ - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags); - //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - if (symtab && !(flags & SearchImportsOnly)) - { - //printf(" look in locals\n"); - auto s1 = symtab.lookup(ident); - if (s1) - { - //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); - return s1; - } - } - //printf(" not found in locals\n"); - - // Look in imported scopes - if (!importedScopes) - return null; - - //printf(" look in imports\n"); - Dsymbol s = null; - OverloadSet a = null; - // Look in imported modules - for (size_t i = 0; i < importedScopes.length; i++) - { - // If private import, don't search it - if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_) - continue; - int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches - Dsymbol ss = (*importedScopes)[i]; - //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport()); - - if (ss.isModule()) - { - if (flags & SearchLocalsOnly) - continue; - } - else // mixin template - { - if (flags & SearchImportsOnly) - continue; - - sflags |= SearchLocalsOnly; - } - - /* Don't find private members if ss is a module - */ - Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); - import dmd.access : symbolIsVisible; - if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)) - continue; - if (!s) - { - s = s2; - if (s && s.isOverloadSet()) - a = mergeOverloadSet(ident, a, s); - } - else if (s2 && s != s2) - { - if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType()) - { - /* After following aliases, we found the same - * symbol, so it's not an ambiguity. But if one - * alias is deprecated or less accessible, prefer - * the other. - */ - if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import i1 = s.isImport(); - Import i2 = s2.isImport(); - if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident))))) - { - /* https://issues.dlang.org/show_bug.cgi?id=8668 - * Public selective import adds AliasDeclaration in module. - * To make an overload set, resolve aliases in here and - * get actual overload roots which accessible via s and s2. - */ - s = s.toAlias(); - s2 = s2.toAlias(); - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - - auto so2 = s2.isOverloadSet(); - if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable())) - { - if (symbolIsVisible(this, s2)) - { - a = mergeOverloadSet(ident, a, s2); - } - if (!symbolIsVisible(this, s)) - s = s2; - continue; - } - - /* Two different overflow sets can have the same members - * https://issues.dlang.org/show_bug.cgi?id=16709 - */ - auto so = s.isOverloadSet(); - if (so && so2) - { - if (so.a.length == so2.a.length) - { - foreach (j; 0 .. so.a.length) - { - if (so.a[j] !is so2.a[j]) - goto L1; - } - continue; // the same - L1: - { } // different - } - } - - if (flags & IgnoreAmbiguous) // if return NULL on ambiguity - return null; - - /* If two imports from C import files, pick first one, as C has global name space - */ - if (s.isCsymbol() && s2.isCsymbol()) - continue; - - if (!(flags & IgnoreErrors)) - ScopeDsymbol.multiplyDefined(loc, s, s2); - break; - } - } - } - } - if (s) - { - /* Build special symbol if we had multiple finds - */ - if (a) - { - if (!s.isOverloadSet()) - a = mergeOverloadSet(ident, a, s); - s = a; - } - //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); - return s; - } - //printf(" not found in imports\n"); - return null; - } - - extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) + extern (D) final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) { if (!os) { @@ -1844,40 +1608,6 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol this.withstate = withstate; } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); - if (flags & SearchImportsOnly) - return null; - // Acts as proxy to the with class declaration - Dsymbol s = null; - Expression eold = null; - for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true)) - { - if (auto se = e.isScopeExp()) - { - s = se.sds; - } - else if (e.isTypeExp()) - { - s = e.type.toDsymbol(null); - } - else - { - Type t = e.type.toBasetype(); - s = t.toDsymbol(null); - } - if (s) - { - s = s.search(loc, ident, flags); - if (s) - return s; - } - eold = e; - } - return null; - } - override inout(WithScopeSymbol) isWithScopeSymbol() inout { return this; @@ -1896,217 +1626,28 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol { // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration. // Discriminated using DYNCAST and, for expressions, also EXP - private RootObject arrayContent; - Scope* sc; + RootObject arrayContent; extern (D) this(Scope* sc, Expression exp) nothrow @safe { super(exp.loc, null); assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array); - this.sc = sc; + this._scope = sc; this.arrayContent = exp; } extern (D) this(Scope* sc, TypeTuple type) nothrow @safe { - this.sc = sc; + this._scope = sc; this.arrayContent = type; } extern (D) this(Scope* sc, TupleDeclaration td) nothrow @safe { - this.sc = sc; + this._scope = sc; this.arrayContent = td; } - /// This override is used to solve `$` - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) - { - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags); - if (ident != Id.dollar) - return null; - - VarDeclaration* pvar; - Expression ce; - - static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc) - { - - /* $ gives the number of type entries in the type tuple - */ - auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); - Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t); - v._init = new ExpInitializer(Loc.initial, e); - v.storage_class |= STC.temp | STC.static_ | STC.const_; - v.dsymbolSemantic(sc); - return v; - } - - const DYNCAST kind = arrayContent.dyncast(); - switch (kind) with (DYNCAST) - { - case dsymbol: - TupleDeclaration td = cast(TupleDeclaration) arrayContent; - /* $ gives the number of elements in the tuple - */ - auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); - Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t); - v._init = new ExpInitializer(Loc.initial, e); - v.storage_class |= STC.temp | STC.static_ | STC.const_; - v.dsymbolSemantic(sc); - return v; - case type: - return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc); - default: - break; - } - Expression exp = cast(Expression) arrayContent; - if (auto ie = exp.isIndexExp()) - { - /* array[index] where index is some function of $ - */ - pvar = &ie.lengthVar; - ce = ie.e1; - } - else if (auto se = exp.isSliceExp()) - { - /* array[lwr .. upr] where lwr or upr is some function of $ - */ - pvar = &se.lengthVar; - ce = se.e1; - } - else if (auto ae = exp.isArrayExp()) - { - /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ - * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) - */ - pvar = &ae.lengthVar; - ce = ae.e1; - } - else - { - /* Didn't find $, look in enclosing scope(s). - */ - return null; - } - ce = ce.lastComma(); - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (auto te = ce.isTypeExp()) - { - if (auto ttp = te.type.isTypeTuple()) - return dollarFromTypeTuple(loc, ttp, sc); - } - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { - /* Create variable v and set it to the value of $ - */ - VarDeclaration v; - Type t; - if (auto tupexp = ce.isTupleExp()) - { - /* It is for an expression tuple, so the - * length will be a const. - */ - Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t); - v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e)); - v.storage_class |= STC.temp | STC.static_ | STC.const_; - } - else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass)) - { - // Look for opDollar - assert(exp.op == EXP.array || exp.op == EXP.slice); - AggregateDeclaration ad = isAggregate(t); - assert(ad); - Dsymbol s = ad.search(loc, Id.opDollar); - if (!s) // no dollar exists -- search in higher scope - return null; - s = s.toAlias(); - Expression e = null; - // Check for multi-dimensional opDollar(dim) template. - if (TemplateDeclaration td = s.isTemplateDeclaration()) - { - dinteger_t dim = 0; - if (auto ae = exp.isArrayExp()) - { - dim = ae.currentDimension; - } - else if (exp.isSliceExp()) - { - dim = 0; // slices are currently always one-dimensional - } - else - { - assert(0); - } - auto tiargs = new Objects(); - Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t); - edim = edim.expressionSemantic(sc); - tiargs.push(edim); - e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs); - } - else - { - /* opDollar exists, but it's not a template. - * This is acceptable ONLY for single-dimension indexing. - * Note that it's impossible to have both template & function opDollar, - * because both take no arguments. - */ - auto ae = exp.isArrayExp(); - if (ae && ae.arguments.length != 1) - { - error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars()); - return null; - } - Declaration d = s.isDeclaration(); - assert(d); - e = new DotVarExp(loc, ce, d); - } - e = e.expressionSemantic(sc); - if (!e.type) - error(exp.loc, "`%s` has no value", e.toChars()); - t = e.type.toBasetype(); - if (t && t.ty == Tfunction) - e = new CallExp(e.loc, e); - v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e)); - v.storage_class |= STC.temp | STC.ctfe | STC.rvalue; - } - else - { - /* For arrays, $ will either be a compile-time constant - * (in which case its value in set during constant-folding), - * or a variable (in which case an expression is created in - * toir.c). - */ - - // https://issues.dlang.org/show_bug.cgi?id=16213 - // For static arrays $ is known at compile time, - // so declare it as a manifest constant. - auto tsa = ce.type ? ce.type.isTypeSArray() : null; - if (tsa) - { - auto e = new ExpInitializer(loc, tsa.dim); - v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest); - } - else - { - auto e = new VoidInitializer(Loc.initial); - e.type = Type.tsize_t; - v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); - v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable - } - } - *pvar = v; - } - (*pvar).dsymbolSemantic(sc); - return (*pvar); - } - override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return this; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 027897532d1..e0c2046bf90 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -228,10 +228,8 @@ public: virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); - virtual void addMember(Scope *sc, ScopeDsymbol *sds); virtual void setScope(Scope *sc); virtual void importAll(Scope *sc); - virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone); virtual bool overloadInsert(Dsymbol *s); virtual uinteger_t size(const Loc &loc); virtual bool isforwardRef(); @@ -331,16 +329,14 @@ public: Dsymbols *members; // all Dsymbol's in this scope DsymbolTable *symtab; // members[] sorted into table unsigned endlinnum; // the linnumber of the statement after the scope (0 if unknown) - -private: Dsymbols *importedScopes; // imported Dsymbol's Visibility::Kind *visibilities; // array of `Visibility.Kind`, one for each import +private: BitArray accessiblePackages, privateAccessiblePackages; public: ScopeDsymbol *syntaxCopy(Dsymbol *s) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; virtual void importScope(Dsymbol *s, Visibility visibility); virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0); bool isforwardRef() override final; @@ -362,7 +358,6 @@ class WithScopeSymbol final : public ScopeDsymbol public: WithStatement *withstate; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; WithScopeSymbol *isWithScopeSymbol() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -372,12 +367,8 @@ public: class ArrayScopeSymbol final : public ScopeDsymbol { -private: - RootObject *arrayContent; public: - Scope *sc; - - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone) override; + RootObject *arrayContent; ArrayScopeSymbol *isArrayScopeSymbol() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -437,3 +428,6 @@ public: // Number of symbols in symbol table size_t length() const; }; + +void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds); +Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 637edd7bf08..430377ff874 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -23,6 +23,7 @@ import dmd.astenums; import dmd.attrib; import dmd.blockexit; import dmd.clone; +import dmd.cond; import dmd.compiler; import dmd.dcast; import dmd.dclass; @@ -1141,7 +1142,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else if (auto ale = ex.isArrayLiteralExp()) { // or an array literal assigned to a `scope` variable - if (global.params.useDIP1000 == FeatureState.enabled + if (sc.useDIP1000 == FeatureState.enabled && !dsym.type.nextOf().needsDestruction()) ale.onstack = true; } @@ -1170,10 +1171,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // https://issues.dlang.org/show_bug.cgi?id=14166 // Don't run CTFE for the temporary variables inside typeof dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); + import dmd.semantic2 : lowerStaticAAs; + lowerStaticAAs(dsym, sc); const init_err = dsym._init.isExpInitializer(); if (init_err && init_err.exp.op == EXP.showCtfeContext) { - errorSupplemental(dsym.loc, "compile time context created here"); + errorSupplemental(dsym.loc, "compile time context created here"); } } } @@ -1979,7 +1982,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!cd.compiled) { cd.decl = compileIt(cd); - cd.AttribDeclaration.addMember(sc, cd.scopesym); + attribAddMember(cd, sc, cd.scopesym); cd.compiled = true; if (cd._scope && cd.decl) @@ -3385,7 +3388,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) { - import core.bitop; + import core.bitop : popcnt; auto mods = MODtoChars(tf.mod); .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods); if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1) @@ -5831,6 +5834,365 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } +/* +Adds dsym as a member of scope sds. + +Params: + dsym = dsymbol to inserted + sc = scope where the dsymbol is declared + sds = ScopeDsymbol where dsym is inserted +*/ +extern(C++) void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds) +{ + auto addMemberVisitor = new AddMemberVisitor(sc, sds); + dsym.accept(addMemberVisitor); +} + +private void attribAddMember(AttribDeclaration atb, Scope* sc, ScopeDsymbol sds) +{ + Dsymbols* d = atb.include(sc); + if (d) + { + Scope* sc2 = atb.newScope(sc); + d.foreachDsymbol( s => s.addMember(sc2, sds) ); + if (sc2 != sc) + sc2.pop(); + } +} + +private extern(C++) class AddMemberVisitor : Visitor +{ + alias visit = Visitor.visit; + + Scope* sc; + ScopeDsymbol sds; + + this(Scope* sc, ScopeDsymbol sds) + { + this.sc = sc; + this.sds = sds; + } + + override void visit(Dsymbol dsym) + { + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab); + dsym.parent = sds; + if (dsym.isAnonymous()) // no name, so can't add it to symbol table + return; + + if (!sds.symtabInsert(dsym)) // if name is already defined + { + if (dsym.isAliasDeclaration() && !dsym._scope) + dsym.setScope(sc); + Dsymbol s2 = sds.symtabLookup(dsym, dsym.ident); + /* https://issues.dlang.org/show_bug.cgi?id=17434 + * + * If we are trying to add an import to the symbol table + * that has already been introduced, then keep the one with + * larger visibility. This is fine for imports because if + * we have multiple imports of the same file, if a single one + * is public then the symbol is reachable. + */ + if (auto i1 = dsym.isImport()) + { + if (auto i2 = s2.isImport()) + { + if (sc.explicitVisibility && sc.visibility > i2.visibility) + sds.symtab.update(dsym); + } + } + + // If using C tag/prototype/forward declaration rules + if (sc.flags & SCOPE.Cfile && !dsym.isImport()) + { + if (handleTagSymbols(*sc, dsym, s2, sds)) + return; + if (handleSymbolRedeclarations(*sc, dsym, s2, sds)) + return; + + sds.multiplyDefined(Loc.initial, dsym, s2); // ImportC doesn't allow overloading + dsym.errors = true; + return; + } + + if (!s2.overloadInsert(dsym)) + { + sds.multiplyDefined(Loc.initial, dsym, s2); + dsym.errors = true; + } + } + if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) + { + if (dsym.ident == Id.__sizeof || + !(sc && sc.flags & SCOPE.Cfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof)) + { + .error(dsym.loc, "%s `%s` `.%s` property cannot be redefined", dsym.kind, dsym.toPrettyChars, dsym.ident.toChars()); + dsym.errors = true; + } + } + } + + + override void visit(StaticAssert _) + { + // we didn't add anything + } + + /***************************** + * Add import to sd's symbol table. + */ + override void visit(Import imp) + { + //printf("Import.addMember(this=%s, sds=%s, sc=%p)\n", imp.toChars(), sds.toChars(), sc); + if (imp.names.length == 0) + return visit(cast(Dsymbol)imp); + if (imp.aliasId) + visit(cast(Dsymbol)imp); + + /* Instead of adding the import to sds's symbol table, + * add each of the alias=name pairs + */ + for (size_t i = 0; i < imp.names.length; i++) + { + Identifier name = imp.names[i]; + Identifier _alias = imp.aliases[i]; + if (!_alias) + _alias = name; + auto tname = new TypeIdentifier(imp.loc, name); + auto ad = new AliasDeclaration(imp.loc, _alias, tname); + ad._import = imp; + addMember(ad, sc, sds); + imp.aliasdecls.push(ad); + } + } + + override void visit(AttribDeclaration atb) + { + attribAddMember(atb, sc, sds); + } + + override void visit(StorageClassDeclaration stcd) + { + Dsymbols* d = stcd.include(sc); + if (d) + { + Scope* sc2 = stcd.newScope(sc); + + d.foreachDsymbol( (s) + { + //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); + // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol) + if (auto decl = s.isDeclaration()) + { + decl.storage_class |= stcd.stc & STC.local; + if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? + { + sdecl.stc |= stcd.stc & STC.local; + } + } + s.addMember(sc2, sds); + }); + + if (sc2 != sc) + sc2.pop(); + } + } + + override void visit(VisibilityDeclaration visd) + { + if (visd.pkg_identifiers) + { + Dsymbol tmp; + Package.resolve(visd.pkg_identifiers, &tmp, null); + visd.visibility.pkg = tmp ? tmp.isPackage() : null; + visd.pkg_identifiers = null; + } + if (visd.visibility.kind == Visibility.Kind.package_ && visd.visibility.pkg && sc._module) + { + Module m = sc._module; + + // https://issues.dlang.org/show_bug.cgi?id=17441 + // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if + // each package's .isModule() properites are equal. + // + // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null. + // This breaks package declarations of the package in question if they are declared in + // the same package.d file, which _do_ have a module associated with them, and hence a non-null + // isModule() + if (!m.isPackage() || !visd.visibility.pkg.ident.equals(m.isPackage().ident)) + { + Package pkg = m.parent ? m.parent.isPackage() : null; + if (!pkg || !visd.visibility.pkg.isAncestorPackageOf(pkg)) + .error(visd.loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", visd.kind(), visd.toPrettyChars(false), m.toPrettyChars(true)); + } + } + attribAddMember(visd, sc, sds); + } + + override void visit(StaticIfDeclaration sid) + { + //printf("StaticIfDeclaration::addMember() '%s'\n", sid.toChars()); + /* This is deferred until the condition evaluated later (by the include() call), + * so that expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + sid.scopesym = sds; + } + + + override void visit(StaticForeachDeclaration sfd) + { + // used only for caching the enclosing symbol + sfd.scopesym = sds; + } + + /*************************************** + * Lazily initializes the scope to forward to. + */ + override void visit(ForwardingAttribDeclaration fad) + { + fad.sym.parent = sds; + sds = fad.sym; + attribAddMember(fad, sc, fad.sym); + } + + override void visit(MixinDeclaration md) + { + //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, md.memnum); + md.scopesym = sds; + } + + override void visit(DebugSymbol ds) + { + //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), ds.toChars()); + Module m = sds.isModule(); + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + if (ds.ident) + { + if (!m) + { + .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars); + ds.errors = true; + } + else + { + if (findCondition(m.debugidsNot, ds.ident)) + { + .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars); + ds.errors = true; + } + if (!m.debugids) + m.debugids = new Identifiers(); + m.debugids.push(ds.ident); + } + } + else + { + if (!m) + { + .error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars); + ds.errors = true; + } + else + m.debuglevel = ds.level; + } + } + + override void visit(VersionSymbol vs) + { + //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), vs.toChars()); + Module m = sds.isModule(); + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + if (vs.ident) + { + VersionCondition.checkReserved(vs.loc, vs.ident.toString()); + if (!m) + { + .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars); + vs.errors = true; + } + else + { + if (findCondition(m.versionidsNot, vs.ident)) + { + .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars); + vs.errors = true; + } + if (!m.versionids) + m.versionids = new Identifiers(); + m.versionids.push(vs.ident); + } + } + else + { + if (!m) + { + .error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars); + vs.errors = true; + } + else + m.versionlevel = vs.level; + } + } + + override void visit(Nspace ns) + { + visit(cast(Dsymbol)ns); + + if (ns.members) + { + if (!ns.symtab) + ns.symtab = new DsymbolTable(); + // The namespace becomes 'imported' into the enclosing scope + for (Scope* sce = sc; 1; sce = sce.enclosing) + { + ScopeDsymbol sds2 = sce.scopesym; + if (sds2) + { + sds2.importScope(ns, Visibility(Visibility.Kind.public_)); + break; + } + } + assert(sc); + sc = sc.push(ns); + sc.linkage = LINK.cpp; // namespaces default to C++ linkage + sc.parent = ns; + ns.members.foreachDsymbol(s => s.addMember(sc, ns)); + sc.pop(); + } + } + + override void visit(EnumDeclaration ed) + { + version (none) + { + printf("EnumDeclaration::addMember() %s\n", ed.toChars()); + for (size_t i = 0; i < ed.members.length; i++) + { + EnumMember em = (*ed.members)[i].isEnumMember(); + printf(" member %s\n", em.toChars()); + } + } + if (!ed.isAnonymous()) + { + visit(cast(Dsymbol)ed); + } + + addEnumMembersToSymtab(ed, sc, sds); + } +} + /******************************************* * Add members of EnumDeclaration to the symbol table(s). * Params: @@ -5904,7 +6266,7 @@ private bool isDRuntimeHook(Identifier id) id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT || id == Id._d_arraysetlengthTTrace || id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace || - id == Id._d_arrayappendcTXImpl; + id == Id._d_arrayappendcTX; } void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList) @@ -7431,3 +7793,617 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* p, funcdecl.toChars()); } } + +/********************************************* + * Search for ident as member of d. + * Params: + * d = dsymbol where ident is searched for + * loc = location to print for error messages + * ident = identifier to search for + * flags = IgnoreXXXX + * Returns: + * null if not found + */ +extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone) +{ + scope v = new SearchVisitor(loc, ident, flags); + d.accept(v); + return v.result; +} + +private extern(C++) class SearchVisitor : Visitor +{ + alias visit = Visitor.visit; + + const Loc loc; + Identifier ident; + int flags; + Dsymbol result; + + this(const ref Loc loc, Identifier ident, int flags) + { + this.loc = loc; + this.ident = ident; + this.flags = flags; + } + + void setResult(Dsymbol d) + { + result = d; + } + + override void visit(Dsymbol d) + { + //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", d, d.toChars(), ident.toChars()); + return setResult(null); + } + + override void visit(ScopeDsymbol sds) + { + //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", sds.toChars(), ident.toChars(), flags); + //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; + + // Look in symbols declared in this module + if (sds.symtab && !(flags & SearchImportsOnly)) + { + //printf(" look in locals\n"); + auto s1 = sds.symtab.lookup(ident); + if (s1) + { + //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); + return setResult(s1); + } + } + //printf(" not found in locals\n"); + + // Look in imported scopes + if (!sds.importedScopes) + return setResult(null); + + //printf(" look in imports\n"); + Dsymbol s = null; + OverloadSet a = null; + // Look in imported modules + for (size_t i = 0; i < sds.importedScopes.length; i++) + { + // If private import, don't search it + if ((flags & IgnorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_) + continue; + int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches + Dsymbol ss = (*sds.importedScopes)[i]; + //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport()); + + if (ss.isModule()) + { + if (flags & SearchLocalsOnly) + continue; + } + else // mixin template + { + if (flags & SearchImportsOnly) + continue; + + sflags |= SearchLocalsOnly; + } + + /* Don't find private members if ss is a module + */ + Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); + import dmd.access : symbolIsVisible; + if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2)) + continue; + if (!s) + { + s = s2; + if (s && s.isOverloadSet()) + a = sds.mergeOverloadSet(ident, a, s); + } + else if (s2 && s != s2) + { + if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType()) + { + /* After following aliases, we found the same + * symbol, so it's not an ambiguity. But if one + * alias is deprecated or less accessible, prefer + * the other. + */ + if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import i1 = s.isImport(); + Import i2 = s2.isImport(); + if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident))))) + { + /* https://issues.dlang.org/show_bug.cgi?id=8668 + * Public selective import adds AliasDeclaration in module. + * To make an overload set, resolve aliases in here and + * get actual overload roots which accessible via s and s2. + */ + s = s.toAlias(); + s2 = s2.toAlias(); + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + + auto so2 = s2.isOverloadSet(); + if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable())) + { + if (symbolIsVisible(sds, s2)) + { + a = sds.mergeOverloadSet(ident, a, s2); + } + if (!symbolIsVisible(sds, s)) + s = s2; + continue; + } + + /* Two different overflow sets can have the same members + * https://issues.dlang.org/show_bug.cgi?id=16709 + */ + auto so = s.isOverloadSet(); + if (so && so2) + { + if (so.a.length == so2.a.length) + { + foreach (j; 0 .. so.a.length) + { + if (so.a[j] !is so2.a[j]) + goto L1; + } + continue; // the same + L1: + { } // different + } + } + + if (flags & IgnoreAmbiguous) // if return NULL on ambiguity + return setResult(null); + + /* If two imports from C import files, pick first one, as C has global name space + */ + if (s.isCsymbol() && s2.isCsymbol()) + continue; + + if (!(flags & IgnoreErrors)) + ScopeDsymbol.multiplyDefined(loc, s, s2); + break; + } + } + } + } + if (s) + { + /* Build special symbol if we had multiple finds + */ + if (a) + { + if (!s.isOverloadSet()) + a = sds.mergeOverloadSet(ident, a, s); + s = a; + } + //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); + return setResult(s); + } + //printf(" not found in imports\n"); + return setResult(null); + } + + override void visit(WithScopeSymbol ws) + { + //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); + if (flags & SearchImportsOnly) + return setResult(null); + // Acts as proxy to the with class declaration + Dsymbol s = null; + Expression eold = null; + for (Expression e = ws.withstate.exp; e && e != eold; e = resolveAliasThis(ws._scope, e, true)) + { + if (auto se = e.isScopeExp()) + { + s = se.sds; + } + else if (e.isTypeExp()) + { + s = e.type.toDsymbol(null); + } + else + { + Type t = e.type.toBasetype(); + s = t.toDsymbol(null); + } + if (s) + { + s = s.search(loc, ident, flags); + if (s) + return setResult(s); + } + eold = e; + } + return setResult(null); + } + + override void visit(ArrayScopeSymbol ass) + { + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags); + if (ident != Id.dollar) + return setResult(null); + + VarDeclaration* pvar; + Expression ce; + + static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc) + { + + /* $ gives the number of type entries in the type tuple + */ + auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t); + v._init = new ExpInitializer(Loc.initial, e); + v.storage_class |= STC.temp | STC.static_ | STC.const_; + v.dsymbolSemantic(sc); + return v; + } + + const DYNCAST kind = ass.arrayContent.dyncast(); + switch (kind) with (DYNCAST) + { + case dsymbol: + TupleDeclaration td = cast(TupleDeclaration) ass.arrayContent; + /* $ gives the number of elements in the tuple + */ + auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t); + v._init = new ExpInitializer(Loc.initial, e); + v.storage_class |= STC.temp | STC.static_ | STC.const_; + v.dsymbolSemantic(ass._scope); + return setResult(v); + case type: + return setResult(dollarFromTypeTuple(loc, cast(TypeTuple) ass.arrayContent, ass._scope)); + default: + break; + } + Expression exp = cast(Expression) ass.arrayContent; + if (auto ie = exp.isIndexExp()) + { + /* array[index] where index is some function of $ + */ + pvar = &ie.lengthVar; + ce = ie.e1; + } + else if (auto se = exp.isSliceExp()) + { + /* array[lwr .. upr] where lwr or upr is some function of $ + */ + pvar = &se.lengthVar; + ce = se.e1; + } + else if (auto ae = exp.isArrayExp()) + { + /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ + * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) + */ + pvar = &ae.lengthVar; + ce = ae.e1; + } + else + { + /* Didn't find $, look in enclosing scope(s). + */ + return setResult(null); + } + ce = ce.lastComma(); + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (auto te = ce.isTypeExp()) + { + if (auto ttp = te.type.isTypeTuple()) + return setResult(dollarFromTypeTuple(loc, ttp, ass._scope)); + } + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { + /* Create variable v and set it to the value of $ + */ + VarDeclaration v; + Type t; + if (auto tupexp = ce.isTupleExp()) + { + /* It is for an expression tuple, so the + * length will be a const. + */ + Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t); + v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e)); + v.storage_class |= STC.temp | STC.static_ | STC.const_; + } + else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass)) + { + // Look for opDollar + assert(exp.op == EXP.array || exp.op == EXP.slice); + AggregateDeclaration ad = isAggregate(t); + assert(ad); + Dsymbol s = ad.search(loc, Id.opDollar); + if (!s) // no dollar exists -- search in higher scope + return setResult(null); + s = s.toAlias(); + Expression e = null; + // Check for multi-dimensional opDollar(dim) template. + if (TemplateDeclaration td = s.isTemplateDeclaration()) + { + dinteger_t dim = 0; + if (auto ae = exp.isArrayExp()) + { + dim = ae.currentDimension; + } + else if (exp.isSliceExp()) + { + dim = 0; // slices are currently always one-dimensional + } + else + { + assert(0); + } + auto tiargs = new Objects(); + Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t); + edim = edim.expressionSemantic(ass._scope); + tiargs.push(edim); + e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs); + } + else + { + /* opDollar exists, but it's not a template. + * This is acceptable ONLY for single-dimension indexing. + * Note that it's impossible to have both template & function opDollar, + * because both take no arguments. + */ + auto ae = exp.isArrayExp(); + if (ae && ae.arguments.length != 1) + { + error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars()); + return setResult(null); + } + Declaration d = s.isDeclaration(); + assert(d); + e = new DotVarExp(loc, ce, d); + } + e = e.expressionSemantic(ass._scope); + if (!e.type) + error(exp.loc, "`%s` has no value", e.toChars()); + t = e.type.toBasetype(); + if (t && t.ty == Tfunction) + e = new CallExp(e.loc, e); + v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e)); + v.storage_class |= STC.temp | STC.ctfe | STC.rvalue; + } + else + { + /* For arrays, $ will either be a compile-time constant + * (in which case its value in set during constant-folding), + * or a variable (in which case an expression is created in + * toir.c). + */ + + // https://issues.dlang.org/show_bug.cgi?id=16213 + // For static arrays $ is known at compile time, + // so declare it as a manifest constant. + auto tsa = ce.type ? ce.type.isTypeSArray() : null; + if (tsa) + { + auto e = new ExpInitializer(loc, tsa.dim); + v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest); + } + else + { + auto e = new VoidInitializer(Loc.initial); + e.type = Type.tsize_t; + v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); + v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable + } + } + *pvar = v; + } + (*pvar).dsymbolSemantic(ass._scope); + return setResult((*pvar)); + + } + + override void visit(Import imp) + { + //printf("%s.Import.search(ident = '%s', flags = x%x)\n", imp.toChars(), ident.toChars(), flags); + if (!imp.pkg) + { + imp.load(null); + imp.mod.importAll(null); + imp.mod.dsymbolSemantic(null); + } + // Forward it to the package/module + return setResult(imp.pkg.search(loc, ident, flags)); + + } + + override void visit(Nspace ns) + { + //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); + if (ns._scope && !ns.symtab) + dsymbolSemantic(ns, ns._scope); + + if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called + { + if (!(flags & IgnoreErrors)) + .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars()); + return setResult(null); + } + + visit(cast(ScopeDsymbol)ns); + } + + override void visit(EnumDeclaration em) + { + //printf("%s.EnumDeclaration::search('%s')\n", em.toChars(), ident.toChars()); + if (em._scope) + { + // Try one last time to resolve this enum + dsymbolSemantic(em, em._scope); + } + + visit(cast(ScopeDsymbol)em); + } + + override void visit(Package pkg) + { + //printf("%s Package.search('%s', flags = x%x)\n", pkg.toChars(), ident.toChars(), flags); + flags &= ~SearchLocalsOnly; // searching an import is always transitive + if (!pkg.isModule() && pkg.mod) + { + // Prefer full package name. + Dsymbol s = pkg.symtab ? pkg.symtab.lookup(ident) : null; + if (s) + return setResult(s); + //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); + return setResult(pkg.mod.search(loc, ident, flags)); + } + + visit(cast(ScopeDsymbol)pkg); + } + + override void visit(Module m) + { + /* Since modules can be circularly referenced, + * need to stop infinite recursive searches. + * This is done with the cache. + */ + //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", m.toChars(), ident.toChars(), flags, m.insearch); + if (m.insearch) + return setResult(null); + + /* Qualified module searches always search their imports, + * even if SearchLocalsOnly + */ + if (!(flags & SearchUnqualifiedModule)) + flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); + + if (m.searchCacheIdent == ident && m.searchCacheFlags == flags) + { + //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", + // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); + return setResult(m.searchCacheSymbol); + } + + uint errors = global.errors; + + m.insearch = true; + visit(cast(ScopeDsymbol)m); + Dsymbol s = result; + m.insearch = false; + + if (errors == global.errors) + { + // https://issues.dlang.org/show_bug.cgi?id=10752 + // Can cache the result only when it does not cause + // access error so the side-effect should be reproduced in later search. + m.searchCacheIdent = ident; + m.searchCacheSymbol = s; + m.searchCacheFlags = flags; + } + return setResult(s); + } + + override void visit(Declaration decl) + { + Dsymbol s = null; + if (decl.type) + { + s = decl.type.toDsymbol(decl._scope); + if (s) + s = s.search(loc, ident, flags); + } + return setResult(s); + } + + override void visit(StructDeclaration sd) + { + //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", sd.toChars(), ident.toChars(), flags); + if (sd._scope && !sd.symtab) + dsymbolSemantic(sd, sd._scope); + + if (!sd.members || !sd.symtab) // opaque or semantic() is not yet called + { + // .stringof is always defined (but may be hidden by some other symbol) + if(ident != Id.stringof && !(flags & IgnoreErrors) && sd.semanticRun < PASS.semanticdone) + .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars()); + return setResult(null); + } + + visit(cast(ScopeDsymbol)sd); + } + + override void visit(ClassDeclaration cd) + { + //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", cd.toChars(), ident.toChars(), flags); + //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); + if (cd._scope && cd.baseok < Baseok.semanticdone) + { + if (!cd.inuse) + { + // must semantic on base class/interfaces + cd.inuse = true; + dsymbolSemantic(cd, null); + cd.inuse = false; + } + } + + if (!cd.members || !cd.symtab) // opaque or addMember is not yet done + { + // .stringof is always defined (but may be hidden by some other symbol) + if (ident != Id.stringof && !(flags & IgnoreErrors) && cd.semanticRun < PASS.semanticdone) + cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); + //*(char*)0=0; + return setResult(null); + } + + visit(cast(ScopeDsymbol)cd); + auto s = result; + + // don't search imports of base classes + if (flags & SearchImportsOnly) + return setResult(s); + + if (s) + return setResult(s); + + // Search bases classes in depth-first, left to right order + foreach (b; (*cd.baseclasses)[]) + { + if (!b.sym) + continue; + + if (!b.sym.symtab) + { + cd.classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars()); + continue; + } + + import dmd.access : symbolIsVisible; + + s = b.sym.search(loc, ident, flags); + if (!s) + continue; + else if (s == cd) // happens if s is nested in this and derives from this + s = null; + else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s)) + s = null; + else + break; + } + + return setResult(s); + } +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 4cf1bae7537..037e0d01196 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -746,7 +746,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol OutBuffer buf; HdrGenState hgs; - buf.writestring(ident.toString()); + buf.writestring(ident == Id.ctor ? "this" : ident.toString()); buf.writeByte('('); foreach (i, const tp; *parameters) { @@ -763,6 +763,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { TypeFunction tf = cast(TypeFunction)fd.type; buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } } } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 7c76da99d1b..9f855743ef9 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -20,6 +20,7 @@ import dmd.astenums; import dmd.arraytypes; import dmd.attrib; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.globals; import dmd.hdrgen; diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d index aa22532061e..31725c80b9b 100644 --- a/gcc/d/dmd/dversion.d +++ b/gcc/d/dmd/dversion.d @@ -68,43 +68,6 @@ extern (C++) final class DebugSymbol : Dsymbol } } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars()); - Module m = sds.isModule(); - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - if (ident) - { - if (!m) - { - .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - { - if (findCondition(m.debugidsNot, ident)) - { - .error(loc, "%s `%s` defined after use", kind, toPrettyChars); - errors = true; - } - if (!m.debugids) - m.debugids = new Identifiers(); - m.debugids.push(ident); - } - } - else - { - if (!m) - { - .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - m.debuglevel = level; - } - } - override const(char)* kind() const nothrow { return "debug"; @@ -162,44 +125,6 @@ extern (C++) final class VersionSymbol : Dsymbol } } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars()); - Module m = sds.isModule(); - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - if (ident) - { - VersionCondition.checkReserved(loc, ident.toString()); - if (!m) - { - .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - { - if (findCondition(m.versionidsNot, ident)) - { - .error(loc, "%s `%s` defined after use", kind, toPrettyChars); - errors = true; - } - if (!m.versionids) - m.versionids = new Identifiers(); - m.versionids.push(ident); - } - } - else - { - if (!m) - { - .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - m.versionlevel = level; - } - } - override const(char)* kind() const nothrow { return "version"; diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index be12c65e6d6..e17e8cf5b0a 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -46,12 +46,10 @@ public: bool inuse(bool v); EnumDeclaration *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; Type *getType() override; const char *kind() const override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool isDeprecated() const override; // is Dsymbol deprecated? Visibility visible() override; bool isSpecial() const; diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 3f85ea08320..e25fc84234e 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -25,7 +25,7 @@ import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.func; -import dmd.globals; +import dmd.globals : FeatureState; import dmd.id; import dmd.identifier; import dmd.init; @@ -169,7 +169,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, if (!(eb.isMutable || eb2.isMutable)) return; - if (!tf.islive && !(global.params.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe())) + if (!tf.islive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe())) return; if (!gag) @@ -377,7 +377,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc)) { result = true; - printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10); + printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), sc.useDIP1000), vPar, 10); } } @@ -1094,7 +1094,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { if (p == sc.func) { - result |= escapingRef(v, global.params.useDIP1000); + result |= escapingRef(v, sc.useDIP1000); continue; } } @@ -1110,7 +1110,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); - result |= escapingRef(v, global.params.useDIP25); + result |= escapingRef(v, sc.useDIP25); continue; } // Don't need to be concerned if v's parent does not return a ref @@ -1125,12 +1125,12 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape"; if (!gag) { - previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars()); + previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars()); } // If -preview=dip25 is used, the user wants an error // Otherwise, issue a deprecation - result |= (global.params.useDIP25 == FeatureState.enabled); + result |= (sc.useDIP25 == FeatureState.enabled); } } @@ -1264,7 +1264,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) // https://issues.dlang.org/show_bug.cgi?id=23191 if (!gag) { - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)(e.loc, + previewErrorFunc(sc.isDeprecated(), sc.useDIP1000)(e.loc, "scope parameter `%s` may not be returned", v.toChars() ); result = true; @@ -1403,7 +1403,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); - escapingRef(v, global.params.useDIP25); + escapingRef(v, sc.useDIP25); continue; } // Don't need to be concerned if v's parent does not return a ref @@ -1415,7 +1415,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { const(char)* msg = "escaping reference to outer local variable `%s`"; if (!gag) - previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars()); + previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars()); result = true; continue; } @@ -2588,7 +2588,7 @@ public bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) { - return setUnsafePreview(sc, global.params.useDIP1000, gag, loc, msg, arg0, arg1, arg2); + return setUnsafePreview(sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2); } /*************************************** diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 47902213504..cd93e54932c 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -4617,7 +4617,9 @@ extern (C++) final class UshrAssignExp : BinAssignExp */ extern (C++) class CatAssignExp : BinAssignExp { - extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe + Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}` + + extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, EXP.concatenateAssign, e1, e2); } diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 12ca6b4566c..b4ace74b496 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -52,7 +52,7 @@ void expandTuples(Expressions *exps, Identifiers *names = nullptr); StringExp *toUTF8(StringExp *se, Scope *sc); Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc); MATCH implicitConvTo(Expression *e, Type *t); -Expression *toLvalue(Expression *_this, Scope *sc); +Expression *toLvalue(Expression *_this, Scope *sc, const char* action); Expression *modifiableLvalue(Expression* exp, Scope *sc); typedef unsigned char OwnedBy; @@ -1114,6 +1114,8 @@ public: class CatAssignExp : public BinAssignExp { public: + Expression *lowering; // lowered druntime hook `_d_arrayappend{cTX,T}` + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index d55ab3bcb26..e6b90183b51 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -2150,7 +2150,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc) * verified instead. This is to keep errors related to the original code * and not the lowering. */ - if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT) + if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX) return false; if (!f.isNogc()) @@ -3129,7 +3129,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); arg = ev.expressionSemantic(sc); } - arg = arg.toLvalue(sc); + arg = arg.toLvalue(sc, "create `in` parameter from"); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); @@ -3147,7 +3147,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); arg = ev.expressionSemantic(sc); } - arg = arg.toLvalue(sc); + arg = arg.toLvalue(sc, "create `ref` parameter from"); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); @@ -3166,7 +3166,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, err |= checkUnsafeAccess(sc, arg, false, true); err |= checkDefCtor(arg.loc, t); // t must be default constructible } - arg = arg.toLvalue(sc); + arg = arg.toLvalue(sc, "create `out` parameter from"); } else if (p.isLazy()) { @@ -3209,7 +3209,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, const explicitScope = p.isLazy() || ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred)); if ((pStc & (STC.scope_ | STC.lazy_)) && - ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) && + ((sc.useDIP1000 == FeatureState.enabled) || explicitScope) && !(pStc & STC.return_)) { /* Argument value cannot escape from the called function. @@ -5115,23 +5115,23 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (nargs == 1) - { - if (global.params.betterC || !sc.needsCodegen()) + if (global.params.betterC || !sc.needsCodegen()) goto LskipNewArrayLowering; - /* Class types may inherit base classes that have errors. - * This may leak errors from the base class to the derived one - * and then to the hook. Semantic analysis is performed eagerly - * to a void this. - */ - if (auto tc = exp.type.nextOf.isTypeClass()) - { - tc.sym.dsymbolSemantic(sc); - if (tc.sym.errors) - goto LskipNewArrayLowering; - } + /* Class types may inherit base classes that have errors. + * This may leak errors from the base class to the derived one + * and then to the hook. Semantic analysis is performed eagerly + * to a void this. + */ + if (auto tc = exp.type.nextOf.isTypeClass()) + { + tc.sym.dsymbolSemantic(sc); + if (tc.sym.errors) + goto LskipNewArrayLowering; + } + if (nargs == 1) + { auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT; if (!verifyHookExist(exp.loc, *sc, hook, "new array")) goto LskipNewArrayLowering; @@ -5163,6 +5163,45 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push((*exp.arguments)[0]); arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool)); + lowering = new CallExp(exp.loc, lowering, arguments); + exp.lowering = lowering.expressionSemantic(sc); + } + else + { + auto hook = global.params.tracegc ? Id._d_newarraymTXTrace : Id._d_newarraymTX; + if (!verifyHookExist(exp.loc, *sc, hook, "new multi-dimensional array")) + goto LskipNewArrayLowering; + + /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)` + * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`. + */ + Expression lowering = new IdentifierExp(exp.loc, Id.empty); + lowering = new DotIdExp(exp.loc, lowering, Id.object); + + auto tbn = exp.type.nextOf(); + while (tbn.ty == Tarray) + tbn = tbn.nextOf(); + auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + + auto tiargs = new Objects(); + tiargs.push(exp.type); + tiargs.push(unqualTbn); + lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs); + + auto arguments = new Expressions(); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? + sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); + arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); + arguments.push(new StringExp(exp.loc, funcname.toDString())); + } + + arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments)); + arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool)); + lowering = new CallExp(exp.loc, lowering, arguments); exp.lowering = lowering.expressionSemantic(sc); } @@ -8295,7 +8334,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else { // `toLvalue` call further below is upon exp.e1, omitting & from the error message - exp.toLvalue(sc); + exp.toLvalue(sc, "take address of"); return setError(); } } @@ -8385,7 +8424,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - exp.e1 = exp.e1.toLvalue(sc); + exp.e1 = exp.e1.toLvalue(sc, "take address of"); if (exp.e1.op == EXP.error) { result = exp.e1; @@ -9017,14 +9056,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - // Look for casting to a vector type - if (tob.ty == Tvector && t1b.ty != Tvector) - { - result = new VectorExp(exp.loc, exp.e1, exp.to); - result = result.expressionSemantic(sc); - return; - } - Expression ex = exp.e1.castTo(sc, exp.to); if (ex.op == EXP.error) { @@ -11727,8 +11758,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = res; - if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && - sc.needsCodegen()) + if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen()) { // if aa ordering is triggered, `res` will be a CommaExp // and `.e2` will be the rewritten original expression. @@ -11772,7 +11802,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(exp.e1); arguments.push(exp.e2); Expression ce = new CallExp(exp.loc, id, arguments); - *output = ce.expressionSemantic(sc); + + exp.lowering = ce.expressionSemantic(sc); + *output = exp; } else if (exp.op == EXP.concatenateElemAssign) { @@ -11792,15 +11824,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX; - if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object)) + if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object)) return setError(); - // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 + // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 Expression id = new IdentifierExp(exp.loc, Id.empty); id = new DotIdExp(exp.loc, id, Id.object); - auto tiargs = new Objects(); - tiargs.push(exp.e1.type); - id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs); id = new DotIdExp(exp.loc, id, hook); auto arguments = new Expressions(); @@ -11827,11 +11856,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { /* Before the template hook, this check was performed in e2ir.d * for expressions like `a ~= a[$-1]`. Here, $ will be modified - * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in + * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in * a temporary variable. */ value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true); - exp.e2 = value2; // `__appendtmp*` will be destroyed together with the array `exp.e1`. auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); @@ -11847,13 +11875,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto e0 = Expression.combine(ce, ae).expressionSemantic(sc); e0 = Expression.combine(e0, value1); e0 = Expression.combine(eValue1, e0); - e0 = Expression.combine(eValue2, e0); - *output = e0.expressionSemantic(sc); + exp.lowering = e0.expressionSemantic(sc); + *output = exp; } } - } override void visit(AddExp exp) @@ -15210,15 +15237,21 @@ Expression addDtorHook(Expression e, Scope* sc) * Params: * _this = expression to convert * sc = scope + * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`) * Returns: converted expression, or `ErrorExp` on error */ -extern(C++) Expression toLvalue(Expression _this, Scope* sc) +extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action) { - return toLvalueImpl(_this, sc, _this); + return toLvalueImpl(_this, sc, action, _this); } // e = original un-lowered expression for error messages, in case of recursive calls -private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { +private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e) +{ + if (!action) + action = "create lvalue of"; + + assert(e); Expression visit(Expression _this) { // BinaryAssignExp does not have an EXP associated @@ -15230,9 +15263,11 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { _this.loc = e.loc; if (e.op == EXP.type) - error(_this.loc, "`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind()); + error(_this.loc, "cannot %s type `%s`", action, e.type.toChars()); + else if (e.op == EXP.template_) + error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars()); else - error(_this.loc, "`%s` is not an lvalue and cannot be modified", e.toChars()); + error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars()); return ErrorExp.get(); } @@ -15241,7 +15276,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { { if (!_this.loc.isValid()) _this.loc = e.loc; - error(e.loc, "cannot modify constant `%s`", e.toChars()); + error(e.loc, "cannot %s constant `%s`", action, e.toChars()); return ErrorExp.get(); } @@ -15285,22 +15320,22 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { auto var = _this.var; if (var.storage_class & STC.manifest) { - error(_this.loc, "manifest constant `%s` cannot be modified", var.toChars()); + error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars()); return ErrorExp.get(); } if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted) { - error(_this.loc, "lazy variable `%s` cannot be modified", var.toChars()); + error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars()); return ErrorExp.get(); } if (var.ident == Id.ctfe) { - error(_this.loc, "cannot modify compiler-generated variable `__ctfe`"); + error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action); return ErrorExp.get(); } if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574 { - error(_this.loc, "cannot modify operator `$`"); + error(_this.loc, "cannot %s operator `$`", action); return ErrorExp.get(); } return _this; @@ -15370,7 +15405,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { Expression visitVectorArray(VectorArrayExp _this) { - _this.e1 = _this.e1.toLvalueImpl(sc, e); + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); return _this; } @@ -15389,19 +15424,19 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { Expression visitComma(CommaExp _this) { - _this.e2 = _this.e2.toLvalue(sc); + _this.e2 = _this.e2.toLvalue(sc, action); return _this; } Expression visitDelegatePointer(DelegatePtrExp _this) { - _this.e1 = _this.e1.toLvalueImpl(sc, e); + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); return _this; } Expression visitDelegateFuncptr(DelegateFuncptrExp _this) { - _this.e1 = _this.e1.toLvalueImpl(sc, e); + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); return _this; } @@ -15430,8 +15465,8 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { { // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) CondExp e = cast(CondExp)(_this.copy()); - e.e1 = _this.e1.toLvalue(sc).addressOf(); - e.e2 = _this.e2.toLvalue(sc).addressOf(); + e.e1 = _this.e1.toLvalue(sc, action).addressOf(); + e.e2 = _this.e2.toLvalue(sc, action).addressOf(); e.type = _this.type.pointerTo(); return new PtrExp(_this.loc, e, _this.type); @@ -15634,12 +15669,13 @@ extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc) // e = original / un-lowered expression to print in error messages private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e) { + assert(e); Expression visit(Expression exp) { //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars()); // See if this expression is a modifiable lvalue (i.e. not const) if (exp.isBinAssignExp()) - return exp.toLvalue(sc); + return exp.toLvalue(sc, "modify"); auto type = exp.type; if (checkModifiable(exp, sc) == Modifiable.yes) @@ -15672,7 +15708,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression return ErrorExp.get(); } } - return exp.toLvalueImpl(sc, e); + return exp.toLvalueImpl(sc, "modify", e); } Expression visitString(StringExp exp) @@ -15762,7 +15798,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression } exp.e1 = exp.e1.modifiableLvalue(sc); exp.e2 = exp.e2.modifiableLvalue(sc); - return exp.toLvalue(sc); + return exp.toLvalue(sc, "modify"); } switch(_this.op) @@ -15803,7 +15839,7 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) } if (sc.func && !sc.intypeof && !v.isDataseg()) { - if (global.params.useDIP1000 != FeatureState.enabled && + if (sc.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)) { diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index edf113e2160..351faa471f2 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -3241,13 +3241,6 @@ unittest assert(mismatches.isMutable); } -private const(char)* prependSpace(const(char)* str) -{ - if (!str || !*str) return ""; - - return (" " ~ str.toDString() ~ "\0").ptr; -} - /// Flag used by $(LREF resolveFuncCall). enum FuncResolveFlag : ubyte { @@ -3361,14 +3354,11 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, const(char)* lastprms = parametersTypeToChars(tf1.parameterList); const(char)* nextprms = parametersTypeToChars(tf2.parameterList); - const(char)* mod1 = prependSpace(MODtoChars(tf1.mod)); - const(char)* mod2 = prependSpace(MODtoChars(tf2.mod)); - .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`", s.parent.toPrettyChars(), s.ident.toChars(), fargsBuf.peekChars(), - m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1, - m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2); + m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(), + m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars()); return null; } @@ -3422,15 +3412,25 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, if (!tf) tf = fd.originalType.toTypeFunction(); - if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch + // modifier mismatch + if (tthis && (fd.isCtorDeclaration() ? + !MODimplicitConv(tf.mod, tthis.mod) : + !MODimplicitConv(tthis.mod, tf.mod))) { OutBuffer thisBuf, funcBuf; MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); if (hasOverloads) { - .error(loc, "none of the overloads of `%s` are callable using a %sobject", - fd.ident.toChars(), thisBuf.peekChars()); + OutBuffer buf; + buf.argExpTypesToCBuffer(fargs); + if (fd.isCtorDeclaration()) + .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`", + fd.toChars(), thisBuf.peekChars(), buf.peekChars()); + else + .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`", + fd.toChars(), thisBuf.peekChars(), buf.peekChars()); + if (!global.gag || global.params.v.showGaggedErrors) printCandidates(loc, fd, sc.isDeprecated()); return null; @@ -3447,8 +3447,12 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; } - .error(loc, "%smethod `%s` is not callable using a %sobject", - funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars()); + if (fd.isCtorDeclaration()) + .error(loc, "%s%s `%s` cannot construct a %sobject", + funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); + else + .error(loc, "%smethod `%s` is not callable using a %sobject", + funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars()); if (mismatches.isNotShared) .errorSupplemental(fd.loc, "Consider adding `shared` here"); @@ -3535,11 +3539,17 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (!print) return true; auto tf = cast(TypeFunction) fd.type; + OutBuffer buf; + buf.writestring(fd.toPrettyChars()); + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } .errorSupplemental(fd.loc, - printed ? " `%s%s`" : - single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`", - fd.toPrettyChars(), - parametersTypeToChars(tf.parameterList)); + printed ? " `%s`" : + single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars()); } else if (auto td = s.isTemplateDeclaration()) { @@ -4621,7 +4631,14 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char) case default_: if (!sc.func) return false; - if (!sc.func.isSafeBypassingInference() && !sc.func.safetyViolation) + if (sc.func.isSafeBypassingInference()) + { + if (!gag) + { + warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""); + } + } + else if (!sc.func.safetyViolation) { import dmd.func : AttributeViolation; sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 8325081dbd2..ac2dda3e89f 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -1943,7 +1943,7 @@ private void visitTemplateParameters(TemplateParameters* parameters, ref OutBuff { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, &hgs); + toCBuffer(p, buf, hgs); } } @@ -2885,10 +2885,10 @@ void floatToBuffer(Type type, const real_t value, ref OutBuffer buf, const bool } } -private void templateParameterToBuffer(TemplateParameter tp, ref OutBuffer buf, HdrGenState* hgs) +void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new TemplateParameterPrettyPrintVisitor(&buf, hgs); - tp.accept(v); + scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs); + (cast() tp).accept(v); } private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor @@ -3262,12 +3262,6 @@ void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) } } -void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs) -{ - scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs); - (cast() tp).accept(v); -} - void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) { if (!objects || !objects.length) @@ -3837,7 +3831,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, hgs); + toCBuffer(p, buf, *hgs); } buf.writeByte(')'); } @@ -3862,6 +3856,11 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState buf.writestring("void"); } + void visitDefault(DefaultInitializer iz) + { + buf.writestring("{ }"); + } + void visitStruct(StructInitializer si) { //printf("StructInitializer::toCBuffer()\n"); diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 5fcda91b435..32221d94744 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -323,6 +323,8 @@ immutable Msgtable[] msgtable = { "_d_newitemTTrace" }, { "_d_newarrayT" }, { "_d_newarrayTTrace" }, + { "_d_newarraymTX" }, + { "_d_newarraymTXTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, @@ -366,7 +368,6 @@ immutable Msgtable[] msgtable = { "_d_arraysetlengthTTrace"}, { "_d_arrayappendT" }, { "_d_arrayappendTTrace" }, - { "_d_arrayappendcTXImpl" }, { "_d_arrayappendcTX" }, { "_d_arrayappendcTXTrace" }, { "_d_arraycatnTX" }, diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index 31ee61a65fb..aeb3621f1eb 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -43,9 +43,7 @@ public: Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees void importAll(Scope *sc) override; Dsymbol *toAlias() override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope* sc) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool overloadInsert(Dsymbol *s) override; Import *isImport() override { return this; } diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 98ac9038a0a..2c7699b45ec 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -20,6 +20,7 @@ import dmd.dcast; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.expressionsem; diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index ebcd011f8a1..e48410082bd 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -68,6 +68,11 @@ extern (C++) class Initializer : ASTNode return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null; } + final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure + { + return kind == InitKind.default_ ? cast(inout DefaultInitializer)cast(void*)this : null; + } + final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure { return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null; @@ -111,6 +116,24 @@ extern (C++) final class VoidInitializer : Initializer } } +/*********************************************************** + * The C23 default initializer `{ }` + */ +extern (C++) final class DefaultInitializer : Initializer +{ + Type type; // type that this will initialize to + + extern (D) this(const ref Loc loc) @safe + { + super(loc, InitKind.default_); + } + + override void accept(Visitor v) + { + v.visit(this); + } +} + /*********************************************************** */ extern (C++) final class ErrorInitializer : Initializer @@ -266,6 +289,11 @@ Initializer syntaxCopy(Initializer inx) return new VoidInitializer(vi.loc); } + static Initializer visitDefault(DefaultInitializer vi) + { + return new DefaultInitializer(vi.loc); + } + static Initializer visitError(ErrorInitializer vi) { return vi; @@ -352,6 +380,7 @@ mixin template VisitInitializer(Result) final switch (init.kind) { case InitKind.void_: mixin(visitCase("Void")); break; + case InitKind.default_: mixin(visitCase("Default")); break; case InitKind.error: mixin(visitCase("Error")); break; case InitKind.struct_: mixin(visitCase("Struct")); break; case InitKind.array: mixin(visitCase("Array")); break; diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 67d0527a3b2..21bd07f4f39 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -20,6 +20,7 @@ class Expression; class Type; class ErrorInitializer; class VoidInitializer; +class DefaultInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; @@ -37,6 +38,7 @@ public: ErrorInitializer *isErrorInitializer(); VoidInitializer *isVoidInitializer(); + DefaultInitializer *isDefaultInitializer(); StructInitializer *isStructInitializer(); ArrayInitializer *isArrayInitializer(); ExpInitializer *isExpInitializer(); @@ -53,6 +55,14 @@ public: void accept(Visitor *v) override { v->visit(this); } }; +class DefaultInitializer final : public Initializer +{ +public: + Type *type; // type that this will initialize to + + void accept(Visitor *v) override { v->visit(this); } +}; + class ErrorInitializer final : public Initializer { public: diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 139db0f59e9..76c2d8916b0 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -24,6 +24,7 @@ import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; @@ -106,6 +107,7 @@ Expression toAssocArrayLiteral(ArrayInitializer ai) */ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret) { + //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars()); Type t = tx; static Initializer err() @@ -119,6 +121,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ return i; } + Initializer visitDefault(DefaultInitializer i) + { + i.type = t; + return i; + } + Initializer visitError(ErrorInitializer i) { return i; @@ -1017,6 +1025,12 @@ Initializer inferType(Initializer init, Scope* sc) return new ErrorInitializer(); } + Initializer visitDefault(DefaultInitializer i) + { + error(i.loc, "cannot infer type from default initializer"); + return new ErrorInitializer(); + } + Initializer visitError(ErrorInitializer i) { return i; @@ -1175,6 +1189,11 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n return null; } + Expression visitDefault(DefaultInitializer di) + { + return di.type ? di.type.defaultInit(Loc.initial, isCfile) : null; + } + Expression visitError(ErrorInitializer) { return ErrorExp.get(); diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index ec070d8ec0b..d19d435f240 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -22,6 +22,7 @@ import dmd.astenums; import dmd.declaration; import dmd.denum; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; import dmd.func; diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 6e8153d485a..92efc1656da 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -43,7 +43,6 @@ public: bool isAncestorPackageOf(const Package * const pkg) const; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; void accept(Visitor *v) override { v->visit(this); } Module *isPackageMod(); @@ -124,7 +123,6 @@ public: Module *parse(); // syntactic parse void importAll(Scope *sc) override; int needModuleInfo(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override; Dsymbol *symtabInsert(Dsymbol *s) override; static void runDeferredSemantic(); diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 59bf1d5d1d5..e59b01019f4 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -108,12 +108,6 @@ public: return; f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } - else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX) - { - if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`")) - return; - f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); - } } override void visit(ArrayLiteralExp e) @@ -187,20 +181,14 @@ public: override void visit(CatAssignExp e) { - /* CatAssignExp will exist in `__traits(compiles, ...)` and in the `.e1` branch of a `__ctfe ? :` CondExp. - * The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about - * GC usage. See visit(CallExp). - */ if (checkOnly) { err = true; return; } - if (f.setGC(e.loc, null)) - { - err = true; + if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`")) return; - } + f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); } override void visit(CatExp e) diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d index 2d3367af804..a49e0bf0cc2 100644 --- a/gcc/d/dmd/nspace.d +++ b/gcc/d/dmd/nspace.d @@ -85,33 +85,6 @@ extern (C++) final class Nspace : ScopeDsymbol return ns; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - ScopeDsymbol.addMember(sc, sds); - - if (members) - { - if (!symtab) - symtab = new DsymbolTable(); - // The namespace becomes 'imported' into the enclosing scope - for (Scope* sce = sc; 1; sce = sce.enclosing) - { - ScopeDsymbol sds2 = sce.scopesym; - if (sds2) - { - sds2.importScope(this, Visibility(Visibility.Kind.public_)); - break; - } - } - assert(sc); - sc = sc.push(this); - sc.linkage = LINK.cpp; // namespaces default to C++ linkage - sc.parent = this; - members.foreachDsymbol(s => s.addMember(sc, this)); - sc.pop(); - } - } - override void setScope(Scope* sc) { ScopeDsymbol.setScope(sc); @@ -126,22 +99,6 @@ extern (C++) final class Nspace : ScopeDsymbol } } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); - if (_scope && !symtab) - dsymbolSemantic(this, _scope); - - if (!members || !symtab) // opaque or semantic() is not yet called - { - if (!(flags & IgnoreErrors)) - .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars()); - return null; - } - - return ScopeDsymbol.search(loc, ident, flags); - } - override bool hasPointers() { //printf("Nspace::hasPointers() %s\n", toChars()); diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index e9fb7bdc777..7d30402c595 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -21,9 +21,7 @@ class Nspace final : public ScopeDsymbol public: Expression *identExp; Nspace *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool hasPointers() override; void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index b445b7b707b..b7bc9257b3e 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -23,6 +23,7 @@ import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 69028fac21d..a9791684df4 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -928,6 +928,14 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) } } + void visitCatAssign(CatAssignExp e) + { + if (auto lowering = e.lowering) + optimize(lowering, result, keepLvalue); + else + visitBinAssign(e); + } + void visitBin(BinExp e) { //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars()); @@ -1392,9 +1400,9 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) case EXP.leftShiftAssign: case EXP.rightShiftAssign: case EXP.unsignedRightShiftAssign: + case EXP.concatenateDcharAssign: visitBinAssign(ex.isBinAssignExp()); break; case EXP.concatenateElemAssign: - case EXP.concatenateDcharAssign: - case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break; + case EXP.concatenateAssign: visitCatAssign(cast(CatAssignExp) ex); break; case EXP.minusMinus: case EXP.plusPlus: diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 51e522d71e4..f9d174ab14f 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -4878,30 +4878,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Declaration v; AST.Dsymbol s; - // try to parse function type: - // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes bool attributesAppended; const StorageClass funcStc = parseTypeCtor(); - Token* tlu = &token; Token* tk; - if (token.value != TOK.function_ && - token.value != TOK.delegate_ && - isBasicType(&tlu) && tlu && - tlu.value == TOK.leftParenthesis) - { - AST.Type tret = parseBasicType(); - auto parameterList = parseParameterList(null); - - parseAttributes(); - if (udas) - error("user-defined attributes not allowed for `alias` declarations"); - - attributesAppended = true; - storage_class = appendStorageClass(storage_class, funcStc); - AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class); - v = new AST.AliasDeclaration(loc, ident, tf); - } - else if (token.value == TOK.function_ || + // function literal? + if (token.value == TOK.function_ || token.value == TOK.delegate_ || token.value == TOK.leftParenthesis && skipAttributes(peekPastParen(&token), &tk) && @@ -4911,10 +4892,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis && skipAttributes(peekPastParen(peek(&token)), &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) || - token.value == TOK.auto_ && peekNext() == TOK.ref_ && - peekNext2() == TOK.leftParenthesis && - skipAttributes(peekPastParen(peek(peek(&token))), &tk) && - (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) + token.value == TOK.auto_ && + (peekNext() == TOK.leftParenthesis || // for better error + peekNext() == TOK.ref_ && + peekNext2() == TOK.leftParenthesis) ) { // function (parameters) { statements... } @@ -4955,21 +4936,46 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - parseAttributes(); // type + parseAttributes(); if (udas) error("user-defined attributes not allowed for `alias` declarations"); - auto t = parseType(); + auto t = parseBasicType(); + t = parseTypeSuffixes(t); + if (token.value == TOK.identifier) + { + error("unexpected identifier `%s` after `%s`", + token.ident.toChars(), t.toChars()); + nextToken(); + } + else if (token.value == TOK.leftParenthesis) + { + // function type: + // StorageClasses Type ( Parameters ) MemberFunctionAttributes + auto parameterList = parseParameterList(null); + udas = null; + parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc); + if (udas) + error("user-defined attributes not allowed for `alias` declarations"); + + attributesAppended = true; + // Note: method types can have a TypeCtor attribute + storage_class = appendStorageClass(storage_class, funcStc); + t = new AST.TypeFunction(parameterList, t, link, storage_class); + } // Disallow meaningless storage classes on type aliases if (storage_class) { // Don't raise errors for STC that are part of a function/delegate type, e.g. // `alias F = ref pure nothrow @nogc @safe int function();` - auto tp = t.isTypePointer; - const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate; - const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class; + const remStc = t.isTypeFunction ? + storage_class & ~(STC.FUNCATTR | STC.TYPECTOR) : { + auto tp = t.isTypePointer; + const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate; + return isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class; + }(); if (remStc) { @@ -7217,6 +7223,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return false; } + // pt = test token. If found, pt is set to the token after BasicType private bool isBasicType(Token** pt) { // This code parallels parseBasicType() diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index a4a9434334e..3d0a5854625 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -298,5 +298,6 @@ public: void visit(AST.StructInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.ArrayInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.VoidInitializer i) { visit(cast(AST.Initializer)i); } + void visit(AST.DefaultInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.CInitializer i) { visit(cast(AST.CInitializer)i); } } diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 178542e37b0..2cac5f2941b 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -61,6 +61,9 @@ enum class SCOPE Cfile = 0x0800, // C semantics apply free = 0x8000, // is on free list fullinst = 0x10000, // fully instantiate templates + ctfeBlock = 0x20000, // inside a `if (__ctfe)` block + dip1000 = 0x40000, // dip1000 errors enabled for this scope + dip25 = 0x80000, // dip25 errors enabled for this scope }; struct Scope @@ -126,4 +129,6 @@ struct Scope AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it + + Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone); }; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index bf220f31d9b..c255701d767 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -918,7 +918,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (f.isref) { // Function returns a reference - exp = exp.toLvalue(sc2); + exp = exp.toLvalue(sc2, "`ref` return"); checkReturnEscapeRef(sc2, exp, false); exp = exp.optimize(WANTvalue, /*keepLvalue*/ true); } diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index f8b2c26df7f..3873adc82ee 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3801,7 +3801,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, { version (none) { - if (global.params.useDIP1000 == FeatureState.enabled) + if (sc2.useDIP1000 == FeatureState.enabled) { message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); } @@ -3809,7 +3809,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, } else { - if (global.params.useDIP1000 == FeatureState.enabled) + if (sc2.useDIP1000 == FeatureState.enabled) ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' } assert(tab.ty == Tstruct || tab.ty == Tclass); diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d index 15c46b304ba..7f22c4c993a 100644 --- a/gcc/d/dmd/staticassert.d +++ b/gcc/d/dmd/staticassert.d @@ -52,11 +52,6 @@ extern (C++) final class StaticAssert : Dsymbol return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null); } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - // we didn't add anything - } - override bool oneMember(Dsymbol* ps, Identifier ident) { //printf("StaticAssert::oneMember())\n"); diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h index 2b7d300f6af..c0d5363a414 100644 --- a/gcc/d/dmd/staticassert.h +++ b/gcc/d/dmd/staticassert.h @@ -21,7 +21,6 @@ public: Expressions *msg; StaticAssert *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; const char *kind() const override; StaticAssert *isStaticAssert() override { return this; } diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 79df7fde02b..0acadbb4604 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -32,6 +32,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -92,43 +93,50 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) } /** - * get an array of size_t values that indicate possible pointer words in memory - * if interpreted as the type given as argument - * Returns: the size of the type in bytes, ulong.max on error + * Fill an array of target size_t values that indicate possible pointer words in memory + * if interpreted as the type given as argument. + * One bit in the array per pointer-sized piece of memory + * Params: + * loc = location for error messages + * t = type to generate pointer bitmap from + * data = array forming the bitmap + * eSink = error message sink + * Returns: + * size of the type `t` in bytes, ulong.max on error */ -ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) +ulong getTypePointerBitmap(Loc loc, Type t, ref Array!(ulong) data, ErrorSink eSink) { - ulong sz; - if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration()) - sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc); - else - sz = t.size(loc); + auto tc = t.isTypeClass(); + const ulong sz = (tc && !tc.sym.isInterfaceDeclaration()) + ? tc.sym.AggregateDeclaration.size(loc) + : t.size(loc); if (sz == SIZE_INVALID) return ulong.max; - const sz_size_t = Type.tsize_t.size(loc); + const sz_size_t = Type.tsize_t.size(loc); // size of target's size_t + assert(sz_size_t <= ulong.sizeof); if (sz > sz.max - sz_size_t) { - error(loc, "size overflow for type `%s`", t.toChars()); + eSink.error(loc, "size overflow for type `%s`", t.toChars()); return ulong.max; } - ulong bitsPerWord = sz_size_t * 8; - ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; - ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; + const ulong bitsPerElement = sz_size_t * 8; // bits used in each array element + const ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; // pointers have same size as sz_size_t + const ulong length = (cntptr + bitsPerElement - 1) / bitsPerElement; // a bit per pointer - data.setDim(cast(size_t)cntdata); + data.setDim(cast(size_t)length); data.zero(); ulong offset; - bool error; + bool error; // sticky error indicator void visit(Type t) { void setpointer(ulong off) { ulong ptroff = off / sz_size_t; - (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t)); + data[cast(size_t)(ptroff / bitsPerElement)] |= 1L << (ptroff % bitsPerElement); } void visitType(Type t) @@ -247,7 +255,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) visit.VisitType(t); } - if (auto tc = t.isTypeClass()) + if (auto tcx = t.isTypeClass()) { // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references void visitTopLevelClass(TypeClass t) @@ -264,7 +272,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) offset = classoff; } - visitTopLevelClass(tc); + visitTopLevelClass(tcx); } else visit(t); @@ -281,28 +289,28 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) * * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...] */ -private Expression pointerBitmap(TraitsExp e) +private Expression pointerBitmap(TraitsExp e, ErrorSink eSink) { if (!e.args || e.args.length != 1) { - error(e.loc, "a single type expected for trait pointerBitmap"); + eSink.error(e.loc, "a single type expected for trait pointerBitmap"); return ErrorExp.get(); } Type t = getType((*e.args)[0]); if (!t) { - error(e.loc, "`%s` is not a type", (*e.args)[0].toChars()); + eSink.error(e.loc, "`%s` is not a type", (*e.args)[0].toChars()); return ErrorExp.get(); } Array!(ulong) data; - ulong sz = getTypePointerBitmap(e.loc, t, &data); + const ulong sz = getTypePointerBitmap(e.loc, t, data, eSink); if (sz == ulong.max) return ErrorExp.get(); auto exps = new Expressions(data.length + 1); - (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t); + (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t); // [0] is size in bytes of t foreach (size_t i; 1 .. exps.length) (*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t); @@ -472,13 +480,13 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (e.ident == Id.isAbstractClass) { - return isTypeX(t => t.toBasetype().ty == Tclass && - (cast(TypeClass)t.toBasetype()).sym.isAbstract()); + return isTypeX(t => t.toBasetype().isTypeClass() && + t.toBasetype().isTypeClass().sym.isAbstract()); } if (e.ident == Id.isFinalClass) { - return isTypeX(t => t.toBasetype().ty == Tclass && - ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0); + return isTypeX(t => t.toBasetype().isTypeClass() && + (t.toBasetype().isTypeClass().sym.storage_class & STC.final_) != 0); } if (e.ident == Id.isTemplate) { @@ -508,7 +516,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } Type tb = t.baseElemOf(); - if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) + auto ts = tb.isTypeStruct(); + if (auto sd = ts ? ts.sym : null) { return sd.isPOD() ? True() : False(); } @@ -529,7 +538,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } Type tb = t.baseElemOf(); - if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) + auto ts = tb.isTypeStruct(); + if (auto sd = ts ? ts.sym : null) { return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False()) : (sd.hasCopyCtor ? True() : False()); @@ -793,10 +803,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not { - if (p.isTemplateInstance()) // `C!2` is a template instance + if (auto ti = p.isTemplateInstance()) // `C!2` is a template instance { s = p; // `C!2`'s parent is `T1` - auto td = (cast(TemplateInstance)p).tempdecl; + auto td = ti.tempdecl; if (td) s = td; // get the declaration context just in case there's two contexts } @@ -1297,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (fd && fd.parent && fd.parent.isTemplateInstance) { fd.functionSemantic3(); - tf = cast(TypeFunction)fd.type; + tf = fd.type.isTypeFunction(); } auto mods = new Expressions(); @@ -1738,9 +1748,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc) ex = ex.expressionSemantic(sc2); ex = resolvePropertiesOnly(sc2, ex); ex = ex.optimize(WANTvalue); - if (sc2.func && sc2.func.type.ty == Tfunction) + if (sc2.func && sc2.func.type.isTypeFunction()) { - const tf = cast(TypeFunction)sc2.func.type; + const tf = sc2.func.type.isTypeFunction(); err |= tf.isnothrow && canThrow(ex, sc2.func, null); } ex = checkGC(sc2, ex); @@ -1868,7 +1878,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (e.ident == Id.getPointerBitmap) { - return pointerBitmap(e); + return pointerBitmap(e, global.errorSink); } if (e.ident == Id.initSymbol) { diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 4a4c5d4f7f0..8795002cd15 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1099,7 +1099,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (isRefOrOut && !isAuto && !(global.params.previewIn && (fparam.storageClass & STC.in_)) && global.params.rvalueRefParam != FeatureState.enabled) - e = e.toLvalue(sc); + e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from"); fparam.defaultArg = e; return (e.op != EXP.error); diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h index 697d46ee211..c268bc9b8cf 100644 --- a/gcc/d/dmd/version.h +++ b/gcc/d/dmd/version.h @@ -20,7 +20,6 @@ public: DebugSymbol *syntaxCopy(Dsymbol *) override; const char *toChars() const override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; const char *kind() const override; DebugSymbol *isDebugSymbol() override; void accept(Visitor *v) override { v->visit(this); } @@ -34,7 +33,6 @@ public: VersionSymbol *syntaxCopy(Dsymbol *) override; const char *toChars() const override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; const char *kind() const override; VersionSymbol *isVersionSymbol() override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 3d8c3e60220..360784a1076 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -176,6 +176,7 @@ class NewDeclaration; class Initializer; class VoidInitializer; +class DefaultInitializer; class ErrorInitializer; class StructInitializer; class ArrayInitializer; @@ -591,6 +592,7 @@ public: virtual void visit(StructInitializer *i) { visit((Initializer *)i); } virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); } virtual void visit(VoidInitializer *i) { visit((Initializer *)i); } + virtual void visit(DefaultInitializer *i) { visit((Initializer *)i); } virtual void visit(CInitializer *i) { visit((Initializer *)i); } }; diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 17801a3bd1e..a907979ba04 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -789,42 +789,58 @@ public: void visit (CatAssignExp *e) final override { + if (!global.params.useGC) + { + error_at (make_location_t (e->loc), + "appending to array in %qs requires the GC and cannot be " + "used with %<-fno-druntime%>", e->toChars ()); + this->result_ = error_mark_node; + return; + } + Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); - Type *etype = tb1->nextOf ()->toBasetype (); - - /* Save the address of `e1', so it can be evaluated first. - As all D run-time library functions for concat assignments update `e1' - in-place and then return its value, the saved address can also be used as - the result of this expression as well. */ - tree lhs = build_expr (e->e1); - tree lexpr = stabilize_expr (&lhs); - tree ptr = d_save_expr (build_address (lhs)); - tree result = NULL_TREE; - if (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar - && (etype->ty == TY::Tchar || etype->ty == TY::Twchar)) + if (e->op == EXP::concatenateDcharAssign) { /* Append a dchar to a char[] or wchar[]: The assignment is handled by the D run-time library, so only need to call `_d_arrayappend[cw]d(&e1, e2)' */ + Type *etype = tb1->nextOf ()->toBasetype (); + + /* Save the address of `e1', so it can be evaluated first. + As all D run-time library functions for concat assignments update + `e1' in-place and then return its value, the saved address can also + be used as the result of this expression as well. */ + tree lhs = build_expr (e->e1); + tree lexpr = stabilize_expr (&lhs); + tree ptr = d_save_expr (build_address (lhs)); + tree result = NULL_TREE; + + gcc_assert (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar + && (etype->ty == TY::Tchar || etype->ty == TY::Twchar)); + libcall_fn libcall = (etype->ty == TY::Tchar) ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD; result = build_libcall (libcall, e->type, 2, ptr, build_expr (e->e2)); + + /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */ + result = compound_expr (compound_expr (lexpr, ptr), result); + this->result_ = compound_expr (result, build_deref (ptr)); } else { + gcc_assert (e->op == EXP::concatenateAssign + || e->op == EXP::concatenateElemAssign); + gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray); /* Appending an element or array to another array has already been handled by the front-end. */ - gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray); - gcc_unreachable (); - } + gcc_assert (e->lowering); - /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */ - result = compound_expr (compound_expr (lexpr, ptr), result); - this->result_ = compound_expr (result, build_deref (ptr)); + this->result_ = build_expr (e->lowering); + } } /* Build an assignment expression. The right operand is implicitly @@ -2359,50 +2375,9 @@ public: /* Allocating memory for a new D array. */ gcc_assert (e->arguments && e->arguments->length >= 1); - if (e->arguments->length == 1) - { - /* Single dimension array allocations has already been handled by - the front-end. */ - gcc_assert (e->lowering); - result = build_expr (e->lowering); - } - else - { - /* Multidimensional array allocations. */ - tree tarray = make_array_type (Type::tsize_t, e->arguments->length); - tree var = build_local_temp (tarray); - vec *elms = NULL; - - /* Get the base element type for the array, generating the - initializer for the dims parameter along the way. */ - Type *telem = e->newtype->toBasetype (); - for (size_t i = 0; i < e->arguments->length; i++) - { - Expression *arg = (*e->arguments)[i]; - CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg)); - - gcc_assert (telem->ty == TY::Tarray); - telem = telem->toBasetype ()->nextOf (); - gcc_assert (telem); - } - - /* Initialize the temporary. */ - tree init = modify_expr (var, build_constructor (tarray, elms)); - var = compound_expr (init, var); - - /* Generate: _d_newarraymTX(ti, dims) - or: _d_newarraymiTX(ti, dims) */ - libcall_fn libcall = telem->isZeroInit () - ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX; - - tree tinfo = build_typeinfo (e, e->type); - tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()), - size_int (e->arguments->length), - build_address (var)); - - result = build_libcall (libcall, e->newtype->toBasetype (), 2, - tinfo, dims); - } + /* Array allocations have already been handled by the front-end. */ + gcc_assert (e->lowering != NULL); + result = build_expr (e->lowering); if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index f7887e1548f..3307b3b8244 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -70,13 +70,6 @@ DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT), DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT), P2(OBJECT, CLASSINFO), 0) -/* Used when calling `new' on a multi-dimensional array. - The `i' variant is for when the initializer is nonzero. */ -DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID), - P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0) -DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID), - P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0) - /* Used for allocating an array literal on the GC heap. */ DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR), P2(CONST_TYPEINFO, SIZE_T), 0) diff --git a/gcc/testsuite/gdc.dg/asm1.d b/gcc/testsuite/gdc.dg/asm1.d index 1b249ee7b35..1593eb6acd3 100644 --- a/gcc/testsuite/gdc.dg/asm1.d +++ b/gcc/testsuite/gdc.dg/asm1.d @@ -58,7 +58,7 @@ void semantic1() void semantic2a(X...)(X expr) { alias X[0] var1; - asm { "%0" : "=m" (var1); } // { dg-error "double' is a 'double' definition and cannot be modified" } + asm { "%0" : "=m" (var1); } // { dg-error "cannot modify type 'double'" } } void semantic2() diff --git a/gcc/testsuite/gdc.test/compilable/issue16020.d b/gcc/testsuite/gdc.test/compilable/issue16020.d index cfd078cdcd1..38a5d624320 100644 --- a/gcc/testsuite/gdc.test/compilable/issue16020.d +++ b/gcc/testsuite/gdc.test/compilable/issue16020.d @@ -1,3 +1,4 @@ +// function type aliases module issue16020; alias F1 = const(int)(); const(int) f1(){return 42;} @@ -36,4 +37,8 @@ alias Specialized = FunTemplate!int; alias Compared = void(int); static assert(is(Specialized == Compared)); -void main() {} +// type suffixes +alias FT = const(int)*(); +static assert(is(FT* == const(int)* function())); +alias FT2 = int*[2]() pure; +static assert(is(FT2* == int*[2] function() pure)); diff --git a/gcc/testsuite/gdc.test/compilable/nogc.d b/gcc/testsuite/gdc.test/compilable/nogc.d index 88cf1229d4d..959adc499cc 100644 --- a/gcc/testsuite/gdc.test/compilable/nogc.d +++ b/gcc/testsuite/gdc.test/compilable/nogc.d @@ -119,3 +119,12 @@ void f(bool cond, string s) @nogc { alias Unused2 = typeof(&inner); // (Does not) INFERS GC (anymore) enum Unused3 = __traits(compiles , &inner); } + +// https://issues.dlang.org/show_bug.cgi?id=24072 + +version (D_SIMD) void f24072() @nogc +{ + alias int4 = __vector(int[4]); + int4 b = cast(int4)[1, 2, 3, 4]; + int4 c = cast(int4)[1, 2]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d index 7baad47f378..3ddcdaaf76b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/b20011.d(25): Error: `S1(cast(ubyte)0u).member` is not an lvalue and cannot be modified -fail_compilation/b20011.d(28): Error: `S2(null).member` is not an lvalue and cannot be modified -fail_compilation/b20011.d(29): Error: `S2(null).member` is not an lvalue and cannot be modified -fail_compilation/b20011.d(32): Error: `U1(cast(ubyte)0u, ).m2` is not an lvalue and cannot be modified +fail_compilation/b20011.d(25): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue +fail_compilation/b20011.d(28): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(29): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(32): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)` fail_compilation/b20011.d(37): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)` diff --git a/gcc/testsuite/gdc.test/fail_compilation/const_ctor.d b/gcc/testsuite/gdc.test/fail_compilation/const_ctor.d new file mode 100644 index 00000000000..ae37023f0a1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/const_ctor.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/const_ctor.d(23): Error: `const` copy constructor `const_ctor.S1.this` cannot construct a mutable object +fail_compilation/const_ctor.d(25): Error: `const` constructor `const_ctor.S2.this` cannot construct a mutable object +--- +*/ + +struct S1 +{ + this(ref const S1 s) const {} + int* i; +} +struct S2 +{ + this(int) const {} + int* i; +} + +void main() +{ + const(S1) s1; + S1 m1 = s1; + + S2 s2 = S2(5); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d b/gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d new file mode 100644 index 00000000000..337ded09fd2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctor_attr.d(26): Error: none of the overloads of `this` can construct a mutable object with argument types `(int)` +fail_compilation/ctor_attr.d(16): Candidates are: `ctor_attr.S.this(int x) const` +fail_compilation/ctor_attr.d(18): `ctor_attr.S.this(string x)` +fail_compilation/ctor_attr.d(17): `this()(int x) shared` +fail_compilation/ctor_attr.d(28): Error: none of the overloads of `foo` are callable using a mutable object with argument types `(int)` +fail_compilation/ctor_attr.d(20): Candidates are: `ctor_attr.S.foo(int x) immutable` +fail_compilation/ctor_attr.d(21): `ctor_attr.S.foo(string x)` +--- +*/ + +struct S +{ + this(int x) const {} + this()(int x) shared {} + this(string x) {} + + void foo(int x) immutable {} + void foo(string x) {} +} + +void f() +{ + auto s = S(1); + S t; + t.foo(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d index 207f6a4aa15..74444327ecb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/diag10415.d(36): Error: none of the overloads of `x` are callable using argument types `(int) const` -fail_compilation/diag10415.d(13): Candidates are: `diag10415.C.x()` +fail_compilation/diag10415.d(13): Candidates are: `diag10415.C.x() const` fail_compilation/diag10415.d(18): `diag10415.C.x(int __param_0)` fail_compilation/diag10415.d(39): Error: d.x is not an lvalue --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d index 3e154979e8c..2c9384159ff 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d @@ -26,10 +26,10 @@ fail_compilation/diag10862.d-mixin-78(78): Error: assignment cannot be used as a fail_compilation/diag10862.d-mixin-79(79): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-80(80): Error: using the result of a comma expression is not allowed fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps `==` was meant? -fail_compilation/diag10862.d-mixin-83(83): Error: `a + b` is not an lvalue and cannot be modified +fail_compilation/diag10862.d-mixin-83(83): Error: cannot modify expression `a + b` because it is not an lvalue fail_compilation/diag10862.d-mixin-84(84): Error: undefined identifier `c` fail_compilation/diag10862.d(86): Error: undefined identifier `semanticError` -fail_compilation/diag10862.d(93): Error: lazy variable `bar` cannot be modified +fail_compilation/diag10862.d(93): Error: cannot modify lazy variable `bar` fail_compilation/diag10862.d(95): Error: template instance `diag10862.test3.foo!int` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d index f98a5b27dea..9bad6336d18 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10926.d(11): Error: `cast(const(int)[])c` is not an lvalue and cannot be modified +fail_compilation/diag10926.d(11): Error: cannot modify expression `cast(const(int)[])c` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d index e93d40b224e..b88dd7803cf 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag14102.d(14): Error: `-x` is not an lvalue and cannot be modified -fail_compilation/diag14102.d(15): Error: `-(x -= 1)` is not an lvalue and cannot be modified -fail_compilation/diag14102.d(16): Error: `-(x -= 1 -= 1)` is not an lvalue and cannot be modified -fail_compilation/diag14102.d(17): Error: `-(x -= 1 -= 1 -= 1)` is not an lvalue and cannot be modified +fail_compilation/diag14102.d(14): Error: cannot modify expression `-x` because it is not an lvalue +fail_compilation/diag14102.d(15): Error: cannot modify expression `-(x -= 1)` because it is not an lvalue +fail_compilation/diag14102.d(16): Error: cannot modify expression `-(x -= 1 -= 1)` because it is not an lvalue +fail_compilation/diag14102.d(17): Error: cannot modify expression `-(x -= 1 -= 1 -= 1)` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d index f6b49d6bd13..d43342bdc58 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified +fail_compilation/diag4596.d(15): Error: cannot modify expression `this` because it is not an lvalue fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue -fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified +fail_compilation/diag4596.d(18): Error: cannot modify expression `super` because it is not an lvalue fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d index a55ef731ad2..626fb827878 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d @@ -6,7 +6,7 @@ fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int __ fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int __param_0, int __param_1)` fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int __param_0)` is not callable using argument types `(double)` fail_compilation/diag8101b.d(30): cannot pass argument `1.0` of type `double` to parameter `int __param_0` -fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object +fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object with argument types `(int)` fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int __param_0)` fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int __param_0, int __param_1)` fail_compilation/diag8101b.d(35): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d deleted file mode 100644 index 77ab52046fc..00000000000 --- a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d +++ /dev/null @@ -1,56 +0,0 @@ -/* -REQUIRED_ARGS: -de -TEST_OUTPUT: ---- -fail_compilation/dip1000_deprecation.d(17): Deprecation: `@safe` function `main` calling `inferred` -fail_compilation/dip1000_deprecation.d(25): which wouldn't be `@safe` because of: -fail_compilation/dip1000_deprecation.d(25): scope variable `x0` may not be returned -fail_compilation/dip1000_deprecation.d(19): Deprecation: `@safe` function `main` calling `inferredC` -fail_compilation/dip1000_deprecation.d(36): which calls `dip1000_deprecation.inferred` -fail_compilation/dip1000_deprecation.d(25): which wouldn't be `@safe` because of: -fail_compilation/dip1000_deprecation.d(25): scope variable `x0` may not be returned ---- -*/ - -void main() @safe -{ - cast(void)inferred(); - cast(void)inferredB(); // no deprecation, trusted - cast(void)inferredC(); // nested deprecation -} - -auto inferred() -{ - scope int* x0; - return x0; -} - -auto inferredB() @trusted -{ - scope int* x1; - return x1; -} - -auto inferredC() -{ - return inferred(); // no deprecation, inferredC is not explicit `@safe` -} - -@safe: - -struct S -{ - int* ptr; - int* incorrectReturnRef() scope return @trusted {return ptr;} -} - -S createS() { return S.init; } - -int* escape(int i) -{ - if (i) return S().incorrectReturnRef(); - if (i) return createS().incorrectReturnRef(); - - S s; - return s.incorrectReturnRef(); -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d index f0eaeba821a..d9cfb047724 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10299.d(11): Error: `foo!string` is not an lvalue and cannot be modified +fail_compilation/fail10299.d(11): Error: cannot take address of expression `foo!string` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d index ac520d79997..156da435c7b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified -fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified +fail_compilation/fail13116.d(14): Error: cannot `ref` return expression `this` because it is not an lvalue +fail_compilation/fail13116.d(23): Error: cannot `ref` return expression `super` because it is not an lvalue --- */ struct S diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d index e3f990c2fdf..6307e902551 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail13336a.d(28): Error: `choose(true)` is not an lvalue and cannot be modified +fail_compilation/fail13336a.d(28): Error: cannot modify expression `choose(true)` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d index b8fb12d1427..f8959a2183c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d @@ -6,8 +6,8 @@ double sy; /* TEST_OUTPUT: --- -fail_compilation/fail13336b.d(16): Error: `cast(double)sx` is not an lvalue and cannot be modified -fail_compilation/fail13336b.d(24): Error: `cast(double)sx` is not an lvalue and cannot be modified +fail_compilation/fail13336b.d(16): Error: cannot `ref` return expression `cast(double)sx` because it is not an lvalue +fail_compilation/fail13336b.d(24): Error: cannot `ref` return expression `cast(double)sx` because it is not an lvalue --- */ ref f1(bool f) diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d index 0fb9708b430..718948c2832 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d @@ -1,13 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/fail17491.d(22): Error: `(S17491).init` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(23): Error: `S17491(0)` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(25): Error: `S17491(0).field` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(26): Error: `S17491(0).field` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(31): Error: `S17491(0)` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(32): Error: `S17491(0)` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(34): Error: `S17491(0).field` is not an lvalue and cannot be modified -fail_compilation/fail17491.d(35): Error: `S17491(0).field` is not an lvalue and cannot be modified +fail_compilation/fail17491.d(22): Error: cannot modify expression `(S17491).init` because it is not an lvalue +fail_compilation/fail17491.d(23): Error: cannot take address of expression `S17491(0)` because it is not an lvalue +fail_compilation/fail17491.d(25): Error: cannot modify expression `S17491(0).field` because it is not an lvalue +fail_compilation/fail17491.d(26): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue +fail_compilation/fail17491.d(31): Error: cannot modify expression `S17491(0)` because it is not an lvalue +fail_compilation/fail17491.d(32): Error: cannot take address of expression `S17491(0)` because it is not an lvalue +fail_compilation/fail17491.d(34): Error: cannot modify expression `S17491(0).field` because it is not an lvalue +fail_compilation/fail17491.d(35): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue --- */ // https://issues.dlang.org/show_bug.cgi?id=17491 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21243.d b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d index 2e170d096c5..0b4117d5bc6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail21243.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d @@ -1,16 +1,12 @@ /+ TEST_OUTPUT: --- -fail_compilation/fail21243.d(16): Error: found `(` when expecting `ref` and function literal following `auto` -fail_compilation/fail21243.d(16): Error: semicolon expected following auto declaration, not `int` -fail_compilation/fail21243.d(16): Error: semicolon needed to end declaration of `x` instead of `)` -fail_compilation/fail21243.d(16): Error: declaration expected, not `)` -fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `auto ref` for function literal return values -fail_compilation/fail21243.d(18): Error: basic type expected, not `(` -fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`) -fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases -fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration, not `=>` -fail_compilation/fail21243.d(18): Error: declaration expected, not `=>` -fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(12): Error: found `(` when expecting `ref` and function literal following `auto` +fail_compilation/fail21243.d(12): Error: semicolon expected following auto declaration, not `int` +fail_compilation/fail21243.d(12): Error: semicolon needed to end declaration of `x` instead of `)` +fail_compilation/fail21243.d(12): Error: declaration expected, not `)` +fail_compilation/fail21243.d(13): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(14): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(15): Error: `auto` can only be used as part of `auto ref` for function literal return values --- +/ auto a = auto (int x) => x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail217.d b/gcc/testsuite/gdc.test/fail_compilation/fail217.d index 11ad76fabdc..ecae1a38e6d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail217.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail217.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail217.d(22): Error: mutable method `fail217.Message.this` is not callable using a `immutable` object +fail_compilation/fail217.d(22): Error: mutable constructor `fail217.Message.this` cannot construct a `immutable` object fail_compilation/fail217.d(13): Consider adding `const` or `inout` here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24224.d b/gcc/testsuite/gdc.test/fail_compilation/fail24224.d new file mode 100644 index 00000000000..db87f5305d7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24224.d @@ -0,0 +1,22 @@ +/+ +TEST_OUTPUT: +--- +fail_compilation/fail24224.d(19): Error: struct / class type expected as argument to __traits(initSymbol) instead of `ES` +fail_compilation/fail24224.d(20): Error: struct / class type expected as argument to __traits(initSymbol) instead of `EU` +fail_compilation/fail24224.d(21): Error: struct / class type expected as argument to __traits(initSymbol) instead of `EC` +--- ++/ +struct S {} +union U {} +class C {} + +enum ES : S { a = S.init } +enum EU : U { a = U.init } +enum EC : C { a = C.init } + +void test() +{ + auto init1 = __traits(initSymbol, ES); + auto init2 = __traits(initSymbol, EU); + auto init3 = __traits(initSymbol, EC); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d index 584a4679ccd..26d44296498 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d @@ -2,12 +2,12 @@ /* TEST_OUTPUT: --- -fail_compilation/fail6795.d(19): Error: `[0][0]` is not an lvalue and cannot be modified -fail_compilation/fail6795.d(20): Error: `[0:0][0]` is not an lvalue and cannot be modified -fail_compilation/fail6795.d(22): Error: `[0][0]` is not an lvalue and cannot be modified -fail_compilation/fail6795.d(23): Error: `[0:0][0]` is not an lvalue and cannot be modified -fail_compilation/fail6795.d(25): Error: `[0][0]` is not an lvalue and cannot be modified -fail_compilation/fail6795.d(26): Error: `[0:0][0]` is not an lvalue and cannot be modified +fail_compilation/fail6795.d(19): Error: cannot modify expression `[0][0]` because it is not an lvalue +fail_compilation/fail6795.d(20): Error: cannot modify expression `[0:0][0]` because it is not an lvalue +fail_compilation/fail6795.d(22): Error: cannot modify expression `[0][0]` because it is not an lvalue +fail_compilation/fail6795.d(23): Error: cannot modify expression `[0:0][0]` because it is not an lvalue +fail_compilation/fail6795.d(25): Error: cannot take address of expression `[0][0]` because it is not an lvalue +fail_compilation/fail6795.d(26): Error: cannot take address of expression `[0:0][0]` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d index 38f47ba0913..920956bf2f9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7424d.d(10): Error: template `this.g()()` has no value +fail_compilation/fail7424d.d(10): Error: template `this.g()() immutable` has no value --- */ struct S7424d diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d index e92b4693d51..ddf9d1a89b3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7424e.d(10): Error: template `this.g()()` has no value +fail_compilation/fail7424e.d(10): Error: template `this.g()() immutable` has no value --- */ struct S7424e diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d index 1af14f83d7e..2f7f8f36153 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7424f.d(10): Error: template `this.g()()` has no value +fail_compilation/fail7424f.d(10): Error: template `this.g()() shared` has no value --- */ struct S7424f diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d index 6352166add5..4e922d6f5be 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7424i.d(10): Error: template `this.g()()` has no value +fail_compilation/fail7424i.d(10): Error: template `this.g()() immutable` has no value --- */ struct S7424g diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d index 76a92c2b193..a106a566a5c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7603a.d(7): Error: cannot modify constant `true` +fail_compilation/fail7603a.d(7): Error: cannot create default argument for `ref` / `out` parameter from constant `true` --- */ void test(ref bool val = true) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d index 9b84d3f6a4d..a6524221afd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7603b.d(7): Error: cannot modify constant `true` +fail_compilation/fail7603b.d(7): Error: cannot create default argument for `ref` / `out` parameter from constant `true` --- */ void test(out bool val = true) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d index 25a7399dd7a..3d030fc9668 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7603c.d(8): Error: cannot modify constant `3` +fail_compilation/fail7603c.d(8): Error: cannot create default argument for `ref` / `out` parameter from constant `3` --- */ enum x = 3; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d index e08badf34a9..4d593e39ddb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail9537.d(26): Error: `foo(tuple(1, 2))` is not an lvalue and cannot be modified +fail_compilation/fail9537.d(26): Error: cannot take address of expression `foo(tuple(1, 2))` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d index b49ffe13dfc..26447a73914 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail9773.d(7): Error: `""` is not an lvalue and cannot be modified +fail_compilation/fail9773.d(7): Error: cannot create default argument for `ref` / `out` parameter from expression `""` because it is not an lvalue --- */ void f(ref string a = "") diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d index 791e734349f..0c2384fccfa 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/fail9891.d(13): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `ref int` of parameter `n` fail_compilation/fail9891.d(18): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `out int` of parameter `n` -fail_compilation/fail9891.d(23): Error: `prop()` is not an lvalue and cannot be modified +fail_compilation/fail9891.d(23): Error: cannot create default argument for `ref` / `out` parameter from expression `prop()` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d index c3c735ed552..0db6a45c9a2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d @@ -207,21 +207,21 @@ fail_compilation/fail_arrayop2.d(265): Error: array operation `[1] * 6` without fail_compilation/fail_arrayop2.d(268): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed -fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified +fail_compilation/fail_arrayop2.d(275): Error: cannot take address of expression `([1] * 6)[0..2]` because it is not an lvalue fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]` fail_compilation/fail_arrayop2.d(281): Error: the `delete` keyword is obsolete fail_compilation/fail_arrayop2.d(281): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed -fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified +fail_compilation/fail_arrayop2.d(290): Error: cannot modify expression `[1] * 6` because it is not an lvalue fail_compilation/fail_arrayop2.d(291): Error: array operation `[1] * 6` without destination memory not allowed -fail_compilation/fail_arrayop2.d(294): Error: `[1] * 6` is not an lvalue and cannot be modified -fail_compilation/fail_arrayop2.d(295): Error: `([1] * 6)[]` is not an lvalue and cannot be modified +fail_compilation/fail_arrayop2.d(294): Error: cannot modify expression `[1] * 6` because it is not an lvalue +fail_compilation/fail_arrayop2.d(295): Error: cannot modify expression `([1] * 6)[]` because it is not an lvalue fail_compilation/fail_arrayop2.d(298): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(299): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(300): Error: array operation `[1] * 6` without destination memory not allowed -fail_compilation/fail_arrayop2.d(303): Error: `[1] * 6` is not an lvalue and cannot be modified -fail_compilation/fail_arrayop2.d(304): Error: `[1] * 6` is not an lvalue and cannot be modified +fail_compilation/fail_arrayop2.d(303): Error: cannot modify expression `[1] * 6` because it is not an lvalue +fail_compilation/fail_arrayop2.d(304): Error: cannot modify expression `[1] * 6` because it is not an lvalue fail_compilation/fail_arrayop2.d(307): Error: `[1] * 6` is not of integral type, it is a `int[]` fail_compilation/fail_arrayop2.d(308): Error: `[1] * 6` is not of integral type, it is a `int[]` fail_compilation/fail_arrayop2.d(309): Error: `[1] * 6` is not of integral type, it is a `int[]` diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d index a9e5429366a..9851ffc1c74 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d @@ -1,10 +1,6 @@ /* TEST_OUTPUT: --- -fail_compilation/fail_scope.d(28): Deprecation: scope parameter `da` may not be returned -fail_compilation/fail_scope.d(30): Deprecation: scope parameter `o` may not be returned -fail_compilation/fail_scope.d(31): Deprecation: scope parameter `dg` may not be returned -fail_compilation/fail_scope.d(38): Deprecation: scope parameter `p` may not be returned fail_compilation/fail_scope.d(43): Error: returning `cast(char[])string` escapes a reference to local variable `string` fail_compilation/fail_scope.d(61): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(72): Error: `fail_scope.foo8` called with argument types `(int)` matches both: @@ -23,6 +19,10 @@ fail_compilation/fail_scope.d(135): Error: returning `foo16226(i)` escapes a ref //fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned */ + + + + alias int delegate() dg_t; int[] checkEscapeScope1(scope int[] da) { return da; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d index 827f0451824..fed8c608569 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10419.d(12): Error: `arr().length` is not an lvalue and cannot be modified +fail_compilation/ice10419.d(12): Error: cannot modify expression `arr().length` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d index c5894d2c7ee..343624dbc39 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/ice12841.d(23): Error: `taskPool().amap(Args...)(Args args)` is not an lvalue and cannot be modified -fail_compilation/ice12841.d(24): Error: `amap(Args...)(Args args)` is not an lvalue and cannot be modified +fail_compilation/ice12841.d(23): Error: cannot take address of expression `taskPool().amap(Args...)(Args args)` because it is not an lvalue +fail_compilation/ice12841.d(24): Error: cannot take address of template `amap(Args...)(Args args)`, perhaps instantiate it first --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d index d34fc60db6a..6998e685a75 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/ice13459.d(12): Error: undefined identifier `B` fail_compilation/ice13459.d(18): Error: none of the overloads of `opSlice` are callable using argument types `(int, int)` -fail_compilation/ice13459.d(11): Candidate is: `ice13459.A.opSlice()` +fail_compilation/ice13459.d(11): Candidate is: `ice13459.A.opSlice() const` --- */ struct A diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d index 0d697e22c9f..df6667d9e4b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d @@ -2,7 +2,7 @@ DISABLED: freebsd32 linux32 osx32 win32 TEST_OUTPUT: --- -fail_compilation/ice20264.d(12): Error: `cast(__vector(float[4]))a` is not an lvalue and cannot be modified +fail_compilation/ice20264.d(12): Error: cannot modify expression `cast(__vector(float[4]))a` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d index 47fd44c6b01..c9ab014b6e6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)` -fail_compilation/ice9284.d(12): Candidate is: `__ctor()(string)` +fail_compilation/ice9284.d(12): Candidate is: `this()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d b/gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d new file mode 100644 index 00000000000..408e4027fd6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/immutable_ctor.d(18): Error: `immutable` copy constructor `immutable_ctor.S1.this` cannot construct a mutable object +--- +*/ + +struct S1 +{ + this(ref const S1 s) immutable { + } + int i; +} + +void main() +{ + const(S1) s1; + S1 ms1 = s1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue16020.d b/gcc/testsuite/gdc.test/fail_compilation/issue16020.d index fe4ad78f1ac..79eda2ea08c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/issue16020.d +++ b/gcc/testsuite/gdc.test/fail_compilation/issue16020.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/issue16020.d(12): Error: user-defined attributes not allowed for `alias` declarations -fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration, not `(` -fail_compilation/issue16020.d(13): Error: declaration expected, not `(` +fail_compilation/issue16020.d(13): Error: user-defined attributes not allowed for `alias` declarations +fail_compilation/issue16020.d(14): Error: semicolon expected to close `alias` declaration, not `(` +fail_compilation/issue16020.d(14): Error: declaration expected, not `(` +fail_compilation/issue16020.d(15): Deprecation: storage class `final` has no effect in type aliases --- */ module issue16020; @@ -11,3 +12,4 @@ module issue16020; struct UDA{} alias Fun = @UDA void(); alias FunTemplate = void(T)(T t); +alias F2 = final int(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue20704.d b/gcc/testsuite/gdc.test/fail_compilation/issue20704.d index 1e1f2e6f34b..ba91b063572 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/issue20704.d +++ b/gcc/testsuite/gdc.test/fail_compilation/issue20704.d @@ -1,12 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/issue20704.d(17): Error: cannot modify constant `0` +fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from constant `0` fail_compilation/issue20704.d(28): Error: template instance `issue20704.f2!int` error instantiating -fail_compilation/issue20704.d(19): Error: cannot modify constant `0` +fail_compilation/issue20704.d(19): Error: cannot create default argument for `ref` / `out` parameter from constant `0` fail_compilation/issue20704.d(30): Error: template instance `issue20704.f4!int` error instantiating -fail_compilation/issue20704.d(17): Error: `S(0)` is not an lvalue and cannot be modified +fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from expression `S(0)` because it is not an lvalue fail_compilation/issue20704.d(36): Error: template instance `issue20704.f2!(S)` error instantiating -fail_compilation/issue20704.d(17): Error: `null` is not an lvalue and cannot be modified +fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from expression `null` because it is not an lvalue fail_compilation/issue20704.d(38): Error: template instance `issue20704.f2!(C)` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16381.d b/gcc/testsuite/gdc.test/fail_compilation/test16381.d index fd92798366c..5847e0459b6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16381.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16381.d @@ -2,7 +2,7 @@ REQUIRED_ARGS: -m64 TEST_OUTPUT: --- -fail_compilation/test16381.d(15): Error: `foo()` is not an lvalue and cannot be modified +fail_compilation/test16381.d(15): Error: cannot take address of expression `foo()` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22048.d b/gcc/testsuite/gdc.test/fail_compilation/test22048.d index e0560689f8d..72b91546a2b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test22048.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test22048.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test22048.d(10): Error: unexpected identifier `p` in declarator +fail_compilation/test22048.d(10): Error: unexpected identifier `p` after `int` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24157.d b/gcc/testsuite/gdc.test/fail_compilation/test24157.d index 5022014a9a1..d78c9b628ef 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test24157.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test24157.d @@ -3,8 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/test24157.d(23): Error: `p.self()` is not an lvalue and cannot be modified -fail_compilation/test24157.d(27): Error: `p.unshared()` is not an lvalue and cannot be modified +fail_compilation/test24157.d(23): Error: cannot take address of expression `p.self()` because it is not an lvalue +fail_compilation/test24157.d(27): Error: cannot take address of expression `p.unshared()` because it is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24159.d b/gcc/testsuite/gdc.test/fail_compilation/test24159.d new file mode 100644 index 00000000000..35c7f364168 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24159.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=24159 +// REQUIRED_ARGS: -betterC +/* +TEST_OUTPUT: +--- +fail_compilation/test24159.d(13): Error: appending to array in `x ~= 3` requires the GC which is not available with -betterC +--- +*/ + +extern(C) void main() +{ + int[] x = null; + x ~= 3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d index 50cebabfda4..1173d14480d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d +++ b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d @@ -5,9 +5,9 @@ TEST_OUTPUT: --- fail_compilation/testrvaluecpctor.d(16): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo` fail_compilation/testrvaluecpctor.d(24): Template instance `testrvaluecpctor.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` creates an rvalue constructor for `struct Foo` -fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `__ctor` are callable using a `immutable` object +fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `this` can construct a `immutable` object with argument types `(immutable(Foo!int))` fail_compilation/testrvaluecpctor.d(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref scope Foo!int rhs)` -fail_compilation/testrvaluecpctor.d(16): `__ctor(Rhs, this This)(scope Rhs rhs)` +fail_compilation/testrvaluecpctor.d(16): `this(Rhs, this This)(scope Rhs rhs)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/tolvalue.d b/gcc/testsuite/gdc.test/fail_compilation/tolvalue.d new file mode 100644 index 00000000000..e911dff7729 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/tolvalue.d @@ -0,0 +1,48 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/tolvalue.d(28): Error: cannot take address of template `templateFunc(T)()`, perhaps instantiate it first +fail_compilation/tolvalue.d(29): Error: cannot take address of type `int` +fail_compilation/tolvalue.d(30): Error: cannot take address of constant `3` +fail_compilation/tolvalue.d(31): Error: cannot take address of operator `$` +fail_compilation/tolvalue.d(32): Error: cannot take address of compiler-generated variable `__ctfe` +fail_compilation/tolvalue.d(33): Error: cannot take address of manifest constant `f` +fail_compilation/tolvalue.d(38): Error: cannot create default argument for `ref` / `out` parameter from constant `3` +fail_compilation/tolvalue.d(39): Error: cannot create default argument for `ref` / `out` parameter from compiler-generated variable `__ctfe` +fail_compilation/tolvalue.d(40): Error: cannot create default argument for `ref` / `out` parameter from manifest constant `f` +fail_compilation/tolvalue.d(45): Error: cannot modify constant `3` +fail_compilation/tolvalue.d(46): Error: cannot modify compiler-generated variable `__ctfe` +fail_compilation/tolvalue.d(47): Error: cannot modify manifest constant `f` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=24238 + +void templateFunc(T)() {} +alias intAlias = int; +enum E { f } + +void addr() +{ + int[] a; + auto x0 = &templateFunc; + auto x1 = &intAlias; + auto x2 = &3; + auto x3 = a[&$]; + auto x4 = &__ctfe; + auto x6 = &E.f; +} + +void refArg() +{ + void f0(ref int = 3) {} + void f1(ref bool = __ctfe) {} + void f3(ref E = E.f) {} +} + +void inc(int lz) +{ + 3++; + __ctfe++; + E.f++; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/vector_cast.d b/gcc/testsuite/gdc.test/fail_compilation/vector_cast.d new file mode 100644 index 00000000000..e8a8d48c790 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/vector_cast.d @@ -0,0 +1,13 @@ +/** +REQUIRED_ARGS: -m64 +TEST_OUTPUT: +--- +fail_compilation/vector_cast.d(11): Error: cannot cast expression `a` of type `int[3]` to `__vector(int[4])` +fail_compilation/vector_cast.d(13): Error: cannot cast expression `a` of type `int[5]` to `__vector(int[4])` +--- +*/ + +alias int4 = __vector(int[4]); +int4 convtest3(int[3] a) { return cast(int4) a; } +int4 convtest4(int[4] a) { return cast(int4) a; } +int4 convtest5(int[5] a) { return cast(int4) a; } diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d index 17a2ecb5ec7..606b70e908a 100644 --- a/gcc/testsuite/gdc.test/runnable/staticaa.d +++ b/gcc/testsuite/gdc.test/runnable/staticaa.d @@ -56,7 +56,7 @@ struct Key { int v; bool opEquals(ref const Key o) const { return v == o.v; } - size_t toHash() const { return v; } + size_t toHash() const nothrow { return v; } } Destructing[Key] dAa = [Key(1): Destructing(10), Key(2): Destructing(20)]; @@ -142,6 +142,18 @@ void testImmutable() ///////////////////////////////////////////// +// https://issues.dlang.org/show_bug.cgi?id=24209 +void testLocalStatic() @trusted +{ + static int[int] aa0 = [1: 2]; + __gshared string[string] aa1 = null; + + assert(aa0[1] == 2); + assert(aa1.length == 0); +} + +///////////////////////////////////////////// + void main() { testSimple(); @@ -150,4 +162,5 @@ void main() testStructInit(); testClassInit(); testImmutable(); + testLocalStatic(); } diff --git a/gcc/testsuite/gdc.test/runnable/test24184.d b/gcc/testsuite/gdc.test/runnable/test24184.d new file mode 100644 index 00000000000..736824fce86 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test24184.d @@ -0,0 +1,30 @@ +// https://issues.dlang.org/show_bug.cgi?id=24184 + +void stage3(alias abc)(ubyte[]) +{ + bool skipSpaces() + { + abc(); + return false; + } + skipSpaces; +} +ubyte[] singleThreadJsonImpl(alias xxx)(ubyte[] table) +{ + align(64) ubyte[] vector; + + ubyte[] abc() { return vector; } + + stage3!(abc)(table); + + return table; +} +ubyte[] singleThreadJsonText() +{ + bool xxx() { return true; } + + return singleThreadJsonImpl!(xxx)([]); +} +void deserializeJson() { singleThreadJsonText(); } + +void main() { deserializeJson(); } diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 235db4b2ef1..aa0062c10eb 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -643b1261bba0757d97efa3ff1f63e461271eb000 +ff57fec51558013b25cadb7e83da9f4675915d56 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 b79bd1df9c4..9c5735728b5 100644 --- a/libphobos/libdruntime/core/cpuid.d +++ b/libphobos/libdruntime/core/cpuid.d @@ -666,10 +666,12 @@ void getAMDcacheinfo() // to determine number of processors. void getCpuInfo0B() { - int level=0; int threadsPerCore; uint a, b, c, d; - do { + // I'm not sure about this. The docs state that there + // are 2 hyperthreads per core if HT is factory enabled. + for (int level = 0; level < 2; level++) + { version (GNU_OR_LDC) asm pure nothrow @nogc { "cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (0x0B), "c" (level); } else asm pure nothrow @nogc { @@ -681,19 +683,20 @@ void getCpuInfo0B() mov c, ECX; mov d, EDX; } - if (b!=0) { - // I'm not sure about this. The docs state that there - // are 2 hyperthreads per core if HT is factory enabled. - if (level==0) + if (b != 0) + { + if (level == 0) threadsPerCore = b & 0xFFFF; - else if (level==1) { + else if (level == 1) + { cpuFeatures.maxThreads = b & 0xFFFF; cpuFeatures.maxCores = cpuFeatures.maxThreads / threadsPerCore; } - } - ++level; - } while (a!=0 || b!=0); + // Got "invalid domain" returned from cpuid + if (a == 0 && b == 0) + break; + } } void cpuidX86() diff --git a/libphobos/libdruntime/core/internal/array/appending.d b/libphobos/libdruntime/core/internal/array/appending.d index bb24813ae9e..ba34727a305 100644 --- a/libphobos/libdruntime/core/internal/array/appending.d +++ b/libphobos/libdruntime/core/internal/array/appending.d @@ -14,56 +14,55 @@ private extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref return scope private enum isCopyingNothrow(T) = __traits(compiles, (ref T rhs) nothrow { T lhs = rhs; }); -/// Implementation of `_d_arrayappendcTX` and `_d_arrayappendcTXTrace` -template _d_arrayappendcTXImpl(Tarr : T[], T) +/** + * Extend an array `px` by `n` elements. + * Caller must initialize those elements. + * Params: + * px = the array that will be extended, taken as a reference + * n = how many new elements to extend it with + * 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. + */ +ref Tarr _d_arrayappendcTX(Tarr : T[], T)(return ref scope Tarr px, size_t n) @trusted { - private enum errorMessage = "Cannot append to array if compiling without support for runtime type information!"; + // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718 + version (DigitalMars) pragma(inline, false); + version (D_TypeInfo) + { + auto ti = typeid(Tarr); + + // _d_arrayappendcTX takes the `px` as a ref byte[], but its length + // should still be the original length + auto pxx = (cast(byte*)px.ptr)[0 .. px.length]; + ._d_arrayappendcTX(ti, pxx, n); + px = (cast(T*)pxx.ptr)[0 .. pxx.length]; + + return px; + } + else + assert(0, "Cannot append to array if compiling without support for runtime type information!"); +} +version (D_ProfileGC) +{ /** - * Extend an array `px` by `n` elements. - * Caller must initialize those elements. - * Params: - * px = the array that will be extended, taken as a reference - * n = how many new elements to extend it with - * 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. + * TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending). */ - ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow + ref Tarr _d_arrayappendcTXTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr px, size_t n) @trusted { - // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718 - version (DigitalMars) pragma(inline, false); version (D_TypeInfo) { - auto ti = typeid(Tarr); - - // _d_arrayappendcTX takes the `px` as a ref byte[], but its length - // should still be the original length - auto pxx = (cast(byte*)px.ptr)[0 .. px.length]; - ._d_arrayappendcTX(ti, pxx, n); - px = (cast(T*)pxx.ptr)[0 .. pxx.length]; + import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(Tarr.stringof, "_d_arrayappendcTX")); - return px; + return _d_arrayappendcTX(px, n); } else - assert(0, errorMessage); - } - - version (D_ProfileGC) - { - import core.internal.array.utils : _d_HookTraceImpl; - - /** - * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl). - * 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. - */ - alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage); + static assert(0, "Cannot append to array if compiling without support for runtime type information!"); } } @@ -78,7 +77,7 @@ ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @ enum hasPostblit = __traits(hasPostblit, T); auto length = x.length; - _d_arrayappendcTXImpl!Tarr._d_arrayappendcTX(x, y.length); + _d_arrayappendcTX(x, y.length); // Only call `copyEmplace` if `T` has a copy ctor and no postblit. static if (hasElaborateCopyConstructor!T && !hasPostblit) @@ -126,7 +125,7 @@ version (D_ProfileGC) return _d_arrayappendT(x, y); } else - assert(0, "Cannot append to array if compiling without support for runtime type information!"); + static assert(0, "Cannot append to array if compiling without support for runtime type information!"); } } diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d index 54f8767139c..655acc8db57 100644 --- a/libphobos/libdruntime/core/internal/array/construction.d +++ b/libphobos/libdruntime/core/internal/array/construction.d @@ -486,3 +486,111 @@ version (D_ProfileGC) assert(0, "Cannot create new array if compiling without support for runtime type information!"); } } + +/** + * Create a new multi-dimensional array. Also initalize elements if their type has an initializer. + * Otherwise, not zero-initialize the array. + * + * --- + * void main() + * { + * S[][] s = new S[][](2, 3) + * + * // lowering: + * S[] s = _d_newarraymTX!(S[][], S)([2, 3]); + * } + * --- + * + * Params: + * dims = array length values for each dimension + * isShared = whether the array should be shared + * + * Returns: + * newly allocated array + */ +Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trusted +{ + debug(PRINTF) printf("_d_newarraymTX(dims.length = %d)\n", dims.length); + + if (dims.length == 0) + return null; + + alias UnqT = Unqual!(T); + + void[] __allocateInnerArray(size_t[] dims) + { + import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc; + + auto dim = dims[0]; + + debug(PRINTF) printf("__allocateInnerArray(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length); + if (dims.length == 1) + { + auto r = _d_newarrayT!UnqT(dim, isShared); + return *cast(void[]*)(&r); + } + + auto allocSize = (void[]).sizeof * dim; + auto info = __arrayAlloc!UnqT(allocSize); + __setArrayAllocLength!UnqT(info, allocSize, isShared); + auto p = __arrayStart(info)[0 .. dim]; + + foreach (i; 0..dim) + { + (cast(void[]*)p.ptr)[i] = __allocateInnerArray(dims[1..$]); + } + return p; + } + + auto result = __allocateInnerArray(dims); + debug(PRINTF) printf("result = %llx\n", result.ptr); + + return (cast(U*) result.ptr)[0 .. dims[0]]; +} + +unittest +{ + int[][] a = _d_newarraymTX!(int[][], int)([2, 3]); + + assert(a.length == 2); + for (size_t i = 0; i < a.length; i++) + { + assert(a[i].length == 3); + for (size_t j = 0; j < a[i].length; j++) + assert(a[i][j] == 0); + } +} + +unittest +{ + struct S { int x = 1; } + + S[][] a = _d_newarraymTX!(S[][], S)([2, 3]); + + assert(a.length == 2); + for (size_t i = 0; i < a.length; i++) + { + assert(a[i].length == 3); + for (size_t j = 0; j < a[i].length; j++) + assert(a[i][j].x == 1); + } +} + +version (D_ProfileGC) +{ + /** + * TraceGC wrapper around $(REF _d_newarraymT, core,internal,array,construction). + */ + Tarr _d_newarraymTXTrace(Tarr : U[], T, U)(string file, int line, string funcname, size_t[] dims, bool isShared=false) @trusted + { + version (D_TypeInfo) + { + import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(T.stringof, "_d_newarraymTX")); + + return _d_newarraymTX!(Tarr, T)(dims, isShared); + } + else + assert(0, "Cannot create new multi-dimensional array if compiling without support for runtime type information!"); + } +} diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d index 5daab89a387..eebf94ee29d 100644 --- a/libphobos/libdruntime/core/internal/atomic.d +++ b/libphobos/libdruntime/core/internal/atomic.d @@ -656,7 +656,7 @@ version (DigitalMars) asm pure nothrow @nogc @trusted { naked; - rep; nop; + pause; ret; } } @@ -665,8 +665,7 @@ version (DigitalMars) asm pure nothrow @nogc @trusted { naked; - // pause; // TODO: DMD should add this opcode to its inline asm - rep; nop; + pause; ret; } } diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d index 39cd30aee16..6f194126e7e 100644 --- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d +++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d @@ -3336,7 +3336,7 @@ Lmark: busyThreads.atomicOp!"+="(1); // main thread is busy - evStart.set(); + evStart.setIfInitialized(); debug(PARALLEL_PRINTF) printf("mark %lld roots\n", cast(ulong)(ptop - pbot)); @@ -3438,7 +3438,7 @@ Lmark: stopGC = true; while (atomicLoad(stoppedThreads) < startedThreads && !allThreadsDead) { - evStart.set(); + evStart.setIfInitialized(); evDone.wait(dur!"msecs"(1)); } @@ -3467,7 +3467,7 @@ Lmark: { evStart.wait(); pullFromScanStack(); - evDone.set(); + evDone.setIfInitialized(); } stoppedThreads.atomicOp!"+="(1); } diff --git a/libphobos/libdruntime/core/internal/newaa.d b/libphobos/libdruntime/core/internal/newaa.d index 314f2554103..2fd93651a22 100644 --- a/libphobos/libdruntime/core/internal/newaa.d +++ b/libphobos/libdruntime/core/internal/newaa.d @@ -50,6 +50,7 @@ struct Impl immutable uint valsz; immutable uint valoff; Flags flags; + size_t delegate(scope const void*) nothrow hashFn; enum Flags : ubyte { @@ -76,15 +77,19 @@ private size_t mix(size_t h) @safe pure nothrow @nogc struct Entry(K, V) { - /*const*/ K key; // this really should be const, but legacy issues. + // can make this const, because we aren't really going to use it aside from + // construction. + const K key; V value; } // create a binary-compatible AA structure that can be used directly as an // associative array. -AAShell makeAA(K, V)(V[K] src) +// NOTE: this must only be called during CTFE +AAShell makeAA(K, V)(V[K] src) @trusted { + assert(__ctfe, "makeAA Must only be called at compile time"); immutable srclen = src.length; assert(srclen <= uint.max); alias E = Entry!(K, V); @@ -96,6 +101,12 @@ AAShell makeAA(K, V)(V[K] src) while (srclen * GROW_DEN > dim * GROW_NUM) dim = dim * GROW_FAC; + // used during runtime. + size_t delegate(scope const void *) nothrow hashFn = (scope const void* val) { + auto x = cast(K*)val; + return hashOf(*x); + }; + Bucket[] buckets; // Allocate and fill the buckets if (__ctfe) @@ -140,5 +151,19 @@ AAShell makeAA(K, V)(V[K] src) } (); // return the new implementation return AAShell(new Impl(buckets, cast(uint)srclen, 0, typeid(E), firstUsed, - K.sizeof, V.sizeof, E.value.offsetof, flags)); + K.sizeof, V.sizeof, E.value.offsetof, flags, hashFn)); +} + +unittest +{ + static struct Foo + { + ubyte x; + double d; + } + static int[Foo] utaa = [Foo(1, 2.0) : 5]; + auto k = Foo(1, 2.0); + // verify that getHash doesn't match hashOf for Foo + assert(typeid(Foo).getHash(&k) != hashOf(k)); + assert(utaa[Foo(1, 2.0)] == 5); } diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d index 288f9c25dc6..0051ecdb7c9 100644 --- a/libphobos/libdruntime/core/stdc/fenv.d +++ b/libphobos/libdruntime/core/stdc/fenv.d @@ -797,7 +797,7 @@ else } else version (LoongArch64) { - // Define bits representing exceptions in the FPSR status word. + // Define bits representing exceptions in the Flags field in FCSR{0,2}. enum { FE_INEXACT = 0x010000, /// @@ -808,13 +808,13 @@ else FE_ALL_EXCEPT = 0x1f0000, /// } - // Define bits representing rounding modes in the FPCR Rmode field. + // Define bits representing rounding modes in the RM field in FCSR{0,3}. enum { FE_TONEAREST = 0x000, /// FE_TOWARDZERO = 0x100, /// - FE_DOWNWARD = 0x200, /// - FE_UPWARD = 0x300, /// + FE_UPWARD = 0x200, /// + FE_DOWNWARD = 0x300, /// } } else diff --git a/libphobos/libdruntime/core/stdc/stdarg.d b/libphobos/libdruntime/core/stdc/stdarg.d index 5b79813ae1b..0ba1ebe34e3 100644 --- a/libphobos/libdruntime/core/stdc/stdarg.d +++ b/libphobos/libdruntime/core/stdc/stdarg.d @@ -257,6 +257,12 @@ T va_arg(T)(ref va_list ap) ap += T.sizeof.alignUp; return *p; } + else version (LoongArch64) + { + auto p = cast(T*) ap; + ap += T.sizeof.alignUp; + return *p; + } else version (MIPS_Any) { auto p = cast(T*) ap; diff --git a/libphobos/libdruntime/core/sync/event.d b/libphobos/libdruntime/core/sync/event.d index 37951061d93..048607f6ed2 100644 --- a/libphobos/libdruntime/core/sync/event.d +++ b/libphobos/libdruntime/core/sync/event.d @@ -61,7 +61,7 @@ struct ProcessFile group.create(&doProcess); buffer = std.file.read(filename); - event.set(); + event.setIfInitialized(); group.joinAll(); event.terminate(); } @@ -162,9 +162,13 @@ nothrow @nogc: } } + deprecated ("Use setIfInitialized() instead") void set() + { + setIfInitialized(); + } /// Set the event to "signaled", so that waiting clients are resumed - void set() + void setIfInitialized() { version (Windows) { @@ -302,7 +306,7 @@ private: // auto-reset, initial state false Event ev1 = Event(false, false); assert(!ev1.wait(1.dur!"msecs")); - ev1.set(); + ev1.setIfInitialized(); assert(ev1.wait()); assert(!ev1.wait(1.dur!"msecs")); @@ -336,7 +340,7 @@ unittest auto start = MonoTime.currTime; assert(numRunning == 0); - event.set(); + event.setIfInitialized(); group.joinAll(); assert(numRunning == numThreads); diff --git a/libphobos/libdruntime/core/sys/elf/package.d b/libphobos/libdruntime/core/sys/elf/package.d index b120ee58f69..60e05d97036 100644 --- a/libphobos/libdruntime/core/sys/elf/package.d +++ b/libphobos/libdruntime/core/sys/elf/package.d @@ -339,6 +339,8 @@ enum EM_CSKY = 252; enum EM_NUM = 253; +enum EM_LOONGARCH = 258; + enum EM_ALPHA = 0x9026; enum EV_NONE = 0; diff --git a/libphobos/libdruntime/core/sys/linux/sys/auxv.d b/libphobos/libdruntime/core/sys/linux/sys/auxv.d index 5f098e98e02..1099fae497f 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/auxv.d +++ b/libphobos/libdruntime/core/sys/linux/sys/auxv.d @@ -13,6 +13,7 @@ extern (C): version (MIPS32) version = MIPS_Any; version (MIPS64) version = MIPS_Any; +version (LoongArch64) version = LoongArch_Any; version (PPC) version = PPC_Any; version (PPC64) version = PPC_Any; version (S390) version = IBMZ_Any; @@ -156,3 +157,19 @@ else version (IBMZ_Any) enum HWCAP_S390_TE = 1024; enum HWCAP_S390_VX = 2048; } +else version (LoongArch_Any) +{ + enum HWCAP_LOONGARCH_CPUCFG = 0x00000001; + enum HWCAP_LOONGARCH_LAM = 0x00000002; + enum HWCAP_LOONGARCH_UAL = 0x00000004; + enum HWCAP_LOONGARCH_FPU = 0x00000008; + enum HWCAP_LOONGARCH_LSX = 0x00000010; + enum HWCAP_LOONGARCH_LASX = 0x00000020; + enum HWCAP_LOONGARCH_CRC32 = 0x00000040; + enum HWCAP_LOONGARCH_COMPLEX = 0x00000080; + enum HWCAP_LOONGARCH_CRYPTO = 0x00000100; + enum HWCAP_LOONGARCH_LVZ = 0x00000200; + enum HWCAP_LOONGARCH_LBT_X86 = 0x00000400; + enum HWCAP_LOONGARCH_LBT_ARM = 0x00000800; + enum HWCAP_LOONGARCH_LBT_MIPS = 0x00001000; +} diff --git a/libphobos/libdruntime/core/sys/linux/sys/mman.d b/libphobos/libdruntime/core/sys/linux/sys/mman.d index 7ed78ef6436..e4765af1490 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/mman.d +++ b/libphobos/libdruntime/core/sys/linux/sys/mman.d @@ -432,6 +432,7 @@ else version (MIPS_Any) MAP_HUGETLB = 0x80000, } } +// http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/bits/mman-map-flags-generic.h else version (LoongArch64) { static if (_DEFAULT_SOURCE) enum diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d index 65878bc1c66..8bbd6e15c4e 100644 --- a/libphobos/libdruntime/core/thread/fiber.d +++ b/libphobos/libdruntime/core/thread/fiber.d @@ -178,8 +178,12 @@ private } else version (LoongArch64) { - version = AsmLoongArch64_Posix; - version = AsmExternal; + version (Posix) + { + version = AsmLoongArch64_Posix; + version = AsmExternal; + version = AlignFiberStackTo16Byte; + } } version (Posix) @@ -1444,24 +1448,28 @@ private: } else version (AsmLoongArch64_Posix) { + // Like others, FP registers and return address ($r1) are kept + // below the saved stack top (tstack) to hide from GC scanning. + // fiber_switchContext expects newp sp to look like this: + // 10: $r21 (reserved) + // 9: $r22 (frame pointer) + // 8: $r23 + // ... + // 0: $r31 <-- newp tstack + // -1: $r1 (return address) [&fiber_entryPoint] + // -2: $f24 + // ... + // -9: $f31 + version (StackGrowsDown) {} - else static assert(0); + else + static assert(false, "Only full descending stacks supported on LoongArch64"); - // Like others, FP registers and return address (ra) are kept - // below the saved stack top (tstack) to hide from GC scanning. - // The newp stack should look like this on LoongArch64: - // 18: fp <- pstack - // ... - // 9: s0 <- newp tstack - // 8: ra [&fiber_entryPoint] - // 7: fs7 - // ... - // 1: fs1 - // 0: fs0 - pstack -= 10 * size_t.sizeof; // skip s0-s8 and fp - // set $ra - push( cast(size_t) &fiber_entryPoint ); - pstack += size_t.sizeof; + // Only need to set return address ($r1). Everything else is fine + // zero initialized. + pstack -= size_t.sizeof * 11; // skip past space reserved for $r21-$r31 + push (cast(size_t) &fiber_entryPoint); + pstack += size_t.sizeof; // adjust sp (newp) above lr } else version (AsmAArch64_Posix) { diff --git a/libphobos/libdruntime/core/vararg.d b/libphobos/libdruntime/core/vararg.d index 2c3e9659fb6..e6dd47d06d3 100644 --- a/libphobos/libdruntime/core/vararg.d +++ b/libphobos/libdruntime/core/vararg.d @@ -129,6 +129,13 @@ void va_arg()(ref va_list ap, TypeInfo ti, void* parmn) ap += tsize.alignUp; parmn[0..tsize] = p[0..tsize]; } + else version (LoongArch64) + { + const tsize = ti.tsize; + auto p = cast(void*) ap; + ap += tsize.alignUp; + parmn[0..tsize] = p[0..tsize]; + } else version (MIPS_Any) { const tsize = ti.tsize; diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 0111be0b617..5589c0a884f 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -642,7 +642,8 @@ class TypeInfo */ size_t getHash(scope const void* p) @trusted nothrow const { - return hashOf(p); + // by default, do not assume anything about the type + return 0; } /// Compares two instances for equality. @@ -2918,19 +2919,19 @@ alias AssociativeArray(Key, Value) = Value[Key]; * Params: * aa = The associative array. */ -void clear(Value, Key)(Value[Key] aa) +void clear(Value, Key)(Value[Key] aa) @trusted { _aaClear(*cast(AA *) &aa); } /** ditto */ -void clear(Value, Key)(Value[Key]* aa) +void clear(Value, Key)(Value[Key]* aa) @trusted { _aaClear(*cast(AA *) aa); } /// -@system unittest +@safe unittest { auto aa = ["k1": 2]; aa.clear; @@ -4666,11 +4667,13 @@ public import core.internal.array.appending : _d_arrayappendT; version (D_ProfileGC) { public import core.internal.array.appending : _d_arrayappendTTrace; + public import core.internal.array.appending : _d_arrayappendcTXTrace; public import core.internal.array.concatenation : _d_arraycatnTXTrace; public import core.lifetime : _d_newitemTTrace; public import core.internal.array.construction : _d_newarrayTTrace; + public import core.internal.array.construction : _d_newarraymTXTrace; } -public import core.internal.array.appending : _d_arrayappendcTXImpl; +public import core.internal.array.appending : _d_arrayappendcTX; public import core.internal.array.comparison : __cmp; public import core.internal.array.equality : __equals; public import core.internal.array.casting: __ArrayCast; @@ -4678,6 +4681,7 @@ public import core.internal.array.concatenation : _d_arraycatnTX; public import core.internal.array.construction : _d_arrayctor; public import core.internal.array.construction : _d_arraysetctor; public import core.internal.array.construction : _d_newarrayT; +public import core.internal.array.construction : _d_newarraymTX; public import core.internal.array.arrayassign : _d_arrayassign_l; public import core.internal.array.arrayassign : _d_arrayassign_r; public import core.internal.array.arrayassign : _d_arraysetassign; diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d index 4014862b4e4..36f25554db3 100644 --- a/libphobos/libdruntime/rt/aaA.d +++ b/libphobos/libdruntime/rt/aaA.d @@ -41,7 +41,7 @@ struct AA Impl* impl; alias impl this; - private @property bool empty() const pure nothrow @nogc + private @property bool empty() const pure nothrow @nogc @safe { return impl is null || !impl.length; } @@ -57,6 +57,7 @@ private: buckets = allocBuckets(sz); firstUsed = cast(uint) buckets.length; valoff = cast(uint) talign(keysz, ti.value.talign); + hashFn = &ti.key.getHash; import rt.lifetime : hasPostblit, unqualify; @@ -78,6 +79,10 @@ private: immutable uint valoff; Flags flags; + // function that calculates hash of a key. Set on creation + // the parameter is a pointer to the key. + size_t delegate(scope const void*) nothrow hashFn; + enum Flags : ubyte { none = 0x0, @@ -85,7 +90,7 @@ private: hasPointers = 0x2, } - @property size_t length() const pure nothrow @nogc + @property size_t length() const pure nothrow @nogc @safe { assert(used >= deleted); return used - deleted; @@ -156,7 +161,7 @@ private: GC.free(obuckets.ptr); // safe to free b/c impossible to reference } - void clear() pure nothrow + void clear() pure nothrow @trusted { import core.stdc.string : memset; // clear all data, but don't change bucket array length @@ -457,9 +462,9 @@ private size_t mix(size_t h) @safe pure nothrow @nogc return h; } -private size_t calcHash(scope const void* pkey, scope const TypeInfo keyti) nothrow +private size_t calcHash(scope const void *pkey, scope const Impl* impl) nothrow { - immutable hash = keyti.getHash(pkey); + immutable hash = impl.hashFn(pkey); // highest bit is set to distinguish empty/deleted from filled buckets return mix(hash) | HASH_FILLED_MARK; } @@ -550,7 +555,7 @@ extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, } // get hash and bucket for key - immutable hash = calcHash(pkey, ti.key); + immutable hash = calcHash(pkey, aa); // found a value => return it if (auto p = aa.findSlotLookup(hash, pkey, ti.key)) @@ -617,7 +622,7 @@ extern (C) inout(void)* _aaInX(inout AA aa, scope const TypeInfo keyti, scope co if (aa.empty) return null; - immutable hash = calcHash(pkey, keyti); + immutable hash = calcHash(pkey, aa); if (auto p = aa.findSlotLookup(hash, pkey, keyti)) return p.entry + aa.valoff; return null; @@ -629,7 +634,7 @@ extern (C) bool _aaDelX(AA aa, scope const TypeInfo keyti, scope const void* pke if (aa.empty) return false; - immutable hash = calcHash(pkey, keyti); + immutable hash = calcHash(pkey, aa); if (auto p = aa.findSlotLookup(hash, pkey, keyti)) { // clear entry @@ -648,7 +653,7 @@ extern (C) bool _aaDelX(AA aa, scope const TypeInfo keyti, scope const void* pke } /// Remove all elements from AA. -extern (C) void _aaClear(AA aa) pure nothrow +extern (C) void _aaClear(AA aa) pure nothrow @safe { if (!aa.empty) { @@ -778,7 +783,7 @@ extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void uint actualLength = 0; foreach (_; 0 .. length) { - immutable hash = calcHash(pkey, ti.key); + immutable hash = calcHash(pkey, aa); auto p = aa.findSlotLookup(hash, pkey, ti.key); if (p is null) diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index af3c6bb1296..8ce2d564bd6 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -1041,98 +1041,6 @@ extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @ } } - -/* - * Helper for creating multi-dimensional arrays - */ -private void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims) -{ - debug(PRINTF) printf("_d_newarrayOpT(ndims = %d)\n", dims.length); - if (dims.length == 0) - return null; - - void[] foo(const TypeInfo ti, size_t[] dims) - { - auto tinext = unqualify(ti.next); - auto dim = dims[0]; - - debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length); - if (dims.length == 1) - { - auto r = op(ti, dim); - return *cast(void[]*)(&r); - } - - auto allocsize = (void[]).sizeof * dim; - auto info = __arrayAlloc(allocsize, ti, tinext); - auto isshared = typeid(ti) is typeid(TypeInfo_Shared); - __setArrayAllocLength(info, allocsize, isshared, tinext); - auto p = __arrayStart(info)[0 .. dim]; - - foreach (i; 0..dim) - { - (cast(void[]*)p.ptr)[i] = foo(tinext, dims[1..$]); - } - return p; - } - - auto result = foo(ti, dims); - debug(PRINTF) printf("result = %llx\n", result.ptr); - - return result; -} - - -/** -Create a new multi-dimensional array - -Has two variants: -- `_d_newarraymTX` which initializes to 0 -- `_d_newarraymiTX` which initializes elements based on `TypeInfo` - ---- -void main() -{ - new int[][](10, 20); - // _d_newarraymTX(typeid(float), [10, 20]); - - new float[][][](10, 20, 30); - // _d_newarraymiTX(typeid(float), [10, 20, 30]); -} ---- - -Params: - ti = `TypeInfo` of the array type - dims = array length values for each dimension - -Returns: - newly allocated array -*/ -extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims) @weak -{ - debug(PRINTF) printf("_d_newarraymT(dims.length = %d)\n", dims.length); - - if (dims.length == 0) - return null; - else - { - return _d_newarrayOpT!(_d_newarrayT)(ti, dims); - } -} - -/// ditto -extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak -{ - debug(PRINTF) printf("_d_newarraymiT(dims.length = %d)\n", dims.length); - - if (dims.length == 0) - return null; - else - { - return _d_newarrayOpT!(_d_newarrayiT)(ti, dims); - } -} - /** Non-template version of $(REF _d_newitemT, core,lifetime) that does not perform initialization. Needed for $(REF allocEntry, rt,aaA). diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 95b2778d141..1b20d58c1e2 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -fc06c514a8c4492f60fc89b8c4f857e6932fbcbd +17bafda797296e04f40f16a9660e5a9685392db4 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index 0adb88b2210..ef1170600b3 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -4809,26 +4809,41 @@ private template ReduceSeedType(E) /++ Implements the homonym function (also known as `accumulate`, $(D compress), `inject`, or `foldl`) present in various programming -languages of functional flavor. The call `fold!(fun)(range, seed)` -first assigns `seed` to an internal variable `result`, -also called the accumulator. Then, for each element `x` in $(D -range), `result = fun(result, x)` gets evaluated. Finally, $(D -result) is returned. The one-argument version `fold!(fun)(range)` +languages of functional flavor, iteratively calling one or more predicates. + +$(P Each predicate in `fun` must take two arguments:) +* An accumulator value +* An element of the range `r` +$(P Each predicate must return a value which implicitly converts to the +type of the accumulator.) + +$(P For a single predicate, +the call `fold!(fun)(range, seed)` will:) + +* Use `seed` to initialize an internal variable `result` (also called + the accumulator). +* For each element `e` in $(D range), evaluate `result = fun(result, e)`. +* Return $(D result). + +$(P The one-argument version `fold!(fun)(range)` works similarly, but it uses the first element of the range as the -seed (the range must be non-empty). +seed (the range must be non-empty) and iterates over the remaining +elements.) + +Multiple results are produced when using multiple predicates. Params: fun = the predicate function(s) to apply to the elements See_Also: - $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function)) + * $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function)) - $(LREF sum) is similar to `fold!((a, b) => a + b)` that offers - precise summing of floating point numbers. + * $(LREF sum) is similar to `fold!((a, b) => a + b)` that offers + precise summing of floating point numbers. - This is functionally equivalent to $(LREF reduce) with the argument order - reversed, and without the need to use $(REF_ALTTEXT `tuple`,tuple,std,typecons) - for multiple seeds. + * `fold` is functionally equivalent to $(LREF reduce) with the argument order + reversed, and without the need to use $(REF_ALTTEXT `tuple`,tuple,std,typecons) + for multiple seeds. +/ template fold(fun...) if (fun.length >= 1) @@ -4836,20 +4851,21 @@ if (fun.length >= 1) /** Params: r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to fold - seed = the initial value of the accumulator + seeds = the initial values of each accumulator (optional), one for each predicate Returns: - the accumulated `result` + Either the accumulated result for a single predicate, or a + $(REF_ALTTEXT `Tuple`,Tuple,std,typecons) of results. */ - auto fold(R, S...)(R r, S seed) + auto fold(R, S...)(R r, S seeds) { static if (S.length < 2) { - return reduce!fun(seed, r); + return reduce!fun(seeds, r); } else { import std.typecons : tuple; - return reduce!fun(tuple(seed), r); + return reduce!fun(tuple(seeds), r); } } } @@ -4860,10 +4876,10 @@ if (fun.length >= 1) immutable arr = [1, 2, 3, 4, 5]; // Sum all elements - assert(arr.fold!((a, b) => a + b) == 15); + assert(arr.fold!((a, e) => a + e) == 15); // Sum all elements with explicit seed - assert(arr.fold!((a, b) => a + b)(6) == 21); + assert(arr.fold!((a, e) => a + e)(6) == 21); import std.algorithm.comparison : min, max; import std.typecons : tuple; @@ -4875,10 +4891,10 @@ if (fun.length >= 1) assert(arr.fold!(min, max)(0, 7) == tuple(0, 7)); // Can be used in a UFCS chain - assert(arr.map!(a => a + 1).fold!((a, b) => a + b) == 20); + assert(arr.map!(a => a + 1).fold!((a, e) => a + e) == 20); // Return the last element of any range - assert(arr.fold!((a, b) => b) == 5); + assert(arr.fold!((a, e) => e) == 5); } @safe @nogc pure nothrow unittest diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index 37a08de7a8f..68979057f54 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -1546,28 +1546,96 @@ if (isInputRange!Range && !isInfinite!Range && } // find +/** +Finds an element `e` of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) +where `pred(e)` is `true`. +$(P +$(PANEL +$(UL +$(LI `find` behaves similarly to `dropWhile` in other languages.) +$(LI To _find the *last* matching element in a +$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`, +call `find!pred(retro(haystack))`. See $(REF retro, std,range).) +))) + +Complexity: + `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`. + +Params: + + pred = The predicate to match an element. + haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) + searched in. + +Returns: + `haystack` advanced such that the front element satisfies `pred`. + If no such element exists, returns an empty `haystack`. +*/ +InputRange find(alias pred, InputRange)(InputRange haystack) +if (isInputRange!InputRange) +{ + alias R = InputRange; + alias predFun = unaryFun!pred; + static if (isNarrowString!R) + { + import std.utf : decode; + + immutable len = haystack.length; + size_t i = 0, next = 0; + while (next < len) + { + if (predFun(decode(haystack, next))) + return haystack[i .. $]; + i = next; + } + return haystack[$ .. $]; + } + else + { + //standard range + for ( ; !haystack.empty; haystack.popFront() ) + { + if (predFun(haystack.front)) + break; + } + return haystack; + } +} + +/// +@safe unittest +{ + auto arr = [ 1, 2, 3, 4, 1 ]; + assert(find!("a > 2")(arr) == [ 3, 4, 1 ]); + + // with predicate alias + bool pred(int e) => e + 1 > 1.5; + assert(find!(pred)(arr) == arr); +} + +@safe pure unittest +{ + int[] r = [ 1, 2, 3 ]; + assert(find!(a=>a > 2)(r) == [3]); + bool pred(int x) { return x + 1 > 1.5; } + assert(find!(pred)(r) == r); + + assert(find!(a=>a > 'v')("hello world") == "world"); + assert(find!(a=>a%4 == 0)("日本語") == "本語"); +} + /** Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). Elements of `haystack` are compared with `needle` by using predicate `pred` with `pred(haystack.front, needle)`. -`find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`. - The predicate is passed to $(REF binaryFun, std, functional), and can either accept a string, or any callable that can be executed via `pred(element, element)`. -To _find the last occurrence of `needle` in a -$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`, -call `find(retro(haystack), needle)`. See $(REF retro, std,range). - -If no `needle` is provided, `pred(haystack.front)` will be evaluated on each -element of the input range. - -If `input` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives), +If `haystack` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives), `needle` can be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) too. In this case `startsWith!pred(haystack, needle)` is evaluated on each evaluation. -Note: - `find` behaves similar to `dropWhile` in other languages. +$(NOTE To find the first element $(I not) matching the needle, use predicate `"a != b"`.) Complexity: `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`. @@ -1579,21 +1647,16 @@ Complexity: Params: pred = The predicate for comparing each element with the needle, defaulting to equality `"a == b"`. - The negated predicate `"a != b"` can be used to search instead for the first - element $(I not) matching the needle. - haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) searched in. - needle = The element searched for. Returns: - `haystack` advanced such that the front element is the one searched for; that is, until `binaryFun!pred(haystack.front, needle)` is `true`. If no such position exists, returns an empty `haystack`. -See_ALso: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith) +See_Also: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith) */ InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle) if (isInputRange!InputRange && @@ -1754,8 +1817,8 @@ if (isInputRange!InputRange && assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]); assert(arr.find(1) == arr); assert(arr.find(9) == [9]); - assert(arr.find!((a, b) => a > b)(4) == [5, 6, 9]); - assert(arr.find!((a, b) => a < b)(4) == arr); + assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]); + assert(arr.find!((e, n) => e < n)(4) == arr); assert(arr.find(0).empty); assert(arr.find(10).empty); assert(arr.find(8).empty); @@ -1770,7 +1833,7 @@ if (isInputRange!InputRange && import std.uni : toLower; string[] s = ["Hello", "world", "!"]; - assert(s.find!((a, b) => toLower(a) == b)("hello") == s); + assert(s.find!((e, n) => toLower(e) == n)("hello") == s); } @safe unittest @@ -1862,60 +1925,6 @@ if (isInputRange!InputRange && assert([x].find(x).empty == false); } -/// ditto -InputRange find(alias pred, InputRange)(InputRange haystack) -if (isInputRange!InputRange) -{ - alias R = InputRange; - alias predFun = unaryFun!pred; - static if (isNarrowString!R) - { - import std.utf : decode; - - immutable len = haystack.length; - size_t i = 0, next = 0; - while (next < len) - { - if (predFun(decode(haystack, next))) - return haystack[i .. $]; - i = next; - } - return haystack[$ .. $]; - } - else - { - //standard range - for ( ; !haystack.empty; haystack.popFront() ) - { - if (predFun(haystack.front)) - break; - } - return haystack; - } -} - -/// -@safe unittest -{ - auto arr = [ 1, 2, 3, 4, 1 ]; - assert(find!("a > 2")(arr) == [ 3, 4, 1 ]); - - // with predicate alias - bool pred(int x) { return x + 1 > 1.5; } - assert(find!(pred)(arr) == arr); -} - -@safe pure unittest -{ - int[] r = [ 1, 2, 3 ]; - assert(find!(a=>a > 2)(r) == [3]); - bool pred(int x) { return x + 1 > 1.5; } - assert(find!(pred)(r) == r); - - assert(find!(a=>a > 'v')("hello world") == "world"); - assert(find!(a=>a%4 == 0)("日本語") == "本語"); -} - /// ditto R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle) if (isForwardRange!R1 && isForwardRange!R2 @@ -2376,9 +2385,9 @@ is considered to be 1.) The strategy used in searching several subranges at once maximizes cache usage by moving in `haystack` as few times as possible. */ -Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...) -(Range haystack, Ranges needles) -if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles)))) +Tuple!(Range, size_t) find(alias pred = "a == b", Range, Needles...) +(Range haystack, Needles needles) +if (Needles.length > 1 && is(typeof(startsWith!pred(haystack, needles)))) { for (;; haystack.popFront()) { @@ -2536,13 +2545,13 @@ was successful. For more information about `pred` see $(LREF find). See_Also: -$(REF among, std,algorithm,comparison) for checking a value against multiple possibilities. +$(REF among, std,algorithm,comparison) for checking a value against multiple arguments. +/ template canFind(alias pred="a == b") { /++ - Returns `true` if and only if any value `v` found in the - input range `range` satisfies the predicate `pred`. + Returns `true` if and only if `pred(e)` is true for any value `e` in the + input range `range`. Performs (at most) $(BIGOH haystack.length) evaluations of `pred`. +/ bool canFind(Range)(Range haystack) @@ -2565,16 +2574,15 @@ template canFind(alias pred="a == b") Returns the 1-based index of the first needle found in `haystack`. If no needle is found, then `0` is returned. - So, if used directly in the condition of an if statement or loop, the result + So, if used directly in the condition of an `if` statement or loop, the result will be `true` if one of the needles is found and `false` if none are found, whereas if the result is used elsewhere, it can either be cast to `bool` for the same effect or used to get which needle was found first - without having to deal with the tuple that `LREF find` returns for the + without having to deal with the tuple that $(LREF find) returns for the same operation. +/ - size_t canFind(Range, Ranges...)(Range haystack, scope Ranges needles) - if (Ranges.length > 1 && - allSatisfy!(isForwardRange, Ranges) && + size_t canFind(Range, Needles...)(Range haystack, scope Needles needles) + if (Needles.length > 1 && is(typeof(find!pred(haystack, needles)))) { return find!pred(haystack, needles)[1]; @@ -2584,15 +2592,21 @@ template canFind(alias pred="a == b") /// @safe unittest { - assert(canFind([0, 1, 2, 3], 2) == true); - assert(canFind([0, 1, 2, 3], [1, 2], [2, 3])); - assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]) == 1); - assert(canFind([0, 1, 2, 3], [1, 7], [2, 3])); - assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]) == 2); + const arr = [0, 1, 2, 3]; + assert(canFind(arr, 2)); + assert(!canFind(arr, 4)); + + // find one of several needles + assert(arr.canFind(3, 2)); + assert(arr.canFind(3, 2) == 2); // second needle found + assert(arr.canFind([1, 3], 2) == 2); - assert(canFind([0, 1, 2, 3], 4) == false); - assert(!canFind([0, 1, 2, 3], [1, 3], [2, 4])); - assert(canFind([0, 1, 2, 3], [1, 3], [2, 4]) == 0); + assert(canFind(arr, [1, 2], [2, 3])); + assert(canFind(arr, [1, 2], [2, 3]) == 1); + assert(canFind(arr, [1, 7], [2, 3])); + assert(canFind(arr, [1, 7], [2, 3]) == 2); + assert(!canFind(arr, [1, 3], [2, 4])); + assert(canFind(arr, [1, 3], [2, 4]) == 0); } /** @@ -2607,10 +2621,10 @@ template canFind(alias pred="a == b") "cardboard" ]; assert(!canFind(words, "bees")); - assert( canFind!((string a, string b) => a.startsWith(b))(words, "bees")); + assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees")); } -/// Search for mutliple items in an array of items (search for needles in an array of hay stacks) +/// Search for multiple items in an array of items (search for needles in an array of haystacks) @safe unittest { string s1 = "aaa111aaa"; @@ -2618,7 +2632,7 @@ template canFind(alias pred="a == b") string s3 = "aaa333aaa"; string s4 = "aaa444aaa"; const hay = [s1, s2, s3, s4]; - assert(hay.canFind!(e => (e.canFind("111", "222")))); + assert(hay.canFind!(e => e.canFind("111", "222"))); } @safe unittest @@ -2736,7 +2750,7 @@ Returns: `seq` advanced to the first matching element, or until empty if there are no matching elements. -See_Also: $(LREF find), $(REF std,algorithm,comparison,among) +See_Also: $(LREF find), $(REF among, std,algorithm,comparison) */ InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)( InputRange seq, ForwardRange choices) diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d index a613a8d9e4a..494fa297b4b 100644 --- a/libphobos/src/std/array.d +++ b/libphobos/src/std/array.d @@ -1201,7 +1201,7 @@ private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow auto a2 = minimallyInitializedArray!(S2[][])(2, 2); assert(a2); enum b2 = minimallyInitializedArray!(S2[][])(2, 2); - assert(b2); + assert(b2 !is null); static struct S3 { //this() @disable; @@ -1210,7 +1210,7 @@ private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow auto a3 = minimallyInitializedArray!(S3[][])(2, 2); assert(a3); enum b3 = minimallyInitializedArray!(S3[][])(2, 2); - assert(b3); + assert(b3 !is null); } /++ diff --git a/libphobos/src/std/logger/package.d b/libphobos/src/std/logger/package.d index 330ef88aa06..14a439486db 100644 --- a/libphobos/src/std/logger/package.d +++ b/libphobos/src/std/logger/package.d @@ -54,7 +54,7 @@ $(UL $(LI `trace`) $(LI `info`) $(LI `warning`) - #(LI `error`) + $(LI `error`) $(LI `critical`) $(LI `fatal`) ) diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d index 81c7302b4c1..cb6cb87845c 100644 --- a/libphobos/src/std/math/hardware.d +++ b/libphobos/src/std/math/hardware.d @@ -33,6 +33,7 @@ version (SPARC64) version = SPARC_Any; version (SystemZ) version = IBMZ_Any; version (RISCV32) version = RISCV_Any; version (RISCV64) version = RISCV_Any; +version (LoongArch64) version = LoongArch_Any; version (D_InlineAsm_X86) version = InlineAsm_X86_Any; version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; @@ -60,6 +61,7 @@ else version (X86_Any) version = IeeeFlagsSupport; else version (PPC_Any) version = IeeeFlagsSupport; else version (RISCV_Any) version = IeeeFlagsSupport; else version (MIPS_Any) version = IeeeFlagsSupport; +else version (LoongArch_Any) version = IeeeFlagsSupport; else version (ARM_Any) version = IeeeFlagsSupport; // Struct FloatingPointControl is only available if hardware FP units are available. @@ -90,6 +92,7 @@ private: // The ARM and PowerPC FPSCR is a 32-bit register. // The SPARC FSR is a 32bit register (64 bits for SPARC 7 & 8, but high bits are uninteresting). // The RISC-V (32 & 64 bit) fcsr is 32-bit register. + // THe LoongArch fcsr (fcsr0) is a 32-bit register. uint flags; version (CRuntime_Microsoft) @@ -216,6 +219,15 @@ private: return result; `); } + else version (LoongArch_Any) + { + uint result = void; + asm pure nothrow @nogc + { + "movfcsr2gr %0,$r2" : "=r" (result); + } + return result & EXCEPTIONS_MASK; + } else assert(0, "Not yet supported"); } @@ -303,6 +315,13 @@ private: } `); } + else version (LoongArch_Any) + { + asm nothrow @nogc + { + "movgr2fcsr $r2,$r0"; + } + } else { /* SPARC: @@ -725,6 +744,21 @@ nothrow @nogc: | inexactException, } } + else version (LoongArch_Any) + { + enum : ExceptionMask + { + inexactException = 0x00, + divByZeroException = 0x01, + overflowException = 0x02, + underflowException = 0x04, + invalidException = 0x08, + severeExceptions = overflowException | divByZeroException + | invalidException, + allExceptions = severeExceptions | underflowException + | inexactException, + } + } else version (MIPS_Any) { enum : ExceptionMask @@ -812,6 +846,8 @@ nothrow @nogc: return true; else version (MIPS_Any) return true; + else version (LoongArch_Any) + return true; else version (ARM_Any) { // The hasExceptionTraps_impl function is basically pure, @@ -885,6 +921,10 @@ private: { alias ControlState = uint; } + else version (LoongArch_Any) + { + alias ControlState = uint; + } else version (MIPS_Any) { alias ControlState = uint; @@ -1008,6 +1048,16 @@ private: return cont; `); } + else version (LoongArch_Any) + { + ControlState cont; + asm pure nothrow @nogc + { + "movfcsr2gr %0,$r0" : "=r" (cont); + } + cont &= (roundingMask | allExceptions); + return cont; + } else assert(0, "Not yet supported"); } @@ -1120,6 +1170,14 @@ private: } `); } + else version (LoongArch_Any) + { + asm nothrow @nogc + { + "movgr2fcsr $r0,%0" : + : "r" (newState & (roundingMask | allExceptions)); + } + } else assert(0, "Not yet supported"); }