From patchwork Thu Nov 2 13:57:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1858551 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=S6C9tLT+; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; 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 [8.43.85.97]) (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 4SLlnh6ygHz1yQ6 for ; Fri, 3 Nov 2023 00:58:00 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DFF1038582A9 for ; Thu, 2 Nov 2023 13:57:58 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [80.241.56.152]) by sourceware.org (Postfix) with ESMTPS id 42D233858D32 for ; Thu, 2 Nov 2023 13:57:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 42D233858D32 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 42D233858D32 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=80.241.56.152 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698933455; cv=none; b=Cmp9z7LHxY/YNbgHd1XB2B6VzeRsfhrUAVo5vZTPxBP4TiQtSFfDN9Wba0x8Wk40SPJFHod8Zqj1c1YwsZARUcsd7qqaxzkMHqG3cyAH8z02wFNZFulSJ1utJoju653d2H6xn1DPjfOxGCpbO+Qd/qaqefNJBqE+WfAYFAlYmUM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698933455; c=relaxed/simple; bh=53FZM9Mg9Imx3OXWSEsdvE46EH7XwCT9twgNTHMzE0w=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=dUcQNB+1SD8/DSmw0gudb87/H0ABLATFqzTCkg7P+5LVnn7SLkqSfA/+BluZgculI9sLU9N7nY0VhJSOJ3whXfdWu/+ROkbpM91IkIQqBguhbrlYlPAt3bGXiDJCp+IMid5ZoL+yojvrHXxuDBsJB/yNDgilz7MaMddFrgRBTx8= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp2.mailbox.org (smtp2.mailbox.org [10.196.197.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4SLlmx14Sfz9scm; Thu, 2 Nov 2023 14:57:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gdcproject.org; s=MBO0001; t=1698933441; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=xZYzhHm7sQxEzR6MsMM9XqfKKOq3NFeqSCZgaemHkHc=; b=S6C9tLT+0bQ+t+0/4eYxUNcAlDS10Eq1gZ6ZCfdy6pUV3G1Mx1mYX78GuUoFklXzZlbNIn 2nd1Y/MvrfqVU2FJfQTsblkOaiSlQAlh72apo5dry10HZdQtqxXo5I6ptOu6cfK+wrwwl8 SAPSnCbJDzyX2DJXcACBAB9UQK6+1LyU08S45Cqr99faVTrYXy214bwplsCxRJLU/tk9Ot bWQNtJ7VKs9cY9kJGwMRLR8qR9T95vVhAtjlEUjLhK2BrAyXyc0eJdy7E2a5TWtPOYqoLT 3yxVG1P0zzyOLxuUZ/HxnCvkkT/vU557gB5nJpN0Hj/HwCCD+g4kGCm2U70VUA== From: Iain Buclaw To: gcc-patches@gcc.gnu.org Cc: Iain Buclaw Subject: [committed] d: Merge upstream dmd, druntime 643b1261bb, phobos 1c98326e7 Date: Thu, 2 Nov 2023 14:57:19 +0100 Message-Id: <20231102135719.33814-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, 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 Hi, This patch merges the D front-end and runtime library with upstream dmd 643b1261bb, and standard library with phobos 1c98326e7. Synchronizing with the v2.106.0-beta.1 release. This is being done a little earlier than usual as there's a lot of internal moving code around within upstream at the moment to reduce both the extern(C++) surface area, and cyclic dependencies between all D modules that implement the compiler. So it is done now to keep the diff below the 400kb threshold enforced on the mailing list. D front-end changes: - Suggested preview switches now give gdc flags (PR109681). - `new S[10]' is now lowered to `_d_newarrayT!S(10)'. D runtime changes: - Runtime compiler library functions `_d_newarrayU', `_d_newarrayT', `_d_newarrayiT' have been converted to templates. Phobos changes: - Add new `std.traits.Unshared' template. Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 643b1261bb. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-lang.cc (d_post_options): Likewise. * decl.cc (layout_class_initializer): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 643b1261bb. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add core/sys/freebsd/ifaddrs.d, core/sys/freebsd/net/if_dl.d, core/sys/freebsd/sys/socket.d, core/sys/freebsd/sys/types.d. (DRUNTIME_DSOURCES_LINUX): Add core/sys/linux/linux/if_arp.d, core/sys/linux/linux/if_packet.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 1c98326e7. --- gcc/d/d-attribs.cc | 2 +- gcc/d/d-lang.cc | 1 - gcc/d/decl.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/aggregate.d | 184 +++--- gcc/d/dmd/attrib.d | 6 +- gcc/d/dmd/cond.d | 1 + gcc/d/dmd/constfold.d | 24 +- gcc/d/dmd/cparse.d | 1 + gcc/d/dmd/dcast.d | 3 +- gcc/d/dmd/dclass.d | 2 +- gcc/d/dmd/declaration.d | 50 +- gcc/d/dmd/dinterpret.d | 3 +- gcc/d/dmd/dmangle.d | 1 + gcc/d/dmd/doc.d | 2 +- gcc/d/dmd/dstruct.d | 2 +- gcc/d/dmd/dsymbol.d | 74 ++- gcc/d/dmd/dsymbolsem.d | 11 +- gcc/d/dmd/dtemplate.d | 15 +- gcc/d/dmd/expression.d | 546 +----------------- gcc/d/dmd/expression.h | 20 +- gcc/d/dmd/expressionsem.d | 511 +++++++++++++++- gcc/d/dmd/func.d | 1 + gcc/d/dmd/globals.h | 1 - gcc/d/dmd/gluelayer.d | 5 - gcc/d/dmd/initsem.d | 1 + gcc/d/dmd/lexer.d | 1 - gcc/d/dmd/mtype.d | 25 +- gcc/d/dmd/mtype.h | 2 +- gcc/d/dmd/optimize.d | 1 + gcc/d/dmd/parse.d | 22 +- gcc/d/dmd/semantic3.d | 7 +- gcc/d/dmd/statementsem.d | 5 +- gcc/d/dmd/staticcond.d | 1 + gcc/d/dmd/templateparamsem.d | 1 + gcc/d/dmd/traits.d | 1 + gcc/d/dmd/typesem.d | 2 + gcc/d/dmd/typinf.d | 30 +- gcc/d/dmd/typinf.h | 22 + gcc/testsuite/gdc.test/compilable/dbitfield.d | 13 + .../gdc.test/compilable/deprecate14283.d | 8 +- .../gdc.test/compilable/named_arguments.d | 18 +- gcc/testsuite/gdc.test/compilable/test20039.d | 2 +- .../gdc.test/fail_compilation/b23686.d | 42 ++ .../gdc.test/fail_compilation/diag4596.d | 4 +- .../gdc.test/fail_compilation/fail13116.d | 2 +- .../gdc.test/fail_compilation/fail24208.d | 20 + .../gdc.test/fail_compilation/fail24212.d | 30 + .../gdc.test/fail_compilation/fail24213.d | 17 + .../gdc.test/fail_compilation/ice23865.d | 32 + .../gdc.test/fail_compilation/ice24188.d | 14 + .../fail_compilation/ice24188_a/ice24188_c.d | 0 .../gdc.test/fail_compilation/test18480.d | 1 + .../gdc.test/fail_compilation/test24157.d | 28 + libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/Makefile.am | 7 +- libphobos/libdruntime/Makefile.in | 34 +- .../libdruntime/core/sys/linux/linux/if_arp.d | 136 +++++ .../core/sys/linux/linux/if_packet.d | 315 ++++++++++ libphobos/src/MERGE | 2 +- libphobos/src/std/parallelism.d | 4 +- libphobos/src/std/range/primitives.d | 17 +- libphobos/src/std/traits.d | 41 ++ 63 files changed, 1594 insertions(+), 786 deletions(-) create mode 100644 gcc/d/dmd/typinf.h create mode 100644 gcc/testsuite/gdc.test/fail_compilation/b23686.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24208.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24212.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24213.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice23865.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice24188.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice24188_a/ice24188_c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24157.d create mode 100644 libphobos/libdruntime/core/sys/linux/linux/if_arp.d create mode 100644 libphobos/libdruntime/core/sys/linux/linux/if_packet.d diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index cc46220ddc2..c0dc0e24ded 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -351,7 +351,7 @@ build_attributes (Expressions *eattrs) /* Get the result of the attribute if it hasn't already been folded. */ if (attr->op == EXP::call) - attr = attr->ctfeInterpret (); + attr = ctfeInterpret (attr); if (attr->op != EXP::structLiteral) { diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 902fd86b5ab..61fc1608b40 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -936,7 +936,6 @@ d_post_options (const char ** fn) fields with params. */ global.compileEnv.previewIn = global.params.previewIn; global.compileEnv.ddocOutput = global.params.ddoc.doOutput; - global.compileEnv.shortenedMethods = global.params.shortenedMethods; if (warn_return_type == -1) warn_return_type = 0; diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index c80bb8aebd7..1a61a1c4498 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -2377,7 +2377,7 @@ layout_class_initializer (ClassDeclaration *cd) NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL); ne->type = cd->type; - Expression *e = ne->ctfeInterpret (); + Expression *e = ctfeInterpret (ne); gcc_assert (e->op == EXP::classReference); return build_class_instance (e->isClassReferenceExp ()); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 2a0baf09a4b..235db4b2ef1 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -e48bc0987dfec35bc76a3015ee3e85906ce86dfd +643b1261bba0757d97efa3ff1f63e461271eb000 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/aggregate.d b/gcc/d/dmd/aggregate.d index d9b48b531d7..d42ef951085 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -501,90 +501,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol return !errors; } - /**************************** - * Do byte or word alignment as necessary. - * Align sizes of 0, as we may not know array sizes yet. - * Params: - * alignment = struct alignment that is in effect - * memalignsize = natural alignment of field - * poffset = pointer to offset to be aligned - */ - extern (D) static void alignmember(structalign_t alignment, uint memalignsize, uint* poffset) pure nothrow @safe - { - //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, *poffset); - uint alignvalue; - - if (alignment.isDefault()) - { - // Alignment in Target::fieldalignsize must match what the - // corresponding C compiler's default alignment behavior is. - alignvalue = memalignsize; - } - else if (alignment.isPack()) // #pragma pack semantics - { - alignvalue = alignment.get(); - if (memalignsize < alignvalue) - alignvalue = memalignsize; // align to min(memalignsize, alignment) - } - else if (alignment.get() > 1) - { - // Align on alignment boundary, which must be a positive power of 2 - alignvalue = alignment.get(); - } - else - return; - - assert(alignvalue > 0 && !(alignvalue & (alignvalue - 1))); - *poffset = (*poffset + alignvalue - 1) & ~(alignvalue - 1); - } - - /**************************************** - * Place a field (mem) into an aggregate (agg), which can be a struct, union or class - * Params: - * nextoffset = location just past the end of the previous field in the aggregate. - * Updated to be just past the end of this field to be placed, i.e. the future nextoffset - * memsize = size of field - * memalignsize = natural alignment of field - * alignment = alignment in effect for this field - * paggsize = size of aggregate (updated) - * paggalignsize = alignment of aggregate (updated) - * isunion = the aggregate is a union - * Returns: - * aligned offset to place field at - * - */ - extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize, - structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion) - { - uint ofs = *nextoffset; - - const uint actualAlignment = - alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get() - ? memalignsize : alignment.get(); - - // Ensure no overflow - bool overflow; - const sz = addu(memsize, actualAlignment, overflow); - addu(ofs, sz, overflow); - if (overflow) assert(0); - - // Skip no-op for noreturn without custom aligment - if (memalignsize != 0 || !alignment.isDefault()) - alignmember(alignment, memalignsize, &ofs); - - uint memoffset = ofs; - ofs += memsize; - if (ofs > *paggsize) - *paggsize = ofs; - if (!isunion) - *nextoffset = ofs; - - if (*paggalignsize < actualAlignment) - *paggalignsize = actualAlignment; - - return memoffset; - } - override final Type getType() { /* Apply storage classes to forward references. (Issue 22254) @@ -844,3 +760,103 @@ int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx) return fp(symbol, ctx); } + +/**************************** + * Do byte or word alignment as necessary. + * Align sizes of 0, as we may not know array sizes yet. + * Params: + * alignment = struct alignment that is in effect + * memalignsize = natural alignment of field + * offset = offset to be aligned + * Returns: + * aligned offset + */ +public uint alignmember(structalign_t alignment, uint memalignsize, uint offset) pure nothrow @safe +{ + //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, offset); + uint alignvalue; + + if (alignment.isDefault()) + { + // Alignment in Target::fieldalignsize must match what the + // corresponding C compiler's default alignment behavior is. + alignvalue = memalignsize; + } + else if (alignment.isPack()) // #pragma pack semantics + { + alignvalue = alignment.get(); + if (memalignsize < alignvalue) + alignvalue = memalignsize; // align to min(memalignsize, alignment) + } + else if (alignment.get() > 1) + { + // Align on alignment boundary, which must be a positive power of 2 + alignvalue = alignment.get(); + } + else + return offset; + + assert(alignvalue && !(alignvalue & (alignvalue - 1))); // non-zero and power of 2 + return (offset + alignvalue - 1) & ~(alignvalue - 1); +} + +/**************************************** + * Place a field (mem) into an aggregate (agg), which can be a struct, union or class + * Params: + * nextoffset = location just past the end of the previous field in the aggregate. + * Updated to be just past the end of this field to be placed, i.e. the future nextoffset + * memsize = size of field + * memalignsize = natural alignment of field + * alignment = alignment in effect for this field + * aggsize = size of aggregate (updated) + * aggalignsize = alignment of aggregate (updated) + * isunion = the aggregate is a union + * Returns: + * aligned offset to place field at + * + */ +public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize, + structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @safe pure nothrow +{ + static if (0) + { + printf("placeField() nextoffset: %u\n", nextoffset); + printf(": memsize: %u\n", memsize); + printf(": memalignsize: %u\n", memalignsize); + printf(": alignment: %u\n", alignment.get()); + printf(": aggsize: %u\n", aggsize); + printf(": aggalignsize: %u\n", aggalignsize); + printf(": isunion: %d\n", isunion); + } + + uint ofs = nextoffset; + + const uint actualAlignment = + alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get() + ? memalignsize : alignment.get(); + + // Ensure no overflow for (memsize + actualAlignment + ofs) + bool overflow; + const sz = addu(memsize, actualAlignment, overflow); + addu(ofs, sz, overflow); + if (overflow) assert(0); + + // Skip no-op for noreturn without custom aligment + if (memalignsize != 0 || !alignment.isDefault()) + ofs = alignmember(alignment, memalignsize, ofs); + + uint memoffset = ofs; + ofs += memsize; + if (ofs > aggsize) + aggsize = ofs; + if (!isunion) + { + nextoffset = ofs; + //printf(" revised nextoffset: %u\n", ofs); + } + + if (aggalignsize < actualAlignment) + aggalignsize = actualAlignment; + + return memoffset; +} diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 7b5def1f765..49fc3082ba8 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -839,10 +839,10 @@ extern (C++) final class AnonDeclaration : AttribDeclaration /* Given the anon 'member's size and alignment, * go ahead and place it. */ - anonoffset = AggregateDeclaration.placeField( - &fieldState.offset, + anonoffset = placeField( + fieldState.offset, anonstructsize, anonalignsize, alignment, - &ad.structsize, &ad.alignsize, + ad.structsize, ad.alignsize, isunion); // Add to the anon fields the base offset of this anonymous aggregate diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 9fa8a25462f..a8d099433a2 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -18,6 +18,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; import dmd.dcast; +import dmd.dinterpret; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index ef408cb5b77..fc3fd3b2486 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -20,6 +20,7 @@ import core.stdc.stdio; import dmd.arraytypes; import dmd.astenums; import dmd.ctfeexpr; +import dmd.dcast; import dmd.declaration; import dmd.dstruct; import dmd.errors; @@ -48,29 +49,6 @@ private Expression expType(Type type, Expression e) return e; } -/************************************ - * Returns: - * true if e is a constant - */ -int isConst(Expression e) @safe -{ - //printf("Expression::isConst(): %s\n", e.toChars()); - switch (e.op) - { - case EXP.int64: - case EXP.float64: - case EXP.complex80: - return 1; - case EXP.null_: - return 0; - case EXP.symbolOffset: - return 2; - default: - return 0; - } - assert(0); -} - /********************************** * Initialize a EXP.cantExpression Expression. * Params: diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 0b738cdc3d5..b8e80527ec7 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -328,6 +328,7 @@ final class CParser(AST) : Parser!AST case TOK._Atomic: case TOK.__attribute__: + case TOK.__declspec: Ldeclaration: { diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index e4d580513fe..f769473f591 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -20,6 +20,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.dclass; import dmd.declaration; +import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; @@ -232,7 +233,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) * Returns: * The `MATCH` level between `e.type` and `t`. */ -MATCH implicitConvTo(Expression e, Type t) +extern(C++) MATCH implicitConvTo(Expression e, Type t) { MATCH visit(Expression e) { diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 09a4f4ef3f2..bae942cbd97 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -613,7 +613,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (!b.sym.alignsize) b.sym.alignsize = target.ptrsize; - alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset); + offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset); assert(bi < vtblInterfaces.length); BaseClass* bv = (*vtblInterfaces)[bi]; diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index d634e7fe545..76a31f4caf7 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -818,6 +818,11 @@ extern (C++) final class AliasDeclaration : Declaration return this._import && this.equals(s); } + // https://issues.dlang.org/show_bug.cgi?id=23865 + // only insert if the symbol can be part of a set + const s1 = s.toAlias(); + const isInsertCandidate = s1.isFuncDeclaration() || s1.isOverDeclaration() || s1.isTemplateDeclaration(); + /* When s is added in member scope by static if, mixin("code") or others, * aliassym is determined already. See the case in: test/compilable/test61.d */ @@ -832,7 +837,8 @@ extern (C++) final class AliasDeclaration : Declaration fa.visibility = visibility; fa.parent = parent; aliassym = fa; - return aliassym.overloadInsert(s); + if (isInsertCandidate) + return aliassym.overloadInsert(s); } if (auto td = sa.isTemplateDeclaration()) { @@ -840,7 +846,8 @@ extern (C++) final class AliasDeclaration : Declaration od.visibility = visibility; od.parent = parent; aliassym = od; - return aliassym.overloadInsert(s); + if (isInsertCandidate) + return aliassym.overloadInsert(s); } if (auto od = sa.isOverDeclaration()) { @@ -851,7 +858,8 @@ extern (C++) final class AliasDeclaration : Declaration od.parent = parent; aliassym = od; } - return od.overloadInsert(s); + if (isInsertCandidate) + return od.overloadInsert(s); } if (auto os = sa.isOverloadSet()) { @@ -877,8 +885,11 @@ extern (C++) final class AliasDeclaration : Declaration os.parent = parent; aliassym = os; } - os.push(s); - return true; + if (isInsertCandidate) + { + os.push(s); + return true; + } } return false; } @@ -1287,10 +1298,10 @@ extern (C++) class VarDeclaration : Declaration assert(sz != SIZE_INVALID && sz < uint.max); uint memsize = cast(uint)sz; // size of member uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - offset = AggregateDeclaration.placeField( - &fieldState.offset, + offset = placeField( + fieldState.offset, memsize, memalignsize, alignment, - &ad.structsize, &ad.alignsize, + ad.structsize, ad.alignsize, isunion); //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); @@ -1813,11 +1824,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); void print(const ref FieldState fieldState) { - printf("FieldState.offset = %d bytes\n", fieldState.offset); - printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset); - printf(" .bitOffset = %d bits\n", fieldState.bitOffset); - printf(" .fieldSize = %d bytes\n", fieldState.fieldSize); - printf(" .inFlight = %d\n", fieldState.inFlight); + fieldState.print(); printf(" fieldWidth = %d bits\n", fieldWidth); } print(fieldState); @@ -1866,11 +1873,11 @@ extern (C++) class BitFieldDeclaration : VarDeclaration alignsize = memsize; // not memalignsize uint dummy; - offset = AggregateDeclaration.placeField( - &fieldState.offset, + offset = placeField( + fieldState.offset, memsize, alignsize, alignment, - &ad.structsize, - (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? &dummy : &ad.alignsize, + ad.structsize, + (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, isunion); fieldState.inFlight = true; @@ -1989,7 +1996,14 @@ extern (C++) class BitFieldDeclaration : VarDeclaration auto size = (pastField + 7) / 8; fieldState.fieldSize = size; //printf(" offset: %d, size: %d\n", offset, size); - ad.structsize = offset + size; + if (isunion) + { + const newstructsize = offset + size; + if (newstructsize > ad.structsize) + ad.structsize = newstructsize; + } + else + ad.structsize = offset + size; } else fieldState.fieldSize = memsize; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index cbd9740e089..90352e32bea 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -22,6 +22,7 @@ import dmd.attrib; import dmd.builtin; import dmd.constfold; import dmd.ctfeexpr; +import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.dstruct; @@ -59,7 +60,7 @@ import dmd.visitor; * functions and may invoke a function that contains `ErrorStatement` in its body. * If that, the "CTFE failed because of previous errors" error is raised. */ -public Expression ctfeInterpret(Expression e) +extern(C++) public Expression ctfeInterpret(Expression e) { switch (e.op) { diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 8fdb1ae835c..c58b5857482 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -139,6 +139,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.dclass; import dmd.declaration; +import dmd.dinterpret; import dmd.dmodule; import dmd.dsymbol; import dmd.dtemplate; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index b1a4c2fe504..5488d5a0008 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -438,7 +438,7 @@ void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink if (!loc.filename) loc.filename = srcfilename.ptr; - size_t commentlen = strlen(cast(char*)m.comment); + size_t commentlen = m.comment ? strlen(cast(char*)m.comment) : 0; Dsymbols a; // https://issues.dlang.org/show_bug.cgi?id=9764 // Don't push m in a, to prevent emphasize ddoc file name. diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 5171e1f3106..f77a263a894 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -357,7 +357,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration sizeok = Sizeok.done; - //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), fields.length, structsize); + //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize); if (errors) return; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 579a542de3c..914213c1e57 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -56,6 +56,8 @@ import dmd.staticassert; import dmd.tokens; import dmd.visitor; +import dmd.common.outbuffer; + /*************************************** * Calls dg(Dsymbol *sym) for each Dsymbol. * If dg returns !=0, stops and returns that value else returns 0. @@ -236,6 +238,15 @@ struct FieldState uint bitOffset; /// bit offset for field bool inFlight; /// bit field is in flight + + void print() const + { + printf("FieldState.offset = %d bytes\n", offset); + printf(" .fieldOffset = %d bytes\n", fieldOffset); + printf(" .bitOffset = %d bits\n", bitOffset); + printf(" .fieldSize = %d bytes\n", fieldSize); + printf(" .inFlight = %d\n", inFlight); + } } // 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos), @@ -684,7 +695,7 @@ extern (C++) class Dsymbol : ASTNode const(char)* toPrettyChars(bool QualifyTypes = false) { if (prettystring && !QualifyTypes) - return prettystring; + return prettystring; // value cached for speed //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); if (!parent) @@ -695,42 +706,22 @@ extern (C++) class Dsymbol : ASTNode return s; } - // Computer number of components - size_t complength = 0; - for (Dsymbol p = this; p; p = p.parent) - ++complength; - - // Allocate temporary array comp[] - alias T = const(char)[]; - auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof)); - auto comp = compptr[0 .. complength]; + OutBuffer buf; - // Fill in comp[] and compute length of final result - size_t length = 0; - int i; - for (Dsymbol p = this; p; p = p.parent) + void addQualifiers(Dsymbol p) { + if (p.parent) + { + addQualifiers(p.parent); + buf.writeByte('.'); + } const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars(); - const len = strlen(s); - comp[i] = s[0 .. len]; - ++i; - length += len + 1; + buf.writestring(s); } - auto s = cast(char*)mem.xmalloc_noscan(length); - auto q = s + length - 1; - *q = 0; - foreach (j; 0 .. complength) - { - const t = comp[j].ptr; - const len = comp[j].length; - q -= len; - memcpy(q, t, len); - if (q == s) - break; - *--q = '.'; - } - free(comp.ptr); + addQualifiers(this); + auto s = buf.extractSlice(true).ptr; + if (!QualifyTypes) prettystring = s; return s; @@ -1734,8 +1725,8 @@ public: Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); parameters.push(p); Type tret = null; - tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d); - tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc); + TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d); + tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction(); } if (fdx) fdx = fdx.overloadExactMatch(tfgetmembers); @@ -1863,11 +1854,11 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol Expression eold = null; for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true)) { - if (e.op == EXP.scope_) + if (auto se = e.isScopeExp()) { - s = (cast(ScopeExp)e).sds; + s = se.sds; } - else if (e.op == EXP.type) + else if (e.isTypeExp()) { s = e.type.toDsymbol(null); } @@ -2041,11 +2032,11 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol if (TemplateDeclaration td = s.isTemplateDeclaration()) { dinteger_t dim = 0; - if (exp.op == EXP.array) + if (auto ae = exp.isArrayExp()) { - dim = (cast(ArrayExp)exp).currentDimension; + dim = ae.currentDimension; } - else if (exp.op == EXP.slice) + else if (exp.isSliceExp()) { dim = 0; // slices are currently always one-dimensional } @@ -2066,7 +2057,8 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol * Note that it's impossible to have both template & function opDollar, * because both take no arguments. */ - if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.length != 1) + auto ae = exp.isArrayExp(); + if (ae && ae.arguments.length != 1) { error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars()); return null; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 8309e4a846b..397c5e53d7f 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -1320,7 +1320,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; if (!(global.params.bitfields || sc.flags & SCOPE.Cfile)) - .error(dsym.loc, "%s `%s` use -preview=bitfields for bitfield support", dsym.kind, dsym.toPrettyChars); + { + version (IN_GCC) + .error(dsym.loc, "%s `%s` use `-fpreview=bitfields` for bitfield support", dsym.kind, dsym.toPrettyChars); + else + .error(dsym.loc, "%s `%s` use -preview=bitfields for bitfield support", dsym.kind, dsym.toPrettyChars); + } if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration()) { @@ -1390,7 +1395,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // if parser errors occur when loading a module // we should just stop compilation if (imp.load(sc)) + { + for (size_t i = 0; i < imp.aliasdecls.length; i++) + imp.aliasdecls[i].type = Type.terror; return; + } if (imp.mod) { diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 5dca6dfec6e..883f4ac94cf 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -49,6 +49,7 @@ import dmd.attrib; import dmd.dcast; import dmd.dclass; import dmd.declaration; +import dmd.dinterpret; import dmd.dmangle; import dmd.dmodule; import dmd.dscope; @@ -5725,13 +5726,19 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter override RootObject defaultArg(const ref Loc instLoc, Scope* sc) { RootObject da = defaultAlias; - Type ta = isType(defaultAlias); - if (ta) + if (auto ta = isType(defaultAlias)) { - if (ta.ty == Tinstance) + switch (ta.ty) { - // If the default arg is a template, instantiate for each type + // If the default arg is a template, instantiate for each type + case Tinstance : + // same if the default arg is a mixin, traits, typeof + // since the content might rely on a previous parameter + // (https://issues.dlang.org/show_bug.cgi?id=23686) + case Tmixin, Ttypeof, Ttraits : da = ta.syntaxCopy(); + break; + default: } } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 32ded3bd5f6..87611f4690f 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -24,24 +24,18 @@ import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; import dmd.gluelayer; -import dmd.constfold; import dmd.ctfeexpr; import dmd.ctorflow; -import dmd.dcast; import dmd.dclass; import dmd.declaration; -import dmd.delegatize; import dmd.dimport; -import dmd.dinterpret; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.errorsink; -import dmd.escape; import dmd.expressionsem; import dmd.func; import dmd.globals; @@ -49,11 +43,8 @@ import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.init; -import dmd.inline; import dmd.location; import dmd.mtype; -import dmd.nspace; -import dmd.objc; import dmd.opover; import dmd.optimize; import dmd.root.complex; @@ -66,10 +57,8 @@ import dmd.rootobject; import dmd.root.string; import dmd.root.utf; import dmd.safe; -import dmd.sideeffect; import dmd.target; import dmd.tokens; -import dmd.typesem; import dmd.visitor; enum LOGSEMANTIC = false; @@ -745,21 +734,6 @@ extern (C++) abstract class Expression : ASTNode return toLvalue(sc, e); } - extern (D) final Expression implicitCastTo(Scope* sc, Type t) - { - return .implicitCastTo(this, sc, t); - } - - final MATCH implicitConvTo(Type t) - { - return .implicitConvTo(this, t); - } - - extern (D) final Expression castTo(Scope* sc, Type t) - { - return .castTo(this, sc, t); - } - /**************************************** * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc. */ @@ -1304,16 +1278,6 @@ extern (C++) abstract class Expression : ASTNode return true; } - /************************************************ - * Destructors are attached to VarDeclarations. - * Hence, if expression returns a temp that needs a destructor, - * make sure and create a VarDeclaration for that temp. - */ - Expression addDtorHook(Scope* sc) - { - return this; - } - /****************************** * Take address of expression. */ @@ -1349,16 +1313,23 @@ extern (C++) abstract class Expression : ASTNode return Expression_optimize(this, result, keepLvalue); } - // Entry point for CTFE. - // A compile-time result is required. Give an error if not possible - final Expression ctfeInterpret() - { - return .ctfeInterpret(this); - } - final int isConst() { - return .isConst(this); + //printf("Expression::isConst(): %s\n", e.toChars()); + switch (op) + { + case EXP.int64: + case EXP.float64: + case EXP.complex80: + return 1; + case EXP.null_: + return 0; + case EXP.symbolOffset: + return 2; + default: + return 0; + } + assert(0); } /****** @@ -2110,13 +2081,19 @@ extern (C++) class ThisExp : Expression return typeof(return)(true); } - override bool isLvalue() + override final bool isLvalue() { - return true; + // Class `this` should be an rvalue; struct `this` should be an lvalue. + return type.toBasetype().ty != Tclass; } - override Expression toLvalue(Scope* sc, Expression e) + override final Expression toLvalue(Scope* sc, Expression e) { + if (type.toBasetype().ty == Tclass) + { + // Class `this` is an rvalue; struct `this` is an lvalue. + return Expression.toLvalue(sc, e); + } return this; } @@ -2136,18 +2113,6 @@ extern (C++) final class SuperExp : ThisExp super(loc, EXP.super_); } - override bool isLvalue() - { - // Class `super` should be an rvalue - return false; - } - - override Expression toLvalue(Scope* sc, Expression e) - { - // Class `super` is an rvalue - return Expression.toLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -2187,12 +2152,13 @@ extern (C++) final class NullExp : Expression override StringExp toStringExp() { - if (implicitConvTo(Type.tstring)) + if (this.type.implicitConvTo(Type.tstring)) { auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]); se.type = Type.tstring; return se; } + return null; } @@ -2417,23 +2383,6 @@ extern (C++) final class StringExp : Expression return this; } - /**************************************** - * Convert string to char[]. - */ - StringExp toUTF8(Scope* sc) - { - if (sz != 1) - { - // Convert to UTF-8 string - committed = false; - Expression e = castTo(sc, Type.tchar.arrayOf()); - e = e.optimize(WANTvalue); - auto se = e.isStringExp(); - assert(se.sz == 1); - return se; - } - return this; - } /** * Compare two `StringExp` by length, then value @@ -3101,34 +3050,6 @@ extern (C++) final class StructLiteralExp : Expression return -1; } - override Expression addDtorHook(Scope* sc) - { - /* If struct requires a destructor, rewrite as: - * (S tmp = S()),tmp - * so that the destructor can be hung on tmp. - */ - if (sd.dtor && sc.func) - { - /* Make an identifier for the temporary of the form: - * __sl%s%d, where %s is the struct name - */ - char[10] buf = void; - const prefix = "__sl"; - const ident = sd.ident.toString; - const fullLen = prefix.length + ident.length; - const len = fullLen < buf.length ? fullLen : buf.length; - buf[0 .. prefix.length] = prefix; - buf[prefix.length .. len] = ident[0 .. len - prefix.length]; - - auto tmp = copyToTemp(0, buf[0 .. len], this); - Expression ae = new DeclarationExp(loc, tmp); - Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e.expressionSemantic(sc); - return e; - } - return this; - } - override Expression toLvalue(Scope* sc, Expression e) { if (sc.flags & SCOPE.Cfile) @@ -3658,173 +3579,6 @@ extern (C++) final class FuncExp : Expression return new FuncExp(loc, fd); } - extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, ErrorSink eSink) - { - MATCH cannotInfer() - { - eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars()); - return MATCH.nomatch; - } - - //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars()); - if (presult) - *presult = null; - - TypeFunction tof = null; - if (to.ty == Tdelegate) - { - if (tok == TOK.function_) - { - eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars()); - return MATCH.nomatch; - } - tof = cast(TypeFunction)to.nextOf(); - } - else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null) - { - if (tok == TOK.delegate_) - { - eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars()); - return MATCH.nomatch; - } - } - - if (td) - { - if (!tof) - { - return cannotInfer(); - } - - // Parameter types inference from 'tof' - assert(td._scope); - TypeFunction tf = fd.type.isTypeFunction(); - //printf("\ttof = %s\n", tof.toChars()); - //printf("\ttf = %s\n", tf.toChars()); - const dim = tf.parameterList.length; - - if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs) - return cannotInfer(); - - auto tiargs = new Objects(); - tiargs.reserve(td.parameters.length); - - foreach (tp; *td.parameters) - { - size_t u = 0; - foreach (i, p; tf.parameterList) - { - if (auto ti = p.type.isTypeIdentifier()) - if (ti && ti.ident == tp.ident) - break; - - ++u; - } - assert(u < dim); - Parameter pto = tof.parameterList[u]; - Type t = pto.type; - if (t.ty == Terror) - return cannotInfer(); - tf.parameterList[u].storageClass = tof.parameterList[u].storageClass; - tiargs.push(t); - } - - // Set target of return type inference - if (!tf.next && tof.next) - fd.treq = to; - - auto ti = new TemplateInstance(loc, td, tiargs); - Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope); - - // Reset inference target for the later re-semantic - fd.treq = null; - - if (ex.op == EXP.error) - return MATCH.nomatch; - if (auto ef = ex.isFuncExp()) - return ef.matchType(to, sc, presult, eSink); - else - return cannotInfer(); - } - - if (!tof || !tof.next) - return MATCH.nomatch; - - assert(type && type != Type.tvoid); - if (fd.type.ty == Terror) - return MATCH.nomatch; - auto tfx = fd.type.isTypeFunction(); - bool convertMatch = (type.ty != to.ty); - - if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert) - { - /* If return type is inferred and covariant return, - * tweak return statements to required return type. - * - * interface I {} - * class C : Object, I{} - * - * I delegate() dg = delegate() { return new class C(); } - */ - convertMatch = true; - - auto tfy = new TypeFunction(tfx.parameterList, tof.next, - tfx.linkage, STC.undefined_); - tfy.mod = tfx.mod; - tfy.trust = tfx.trust; - tfy.isnothrow = tfx.isnothrow; - tfy.isnogc = tfx.isnogc; - tfy.purity = tfx.purity; - tfy.isproperty = tfx.isproperty; - tfy.isref = tfx.isref; - tfy.isInOutParam = tfx.isInOutParam; - tfy.isInOutQual = tfx.isInOutQual; - tfy.deco = tfy.merge().deco; - - tfx = tfy; - } - Type tx; - if (tok == TOK.delegate_ || - tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate)) - { - // Allow conversion from implicit function pointer to delegate - tx = new TypeDelegate(tfx); - tx.deco = tx.merge().deco; - } - else - { - assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors); - tx = tfx.pointerTo(); - } - //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars()); - - MATCH m = tx.implicitConvTo(to); - if (m > MATCH.nomatch) - { - // MATCH.exact: exact type match - // MATCH.constant: covairiant type match (eg. attributes difference) - // MATCH.convert: context conversion - m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant; - - if (presult) - { - (*presult) = cast(FuncExp)copy(); - (*presult).type = to; - - // https://issues.dlang.org/show_bug.cgi?id=12508 - // Tweak function body for covariant returns. - (*presult).fd.modifyReturns(sc, tof.next); - } - } - else if (!cast(ErrorSinkNull)eSink) - { - auto ts = toAutoQualChars(tx, to); - eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", - toChars(), ts[0], ts[1]); - } - return m; - } - override const(char)* toChars() const { return fd.toChars(); @@ -4133,153 +3887,6 @@ extern (C++) abstract class BinExp : Expression return ErrorExp.get(); } - extern (D) final Expression checkOpAssignTypes(Scope* sc) - { - // At that point t1 and t2 are the merged types. type is the original type of the lhs. - Type t1 = e1.type; - Type t2 = e2.type; - - // T opAssign floating yields a floating. Prevent truncating conversions (float to int). - // See https://issues.dlang.org/show_bug.cgi?id=3841. - // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ? - if (op == EXP.addAssign || op == EXP.minAssign || - op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || - op == EXP.powAssign) - { - if ((type.isintegral() && t2.isfloating())) - { - warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars()); - } - } - - // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary - if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign) - { - // Any multiplication by an imaginary or complex number yields a complex result. - // r *= c, i*=c, r*=i, i*=i are all forbidden operations. - const(char)* opstr = EXPtoString(op).ptr; - if (t1.isreal() && t2.iscomplex()) - { - error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); - return ErrorExp.get(); - } - else if (t1.isimaginary() && t2.iscomplex()) - { - error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); - return ErrorExp.get(); - } - else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary()) - { - error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars()); - return ErrorExp.get(); - } - } - - // generate an error if this is a nonsensical += or -=, eg real += imaginary - if (op == EXP.addAssign || op == EXP.minAssign) - { - // Addition or subtraction of a real and an imaginary is a complex result. - // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. - if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) - { - error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars()); - return ErrorExp.get(); - } - if (type.isreal() || type.isimaginary()) - { - assert(global.errors || t2.isfloating()); - e2 = e2.castTo(sc, t1); - } - } - if (op == EXP.mulAssign) - { - if (t2.isfloating()) - { - if (t1.isreal()) - { - if (t2.isimaginary() || t2.iscomplex()) - { - e2 = e2.castTo(sc, t1); - } - } - else if (t1.isimaginary()) - { - if (t2.isimaginary() || t2.iscomplex()) - { - switch (t1.ty) - { - case Timaginary32: - t2 = Type.tfloat32; - break; - - case Timaginary64: - t2 = Type.tfloat64; - break; - - case Timaginary80: - t2 = Type.tfloat80; - break; - - default: - assert(0); - } - e2 = e2.castTo(sc, t2); - } - } - } - } - else if (op == EXP.divAssign) - { - if (t2.isimaginary()) - { - if (t1.isreal()) - { - // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1)); - e2.type = t1; - Expression e = new AssignExp(loc, e1, e2); - e.type = t1; - return e; - } - else if (t1.isimaginary()) - { - Type t3; - switch (t1.ty) - { - case Timaginary32: - t3 = Type.tfloat32; - break; - - case Timaginary64: - t3 = Type.tfloat64; - break; - - case Timaginary80: - t3 = Type.tfloat80; - break; - - default: - assert(0); - } - e2 = e2.castTo(sc, t3); - Expression e = new AssignExp(loc, e1, e2); - e.type = t1; - return e; - } - } - } - else if (op == EXP.modAssign) - { - if (t2.iscomplex()) - { - error(loc, "cannot perform modulo complex arithmetic"); - return ErrorExp.get(); - } - } - return this; - } - extern (D) final bool checkIntegralBin() { bool r1 = e1.checkIntegral(); @@ -4294,13 +3901,6 @@ extern (C++) abstract class BinExp : Expression return (r1 || r2); } - extern (D) final bool checkSharedAccessBin(Scope* sc) - { - const r1 = e1.checkSharedAccess(sc); - const r2 = e2.checkSharedAccess(sc); - return (r1 || r2); - } - /********************* * Mark the operands as will never be dereferenced, * which is useful info for @safe checks. @@ -4315,54 +3915,6 @@ extern (C++) abstract class BinExp : Expression } - extern (D) final Expression reorderSettingAAElem(Scope* sc) - { - BinExp be = this; - - auto ie = be.e1.isIndexExp(); - if (!ie) - return be; - if (ie.e1.type.toBasetype().ty != Taarray) - return be; - - /* Fix evaluation order of setting AA element - * https://issues.dlang.org/show_bug.cgi?id=3825 - * Rewrite: - * aa[k1][k2][k3] op= val; - * as: - * auto ref __aatmp = aa; - * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3; - * auto ref __aaval = val; - * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment - */ - - Expression e0; - while (1) - { - Expression de; - ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2); - e0 = Expression.combine(de, e0); - - auto ie1 = ie.e1.isIndexExp(); - if (!ie1 || - ie1.e1.type.toBasetype().ty != Taarray) - { - break; - } - ie = ie1; - } - assert(ie.e1.type.toBasetype().ty == Taarray); - - Expression de; - ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1); - e0 = Expression.combine(de, e0); - - be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true); - - //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars()); - return Expression.combine(e0, be); - } - override void accept(Visitor v) { v.visit(this); @@ -4941,38 +4493,6 @@ extern (C++) final class CallExp : UnaExp return Expression.toLvalue(sc, e); } - override Expression addDtorHook(Scope* sc) - { - /* Only need to add dtor hook if it's a type that needs destruction. - * Use same logic as VarDeclaration::callScopeDtor() - */ - - if (auto tf = e1.type.isTypeFunction()) - { - if (tf.isref) - return this; - } - - Type tv = type.baseElemOf(); - if (auto ts = tv.isTypeStruct()) - { - StructDeclaration sd = ts.sym; - if (sd.dtor) - { - /* Type needs destruction, so declare a tmp - * which the back end will recognize and call dtor on - */ - auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this); - auto de = new DeclarationExp(loc, tmp); - auto ve = new VarExp(loc, tmp); - Expression e = new CommaExp(loc, de, ve); - e = e.expressionSemantic(sc); - return e; - } - } - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -5248,13 +4768,6 @@ extern (C++) final class CastExp : UnaExp return Expression.toLvalue(sc, e); } - override Expression addDtorHook(Scope* sc) - { - if (to.toBasetype().ty == Tvoid) // look past the cast(void) - e1 = e1.addDtorHook(sc); - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -5522,12 +5035,6 @@ extern (C++) final class CommaExp : BinExp return e2.toBool(); } - override Expression addDtorHook(Scope* sc) - { - e2 = e2.addDtorHook(sc); - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -6785,7 +6292,6 @@ extern (C++) final class ObjcClassReferenceExp : Expression { super(loc, EXP.objcClassReference); this.classDeclaration = classDeclaration; - type = objc.getRuntimeMetaclass(classDeclaration).getType(); } override void accept(Visitor v) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index cfd5198ce79..f7f6b0b63ff 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -45,7 +45,12 @@ typedef union tree_node Symbol; struct Symbol; // back end symbol #endif +// Entry point for CTFE. +// A compile-time result is required. Give an error if not possible +Expression *ctfeInterpret(Expression *e); void expandTuples(Expressions *exps, Identifiers *names = nullptr); +StringExp *toUTF8(StringExp *se, Scope *sc); +MATCH implicitConvTo(Expression *e, Type *t); typedef unsigned char OwnedBy; enum @@ -96,19 +101,14 @@ public: virtual bool isLvalue(); virtual Expression *toLvalue(Scope *sc, Expression *e); virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - MATCH implicitConvTo(Type *t); virtual Expression *resolveLoc(const Loc &loc, Scope *sc); virtual bool checkType(); virtual bool checkValue(); - virtual Expression *addDtorHook(Scope *sc); Expression *addressOf(); Expression *deref(); Expression *optimize(int result, bool keepLvalue = false); - // Entry point for CTFE. - // A compile-time result is required. Give an error if not possible - Expression *ctfeInterpret(); int isConst(); virtual bool isIdentical(const Expression *e) const; virtual Optional toBool(); @@ -331,8 +331,8 @@ public: ThisExp *syntaxCopy() override; Optional toBool() override; - bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; + bool isLvalue() override final; + Expression *toLvalue(Scope *sc, Expression *e) override final; void accept(Visitor *v) override { v->visit(this); } }; @@ -340,8 +340,6 @@ public: class SuperExp final : public ThisExp { public: - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) final override; void accept(Visitor *v) override { v->visit(this); } }; @@ -370,7 +368,6 @@ public: bool equals(const RootObject * const o) const override; char32_t getCodeUnit(d_size_t i) const; StringExp *toStringExp() override; - StringExp *toUTF8(Scope *sc); Optional toBool() override; bool isLvalue() override; Expression *toLvalue(Scope *sc, Expression *e) override; @@ -472,7 +469,6 @@ public: static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL); bool equals(const RootObject * const o) const override; StructLiteralExp *syntaxCopy() override; - Expression *addDtorHook(Scope *sc) override; Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } @@ -826,7 +822,6 @@ public: CallExp *syntaxCopy() override; bool isLvalue() override; Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *addDtorHook(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -1005,7 +1000,6 @@ public: Expression *toLvalue(Scope *sc, Expression *e) override; Expression *modifiableLvalue(Scope *sc, Expression *e) override; Optional toBool() override; - Expression *addDtorHook(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index ac8e5715b28..1ddb2b1ea08 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -41,6 +41,7 @@ import dmd.dstruct; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.escape; import dmd.expression; import dmd.file_manager; @@ -59,6 +60,7 @@ import dmd.location; import dmd.mtype; import dmd.mustuse; import dmd.nspace; +import dmd.objc; import dmd.opover; import dmd.optimize; import dmd.parse; @@ -231,6 +233,226 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s) return se; } +/**************************************** + * Convert string to char[]. + */ +StringExp toUTF8(StringExp se, Scope* sc) +{ + if (se.sz != 1) + { + // Convert to UTF-8 string + se.committed = false; + Expression e = castTo(se, sc, Type.tchar.arrayOf()); + e = e.optimize(WANTvalue); + auto result = e.isStringExp(); + assert(result.sz == 1); + return result; + } + return se; +} + +private Expression reorderSettingAAElem(BinExp exp, Scope* sc) +{ + BinExp be = exp; + + auto ie = be.e1.isIndexExp(); + if (!ie) + return be; + if (ie.e1.type.toBasetype().ty != Taarray) + return be; + + /* Fix evaluation order of setting AA element + * https://issues.dlang.org/show_bug.cgi?id=3825 + * Rewrite: + * aa[k1][k2][k3] op= val; + * as: + * auto ref __aatmp = aa; + * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3; + * auto ref __aaval = val; + * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment + */ + + Expression e0; + while (1) + { + Expression de; + ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2); + e0 = Expression.combine(de, e0); + + auto ie1 = ie.e1.isIndexExp(); + if (!ie1 || + ie1.e1.type.toBasetype().ty != Taarray) + { + break; + } + ie = ie1; + } + assert(ie.e1.type.toBasetype().ty == Taarray); + + Expression de; + ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1); + e0 = Expression.combine(de, e0); + + be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true); + + //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars()); + return Expression.combine(e0, be); +} + + +private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) +{ + auto e1 = binExp.e1; + auto e2 = binExp.e2; + auto op = binExp.op; + auto type = binExp.type; + auto loc = binExp.loc; + + // At that point t1 and t2 are the merged types. type is the original type of the lhs. + Type t1 = e1.type; + Type t2 = e2.type; + + // T opAssign floating yields a floating. Prevent truncating conversions (float to int). + // See https://issues.dlang.org/show_bug.cgi?id=3841. + // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ? + if (op == EXP.addAssign || op == EXP.minAssign || + op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || + op == EXP.powAssign) + { + if ((type.isintegral() && t2.isfloating())) + { + warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars()); + } + } + + // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary + if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign) + { + // Any multiplication by an imaginary or complex number yields a complex result. + // r *= c, i*=c, r*=i, i*=i are all forbidden operations. + const(char)* opstr = EXPtoString(op).ptr; + if (t1.isreal() && t2.iscomplex()) + { + error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); + return ErrorExp.get(); + } + else if (t1.isimaginary() && t2.iscomplex()) + { + error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); + return ErrorExp.get(); + } + else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary()) + { + error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars()); + return ErrorExp.get(); + } + } + + // generate an error if this is a nonsensical += or -=, eg real += imaginary + if (op == EXP.addAssign || op == EXP.minAssign) + { + // Addition or subtraction of a real and an imaginary is a complex result. + // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. + if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) + { + error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars()); + return ErrorExp.get(); + } + if (type.isreal() || type.isimaginary()) + { + assert(global.errors || t2.isfloating()); + e2 = e2.castTo(sc, t1); + } + } + if (op == EXP.mulAssign) + { + if (t2.isfloating()) + { + if (t1.isreal()) + { + if (t2.isimaginary() || t2.iscomplex()) + { + e2 = e2.castTo(sc, t1); + } + } + else if (t1.isimaginary()) + { + if (t2.isimaginary() || t2.iscomplex()) + { + switch (t1.ty) + { + case Timaginary32: + t2 = Type.tfloat32; + break; + + case Timaginary64: + t2 = Type.tfloat64; + break; + + case Timaginary80: + t2 = Type.tfloat80; + break; + + default: + assert(0); + } + e2 = e2.castTo(sc, t2); + } + } + } + } + else if (op == EXP.divAssign) + { + if (t2.isimaginary()) + { + if (t1.isreal()) + { + // x/iv = i(-x/v) + // Therefore, the result is 0 + e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1)); + e2.type = t1; + Expression e = new AssignExp(loc, e1, e2); + e.type = t1; + return e; + } + else if (t1.isimaginary()) + { + Type t3; + switch (t1.ty) + { + case Timaginary32: + t3 = Type.tfloat32; + break; + + case Timaginary64: + t3 = Type.tfloat64; + break; + + case Timaginary80: + t3 = Type.tfloat80; + break; + + default: + assert(0); + } + e2 = e2.castTo(sc, t3); + Expression e = new AssignExp(loc, e1, e2); + e.type = t1; + return e; + } + } + } + else if (op == EXP.modAssign) + { + if (t2.iscomplex()) + { + error(loc, "cannot perform modulo complex arithmetic"); + return ErrorExp.get(); + } + } + return binExp; +} + private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) { Expression e0; @@ -1364,7 +1586,10 @@ L1: var.isFuncDeclaration && var.isFuncDeclaration.isStatic && var.isFuncDeclaration.objc.selector) { - return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration()); + auto cls = ad.isClassDeclaration(); + auto classObj = new ObjcClassReferenceExp(e1.loc, cls); + classObj.type = objc.getRuntimeMetaclass(cls).getType(); + return classObj; } /* Access of a member which is a template parameter in dual-scope scenario @@ -2471,7 +2696,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, //printf("type: %s\n", arg.type.toChars()); //printf("param: %s\n", p.toChars()); - const pStc = tf.parameterStorageClass(tthis, p); + const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal()); + const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect); if (firstArg && (pStc & STC.return_)) { @@ -5176,7 +5402,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else assert(0); - e = new CallExp(exp.loc, e, exp.arguments); + e = new CallExp(exp.loc, e, exp.arguments, exp.names); e = e.expressionSemantic(sc); result = e; return; @@ -13890,6 +14116,186 @@ Lerr: return errorExp(); } +MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink) +{ + auto loc = funcExp.loc; + auto tok = funcExp.tok; + auto td = funcExp.td; + auto fd = funcExp.fd; + auto type = funcExp.type; + + MATCH cannotInfer() + { + eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars()); + return MATCH.nomatch; + } + + //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars()); + if (presult) + *presult = null; + + TypeFunction tof = null; + if (to.ty == Tdelegate) + { + if (tok == TOK.function_) + { + eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars()); + return MATCH.nomatch; + } + tof = cast(TypeFunction)to.nextOf(); + } + else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null) + { + if (tok == TOK.delegate_) + { + eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars()); + return MATCH.nomatch; + } + } + + if (td) + { + if (!tof) + { + return cannotInfer(); + } + + // Parameter types inference from 'tof' + assert(td._scope); + TypeFunction tf = fd.type.isTypeFunction(); + //printf("\ttof = %s\n", tof.toChars()); + //printf("\ttf = %s\n", tf.toChars()); + const dim = tf.parameterList.length; + + if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs) + return cannotInfer(); + + auto tiargs = new Objects(); + tiargs.reserve(td.parameters.length); + + foreach (tp; *td.parameters) + { + size_t u = 0; + foreach (i, p; tf.parameterList) + { + if (auto ti = p.type.isTypeIdentifier()) + if (ti && ti.ident == tp.ident) + break; + + ++u; + } + assert(u < dim); + Parameter pto = tof.parameterList[u]; + Type t = pto.type; + if (t.ty == Terror) + return cannotInfer(); + tf.parameterList[u].storageClass = tof.parameterList[u].storageClass; + tiargs.push(t); + } + + // Set target of return type inference + if (!tf.next && tof.next) + fd.treq = to; + + auto ti = new TemplateInstance(loc, td, tiargs); + Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope); + + // Reset inference target for the later re-semantic + fd.treq = null; + + if (ex.op == EXP.error) + return MATCH.nomatch; + if (auto ef = ex.isFuncExp()) + return ef.matchType(to, sc, presult, eSink); + else + return cannotInfer(); + } + + if (!tof || !tof.next) + return MATCH.nomatch; + + assert(type && type != Type.tvoid); + if (fd.type.ty == Terror) + return MATCH.nomatch; + auto tfx = fd.type.isTypeFunction(); + bool convertMatch = (type.ty != to.ty); + + if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert) + { + /* If return type is inferred and covariant return, + * tweak return statements to required return type. + * + * interface I {} + * class C : Object, I{} + * + * I delegate() dg = delegate() { return new class C(); } + */ + convertMatch = true; + + auto tfy = new TypeFunction(tfx.parameterList, tof.next, + tfx.linkage, STC.undefined_); + tfy.mod = tfx.mod; + tfy.trust = tfx.trust; + tfy.isnothrow = tfx.isnothrow; + tfy.isnogc = tfx.isnogc; + tfy.purity = tfx.purity; + tfy.isproperty = tfx.isproperty; + tfy.isref = tfx.isref; + tfy.isInOutParam = tfx.isInOutParam; + tfy.isInOutQual = tfx.isInOutQual; + tfy.deco = tfy.merge().deco; + + tfx = tfy; + } + Type tx; + if (tok == TOK.delegate_ || + tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate)) + { + // Allow conversion from implicit function pointer to delegate + tx = new TypeDelegate(tfx); + tx.deco = tx.merge().deco; + } + else + { + assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors); + tx = tfx.pointerTo(); + } + //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars()); + + MATCH m = tx.implicitConvTo(to); + if (m > MATCH.nomatch) + { + // MATCH.exact: exact type match + // MATCH.constant: covairiant type match (eg. attributes difference) + // MATCH.convert: context conversion + m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant; + + if (presult) + { + (*presult) = cast(FuncExp)funcExp.copy(); + (*presult).type = to; + + // https://issues.dlang.org/show_bug.cgi?id=12508 + // Tweak function body for covariant returns. + (*presult).fd.modifyReturns(sc, tof.next); + } + } + else if (!cast(ErrorSinkNull)eSink) + { + auto ts = toAutoQualChars(tx, to); + eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", + funcExp.toChars(), ts[0], ts[1]); + } + return m; +} + +private bool checkSharedAccessBin(BinExp binExp, Scope* sc) +{ + const r1 = binExp.e1.checkSharedAccess(sc); + const r2 = binExp.e2.checkSharedAccess(sc); + return (r1 || r2); +} + /*************************************** * If expression is shared, check that we can access it. * Give error message if not. @@ -14060,7 +14466,106 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) return check(e, returnRef); } +/************************************************ + * Destructors are attached to VarDeclarations. + * Hence, if expression returns a temp that needs a destructor, + * make sure and create a VarDeclaration for that temp. + */ +Expression addDtorHook(Expression e, Scope* sc) +{ + Expression visit(Expression exp) + { + return exp; + } + + Expression visitStructLiteral(StructLiteralExp exp) + { + auto sd = exp.sd; + /* If struct requires a destructor, rewrite as: + * (S tmp = S()),tmp + * so that the destructor can be hung on tmp. + */ + if (sd.dtor && sc.func) + { + /* Make an identifier for the temporary of the form: + * __sl%s%d, where %s is the struct name + */ + char[10] buf = void; + const prefix = "__sl"; + const ident = sd.ident.toString; + const fullLen = prefix.length + ident.length; + const len = fullLen < buf.length ? fullLen : buf.length; + buf[0 .. prefix.length] = prefix; + buf[prefix.length .. len] = ident[0 .. len - prefix.length]; + + auto tmp = copyToTemp(0, buf[0 .. len], exp); + Expression ae = new DeclarationExp(exp.loc, tmp); + Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp)); + e = e.expressionSemantic(sc); + return e; + } + + return exp; + } + + Expression visitCall(CallExp exp) + { + auto e1 = exp.e1; + auto type = exp.type; + /* Only need to add dtor hook if it's a type that needs destruction. + * Use same logic as VarDeclaration::callScopeDtor() + */ + + if (auto tf = e1.type.isTypeFunction()) + { + if (tf.isref) + return exp; + } + Type tv = type.baseElemOf(); + if (auto ts = tv.isTypeStruct()) + { + StructDeclaration sd = ts.sym; + if (sd.dtor) + { + /* Type needs destruction, so declare a tmp + * which the back end will recognize and call dtor on + */ + auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp); + auto de = new DeclarationExp(exp.loc, tmp); + auto ve = new VarExp(exp.loc, tmp); + Expression e = new CommaExp(exp.loc, de, ve); + e = e.expressionSemantic(sc); + return e; + } + } + + return exp; + } + + Expression visitCast(CastExp exp) + { + if (exp.to.toBasetype().ty == Tvoid) // look past the cast(void) + exp.e1 = exp.e1.addDtorHook(sc); + return exp; + } + + Expression visitComma(CommaExp exp) + { + exp.e2 = exp.e2.addDtorHook(sc); + return exp; + } + + switch(e.op) + { + default: return visit(e); + + case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); + case EXP.call: return visitCall(e.isCallExp()); + case EXP.cast_: return visitCast(e.isCastExp()); + case EXP.comma: return visitComma(e.isCommaExp()); + } +} /**************************************************** * Determine if `exp`, which gets its address taken, can do so safely. diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 99848d80643..edf113e2160 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -25,6 +25,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.blockexit; import dmd.gluelayer; +import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.delegatize; diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 5c21be186d8..4284f858466 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -274,7 +274,6 @@ struct CompileEnv DString timestamp; d_bool previewIn; d_bool ddocOutput; - d_bool shortenedMethods; }; struct Global diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d index 1793700463c..756c0e523f9 100644 --- a/gcc/d/dmd/gluelayer.d +++ b/gcc/d/dmd/gluelayer.d @@ -39,9 +39,6 @@ version (NoBackend) return null; } - // toir - void toObjFile(Dsymbol ds, bool multiobj) {} - extern(C++) abstract class ObjcGlue { static void initialize() {} @@ -59,7 +56,6 @@ else version (IN_GCC) extern (C++) { Statement asmSemantic(AsmStatement s, Scope* sc); - void toObjFile(Dsymbol ds, bool multiobj); } // stubs @@ -76,5 +72,4 @@ else public import dmd.backend.code_x86 : code; public import dmd.iasm : asmSemantic; public import dmd.objc_glue : ObjcGlue; - public import dmd.toobj : toObjFile; } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 28c7c2bb52e..632c0d0a682 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -20,6 +20,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.dcast; import dmd.declaration; +import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 882f2eac06c..a1214b2623e 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -50,7 +50,6 @@ struct CompileEnv bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues bool ddocOutput; /// collect embedded documentation comments - bool shortenedMethods = true; /// allow => in normal function declarations bool masm; /// use MASM inline asm syntax } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 6af140f7491..8860f143715 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -24,6 +24,7 @@ import dmd.astenums; import dmd.ast_node; import dmd.gluelayer; import dmd.dclass; +import dmd.dcast; import dmd.declaration; import dmd.denum; import dmd.dmangle; @@ -4404,10 +4405,13 @@ extern (C++) final class TypeFunction : TypeNext * Params: * tthis = type of `this` parameter, null if none * p = parameter to this function + * outerVars = context variables p could escape into, if any + * indirect = is this for an indirect or virtual function call? * Returns: * storage class with STC.scope_ or STC.return_ OR'd in */ - StorageClass parameterStorageClass(Type tthis, Parameter p) + StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null, + bool indirect = false) { //printf("parameterStorageClass(p: %s)\n", p.toChars()); auto stc = p.storageClass; @@ -4441,6 +4445,15 @@ extern (C++) final class TypeFunction : TypeNext // See if p can escape via any of the other parameters if (purity == PURE.weak) { + /* + * Indirect calls may escape p through a nested context + * See: + * https://issues.dlang.org/show_bug.cgi?id=24212 + * https://issues.dlang.org/show_bug.cgi?id=24213 + */ + if (indirect) + return stc; + // Check escaping through parameters foreach (i, fparam; parameterList) { @@ -4478,6 +4491,16 @@ extern (C++) final class TypeFunction : TypeNext return stc; } } + + // Check escaping through nested context + if (outerVars && this.isMutable()) + { + foreach (VarDeclaration v; *outerVars) + { + if (v.hasPointers()) + return stc; + } + } } // Check escaping through return value diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index e72d9187ca4..675e944050b 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -610,7 +610,7 @@ public: void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; - StorageClass parameterStorageClass(Parameter *p); + StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false); Type *addStorageClass(StorageClass stc) override; Type *substWildTo(unsigned mod) override; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index d108cffd392..0065b016f83 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -16,6 +16,7 @@ import core.stdc.stdio; import dmd.astenums; import dmd.constfold; import dmd.ctfeexpr; +import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.dsymbol; diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 9a13d5c254e..51e522d71e4 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1223,11 +1223,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (added & STC.ref_) { - // accept for legacy compatibility - //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead"); + // accept using `in ref` for legacy compatibility } else - error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead"); + { + version (IN_GCC) + error("attribute `scope` cannot be applied with `in`, use `-fpreview=in` instead"); + else + error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead"); + } return orig; } @@ -1244,11 +1248,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (orig & STC.ref_) { - // accept for legacy compatibility - //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead"); + // accept using `in ref` for legacy compatibility } else - error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`"); + { + version (IN_GCC) + error("attribute `in` cannot be added after `scope`: remove `scope` and use `-fpreview=in`"); + else + error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`"); + } return orig; } @@ -5203,8 +5211,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.goesTo: if (requireDo) error("missing `do { ... }` after `in` or `out`"); - if (!compileEnv.shortenedMethods) - error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`"); const returnloc = token.loc; nextToken(); f.fbody = new AST.ReturnStatement(returnloc, parseExpression()); diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 2f1839cdac1..0b0ca916db2 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -412,7 +412,12 @@ private extern(C++) final class Semantic3Visitor : Visitor if (!global.params.useTypeInfo || !Type.dtypeinfo || !Type.typeinfotypelist) { if (!global.params.useTypeInfo) - .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars); + { + version (IN_GCC) + .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with `-fno-rtti`", funcdecl.kind, funcdecl.toPrettyChars); + else + .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars); + } else if (!Type.typeinfotypelist) .error(funcdecl.loc, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars); else diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 962ef625f5b..d43d915e2e3 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3483,7 +3483,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // https://issues.dlang.org/show_bug.cgi?id=23159 if (!global.params.useExceptions) { - error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok)); + version (IN_GCC) + error(oss.loc, "`%s` cannot be used with `-fno-exceptions`", Token.toChars(oss.tok)); + else + error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok)); return setError(); } diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d index 45e777375a0..923f1a99e80 100644 --- a/gcc/d/dmd/staticcond.d +++ b/gcc/d/dmd/staticcond.d @@ -12,6 +12,7 @@ module dmd.staticcond; import dmd.arraytypes; +import dmd.dinterpret; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index de40c1f2bb2..7762363c8d6 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -12,6 +12,7 @@ module dmd.templateparamsem; import dmd.arraytypes; +import dmd.dinterpret; import dmd.dsymbol; import dmd.dscope; import dmd.dtemplate; diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 254900e6030..ca2af79dde4 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -24,6 +24,7 @@ import dmd.canthrow; import dmd.dclass; import dmd.declaration; import dmd.dimport; +import dmd.dinterpret; import dmd.dmangle; import dmd.dmodule; import dmd.dscope; diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index fe54e293750..bbe11f63d4b 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -27,6 +27,7 @@ import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; +import dmd.dinterpret; import dmd.dmangle; import dmd.dmodule; import dmd.dscope; @@ -4305,6 +4306,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag && d.isFuncDeclaration().objc.selector) { auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym); + classRef.type = objc.getRuntimeMetaclass(mt.sym).getType(); return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc); } else if (d.needThis() && sc.intypeof != 1) diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index 6e05695d6c8..485ca3ff66c 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -4,7 +4,7 @@ * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typeinf.d, _typeinf.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d) * Documentation: https://dlang.org/phobos/dmd_typinf.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d */ @@ -20,10 +20,8 @@ import dmd.dstruct; import dmd.errors; import dmd.expression; import dmd.globals; -import dmd.gluelayer; import dmd.location; import dmd.mtype; -import dmd.visitor; import core.stdc.stdio; /**************************************************** @@ -34,9 +32,10 @@ import core.stdc.stdio; * loc = the location for reporting line numbers in errors * torig = the type to generate the `TypeInfo` object for * sc = the scope - * genObjCode = if true, object code will be generated for the obtained TypeInfo + * Returns: + * true if `TypeInfo` was generated and needs compiling to object file */ -extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc, bool genObjCode = true) +extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc) { // printf("genTypeInfo() %s\n", torig.toChars()); @@ -67,6 +66,7 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope } Type t = torig.merge2(); // do this since not all Type's are merge'd + bool needsCodegen = false; if (!t.vtinfo) { if (t.isShared()) // does both 'shared' and 'shared const' @@ -84,25 +84,13 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope // ClassInfos are generated as part of ClassDeclaration codegen const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod); - // generate a COMDAT for other TypeInfos not available as builtins in - // druntime - if (!isUnqualifiedClassInfo && !builtinTypeInfo(t) && genObjCode) - { - if (sc) // if in semantic() pass - { - // Find module that will go all the way to an object file - Module m = sc._module.importedFrom; - m.members.push(t.vtinfo); - } - else // if in obj generation pass - { - toObjFile(t.vtinfo, global.params.multiobj); - } - } + if (!isUnqualifiedClassInfo && !builtinTypeInfo(t)) + needsCodegen = true; } if (!torig.vtinfo) torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's assert(torig.vtinfo); + return needsCodegen; } /**************************************************** @@ -158,7 +146,7 @@ private TypeInfoDeclaration getTypeInfoDeclaration(Type t) * true if any part of type t is speculative. * if t is null, returns false. */ -bool isSpeculativeType(Type t) +extern (C++) bool isSpeculativeType(Type t) { static bool visitVector(TypeVector t) { diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h new file mode 100644 index 00000000000..76f623a0a3e --- /dev/null +++ b/gcc/d/dmd/typinf.h @@ -0,0 +1,22 @@ + +/* Compiler implementation of the D programming language + * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * written by Walter Bright + * https://www.digitalmars.com + * Distributed under the Boost Software License, Version 1.0. + * https://www.boost.org/LICENSE_1_0.txt + * https://github.com/dlang/dmd/blob/master/src/dmd/typinf.h + */ + +#pragma once + +#include "globals.h" + +class Expression; +class Type; +struct Scope; + +bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc); +Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true); +bool isSpeculativeType(Type *t); +bool builtinTypeInfo(Type *t); diff --git a/gcc/testsuite/gdc.test/compilable/dbitfield.d b/gcc/testsuite/gdc.test/compilable/dbitfield.d index e2883fdd095..7187c37410e 100644 --- a/gcc/testsuite/gdc.test/compilable/dbitfield.d +++ b/gcc/testsuite/gdc.test/compilable/dbitfield.d @@ -86,3 +86,16 @@ int testu() } static assert(testu() == 1); + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24193 + +union U24193 { + struct S { + int aa,bb; + } + S ss; + int tt:8; +} + +static assert(U24193.sizeof == 8); diff --git a/gcc/testsuite/gdc.test/compilable/deprecate14283.d b/gcc/testsuite/gdc.test/compilable/deprecate14283.d index fc51cf3f0b6..e91db649cee 100644 --- a/gcc/testsuite/gdc.test/compilable/deprecate14283.d +++ b/gcc/testsuite/gdc.test/compilable/deprecate14283.d @@ -1,12 +1,12 @@ -// REQUIRED_ARGS: +// REQUIRED_ARGS: -dw // PERMUTE_ARGS: class C { void bug() { - autoref!(true, C)(this); // 'auto ref' becomes ref parameter - autoref!(false, Object)(super); // 'auto ref' becomes non-ref parameter + autoref(this); // 'auto ref' becomes non-ref parameter + autoref(super); // 'auto ref' becomes non-ref parameter } } -void autoref(bool result, T)(auto ref T t) { static assert(__traits(isRef, t) == result); } +void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); } diff --git a/gcc/testsuite/gdc.test/compilable/named_arguments.d b/gcc/testsuite/gdc.test/compilable/named_arguments.d index f287ccdea95..25d84e6b83e 100644 --- a/gcc/testsuite/gdc.test/compilable/named_arguments.d +++ b/gcc/testsuite/gdc.test/compilable/named_arguments.d @@ -20,9 +20,21 @@ string fun2(string x = "x", string y, string z = "z") static assert(fun2(y: "y") == "xyz"); -// The assumption that first parameter having a default implies all parameters have a default is no longer valid, -// so this struct constructor shouldn't be mistaken for a default constructor. -struct SD { this(int x = 1, int y) { } } +struct SD +{ + int x; + int y; + + // The assumption that first parameter having a default implies all parameters have a default is no longer valid, + // so this struct constructor shouldn't be mistaken for a default constructor. + this(int x = 10, int y) + { + this.x = x; + this.y = y; + } +} + +static assert(SD(y: 20) == SD(10, 20)); // UFCS static assert("x".fun("y", w: "w") == "xyZw"); diff --git a/gcc/testsuite/gdc.test/compilable/test20039.d b/gcc/testsuite/gdc.test/compilable/test20039.d index d912139d803..5b6e9afeacc 100644 --- a/gcc/testsuite/gdc.test/compilable/test20039.d +++ b/gcc/testsuite/gdc.test/compilable/test20039.d @@ -1,5 +1,5 @@ void foo()() { } -class bar { } +void bar(int) { } alias bug = foo; alias bug = bar; diff --git a/gcc/testsuite/gdc.test/fail_compilation/b23686.d b/gcc/testsuite/gdc.test/fail_compilation/b23686.d new file mode 100644 index 00000000000..4c2a5bd026d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/b23686.d @@ -0,0 +1,42 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/b23686.d(107): Error: undefined identifier `eFN1`, did you mean template `eFN0()()`? +fail_compilation/b23686.d(107): Error: `mixin(_error_)` does not give a valid type +fail_compilation/b23686.d(115): while looking for match for `eload!(int, 1)` +fail_compilation/b23686.d(121): Error: undefined identifier `FNwtf` +fail_compilation/b23686.d(121): Error: `mixin(_error_)` does not give a valid type +fail_compilation/b23686.d(126): while looking for match for `load!"wtf"` +--- +*/ +module b23686; + +#line 100 + +//------------------- + +void eFN0()() +{ +} + +void eload(I, I name, alias T = mixin("eFN" ~ name.stringof))() +{ + T!()(); +} + +void test2() +{ + eload!(int,0)(); + eload!(int,1)(); +} + +//------------------- + +void FNfoo() {} +void load(string name, alias T = mixin("FN" ~ name))() {} + +void test1() +{ + load!"foo"(); + load!"wtf"(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d index 517b328e8d6..f6b49d6bd13 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d @@ -1,13 +1,13 @@ /* TEST_OUTPUT: --- +fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified +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(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue --- */ - - class NoGo4596 { void fun() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d index 077fa75ac77..ac520d79997 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail13116.d(14): Error: returning `this` escapes a reference to parameter `this` +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 --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24208.d b/gcc/testsuite/gdc.test/fail_compilation/fail24208.d new file mode 100644 index 00000000000..149c1386f5d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24208.d @@ -0,0 +1,20 @@ +/+ +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/fail24208.d(19): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `escape` +fail_compilation/fail24208.d(15): which is not `scope` because of `escaped = p` +--- ++/ +void test() @safe +{ + int* escaped; + + void escape(int* p) @safe + { + escaped = p; + } + + int n; + escape(&n); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24212.d b/gcc/testsuite/gdc.test/fail_compilation/fail24212.d new file mode 100644 index 00000000000..767951dafb4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24212.d @@ -0,0 +1,30 @@ +/+ +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/fail24212.d(29): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `fun` +--- ++/ +class Base +{ + @safe pure nothrow + void fun(int* p) {} +} + +void test() @safe +{ + int* escaped; + + class Escaper : Base + { + @safe pure nothrow + override void fun(int* p) + { + escaped = p; + } + } + + int n; + Base base = new Escaper; + base.fun(&n); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24213.d b/gcc/testsuite/gdc.test/fail_compilation/fail24213.d new file mode 100644 index 00000000000..e2af6fd1b92 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24213.d @@ -0,0 +1,17 @@ +/+ +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/fail24213.d(16): Error: reference to local variable `n` assigned to non-scope parameter `p` +--- ++/ +alias Dg = void delegate(int* p) @safe pure nothrow; + +void main() @safe +{ + int* escaped; + + int n; + Dg dg = delegate void (int* p) { escaped = p; }; + dg(&n); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23865.d b/gcc/testsuite/gdc.test/fail_compilation/ice23865.d new file mode 100644 index 00000000000..44886dfb8a3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice23865.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice23865.d(64): Error: alias `ice23865.AssignableRange.back` conflicts with alias `ice23865.AssignableRange.back` at fail_compilation/ice23865.d(58) +--- +*/ +module ice23865; + +#line 50 + +class AssignableRange +{ + int element; + int front() + { + return element; + } + alias back = front; + + void front(int newValue) + { + element = newValue; + } + alias back = element; +} + +void test() +{ + AssignableRange a = new AssignableRange(); + + a.back; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice24188.d b/gcc/testsuite/gdc.test/fail_compilation/ice24188.d new file mode 100644 index 00000000000..50c06641455 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice24188.d @@ -0,0 +1,14 @@ +/* +REQUIRED_ARGS: fail_compilation/ice24188_a/ice24188_c.d +TEST_OUTPUT: +--- +fail_compilation/ice24188.d(9): Error: module `ice24188_c` from file fail_compilation/ice24188_a/ice24188_c.d must be imported with 'import ice24188_c;' +--- +*/ +auto b() { + import fail_compilation.ice24188_a.ice24188_c : D; + + struct A { + D e; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice24188_a/ice24188_c.d b/gcc/testsuite/gdc.test/fail_compilation/ice24188_a/ice24188_c.d new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18480.d b/gcc/testsuite/gdc.test/fail_compilation/test18480.d index 49f306ba988..848cd388303 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test18480.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test18480.d @@ -3,6 +3,7 @@ TEST_OUTPUT: --- fail_compilation/imports/test18480a.d(2): Error: `alias TestTemplate = TestTemplate;` cannot alias itself, use a qualified name to create an overload set +fail_compilation/imports/test18480a.d(2): Error: alias `test18480a.TestTemplate` conflicts with alias `test18480a.TestTemplate` at fail_compilation/imports/test18480a.d(1) --- https://issues.dlang.org/show_bug.cgi?id=18480 */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24157.d b/gcc/testsuite/gdc.test/fail_compilation/test24157.d new file mode 100644 index 00000000000..5022014a9a1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24157.d @@ -0,0 +1,28 @@ +// https://issues.dlang.org/show_bug.cgi?id=24157 + +/* +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 +--- +*/ + +class Promise { + auto ref self() { + return this; + } + + auto ref unshared() shared { + return cast() this; + } +} + + +void testThis(Promise p) { + auto ptr = &p.self(); // must not return a ref to the Promise class ref +} + +void testCastThis(shared Promise p) { + auto ptr = &p.unshared(); // ditto +} diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 2a0baf09a4b..235db4b2ef1 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -e48bc0987dfec35bc76a3015ee3e85906ce86dfd +643b1261bba0757d97efa3ff1f63e461271eb000 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/Makefile.am b/libphobos/libdruntime/Makefile.am index f57c640f363..23205fd3301 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -261,7 +261,8 @@ DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \ core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \ - core/sys/freebsd/execinfo.d core/sys/freebsd/netinet/in_.d \ + core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \ + core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \ core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \ core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \ core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \ @@ -269,7 +270,8 @@ DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \ core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \ core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \ core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \ - core/sys/freebsd/sys/sysctl.d core/sys/freebsd/time.d \ + core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \ + core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \ core/sys/freebsd/unistd.d DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \ @@ -278,6 +280,7 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \ core/sys/linux/fcntl.d core/sys/linux/fs.d core/sys/linux/ifaddrs.d \ core/sys/linux/input.d core/sys/linux/input_event_codes.d \ core/sys/linux/io_uring.d core/sys/linux/link.d \ + core/sys/linux/linux/if_arp.d core/sys/linux/linux/if_packet.d \ core/sys/linux/netinet/in_.d core/sys/linux/netinet/tcp.d \ core/sys/linux/perf_event.d core/sys/linux/sched.d \ core/sys/linux/stdio.d core/sys/linux/string.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 363a4a09aa1..410245d71ca 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -327,6 +327,7 @@ am__objects_11 = core/sys/bionic/err.lo core/sys/bionic/fcntl.lo \ @DRUNTIME_OS_ANDROID_TRUE@am__objects_12 = $(am__objects_11) am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \ core/sys/freebsd/err.lo core/sys/freebsd/execinfo.lo \ + core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_dl.lo \ core/sys/freebsd/netinet/in_.lo core/sys/freebsd/pthread_np.lo \ core/sys/freebsd/stdlib.lo core/sys/freebsd/string.lo \ core/sys/freebsd/sys/_bitset.lo \ @@ -336,7 +337,8 @@ am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \ core/sys/freebsd/sys/elf_common.lo \ core/sys/freebsd/sys/event.lo core/sys/freebsd/sys/link_elf.lo \ core/sys/freebsd/sys/mman.lo core/sys/freebsd/sys/mount.lo \ - core/sys/freebsd/sys/sysctl.lo core/sys/freebsd/time.lo \ + core/sys/freebsd/sys/socket.lo core/sys/freebsd/sys/sysctl.lo \ + core/sys/freebsd/sys/types.lo core/sys/freebsd/time.lo \ core/sys/freebsd/unistd.lo @DRUNTIME_OS_FREEBSD_TRUE@am__objects_14 = $(am__objects_13) am__objects_15 = core/sys/netbsd/dlfcn.lo core/sys/netbsd/err.lo \ @@ -366,6 +368,8 @@ am__objects_19 = core/sys/linux/config.lo core/sys/linux/dlfcn.lo \ core/sys/linux/fs.lo core/sys/linux/ifaddrs.lo \ core/sys/linux/input.lo core/sys/linux/input_event_codes.lo \ core/sys/linux/io_uring.lo core/sys/linux/link.lo \ + core/sys/linux/linux/if_arp.lo \ + core/sys/linux/linux/if_packet.lo \ core/sys/linux/netinet/in_.lo core/sys/linux/netinet/tcp.lo \ core/sys/linux/perf_event.lo core/sys/linux/sched.lo \ core/sys/linux/stdio.lo core/sys/linux/string.lo \ @@ -931,7 +935,8 @@ DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \ DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \ core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \ - core/sys/freebsd/execinfo.d core/sys/freebsd/netinet/in_.d \ + core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \ + core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \ core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \ core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \ core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \ @@ -939,7 +944,8 @@ DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \ core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \ core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \ core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \ - core/sys/freebsd/sys/sysctl.d core/sys/freebsd/time.d \ + core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \ + core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \ core/sys/freebsd/unistd.d DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \ @@ -948,6 +954,7 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \ core/sys/linux/fcntl.d core/sys/linux/fs.d core/sys/linux/ifaddrs.d \ core/sys/linux/input.d core/sys/linux/input_event_codes.d \ core/sys/linux/io_uring.d core/sys/linux/link.d \ + core/sys/linux/linux/if_arp.d core/sys/linux/linux/if_packet.d \ core/sys/linux/netinet/in_.d core/sys/linux/netinet/tcp.d \ core/sys/linux/perf_event.d core/sys/linux/sched.d \ core/sys/linux/stdio.d core/sys/linux/string.d \ @@ -1593,6 +1600,11 @@ core/sys/freebsd/config.lo: core/sys/freebsd/$(am__dirstamp) core/sys/freebsd/dlfcn.lo: core/sys/freebsd/$(am__dirstamp) core/sys/freebsd/err.lo: core/sys/freebsd/$(am__dirstamp) core/sys/freebsd/execinfo.lo: core/sys/freebsd/$(am__dirstamp) +core/sys/freebsd/ifaddrs.lo: core/sys/freebsd/$(am__dirstamp) +core/sys/freebsd/net/$(am__dirstamp): + @$(MKDIR_P) core/sys/freebsd/net + @: > core/sys/freebsd/net/$(am__dirstamp) +core/sys/freebsd/net/if_dl.lo: core/sys/freebsd/net/$(am__dirstamp) core/sys/freebsd/netinet/$(am__dirstamp): @$(MKDIR_P) core/sys/freebsd/netinet @: > core/sys/freebsd/netinet/$(am__dirstamp) @@ -1617,7 +1629,9 @@ core/sys/freebsd/sys/link_elf.lo: \ core/sys/freebsd/sys/$(am__dirstamp) core/sys/freebsd/sys/mman.lo: core/sys/freebsd/sys/$(am__dirstamp) core/sys/freebsd/sys/mount.lo: core/sys/freebsd/sys/$(am__dirstamp) +core/sys/freebsd/sys/socket.lo: core/sys/freebsd/sys/$(am__dirstamp) core/sys/freebsd/sys/sysctl.lo: core/sys/freebsd/sys/$(am__dirstamp) +core/sys/freebsd/sys/types.lo: core/sys/freebsd/sys/$(am__dirstamp) core/sys/freebsd/time.lo: core/sys/freebsd/$(am__dirstamp) core/sys/freebsd/unistd.lo: core/sys/freebsd/$(am__dirstamp) core/sys/netbsd/$(am__dirstamp): @@ -1685,6 +1699,12 @@ core/sys/linux/input.lo: core/sys/linux/$(am__dirstamp) core/sys/linux/input_event_codes.lo: core/sys/linux/$(am__dirstamp) core/sys/linux/io_uring.lo: core/sys/linux/$(am__dirstamp) core/sys/linux/link.lo: core/sys/linux/$(am__dirstamp) +core/sys/linux/linux/$(am__dirstamp): + @$(MKDIR_P) core/sys/linux/linux + @: > core/sys/linux/linux/$(am__dirstamp) +core/sys/linux/linux/if_arp.lo: core/sys/linux/linux/$(am__dirstamp) +core/sys/linux/linux/if_packet.lo: \ + core/sys/linux/linux/$(am__dirstamp) core/sys/linux/netinet/$(am__dirstamp): @$(MKDIR_P) core/sys/linux/netinet @: > core/sys/linux/netinet/$(am__dirstamp) @@ -2055,12 +2075,16 @@ mostlyclean-compile: -rm -f core/sys/elf/*.lo -rm -f core/sys/freebsd/*.$(OBJEXT) -rm -f core/sys/freebsd/*.lo + -rm -f core/sys/freebsd/net/*.$(OBJEXT) + -rm -f core/sys/freebsd/net/*.lo -rm -f core/sys/freebsd/netinet/*.$(OBJEXT) -rm -f core/sys/freebsd/netinet/*.lo -rm -f core/sys/freebsd/sys/*.$(OBJEXT) -rm -f core/sys/freebsd/sys/*.lo -rm -f core/sys/linux/*.$(OBJEXT) -rm -f core/sys/linux/*.lo + -rm -f core/sys/linux/linux/*.$(OBJEXT) + -rm -f core/sys/linux/linux/*.lo -rm -f core/sys/linux/netinet/*.$(OBJEXT) -rm -f core/sys/linux/netinet/*.lo -rm -f core/sys/linux/sys/*.$(OBJEXT) @@ -2231,9 +2255,11 @@ clean-libtool: -rm -rf core/sys/dragonflybsd/sys/.libs core/sys/dragonflybsd/sys/_libs -rm -rf core/sys/elf/.libs core/sys/elf/_libs -rm -rf core/sys/freebsd/.libs core/sys/freebsd/_libs + -rm -rf core/sys/freebsd/net/.libs core/sys/freebsd/net/_libs -rm -rf core/sys/freebsd/netinet/.libs core/sys/freebsd/netinet/_libs -rm -rf core/sys/freebsd/sys/.libs core/sys/freebsd/sys/_libs -rm -rf core/sys/linux/.libs core/sys/linux/_libs + -rm -rf core/sys/linux/linux/.libs core/sys/linux/linux/_libs -rm -rf core/sys/linux/netinet/.libs core/sys/linux/netinet/_libs -rm -rf core/sys/linux/sys/.libs core/sys/linux/sys/_libs -rm -rf core/sys/netbsd/.libs core/sys/netbsd/_libs @@ -2394,9 +2420,11 @@ distclean-generic: -rm -f core/sys/dragonflybsd/sys/$(am__dirstamp) -rm -f core/sys/elf/$(am__dirstamp) -rm -f core/sys/freebsd/$(am__dirstamp) + -rm -f core/sys/freebsd/net/$(am__dirstamp) -rm -f core/sys/freebsd/netinet/$(am__dirstamp) -rm -f core/sys/freebsd/sys/$(am__dirstamp) -rm -f core/sys/linux/$(am__dirstamp) + -rm -f core/sys/linux/linux/$(am__dirstamp) -rm -f core/sys/linux/netinet/$(am__dirstamp) -rm -f core/sys/linux/sys/$(am__dirstamp) -rm -f core/sys/netbsd/$(am__dirstamp) diff --git a/libphobos/libdruntime/core/sys/linux/linux/if_arp.d b/libphobos/libdruntime/core/sys/linux/linux/if_arp.d new file mode 100644 index 00000000000..dea0ab57a17 --- /dev/null +++ b/libphobos/libdruntime/core/sys/linux/linux/if_arp.d @@ -0,0 +1,136 @@ +//Written in the D programming language + +/++ + D header file for Linux's linux/if_arp.h. + + Copyright: Copyright 2023 + License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) + +/ +module core.sys.linux.linux.if_arp; + +version (linux): +extern(C): +@nogc: +nothrow: + +import core.sys.posix.net.if_ : IF_NAMESIZE; +import core.sys.posix.sys.socket : sockaddr; + +enum : ushort +{ + ARPHRD_NETROM = 0, + ARPHRD_ETHER = 1, + ARPHRD_EETHER = 2, + ARPHRD_AX25 = 3, + ARPHRD_PRONET = 4, + ARPHRD_CHAOS = 5, + ARPHRD_IEEE802 = 6, + ARPHRD_ARCNET = 7, + ARPHRD_APPLETLK = 8, + ARPHRD_DLCI =15, + ARPHRD_ATM =19, + ARPHRD_METRICOM = 23, + ARPHRD_IEEE1394 = 24, + ARPHRD_EUI64 = 27, + ARPHRD_INFINIBAND = 32, + + ARPHRD_SLIP = 256, + ARPHRD_CSLIP = 257, + ARPHRD_SLIP6 = 258, + ARPHRD_CSLIP6 = 259, + ARPHRD_RSRVD = 260, + ARPHRD_ADAPT = 264, + ARPHRD_ROSE = 270, + ARPHRD_X25 = 271, + ARPHRD_HWX25 = 272, + ARPHRD_CAN = 280, + ARPHRD_MCTP = 290, + ARPHRD_PPP = 512, + ARPHRD_CISCO = 513, + ARPHRD_HDLC = ARPHRD_CISCO, + ARPHRD_LAPB = 516, + ARPHRD_DDCMP = 517, + ARPHRD_RAWHDLC = 518, + ARPHRD_RAWIP = 519, + + ARPHRD_TUNNEL = 768, + ARPHRD_TUNNEL6 = 769, + ARPHRD_FRAD = 770, + ARPHRD_SKIP = 771, + ARPHRD_LOOPBACK = 772, + ARPHRD_LOCALTLK = 773, + ARPHRD_FDDI = 774, + ARPHRD_BIF = 775, + ARPHRD_SIT = 776, + ARPHRD_IPDDP = 777, + ARPHRD_IPGRE = 778, + ARPHRD_PIMREG = 779, + ARPHRD_HIPPI = 780, + ARPHRD_ASH = 781, + ARPHRD_ECONET = 782, + ARPHRD_IRDA = 783, + + ARPHRD_FCPP = 784, + ARPHRD_FCAL = 785, + ARPHRD_FCPL = 786, + ARPHRD_FCFABRIC = 787, + + ARPHRD_IEEE802_TR = 800, + ARPHRD_IEEE80211 = 801, + ARPHRD_IEEE80211_PRISM = 802, + ARPHRD_IEEE80211_RADIOTAP = 803, + ARPHRD_IEEE802154 = 804, + ARPHRD_IEEE802154_MONITOR = 805, + + ARPHRD_PHONET = 820, + ARPHRD_PHONET_PIPE = 821, + ARPHRD_CAIF = 822, + ARPHRD_IP6GRE = 823, + ARPHRD_NETLINK = 824, + ARPHRD_6LOWPAN = 825, + ARPHRD_VSOCKMON = 826, + + ARPHRD_VOID = 0xFFFF, + ARPHRD_NONE = 0xFFFE, +} + +enum : ushort +{ + ARPOP_REQUEST = 1, + ARPOP_REPLY = 2, + ARPOP_RREQUEST = 3, + ARPOP_RREPLY = 4, + ARPOP_InREQUEST = 8, + ARPOP_InREPLY = 9, + ARPOP_NAK = 10, +} + +struct arpreq +{ + sockaddr arp_pa; + sockaddr arp_ha; + int arp_flags; + sockaddr arp_netmask; + char[IF_NAMESIZE] arp_dev; +} + +enum +{ + ATF_COM = 0x02, + ATF_PERM = 0x04, + ATF_PUBL = 0x08, + ATF_USETRAILERS = 0x10, + ATF_NETMASK = 0x20, + + ATF_DONTPUB = 0x40, +} + +struct arphdr +{ + ushort ar_hrd; + ushort ar_pro; + ubyte ar_hln; + ubyte ar_pln; + ushort ar_op; +} diff --git a/libphobos/libdruntime/core/sys/linux/linux/if_packet.d b/libphobos/libdruntime/core/sys/linux/linux/if_packet.d new file mode 100644 index 00000000000..b50b6a33914 --- /dev/null +++ b/libphobos/libdruntime/core/sys/linux/linux/if_packet.d @@ -0,0 +1,315 @@ +//Written in the D programming language + +/++ + D header file for Linux's linux/if_packet.h. + + Copyright: Copyright 2023 + License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) + +/ +module core.sys.linux.linux.if_packet; + +version (linux): +extern(C): +@nogc: +nothrow: + +import core.stdc.config : c_ulong; +import core.sys.posix.sys.socket : sa_family_t; + +struct sockaddr_pkt +{ + sa_family_t spkt_family; + ubyte[14] spkt_device; + ushort spkt_protocol; +} + +struct sockaddr_ll +{ + sa_family_t sll_family; + ushort sll_protocol; + int sll_ifindex; + ushort sll_hatype; + ubyte sll_pkttype; + ubyte sll_halen; + ubyte[8] sll_addr; +} + +enum : ubyte +{ + PACKET_HOST = 0, + PACKET_BROADCAST = 1, + PACKET_MULTICAST = 2, + PACKET_OTHERHOST = 3, + PACKET_OUTGOING = 4, + PACKET_LOOPBACK = 5, + PACKET_USER = 6, + PACKET_KERNEL = 7, +} + +enum +{ + PACKET_ADD_MEMBERSHIP = 1, + PACKET_DROP_MEMBERSHIP = 2, + PACKET_RECV_OUTPUT = 3, + + PACKET_RX_RING = 5, + PACKET_STATISTICS = 6, + PACKET_COPY_THRESH = 7, + PACKET_AUXDATA = 8, + PACKET_ORIGDEV = 9, + PACKET_VERSION = 10, + PACKET_HDRLEN = 11, + PACKET_RESERVE = 12, + PACKET_TX_RING = 13, + PACKET_LOSS = 14, + PACKET_VNET_HDR = 15, + PACKET_TX_TIMESTAMP = 16, + PACKET_TIMESTAMP = 17, + PACKET_FANOUT = 18, + PACKET_TX_HAS_OFF = 19, + PACKET_QDISC_BYPASS = 20, + PACKET_ROLLOVER_STATS = 21, + PACKET_FANOUT_DATA = 22, + PACKET_IGNORE_OUTGOING = 23, + PACKET_VNET_HDR_SZ = 24, + + PACKET_FANOUT_HASH = 0, + PACKET_FANOUT_LB = 1, + PACKET_FANOUT_CPU = 2, + PACKET_FANOUT_ROLLOVER = 3, + PACKET_FANOUT_RND = 4, + PACKET_FANOUT_QM = 5, + PACKET_FANOUT_CBPF = 6, + PACKET_FANOUT_EBPF = 7, + + PACKET_FANOUT_FLAG_ROLLOVER = 0x1000, + PACKET_FANOUT_FLAG_UNIQUEID = 0x2000, + PACKET_FANOUT_FLAG_IGNORE_OUTGOING = 0x4000, + PACKET_FANOUT_FLAG_DEFRAG = 0x8000, +} + +struct tpacket_stats +{ + uint tp_packets; + uint tp_drops; +} + +struct tpacket_stats_v3 +{ + uint tp_packets; + uint tp_drops; + uint tp_freeze_q_cnt; +} + +struct tpacket_rollover_stats +{ + align(8): + ulong tp_all; + ulong tp_huge; + ulong tp_failed; +} + +union tpacket_stats_u +{ + tpacket_stats stats1; + tpacket_stats_v3 stats3; +} + +struct tpacket_auxdata +{ + uint tp_status; + uint tp_len; + uint tp_snaplen; + ushort tp_mac; + ushort tp_net; + ushort tp_vlan_tci; + ushort tp_vlan_tpid; +} + +enum : uint +{ + TP_STATUS_KERNEL = 0, + TP_STATUS_USER = 1 << 0, + TP_STATUS_COPY = 1 << 1, + TP_STATUS_LOSING = 1 << 2, + TP_STATUS_CSUMNOTREADY = 1 << 3, + TP_STATUS_VLAN_VALID = 1 << 4, + TP_STATUS_BLK_TMO = 1 << 5, + TP_STATUS_VLAN_TPID_VALID = 1 << 6, + TP_STATUS_CSUM_VALID = 1 << 7, + TP_STATUS_GSO_TCP = 1 << 8, +} + +enum : uint +{ + TP_STATUS_AVAILABLE = 0, + TP_STATUS_SEND_REQUEST = 1 << 0, + TP_STATUS_SENDING = 1 << 1, + TP_STATUS_WRONG_FORMAT = 1 << 2, +} + +enum : uint +{ + TP_STATUS_TS_SOFTWARE = 1 << 29, + TP_STATUS_TS_RAW_HARDWARE = 1U << 31, +} + +enum uint TP_FT_REQ_FILL_RXHASH = 0x1; + +struct tpacket_hdr +{ + c_ulong tp_status; + uint tp_len; + uint tp_snaplen; + ushort tp_mac; + ushort tp_net; + uint tp_sec; + uint tp_usec; +} + +enum TPACKET_ALIGNMENT = 16; +size_t TPACKET_ALIGN(size_t x) { return (x + TPACKET_ALIGNMENT - 1) &~ (TPACKET_ALIGNMENT - 1); } +enum TPACKET_HDRLEN = TPACKET_ALIGN(tpacket_hdr.sizeof) + sockaddr_ll.sizeof; + +struct tpacket2_hdr +{ + uint tp_status; + uint tp_len; + uint tp_snaplen; + ushort tp_mac; + ushort tp_net; + uint tp_sec; + uint tp_nsec; + ushort tp_vlan_tci; + ushort tp_vlan_tpid; + ubyte[4] tp_padding; +} + +struct tpacket_hdr_variant1 +{ + uint tp_rxhash; + uint tp_vlan_tci; + ushort tp_vlan_tpid; + ushort tp_padding; +} + +struct tpacket3_hdr +{ + uint tp_next_offset; + uint tp_sec; + uint tp_nsec; + uint tp_snaplen; + uint tp_len; + uint tp_status; + ushort tp_mac; + ushort tp_net; + + union + { + tpacket_hdr_variant1 hv1; + } + + ubyte[8] tp_padding; +} + +struct tpacket_bd_ts +{ + uint ts_sec; + + union + { + uint ts_usec; + uint ts_nsec; + } +} + +struct tpacket_hdr_v1 +{ + uint block_status; + uint num_pkts; + uint offset_to_first_pkt; + uint blk_len; + align(8) ulong seq_num; + tpacket_bd_ts ts_first_pkt; + tpacket_bd_ts ts_last_pkt; +} + +union tpacket_bd_header_u +{ + tpacket_hdr_v1 bh1; +} + +struct tpacket_block_desc +{ + uint version_; + uint offset_to_priv; + tpacket_bd_header_u hdr; +} + +enum TPACKET2_HDRLEN = TPACKET_ALIGN(tpacket2_hdr.sizeof) + sockaddr_ll.sizeof; +enum TPACKET3_HDRLEN = TPACKET_ALIGN(tpacket3_hdr.sizeof) + sockaddr_ll.sizeof; + +enum tpacket_versions +{ + TPACKET_V1, + TPACKET_V2, + TPACKET_V3 +} + +struct tpacket_req +{ + uint tp_block_size; + uint tp_block_nr; + uint tp_frame_size; + uint tp_frame_nr; +} + +struct tpacket_req3 +{ + uint tp_block_size; + uint tp_block_nr; + uint tp_frame_size; + uint tp_frame_nr; + uint tp_retire_blk_tov; + uint tp_sizeof_priv; + uint tp_feature_req_word; +} + +union tpacket_req_u +{ + tpacket_req req; + tpacket_req3 req3; +} + +struct packet_mreq +{ + int mr_ifindex; + ushort mr_type; + ushort mr_alen; + ubyte[8] mr_address; +} + +struct fanout_args +{ + version(LittleEndian) + { + ushort id; + ushort type_flags; + } + else + { + ushort type_flags; + ushort id; + } + + uint max_num_members; +} + +enum +{ + PACKET_MR_MULTICAST = 0, + PACKET_MR_PROMISC = 1, + PACKET_MR_ALLMULTI = 2, + PACKET_MR_UNICAST = 3, +} diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index a7bf856d747..8c536ce71a5 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -2458e8f82e3004197d8a66239a6b72e17264bb26 +1c98326e787e504d9045004e593273ec99b13121 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/parallelism.d b/libphobos/src/std/parallelism.d index 3fe8cd61fe0..fadb4c1759d 100644 --- a/libphobos/src/std/parallelism.d +++ b/libphobos/src/std/parallelism.d @@ -418,8 +418,8 @@ Bugs: Changes to `ref` and `out` arguments are not propagated to the */ struct Task(alias fun, Args...) { - AbstractTask base = {runTask : &impl}; - alias base this; + private AbstractTask base = {runTask : &impl}; + private alias base this; private @property AbstractTask* basePtr() { diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d index 1a3fb06cf99..89cfa07cc1f 100644 --- a/libphobos/src/std/range/primitives.d +++ b/libphobos/src/std/range/primitives.d @@ -165,21 +165,24 @@ See_Also: Params: R = type to be tested - E = the type of the elements of the range if not `void` + E = if present, the elements of the range must be + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) + to this type Returns: `true` if R is an input range (possibly with element type `E`), `false` if not */ -enum bool isInputRange(R, E = void) = +enum bool isInputRange(R) = is(typeof(R.init) == R) && is(typeof((R r) { return r.empty; } (R.init)) == bool) && (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front))) && !is(typeof((R r) { return r.front; } (R.init)) == void) - && is(typeof((R r) => r.popFront)) - && (is(E == void) || - is(ElementType!R == E) || - is(const(ElementType!R) == E) || - (is(const(ElementType!R) == immutable E) && is(const(E) == E))); + && is(typeof((R r) => r.popFront)); + +/// ditto +enum bool isInputRange(R, E) = + .isInputRange!R && isQualifierConvertible!(ElementType!R, E); + /// @safe unittest { diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d index aa69aacfd10..2e7a4f6a30b 100644 --- a/libphobos/src/std/traits.d +++ b/libphobos/src/std/traits.d @@ -132,6 +132,7 @@ * $(LREF PointerTarget) * $(LREF Signed) * $(LREF Unconst) + * $(LREF Unshared) * $(LREF Unqual) * $(LREF Unsigned) * $(LREF ValueType) @@ -7848,6 +7849,46 @@ else static assert(is(Unconst!ImmIntArr == immutable(int)[])); } +/++ + Removes `shared` qualifier, if any, from type `T`. + + Note that while `immutable` is implicitly `shared`, it is unaffected by + Unshared. Only explict `shared` is removed. + +/ +template Unshared(T) +{ + static if (is(T == shared U, U)) + alias Unshared = U; + else + alias Unshared = T; +} + +/// +@safe unittest +{ + static assert(is(Unshared!int == int)); + static assert(is(Unshared!(const int) == const int)); + static assert(is(Unshared!(immutable int) == immutable int)); + + static assert(is(Unshared!(shared int) == int)); + static assert(is(Unshared!(shared(const int)) == const int)); + + static assert(is(Unshared!(shared(int[])) == shared(int)[])); +} + +@safe unittest +{ + static assert(is(Unshared!( int) == int)); + static assert(is(Unshared!( const int) == const int)); + static assert(is(Unshared!( inout int) == inout int)); + static assert(is(Unshared!( inout const int) == inout const int)); + static assert(is(Unshared!(shared int) == int)); + static assert(is(Unshared!(shared const int) == const int)); + static assert(is(Unshared!(shared inout int) == inout int)); + static assert(is(Unshared!(shared inout const int) == inout const int)); + static assert(is(Unshared!( immutable int) == immutable int)); +} + version (StdDdoc) { /**