From patchwork Sun Feb 25 23:10:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1903993 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=cKC717sj; 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 4Tjfcz644Bz23cw for ; Mon, 26 Feb 2024 10:11:15 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B774B3858D39 for ; Sun, 25 Feb 2024 23:11:13 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-101.mailbox.org (mout-p-101.mailbox.org [IPv6:2001:67c:2050:0:465::101]) by sourceware.org (Postfix) with ESMTPS id AF5BF3858D1E for ; Sun, 25 Feb 2024 23:10:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AF5BF3858D1E 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 AF5BF3858D1E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:67c:2050:0:465::101 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1708902630; cv=none; b=Qxb4nXHhZU41iK9K7WBDBU/HiQ5PE7ydFTgfVbcLYXO5m/xtSsJTJmlNwcn9EXYXtE6J9y55YoLI3tmLAwSN0o5widkh2Q32hx6jLEqnL8vxFwSdCfVQd8YLzSv3VPJ0Nxhuaq0ZjynN0v2VrXc78GXXXv17uRvvI9vReIcRrDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1708902630; c=relaxed/simple; bh=k0keU2/Xfo0MiQqEB38a0CIj43MV271+4YRfg3YGfVo=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=sDcDqgdl2C+52z3tZII3r54uQ6TxN/1hgotMPPDGfoi4u1zMPGxSIJPV0AvWOH1q95jcqNjrQ0q6aQwMvyJMZBiwcaMzZSLcitUia75d4nbanHYHO2fXmQ7vMdhUrRmOYut4GEdEQnISORodIwjc6G3EVt2ZBbghFakXJKiwqsU= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-101.mailbox.org (Postfix) with ESMTPS id 4Tjfbw2WTRz9sSZ; Mon, 26 Feb 2024 00:10:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gdcproject.org; s=MBO0001; t=1708902620; 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=Tx6a3Bgp+Yfg1lZjrLXKT/FIkYX9OCLiJJyrKR8g8PQ=; b=cKC717sjGXINxEUpZdBO3TRQDEd74VqctcUmTLnPfHY218wELrOanSBUwdeZpudmbyLELi LVF/MDzGIugm9s95E4HP/hzsg64+ilN4kZkT36gopBVERCurH+CO38G6FaHtcUCttcQNSx kKm58shFZ6mWdSyy7Ltl0rWSzlVn2BbxEl0kdzZLDFLy1DJqK7fkZAY0+WONiBGInzk03o VsqPkzfbHCDAJpMIDp3OhON74YVV+NGmtPA7PIqJf0Jsd7ohmkRhRIPYGF11i58uCPkeAf NE1BBdxyRb5GzVf1dyJGc+OzktcOfXTwcILNaO33yGLIX7b8kHG7W4y5IjOrrw== From: Iain Buclaw To: gcc-patches@gcc.gnu.org Cc: Iain Buclaw Subject: [committed] d: Merge dmd, druntime ceff48bf7d, phobos dcbfbd43a Date: Mon, 26 Feb 2024 00:10:15 +0100 Message-Id: <20240225231015.580225-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4Tjfbw2WTRz9sSZ 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, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE, URI_TRY_3LD autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Hi, This patch merges the D front-end and runtime library with upstream dmd ceff48bf7d, and the standard library with phobos dcbfbd43a. D front-end changes: - Import latest fixes from dmd v2.107.1-rc.1. D runtime changes: - Import latest fixes from druntime v2.107.1-rc.1. Phobos changes: - Import latest fixes from phobos v2.107.1-rc.1. Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd ceff48bf7d. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime ceff48bf7d. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add core/sys/freebsd/net/if_.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos dcbfbd43a. --- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/arrayop.d | 2 +- gcc/d/dmd/ast_node.h | 2 +- gcc/d/dmd/common/file.d | 89 ++-- gcc/d/dmd/common/smallbuffer.d | 30 +- gcc/d/dmd/cparse.d | 150 +++++- gcc/d/dmd/dimport.d | 109 +--- gcc/d/dmd/dmodule.d | 32 +- gcc/d/dmd/dsymbolsem.d | 97 ++++ gcc/d/dmd/expression.d | 4 +- gcc/d/dmd/expression.h | 2 +- gcc/d/dmd/expressionsem.d | 97 ++++ gcc/d/dmd/func.d | 394 +------------- gcc/d/dmd/funcsem.d | 390 ++++++++++++++ gcc/d/dmd/identifier.h | 2 +- gcc/d/dmd/importc.d | 7 +- gcc/d/dmd/mtype.d | 1 - gcc/d/dmd/parse.d | 48 +- gcc/d/dmd/root/array.h | 3 +- gcc/d/dmd/root/bitarray.h | 1 - gcc/d/dmd/{root/object.h => rootobject.h} | 6 +- gcc/d/dmd/statementsem.d | 2 +- gcc/d/dmd/staticcond.d | 107 ---- gcc/d/dmd/template.h | 2 +- .../gdc.test/compilable/imports/defines.c | 25 + .../gdc.test/compilable/testdefines.d | 10 + .../gdc.test/fail_compilation/warn13679.d | 4 +- libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/Makefile.am | 22 +- libphobos/libdruntime/Makefile.in | 31 +- .../libdruntime/core/sys/freebsd/ifaddrs.d | 3 +- .../libdruntime/core/sys/freebsd/net/if_.d | 493 ++++++++++++++++++ .../libdruntime/core/sys/linux/sys/socket.d | 1 - libphobos/libdruntime/core/thread/fiber.d | 2 +- libphobos/src/MERGE | 2 +- libphobos/src/std/typecons.d | 35 +- 36 files changed, 1417 insertions(+), 792 deletions(-) rename gcc/d/dmd/{root/object.h => rootobject.h} (91%) create mode 100644 libphobos/libdruntime/core/sys/freebsd/net/if_.d diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 021149aabc7..f11c5fbfb0b 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -9471b25db9ed44d71e0e27956430c0c6a09c16db +ceff48bf7db05503117f54fdc0cefcb89b711136 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/arrayop.d b/gcc/d/dmd/arrayop.d index afe6054f4aa..af3875ea6c5 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -22,7 +22,7 @@ import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.expressionsem; -import dmd.func; +import dmd.funcsem; import dmd.hdrgen; import dmd.id; import dmd.identifier; diff --git a/gcc/d/dmd/ast_node.h b/gcc/d/dmd/ast_node.h index a24218a86d0..db8608e7cdd 100644 --- a/gcc/d/dmd/ast_node.h +++ b/gcc/d/dmd/ast_node.h @@ -10,7 +10,7 @@ #pragma once -#include "root/object.h" +#include "rootobject.h" class Visitor; diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d index 8a284241fc2..80677f66ff8 100644 --- a/gcc/d/dmd/common/file.d +++ b/gcc/d/dmd/common/file.d @@ -16,24 +16,37 @@ module dmd.common.file; import core.stdc.errno : errno; import core.stdc.stdio : fprintf, remove, rename, stderr; -import core.stdc.stdlib : exit; -import core.stdc.string : strerror, strlen; -import core.sys.windows.winbase; -import core.sys.windows.winnt; -import core.sys.posix.fcntl; -import core.sys.posix.unistd; +import core.stdc.stdlib; +import core.stdc.string : strerror, strlen, memcpy; import dmd.common.smallbuffer; -nothrow: - version (Windows) { + import core.sys.windows.winbase; import core.sys.windows.winnls : CP_ACP; + import core.sys.windows.winnt; + + enum CodePage = CP_ACP; // assume filenames encoded in system default Windows ANSI code page + enum invalidHandle = INVALID_HANDLE_VALUE; +} +else version (Posix) +{ + import core.sys.posix.fcntl; + import core.sys.posix.sys.mman; + import core.sys.posix.sys.stat; + import core.sys.posix.unistd; + import core.sys.posix.utime; - // assume filenames encoded in system default Windows ANSI code page - enum CodePage = CP_ACP; + enum invalidHandle = -1; } +else + static assert(0); + + + + +nothrow: /** Encapsulated management of a memory-mapped file. @@ -48,9 +61,6 @@ struct FileMapping(Datum) static assert(__traits(isPOD, Datum) && Datum.sizeof == 1, "Not tested with other data types yet. Add new types with care."); - version(Posix) enum invalidHandle = -1; - else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE; - // state { /// Handle of underlying file private auto handle = invalidHandle; @@ -82,9 +92,6 @@ struct FileMapping(Datum) { version (Posix) { - import core.sys.posix.sys.mman; - import core.sys.posix.fcntl : open, O_CREAT, O_RDONLY, O_RDWR, S_IRGRP, S_IROTH, S_IRUSR, S_IWUSR; - handle = open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); @@ -150,9 +157,6 @@ struct FileMapping(Datum) // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN. // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx. // But just saving the name is simplest, fastest, and most portable... - import core.stdc.string : strlen; - import core.stdc.stdlib : malloc; - import core.stdc.string : memcpy; const totalNameLength = filename.strlen() + 1; auto namex = cast(char*) malloc(totalNameLength); if (!namex) @@ -224,9 +228,6 @@ struct FileMapping(Datum) fakePure({ version (Posix) { - import core.sys.posix.sys.mman : munmap; - import core.sys.posix.unistd : close; - // Cannot call fprintf from inside a destructor, so exiting silently. if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0) @@ -234,7 +235,7 @@ struct FileMapping(Datum) exit(1); } data = null; - if (handle != invalidHandle && close(handle) != 0) + if (handle != invalidHandle && .close(handle) != 0) { exit(1); } @@ -303,7 +304,6 @@ struct FileMapping(Datum) // In-memory resource freed, now get rid of the underlying temp file. version(Posix) { - import core.sys.posix.unistd : unlink; if (unlink(deleteme) != 0) { fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno)); @@ -312,7 +312,6 @@ struct FileMapping(Datum) } else version(Windows) { - import core.sys.windows.winbase; if (deleteme[0 .. strlen(deleteme)].extendedPathThen!(p => DeleteFileW(p.ptr)) == 0) { fprintf(stderr, "DeleteFileW error %d\n", GetLastError()); @@ -361,9 +360,6 @@ struct FileMapping(Datum) fakePure({ version(Posix) { - import core.sys.posix.unistd : ftruncate; - import core.sys.posix.sys.mman; - if (data.length) { assert(data.ptr, "Corrupt memory mapping"); @@ -431,7 +427,6 @@ struct FileMapping(Datum) // Fetch the name and then set it to `null` so it doesn't get deallocated auto oldname = name; - import core.stdc.stdlib; scope(exit) free(cast(void*) oldname); name = null; close(); @@ -447,7 +442,6 @@ struct FileMapping(Datum) } else version(Windows) { - import core.sys.windows.winbase; auto r = oldname[0 .. strlen(oldname)].extendedPathThen!( p1 => filename[0 .. strlen(filename)].extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING)) ); @@ -527,8 +521,6 @@ bool touchFile(const char* namez) GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); - import core.stdc.string : strlen; - // get handle to file HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -546,7 +538,6 @@ bool touchFile(const char* namez) } else version (Posix) { - import core.sys.posix.utime; return utime(namez, null) == 0; } else @@ -560,24 +551,28 @@ Params: fd = file handle Returns: file size in bytes, or `ulong.max` on any error. */ version (Posix) -private ulong fileSize(int fd) { - import core.sys.posix.sys.stat; - stat_t buf; - if (fstat(fd, &buf) == 0) - return buf.st_size; - return ulong.max; + private ulong fileSize(int fd) + { + stat_t buf; + if (fstat(fd, &buf) == 0) + return buf.st_size; + return ulong.max; + } } - -/// Ditto -version (Windows) -private ulong fileSize(HANDLE fd) +else version (Windows) { - ulong result; - if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0) - return result; - return ulong.max; + /// Ditto + private ulong fileSize(HANDLE fd) + { + ulong result; + if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0) + return result; + return ulong.max; + } } +else + static assert(0); /** Runs a non-pure function or delegate as pure code. Use with caution. diff --git a/gcc/d/dmd/common/smallbuffer.d b/gcc/d/dmd/common/smallbuffer.d index c6aa7abbc60..608ecc8c6b6 100644 --- a/gcc/d/dmd/common/smallbuffer.d +++ b/gcc/d/dmd/common/smallbuffer.d @@ -107,28 +107,30 @@ unittest } /** -(Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by -`buffer` containing the converted string. The terminating zero is not part of the returned slice, -but is guaranteed to follow it. + * (Windows only) Converts a narrow string to a wide string using `buffer` as strorage. + * Params: + * narrow = string to be converted + * buffer = where to place the converted string + * Returns: a slice of `buffer` containing the converted string. A zero follows the slice. */ version(Windows) wchar[] toWStringz(scope const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow { - import core.sys.windows.winnls : MultiByteToWideChar; - import dmd.common.file : CodePage; - if (narrow is null) return null; - size_t length; - int i; - while (1) + size_t charsToWchars(scope const(char)[] narrow, scope wchar[] buffer) { // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar - length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); - if (length < buffer.length) - break; - buffer.create(length + 1); - assert(++i == 1); // ensure loop should only execute once or twice + import core.sys.windows.winnls : MultiByteToWideChar, CP_ACP; + return MultiByteToWideChar(CP_ACP, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); + } + + size_t length = charsToWchars(narrow, buffer[]); + if (length >= buffer.length) // not enough room in buffer[] + { + buffer.create(length + 1); // extend buffer length + length = charsToWchars(narrow, buffer[]); // try again + assert(length < buffer.length); } buffer[length] = 0; return buffer[0 .. length]; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 536a212536d..e917d2cb7e7 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1682,9 +1682,12 @@ final class CParser(AST) : Parser!AST AST.ParameterList parameterList; StorageClass stc = 0; const loc = token.loc; + auto symbolsSave = symbols; + symbols = new AST.Dsymbols(); typedefTab.push(null); auto fbody = cparseStatement(ParseStatementFlags.scope_); typedefTab.pop(); // end of function scope + symbols = symbolsSave; // Rewrite last ExpStatement (if there is one) as a ReturnStatement auto ss = fbody.isScopeStatement(); @@ -1693,8 +1696,11 @@ final class CParser(AST) : Parser!AST if (const len = (*cs.statements).length) { auto s = (*cs.statements)[len - 1]; - if (auto es = s.isExpStatement()) - (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp); + if (s) // error recovery should be with ErrorStatement, not null + { + if (auto es = s.isExpStatement()) + (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp); + } } auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc); @@ -5520,7 +5526,7 @@ final class CParser(AST) : Parser!AST defines.writeByte('#'); defines.writestring(n.ident.toString()); skipToNextLine(defines); - defines.writeByte('\n'); + defines.writeByte(0); // each #define line is 0 terminated return true; } else if (n.ident == Id.__pragma) @@ -5840,7 +5846,8 @@ final class CParser(AST) : Parser!AST const length = buf.length; buf.writeByte(0); auto slice = buf.peekChars()[0 .. length]; - resetDefineLines(slice); // reset lexer + auto scanlocSave = scanloc; + resetDefineLines(slice); // reset lexer auto save = eSink; auto eLatch = new ErrorSinkLatch(); eSink = eLatch; @@ -5865,12 +5872,14 @@ final class CParser(AST) : Parser!AST (*symbols)[*pd] = s; return; } + assert(symbols, "symbols is null"); defineTab[cast(void*)s.ident] = symbols.length; symbols.push(s); } while (p < endp) { + //printf("|%s|\n", p); if (p[0 .. 7] == "#define") { p += 7; @@ -5884,10 +5893,11 @@ final class CParser(AST) : Parser!AST AST.Type t; + Lswitch: switch (token.value) { - case TOK.endOfLine: // #define identifier - nextDefineLine(); + case TOK.endOfFile: // #define identifier + ++p; continue; case TOK.int32Literal: @@ -5901,7 +5911,7 @@ final class CParser(AST) : Parser!AST Linteger: const intvalue = token.intvalue; nextToken(); - if (token.value == TOK.endOfLine) + if (token.value == TOK.endOfFile) { /* Declare manifest constant: * enum id = intvalue; @@ -5909,7 +5919,7 @@ final class CParser(AST) : Parser!AST AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t); auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest); addVar(v); - nextDefineLine(); + ++p; continue; } break; @@ -5924,7 +5934,7 @@ final class CParser(AST) : Parser!AST Lfloat: const floatvalue = token.floatvalue; nextToken(); - if (token.value == TOK.endOfLine) + if (token.value == TOK.endOfFile) { /* Declare manifest constant: * enum id = floatvalue; @@ -5932,7 +5942,7 @@ final class CParser(AST) : Parser!AST AST.Expression e = new AST.RealExp(scanloc, floatvalue, t); auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest); addVar(v); - nextDefineLine(); + ++p; continue; } break; @@ -5942,7 +5952,7 @@ final class CParser(AST) : Parser!AST const len = token.len; const postfix = token.postfix; nextToken(); - if (token.value == TOK.endOfLine) + if (token.value == TOK.endOfFile) { /* Declare manifest constant: * enum id = "string"; @@ -5950,19 +5960,20 @@ final class CParser(AST) : Parser!AST AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix); auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest); addVar(v); - nextDefineLine(); + ++p; continue; } break; case TOK.leftParenthesis: + { /* Look for: * #define ID ( expression ) * and rewrite it to a template function: * auto ID()() { return expression; } */ if (params) - break; // no parameters + goto caseFunctionLike; // version with parameters nextToken(); eLatch.sawErrors = false; auto exp = cparseExpression(); @@ -5971,7 +5982,7 @@ final class CParser(AST) : Parser!AST if (token.value != TOK.rightParenthesis) break; nextToken(); - if (token.value != TOK.endOfLine) + if (token.value != TOK.endOfFile) break; auto ret = new AST.ReturnStatement(exp.loc, exp); auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0); @@ -5985,26 +5996,115 @@ final class CParser(AST) : Parser!AST AST.Expression constraint = null; auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false); addVar(tempdecl); - nextDefineLine(); + ++p; continue; + } + + caseFunctionLike: + { + /* Parse `( a, b ) expression` + * Create template function: + * auto id(__MP1, __MP2)(__MP1 a, __MP1 b) { return expression; } + */ + //printf("functionlike %s\n", id.toChars()); + + // Capture the parameter list + VarArg varargs = VarArg.none; + auto parameters = new AST.Parameters(); + nextToken(); // skip past `(` + Lwhile: + while (1) + { + if (token.value == TOK.rightParenthesis) + break; + if (token.value == TOK.dotDotDot) + { + static if (0) // variadic macros not supported yet + { + varargs = AST.VarArg.variadic; // C-style variadics + nextToken(); + if (token.value == TOK.rightParenthesis) + break Lwhile; + } + break Lswitch; + } + + if (token.value != TOK.identifier) + break Lswitch; + auto param = new AST.Parameter(token.loc, 0, null, token.ident, null, null); + parameters.push(param); + nextToken(); + if (token.value == TOK.comma) + { + nextToken(); + continue; + } + break; + } + if (token.value != TOK.rightParenthesis) + break; + + //auto pstart = p; + nextToken(); + auto parameterList = AST.ParameterList(parameters, varargs, 0); + /* Create a type for each parameter. Add it to the template parameter list, + * and the parameter list. + */ + auto tpl = new AST.TemplateParameters(); + foreach (param; (*parameters)[]) + { + auto idtype = Identifier.generateId("__MP"); + auto loc = param.loc; + auto tp = new AST.TemplateTypeParameter(loc, idtype, null, null); + tpl.push(tp); + + auto at = new AST.TypeIdentifier(loc, idtype); + param.type = at; + } + + eLatch.sawErrors = false; + auto exp = cparseExpression(); + + //printf("exp: %s tok: %s\n", exp.toChars(), Token.toChars(token.value)); + //printf("parsed: '%.*s'\n", cast(int)(p - pstart), pstart); + assert(symbols); + + if (eLatch.sawErrors) // parsing errors + break; // abandon this #define + + if (token.value != TOK.endOfFile) // did not consume the entire line + break; + + // Generate function + auto ret = new AST.ReturnStatement(exp.loc, exp); + StorageClass stc = STC.auto_; + auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc); + auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0); + fd.fbody = ret; + + // Wrap it in an eponymous template + AST.Dsymbols* decldefs = new AST.Dsymbols(); + decldefs.push(fd); + auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false); + addVar(tempdecl); + + ++p; + continue; + } default: break; } } - skipToNextLine(); - } - else - { - scan(&token); - if (token.value != TOK.endOfLine) - { - skipToNextLine(); - } } - nextDefineLine(); + // scan to end of line + while (*p) + ++p; + ++p; // advance to start of next line + scanloc.linnum = scanloc.linnum + 1; } + scanloc = scanlocSave; eSink = save; defines = buf; } diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index b083c03aebe..2efdd31bbba 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -12,21 +12,13 @@ module dmd.dimport; import dmd.arraytypes; -import dmd.astenums; -import dmd.declaration; import dmd.dmodule; -import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.errors; -import dmd.expression; -import dmd.globals; import dmd.identifier; import dmd.location; -import dmd.mtype; import dmd.visitor; -import core.stdc.stdio; /*********************************************************** */ extern (C++) final class Import : Dsymbol @@ -76,6 +68,8 @@ extern (C++) final class Import : Dsymbol assert(id); version (none) { + import core.stdc.stdio; + printf("Import::Import("); foreach (id; packages) { @@ -123,105 +117,6 @@ extern (C++) final class Import : Dsymbol return si; } - /******************************* - * Load this module. - * Returns: - * true for errors, false for success - */ - extern (D) bool load(Scope* sc) - { - //printf("Import::load('%s') %p\n", toPrettyChars(), this); - // See if existing module - const errors = global.errors; - DsymbolTable dst = Package.resolve(packages, null, &pkg); - version (none) - { - if (pkg && pkg.isModule()) - { - .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars()); - mod = pkg.isModule(); // Error recovery - treat as import of that module - return true; - } - } - Dsymbol s = dst.lookup(id); - if (s) - { - if (s.isModule()) - mod = cast(Module)s; - else - { - if (s.isAliasDeclaration()) - { - .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars()); - } - else if (Package p = s.isPackage()) - { - if (p.isPkgMod == PKG.unknown) - { - uint preverrors = global.errors; - mod = Module.load(loc, packages, id); - if (!mod) - p.isPkgMod = PKG.package_; - else - { - // mod is a package.d, or a normal module which conflicts with the package name. - if (mod.isPackageFile) - mod.tag = p.tag; // reuse the same package tag - else - { - // show error if Module.load does not - if (preverrors == global.errors) - .error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars()); - return true; - } - } - } - else - { - mod = p.isPackageMod(); - } - if (!mod) - { - .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars()); - } - } - else if (pkg) - { - .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars()); - } - else - { - .error(loc, "can only import from a module, not from package `%s`", id.toChars()); - } - } - } - if (!mod) - { - // Load module - mod = Module.load(loc, packages, id); - if (mod) - { - // id may be different from mod.ident, if so then insert alias - dst.insert(id, mod); - } - } - if (mod && !mod.importedFrom) - mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; - if (!pkg) - { - if (mod && mod.isPackageFile) - { - // one level depth package.d file (import pkg; ./pkg/package.d) - // it's necessary to use the wrapping Package already created - pkg = mod.pkg; - } - else - pkg = mod; - } - //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); - return global.errors != errors; - } - /******************************* * Mark the imported packages as accessible from the current * scope. This access check is necessary when using FQN b/c diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 07d5077ee49..a77e4f303cd 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -16,12 +16,14 @@ module dmd.dmodule; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; + import dmd.aggregate; import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; +import dmd.common.outbuffer; import dmd.compiler; -import dmd.gluelayer; +import dmd.cparse; import dmd.dimport; import dmd.dmacro; import dmd.doc; @@ -35,25 +37,37 @@ import dmd.expressionsem; import dmd.file_manager; import dmd.func; import dmd.globals; +import dmd.gluelayer; import dmd.id; import dmd.identifier; import dmd.location; import dmd.parse; -import dmd.cparse; import dmd.root.array; import dmd.root.file; import dmd.root.filename; -import dmd.common.outbuffer; import dmd.root.port; import dmd.root.rmem; -import dmd.rootobject; import dmd.root.string; +import dmd.rootobject; import dmd.semantic2; import dmd.semantic3; import dmd.target; import dmd.utils; import dmd.visitor; +version (Windows) +{ + import core.sys.windows.winbase : getpid = GetCurrentProcessId; + enum PathSeparator = '\\'; +} +else version (Posix) +{ + import core.sys.posix.unistd : getpid; + enum PathSeparator = '/'; +} +else + static assert(0); + version (IN_GCC) {} else version (IN_LLVM) {} else version = MARS; @@ -141,11 +155,7 @@ private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothr buf.writestring(p); if (modAliases.length) checkModFileAlias(p); - version (Windows) - enum FileSeparator = '\\'; - else - enum FileSeparator = '/'; - buf.writeByte(FileSeparator); + buf.writeByte(PathSeparator); } buf.writestring(filename); if (modAliases.length) @@ -558,10 +568,6 @@ extern (C++) final class Module : Package OutBuffer buf; if (arg == "__stdin.d") { - version (Posix) - import core.sys.posix.unistd : getpid; - else version (Windows) - import core.sys.windows.winbase : getpid = GetCurrentProcessId; buf.printf("__stdin_%d.d", getpid()); arg = buf[]; } diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index c15d925ce0a..bb0a1d6e2cc 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -6916,6 +6916,103 @@ extern(C++) class ImportAllVisitor : Visitor override void visit(StaticForeachDeclaration _) {} } +/******************************* + * Load module. + * Returns: + * true for errors, false for success + */ +extern (D) bool load(Import imp, Scope* sc) +{ + // See if existing module + const errors = global.errors; + DsymbolTable dst = Package.resolve(imp.packages, null, &imp.pkg); + version (none) + { + if (pkg && pkg.isModule()) + { + .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars()); + mod = pkg.isModule(); // Error recovery - treat as import of that module + return true; + } + } + Dsymbol s = dst.lookup(imp.id); + if (s) + { + if (s.isModule()) + imp.mod = cast(Module)s; + else + { + if (s.isAliasDeclaration()) + { + .error(imp.loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), imp.id.toChars()); + } + else if (Package p = s.isPackage()) + { + if (p.isPkgMod == PKG.unknown) + { + uint preverrors = global.errors; + imp.mod = Module.load(imp.loc, imp.packages, imp.id); + if (!imp.mod) + p.isPkgMod = PKG.package_; + else + { + // imp.mod is a package.d, or a normal module which conflicts with the package name. + if (imp.mod.isPackageFile) + imp.mod.tag = p.tag; // reuse the same package tag + else + { + // show error if Module.load does not + if (preverrors == global.errors) + .error(imp.loc, "%s `%s` from file %s conflicts with %s `%s`", imp.mod.kind(), imp.mod.toPrettyChars(), imp.mod.srcfile.toChars, p.kind(), p.toPrettyChars()); + return true; + } + } + } + else + { + imp.mod = p.isPackageMod(); + } + if (!imp.mod) + { + .error(imp.loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), imp.id.toChars()); + } + } + else if (imp.pkg) + { + .error(imp.loc, "can only import from a module, not from package `%s.%s`", imp.pkg.toPrettyChars(), imp.id.toChars()); + } + else + { + .error(imp.loc, "can only import from a module, not from package `%s`", imp.id.toChars()); + } + } + } + if (!imp.mod) + { + // Load module + imp.mod = Module.load(imp.loc, imp.packages, imp.id); + if (imp.mod) + { + // imp.id may be different from mod.ident, if so then insert alias + dst.insert(imp.id, imp.mod); + } + } + if (imp.mod && !imp.mod.importedFrom) + imp.mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; + if (!imp.pkg) + { + if (imp.mod && imp.mod.isPackageFile) + { + // one level depth package.d file (import pkg; ./pkg/package.d) + // it's necessary to use the wrapping Package already created + imp.pkg = imp.mod.pkg; + } + else + imp.pkg = imp.mod; + } + return global.errors != errors; +} + void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion) { scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion); diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index bc907cfd2f4..479ad3ade5f 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -314,6 +314,7 @@ extern (C++) abstract class Expression : ASTNode Type type; // !=null means that semantic() has been run Loc loc; // file location const EXP op; // to minimize use of dynamic_cast + bool parens; // if this is a parenthesized expression extern (D) this(const ref Loc loc, EXP op) scope @safe { @@ -1310,7 +1311,6 @@ extern (C++) final class ComplexExp : Expression extern (C++) class IdentifierExp : Expression { Identifier ident; - bool parens; // if it appears as (identifier) extern (D) this(const ref Loc loc, Identifier ident) scope @safe { @@ -2432,8 +2432,6 @@ extern (C++) final class CompoundLiteralExp : Expression */ extern (C++) final class TypeExp : Expression { - bool parens; // if this is a parenthesized expression - extern (D) this(const ref Loc loc, Type type) @safe { super(loc, EXP.type); diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 3bd8ca7568e..9cd73a965ba 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -90,6 +90,7 @@ public: Type *type; // !=NULL means that semantic() has been run Loc loc; // file location EXP op; // to minimize use of dynamic_cast + d_bool parens; // if this is a parenthesized expression size_t size() const; static void _init(); @@ -300,7 +301,6 @@ class IdentifierExp : public Expression { public: Identifier *ident; - d_bool parens; static IdentifierExp *create(const Loc &loc, Identifier *ident); bool isLvalue() override final; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index cc589b991d1..b4d5274e7c3 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -16628,3 +16628,100 @@ Expression toBoolean(Expression exp, Scope* sc) return e; } } + +/******************************************** + * Semantically analyze and then evaluate a static condition at compile time. + * This is special because short circuit operators &&, || and ?: at the top + * level are not semantically analyzed if the result of the expression is not + * necessary. + * Params: + * sc = instantiating scope + * original = original expression, for error messages + * e = resulting expression + * errors = set to `true` if errors occurred + * negatives = array to store negative clauses + * Returns: + * true if evaluates to true + */ +bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null) +{ + if (negatives) + negatives.setDim(0); + + bool impl(Expression e) + { + if (e.isNotExp()) + { + NotExp ne = cast(NotExp)e; + return !impl(ne.e1); + } + + if (e.op == EXP.andAnd || e.op == EXP.orOr) + { + LogicalExp aae = cast(LogicalExp)e; + bool result = impl(aae.e1); + if (errors) + return false; + if (e.op == EXP.andAnd) + { + if (!result) + return false; + } + else + { + if (result) + return true; + } + result = impl(aae.e2); + return !errors && result; + } + + if (e.op == EXP.question) + { + CondExp ce = cast(CondExp)e; + bool result = impl(ce.econd); + if (errors) + return false; + Expression leg = result ? ce.e1 : ce.e2; + result = impl(leg); + return !errors && result; + } + + Expression before = e; + const uint nerrors = global.errors; + + sc = sc.startCTFE(); + sc.flags |= SCOPE.condition; + + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.toBoolean(sc); + + sc = sc.endCTFE(); + e = e.optimize(WANTvalue); + + if (nerrors != global.errors || + e.isErrorExp() || + e.type.toBasetype() == Type.terror) + { + errors = true; + return false; + } + + e = e.ctfeInterpret(); + + const opt = e.toBool(); + if (opt.isEmpty()) + { + if (!e.type.isTypeError()) + error(e.loc, "expression `%s` is not constant", e.toChars()); + errors = true; + return false; + } + + if (negatives && !opt.get()) + negatives.push(before); + return opt.get(); + } + return impl(e); +} diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 4881ad6c020..d890811115c 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -58,7 +58,6 @@ import dmd.semantic3; import dmd.statement_rewrite_walker; import dmd.statement; import dmd.statementsem; -import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; @@ -2925,395 +2924,6 @@ unittest assert(mismatches.isMutable); } -/// Flag used by $(LREF resolveFuncCall). -enum FuncResolveFlag : ubyte -{ - standard = 0, /// issue error messages, solve the call. - quiet = 1, /// do not issue error message on no match, just return `null`. - overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous - /// matches and need explicit this. - ufcs = 4, /// trying to resolve UFCS call -} - -/******************************************* - * Given a symbol that could be either a FuncDeclaration or - * a function template, resolve it to a function symbol. - * Params: - * loc = instantiation location - * sc = instantiation scope - * s = instantiation symbol - * tiargs = initial list of template arguments - * tthis = if !NULL, the `this` argument type - * argumentList = arguments to function - * flags = see $(LREF FuncResolveFlag). - * Returns: - * if match is found, then function symbol, else null - */ -FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, - Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags) -{ - auto fargs = argumentList.arguments; - if (!s) - return null; // no match - - version (none) - { - printf("resolveFuncCall('%s')\n", s.toChars()); - if (tthis) - printf("\tthis: %s\n", tthis.toChars()); - if (fargs) - { - for (size_t i = 0; i < fargs.length; i++) - { - Expression arg = (*fargs)[i]; - assert(arg.type); - printf("\t%s: %s\n", arg.toChars(), arg.type.toChars()); - } - } - printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); - } - - if (tiargs && arrayObjectIsError(*tiargs)) - return null; - if (fargs !is null) - foreach (arg; *fargs) - if (isError(arg)) - return null; - - MatchAccumulator m; - functionResolve(m, s, loc, sc, tiargs, tthis, argumentList); - auto orig_s = s; - - if (m.last > MATCH.nomatch && m.lastf) - { - if (m.count == 1) // exactly one match - { - if (!(flags & FuncResolveFlag.quiet)) - functionSemantic(m.lastf); - return m.lastf; - } - if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) - { - return m.lastf; - } - } - - /* Failed to find a best match. - * Do nothing or print error. - */ - if (m.last == MATCH.nomatch) - { - // error was caused on matched function, not on the matching itself, - // so return the function to produce a better diagnostic - if (m.count == 1) - return m.lastf; - } - - // We are done at this point, as the rest of this function generate - // a diagnostic on invalid match - if (flags & FuncResolveFlag.quiet) - return null; - - auto fd = s.isFuncDeclaration(); - auto od = s.isOverDeclaration(); - auto td = s.isTemplateDeclaration(); - if (td && td.funcroot) - s = fd = td.funcroot; - - OutBuffer tiargsBuf; - arrayObjectsToBuffer(tiargsBuf, tiargs); - - OutBuffer fargsBuf; - fargsBuf.writeByte('('); - argExpTypesToCBuffer(fargsBuf, fargs); - fargsBuf.writeByte(')'); - if (tthis) - tthis.modToBuffer(fargsBuf); - - // The call is ambiguous - if (m.lastf && m.nextf) - { - TypeFunction tf1 = m.lastf.type.toTypeFunction(); - TypeFunction tf2 = m.nextf.type.toTypeFunction(); - const(char)* lastprms = parametersTypeToChars(tf1.parameterList); - const(char)* nextprms = parametersTypeToChars(tf2.parameterList); - - .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`", - s.parent.toPrettyChars(), s.ident.toChars(), - fargsBuf.peekChars(), - m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(), - m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars()); - return null; - } - - // no match, generate an error messages - if (flags & FuncResolveFlag.ufcs) - { - auto arg = (*fargs)[0]; - .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars()); - .errorSupplemental(loc, "the following error occured while looking for a UFCS match"); - } - - if (!fd) - { - // all of overloads are templates - if (td) - { - if (!od && !td.overnext) - { - .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`", - td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); - } - else - { - .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", - td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), - tiargsBuf.peekChars(), fargsBuf.peekChars()); - } - - - if (!global.gag || global.params.v.showGaggedErrors) - printCandidates(loc, td, sc.isDeprecated()); - return null; - } - /* This case used to happen when several ctors are mixed in an agregate. - A (bad) error message is already generated in overloadApply(). - see https://issues.dlang.org/show_bug.cgi?id=19729 - and https://issues.dlang.org/show_bug.cgi?id=17259 - */ - if (!od) - return null; - } - - if (od) - { - .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`", - od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); - return null; - } - - // remove when deprecation period of class allocators and deallocators is over - if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc)) - return null; - - bool hasOverloads = fd.overnext !is null; - auto tf = fd.type.isTypeFunction(); - // if type is an error, the original type should be there for better diagnostics - if (!tf) - tf = fd.originalType.toTypeFunction(); - - // modifier mismatch - if (tthis && (fd.isCtorDeclaration() ? - !MODimplicitConv(tf.mod, tthis.mod) : - !MODimplicitConv(tthis.mod, tf.mod))) - { - OutBuffer thisBuf, funcBuf; - MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); - auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); - if (hasOverloads) - { - OutBuffer buf; - buf.argExpTypesToCBuffer(fargs); - if (fd.isCtorDeclaration()) - .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`", - fd.toChars(), thisBuf.peekChars(), buf.peekChars()); - else - .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`", - fd.toChars(), thisBuf.peekChars(), buf.peekChars()); - - if (!global.gag || global.params.v.showGaggedErrors) - printCandidates(loc, fd, sc.isDeprecated()); - return null; - } - - bool calledHelper; - void errorHelper(const(char)* failMessage) scope - { - .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", - fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), - tf.modToChars(), fargsBuf.peekChars()); - errorSupplemental(loc, failMessage); - calledHelper = true; - } - - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper); - if (calledHelper) - return null; - - if (fd.isCtorDeclaration()) - .error(loc, "%s%s `%s` cannot construct a %sobject", - funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); - else - .error(loc, "%smethod `%s` is not callable using a %sobject", - funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars()); - - if (mismatches.isNotShared) - .errorSupplemental(fd.loc, "Consider adding `shared` here"); - else if (mismatches.isMutable) - .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here"); - return null; - } - - //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco); - if (hasOverloads) - { - .error(loc, "none of the overloads of `%s` are callable using argument types `%s`", - fd.toChars(), fargsBuf.peekChars()); - if (!global.gag || global.params.v.showGaggedErrors) - printCandidates(loc, fd, sc.isDeprecated()); - return null; - } - - .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", - fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), - tf.modToChars(), fargsBuf.peekChars()); - - // re-resolve to check for supplemental message - if (!global.gag || global.params.v.showGaggedErrors) - { - if (tthis) - { - if (auto classType = tthis.isTypeClass()) - { - if (auto baseClass = classType.sym.baseClass) - { - if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident)) - { - MatchAccumulator mErr; - functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList); - if (mErr.last > MATCH.nomatch && mErr.lastf) - { - errorSupplemental(loc, "%s `%s` hides base class function `%s`", - fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars()); - errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets", - fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars()); - return null; - } - } - } - } - } - - void errorHelper2(const(char)* failMessage) scope - { - errorSupplemental(loc, failMessage); - } - - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2); - } - return null; -} - -/******************************************* - * Prints template and function overload candidates as supplemental errors. - * Params: - * loc = instantiation location - * declaration = the declaration to print overload candidates for - * showDeprecated = If `false`, `deprecated` function won't be shown - */ -private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated) -if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) -{ - // max num of overloads to print (-v or -verror-supplements overrides this). - const uint DisplayLimit = global.params.v.errorSupplementCount(); - const(char)* constraintsTip; - // determine if the first candidate was printed - int printed; - - bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false) - { - if (auto fd = s.isFuncDeclaration()) - { - // Don't print overloads which have errors. - // Not that if the whole overload set has errors, we'll never reach - // this point so there's no risk of printing no candidate - if (fd.errors || fd.type.ty == Terror) - return false; - // Don't print disabled functions, or `deprecated` outside of deprecated scope - if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated)) - return false; - if (!print) - return true; - auto tf = cast(TypeFunction) fd.type; - OutBuffer buf; - buf.writestring(fd.toPrettyChars()); - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) - { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); - } - .errorSupplemental(fd.loc, - printed ? " `%s`" : - single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars()); - } - else if (auto td = s.isTemplateDeclaration()) - { - import dmd.staticcond; - - if (!print) - return true; - OutBuffer buf; - HdrGenState hgs; - hgs.skipConstraints = true; - toCharsMaybeConstraints(td, buf, hgs); - const tmsg = buf.peekChars(); - const cmsg = td.getConstraintEvalError(constraintsTip); - - // add blank space if there are multiple candidates - // the length of the blank space is `strlen("Candidates are: ")` - - if (cmsg) - { - .errorSupplemental(td.loc, - printed ? " `%s`\n%s" : - single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s", - tmsg, cmsg); - } - else - { - .errorSupplemental(td.loc, - printed ? " `%s`" : - single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", - tmsg); - } - } - return true; - } - // determine if there's > 1 candidate - int count = 0; - overloadApply(declaration, (s) { - if (matchSymbol(s, false)) - count++; - return count > 1; - }); - int skipped = 0; - overloadApply(declaration, (s) { - if (global.params.v.verbose || printed < DisplayLimit) - { - if (matchSymbol(s, true, count == 1)) - printed++; - } - else - { - // Too many overloads to sensibly display. - // Just show count of remaining overloads. - if (matchSymbol(s, false)) - skipped++; - } - return 0; - }); - if (skipped > 0) - .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped); - - // Nothing was displayed, all overloads are either disabled or deprecated - if (!printed) - .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`"); - // should be only in verbose mode - if (constraintsTip) - .tip(constraintsTip); -} - /************************************** * Returns an indirect type one step from t. */ @@ -4336,9 +3946,9 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char) return false; if (sc.func.isSafeBypassingInference()) { - if (!gag) + if (!gag && !sc.isDeprecated()) { - warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""); + deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""); } } else if (!sc.func.safetyViolation) diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d index 49da6b20136..b8b185c94f3 100644 --- a/gcc/d/dmd/funcsem.d +++ b/gcc/d/dmd/funcsem.d @@ -60,6 +60,7 @@ import dmd.statement_rewrite_walker; import dmd.statement; import dmd.statementsem; import dmd.target; +import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; @@ -1365,3 +1366,392 @@ BaseClass* overrideInterface(FuncDeclaration fd) } return null; } + +/// Flag used by $(LREF resolveFuncCall). +enum FuncResolveFlag : ubyte +{ + standard = 0, /// issue error messages, solve the call. + quiet = 1, /// do not issue error message on no match, just return `null`. + overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous + /// matches and need explicit this. + ufcs = 4, /// trying to resolve UFCS call +} + +/******************************************* + * Given a symbol that could be either a FuncDeclaration or + * a function template, resolve it to a function symbol. + * Params: + * loc = instantiation location + * sc = instantiation scope + * s = instantiation symbol + * tiargs = initial list of template arguments + * tthis = if !NULL, the `this` argument type + * argumentList = arguments to function + * flags = see $(LREF FuncResolveFlag). + * Returns: + * if match is found, then function symbol, else null + */ +FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, + Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags) +{ + auto fargs = argumentList.arguments; + if (!s) + return null; // no match + + version (none) + { + printf("resolveFuncCall('%s')\n", s.toChars()); + if (tthis) + printf("\tthis: %s\n", tthis.toChars()); + if (fargs) + { + for (size_t i = 0; i < fargs.length; i++) + { + Expression arg = (*fargs)[i]; + assert(arg.type); + printf("\t%s: %s\n", arg.toChars(), arg.type.toChars()); + } + } + printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); + } + + if (tiargs && arrayObjectIsError(*tiargs)) + return null; + if (fargs !is null) + foreach (arg; *fargs) + if (isError(arg)) + return null; + + MatchAccumulator m; + functionResolve(m, s, loc, sc, tiargs, tthis, argumentList); + auto orig_s = s; + + if (m.last > MATCH.nomatch && m.lastf) + { + if (m.count == 1) // exactly one match + { + if (!(flags & FuncResolveFlag.quiet)) + functionSemantic(m.lastf); + return m.lastf; + } + if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) + { + return m.lastf; + } + } + + /* Failed to find a best match. + * Do nothing or print error. + */ + if (m.last == MATCH.nomatch) + { + // error was caused on matched function, not on the matching itself, + // so return the function to produce a better diagnostic + if (m.count == 1) + return m.lastf; + } + + // We are done at this point, as the rest of this function generate + // a diagnostic on invalid match + if (flags & FuncResolveFlag.quiet) + return null; + + auto fd = s.isFuncDeclaration(); + auto od = s.isOverDeclaration(); + auto td = s.isTemplateDeclaration(); + if (td && td.funcroot) + s = fd = td.funcroot; + + OutBuffer tiargsBuf; + arrayObjectsToBuffer(tiargsBuf, tiargs); + + OutBuffer fargsBuf; + fargsBuf.writeByte('('); + argExpTypesToCBuffer(fargsBuf, fargs); + fargsBuf.writeByte(')'); + if (tthis) + tthis.modToBuffer(fargsBuf); + + // The call is ambiguous + if (m.lastf && m.nextf) + { + TypeFunction tf1 = m.lastf.type.toTypeFunction(); + TypeFunction tf2 = m.nextf.type.toTypeFunction(); + const(char)* lastprms = parametersTypeToChars(tf1.parameterList); + const(char)* nextprms = parametersTypeToChars(tf2.parameterList); + + .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`", + s.parent.toPrettyChars(), s.ident.toChars(), + fargsBuf.peekChars(), + m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(), + m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars()); + return null; + } + + // no match, generate an error messages + if (flags & FuncResolveFlag.ufcs) + { + auto arg = (*fargs)[0]; + .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars()); + .errorSupplemental(loc, "the following error occured while looking for a UFCS match"); + } + + if (!fd) + { + // all of overloads are templates + if (td) + { + if (!od && !td.overnext) + { + .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`", + td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + else + { + .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", + td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), + tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + + + if (!global.gag || global.params.v.showGaggedErrors) + printCandidates(loc, td, sc.isDeprecated()); + return null; + } + /* This case used to happen when several ctors are mixed in an agregate. + A (bad) error message is already generated in overloadApply(). + see https://issues.dlang.org/show_bug.cgi?id=19729 + and https://issues.dlang.org/show_bug.cgi?id=17259 + */ + if (!od) + return null; + } + + if (od) + { + .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`", + od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + return null; + } + + // remove when deprecation period of class allocators and deallocators is over + if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc)) + return null; + + bool hasOverloads = fd.overnext !is null; + auto tf = fd.type.isTypeFunction(); + // if type is an error, the original type should be there for better diagnostics + if (!tf) + tf = fd.originalType.toTypeFunction(); + + // modifier mismatch + if (tthis && (fd.isCtorDeclaration() ? + !MODimplicitConv(tf.mod, tthis.mod) : + !MODimplicitConv(tthis.mod, tf.mod))) + { + OutBuffer thisBuf, funcBuf; + MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); + auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); + if (hasOverloads) + { + OutBuffer buf; + buf.argExpTypesToCBuffer(fargs); + if (fd.isCtorDeclaration()) + .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`", + fd.toChars(), thisBuf.peekChars(), buf.peekChars()); + else + .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`", + fd.toChars(), thisBuf.peekChars(), buf.peekChars()); + + if (!global.gag || global.params.v.showGaggedErrors) + printCandidates(loc, fd, sc.isDeprecated()); + return null; + } + + bool calledHelper; + void errorHelper(const(char)* failMessage) scope + { + .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", + fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), + tf.modToChars(), fargsBuf.peekChars()); + errorSupplemental(loc, failMessage); + calledHelper = true; + } + + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper); + if (calledHelper) + return null; + + if (fd.isCtorDeclaration()) + .error(loc, "%s%s `%s` cannot construct a %sobject", + funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); + else + .error(loc, "%smethod `%s` is not callable using a %sobject", + funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars()); + + if (mismatches.isNotShared) + .errorSupplemental(fd.loc, "Consider adding `shared` here"); + else if (mismatches.isMutable) + .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here"); + return null; + } + + //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco); + if (hasOverloads) + { + .error(loc, "none of the overloads of `%s` are callable using argument types `%s`", + fd.toChars(), fargsBuf.peekChars()); + if (!global.gag || global.params.v.showGaggedErrors) + printCandidates(loc, fd, sc.isDeprecated()); + return null; + } + + .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", + fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), + tf.modToChars(), fargsBuf.peekChars()); + + // re-resolve to check for supplemental message + if (!global.gag || global.params.v.showGaggedErrors) + { + if (tthis) + { + if (auto classType = tthis.isTypeClass()) + { + if (auto baseClass = classType.sym.baseClass) + { + if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident)) + { + MatchAccumulator mErr; + functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList); + if (mErr.last > MATCH.nomatch && mErr.lastf) + { + errorSupplemental(loc, "%s `%s` hides base class function `%s`", + fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars()); + errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets", + fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars()); + return null; + } + } + } + } + } + + void errorHelper2(const(char)* failMessage) scope + { + errorSupplemental(loc, failMessage); + } + + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2); + } + return null; +} + +/******************************************* + * Prints template and function overload candidates as supplemental errors. + * Params: + * loc = instantiation location + * declaration = the declaration to print overload candidates for + * showDeprecated = If `false`, `deprecated` function won't be shown + */ +private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated) +if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) +{ + // max num of overloads to print (-v or -verror-supplements overrides this). + const uint DisplayLimit = global.params.v.errorSupplementCount(); + const(char)* constraintsTip; + // determine if the first candidate was printed + int printed; + + bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false) + { + if (auto fd = s.isFuncDeclaration()) + { + // Don't print overloads which have errors. + // Not that if the whole overload set has errors, we'll never reach + // this point so there's no risk of printing no candidate + if (fd.errors || fd.type.ty == Terror) + return false; + // Don't print disabled functions, or `deprecated` outside of deprecated scope + if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated)) + return false; + if (!print) + return true; + auto tf = cast(TypeFunction) fd.type; + OutBuffer buf; + buf.writestring(fd.toPrettyChars()); + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } + .errorSupplemental(fd.loc, + printed ? " `%s`" : + single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars()); + } + else if (auto td = s.isTemplateDeclaration()) + { + import dmd.staticcond; + + if (!print) + return true; + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(td, buf, hgs); + const tmsg = buf.peekChars(); + const cmsg = td.getConstraintEvalError(constraintsTip); + + // add blank space if there are multiple candidates + // the length of the blank space is `strlen("Candidates are: ")` + + if (cmsg) + { + .errorSupplemental(td.loc, + printed ? " `%s`\n%s" : + single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s", + tmsg, cmsg); + } + else + { + .errorSupplemental(td.loc, + printed ? " `%s`" : + single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", + tmsg); + } + } + return true; + } + // determine if there's > 1 candidate + int count = 0; + overloadApply(declaration, (s) { + if (matchSymbol(s, false)) + count++; + return count > 1; + }); + int skipped = 0; + overloadApply(declaration, (s) { + if (global.params.v.verbose || printed < DisplayLimit) + { + if (matchSymbol(s, true, count == 1)) + printed++; + } + else + { + // Too many overloads to sensibly display. + // Just show count of remaining overloads. + if (matchSymbol(s, false)) + skipped++; + } + return 0; + }); + if (skipped > 0) + .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped); + + // Nothing was displayed, all overloads are either disabled or deprecated + if (!printed) + .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`"); + // should be only in verbose mode + if (constraintsTip) + .tip(constraintsTip); +} diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h index afd3664bfa8..4f26801356e 100644 --- a/gcc/d/dmd/identifier.h +++ b/gcc/d/dmd/identifier.h @@ -11,7 +11,7 @@ #pragma once #include "root/dcompat.h" -#include "root/object.h" +#include "rootobject.h" class Identifier final : public RootObject { diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index e4d5aa2cae1..ece56c8d1bc 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -243,16 +243,15 @@ Expression castCallAmbiguity(Expression e, Scope* sc) case EXP.call: auto ce = (*pe).isCallExp(); - auto ie = ce.e1.isIdentifierExp(); - if (ie && ie.parens) + if (ce.e1.parens) { - ce.e1 = expressionSemantic(ie, sc); + ce.e1 = expressionSemantic(ce.e1, sc); if (ce.e1.op == EXP.type) { const numArgs = ce.arguments ? ce.arguments.length : 0; if (numArgs >= 1) { - ie.parens = false; + ce.e1.parens = false; Expression arg; foreach (a; (*ce.arguments)[]) { diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 09ed630fe8b..843c402031d 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -30,7 +30,6 @@ import dmd.dtemplate; import dmd.enumsem; import dmd.errors; import dmd.expression; -import dmd.func; import dmd.funcsem; import dmd.globals; import dmd.hdrgen; diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 9c446eb1bf3..646c4b7d3db 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -7130,7 +7130,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer private void checkParens(TOK value, AST.Expression e) { - if (precedence[e.op] == PREC.rel) + if (precedence[e.op] == PREC.rel && !e.parens) error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value)); } @@ -8550,6 +8550,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // ( expression ) nextToken(); e = parseExpression(); + e.parens = true; check(loc, TOK.rightParenthesis); break; } @@ -8874,9 +8875,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); return AST.ErrorExp.get(); } - auto te = new AST.TypeExp(loc, t); - te.parens = true; - e = parsePostExp(te); + e = new AST.TypeExp(loc, t); + e.parens = true; + e = parsePostExp(e); } else if (token.value == TOK.leftParenthesis || token.value == TOK.plusPlus || token.value == TOK.minusMinus) @@ -9193,18 +9194,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer private AST.Expression parseAndExp() { Loc loc = token.loc; - bool parens = token.value == TOK.leftParenthesis; auto e = parseCmpExp(); while (token.value == TOK.and) { - if (!parens) - checkParens(TOK.and, e); - parens = nextToken() == TOK.leftParenthesis; + checkParens(TOK.and, e); + nextToken(); auto e2 = parseCmpExp(); - if (!parens) - checkParens(TOK.and, e2); + checkParens(TOK.and, e2); e = new AST.AndExp(loc, e, e2); - parens = true; // don't call checkParens() for And loc = token.loc; } return e; @@ -9212,42 +9209,32 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer private AST.Expression parseXorExp() { - Loc loc = token.loc; + const loc = token.loc; - bool parens = token.value == TOK.leftParenthesis; auto e = parseAndExp(); while (token.value == TOK.xor) { - if (!parens) - checkParens(TOK.xor, e); - parens = nextToken() == TOK.leftParenthesis; + checkParens(TOK.xor, e); + nextToken(); auto e2 = parseAndExp(); - if (!parens) - checkParens(TOK.xor, e2); + checkParens(TOK.xor, e2); e = new AST.XorExp(loc, e, e2); - parens = true; - loc = token.loc; } return e; } private AST.Expression parseOrExp() { - Loc loc = token.loc; + const loc = token.loc; - bool parens = token.value == TOK.leftParenthesis; auto e = parseXorExp(); while (token.value == TOK.or) { - if (!parens) - checkParens(TOK.or, e); - parens = nextToken() == TOK.leftParenthesis; + checkParens(TOK.or, e); + nextToken(); auto e2 = parseXorExp(); - if (!parens) - checkParens(TOK.or, e2); + checkParens(TOK.or, e2); e = new AST.OrExp(loc, e, e2); - parens = true; - loc = token.loc; } return e; } @@ -9298,7 +9285,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Expression parseAssignExp() { - bool parens = token.value == TOK.leftParenthesis; AST.Expression e; e = parseCondExp(); if (e is null) @@ -9307,7 +9293,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // require parens for e.g. `t ? a = 1 : b = 2` void checkRequiredParens() { - if (e.op == EXP.question && !parens) + if (e.op == EXP.question && !e.parens) eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(token.value)); } diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h index 1033b22237a..3e2880431e9 100644 --- a/gcc/d/dmd/root/array.h +++ b/gcc/d/dmd/root/array.h @@ -9,7 +9,6 @@ #pragma once #include "dsystem.h" -#include "object.h" #include "rmem.h" template @@ -44,7 +43,7 @@ struct Array d_size_t len = 2; for (d_size_t u = 0; u < length; u++) { - buf[u] = ((RootObject *)data.ptr[u])->toChars(); + buf[u] = ((TYPE)data.ptr[u])->toChars(); len += strlen(buf[u]) + 1; } char *str = (char *)mem.xmalloc(len); diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h index 2cd7152f725..2a827033587 100644 --- a/gcc/d/dmd/root/bitarray.h +++ b/gcc/d/dmd/root/bitarray.h @@ -9,7 +9,6 @@ #pragma once #include "dsystem.h" -#include "object.h" #include "rmem.h" struct BitArray diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/rootobject.h similarity index 91% rename from gcc/d/dmd/root/object.h rename to gcc/d/dmd/rootobject.h index f56cb176017..718a54f0275 100644 --- a/gcc/d/dmd/root/object.h +++ b/gcc/d/dmd/rootobject.h @@ -4,13 +4,13 @@ * 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/root/object.h + * https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.h */ #pragma once -#include "dsystem.h" -#include "dcompat.h" +#include "root/dsystem.h" +#include "root/dcompat.h" typedef size_t hash_t; diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 5013c569933..1bf36e3082d 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -1196,7 +1196,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } case Taarray: if (fs.op == TOK.foreach_reverse_) - warning(fs.loc, "cannot use `foreach_reverse` with an associative array"); + error(fs.loc, "cannot use `foreach_reverse` with an associative array"); if (checkForArgTypes(fs)) return retError(); diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d index 72afe029641..3ab6885586a 100644 --- a/gcc/d/dmd/staticcond.d +++ b/gcc/d/dmd/staticcond.d @@ -11,120 +11,13 @@ module dmd.staticcond; -import dmd.arraytypes; -import dmd.dinterpret; -import dmd.dmodule; -import dmd.dscope; -import dmd.dsymbol; -import dmd.errors; import dmd.expression; -import dmd.expressionsem; -import dmd.globals; -import dmd.identifier; -import dmd.mtype; -import dmd.optimize; import dmd.root.array; import dmd.common.outbuffer; import dmd.tokens; -/******************************************** - * Semantically analyze and then evaluate a static condition at compile time. - * This is special because short circuit operators &&, || and ?: at the top - * level are not semantically analyzed if the result of the expression is not - * necessary. - * Params: - * sc = instantiating scope - * original = original expression, for error messages - * e = resulting expression - * errors = set to `true` if errors occurred - * negatives = array to store negative clauses - * Returns: - * true if evaluates to true - */ -bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null) -{ - if (negatives) - negatives.setDim(0); - - bool impl(Expression e) - { - if (e.isNotExp()) - { - NotExp ne = cast(NotExp)e; - return !impl(ne.e1); - } - - if (e.op == EXP.andAnd || e.op == EXP.orOr) - { - LogicalExp aae = cast(LogicalExp)e; - bool result = impl(aae.e1); - if (errors) - return false; - if (e.op == EXP.andAnd) - { - if (!result) - return false; - } - else - { - if (result) - return true; - } - result = impl(aae.e2); - return !errors && result; - } - - if (e.op == EXP.question) - { - CondExp ce = cast(CondExp)e; - bool result = impl(ce.econd); - if (errors) - return false; - Expression leg = result ? ce.e1 : ce.e2; - result = impl(leg); - return !errors && result; - } - - Expression before = e; - const uint nerrors = global.errors; - - sc = sc.startCTFE(); - sc.flags |= SCOPE.condition; - - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.toBoolean(sc); - - sc = sc.endCTFE(); - e = e.optimize(WANTvalue); - - if (nerrors != global.errors || - e.isErrorExp() || - e.type.toBasetype() == Type.terror) - { - errors = true; - return false; - } - - e = e.ctfeInterpret(); - - const opt = e.toBool(); - if (opt.isEmpty()) - { - if (!e.type.isTypeError()) - error(e.loc, "expression `%s` is not constant", e.toChars()); - errors = true; - return false; - } - - if (negatives && !opt.get()) - negatives.push(before); - return opt.get(); - } - return impl(e); -} /******************************************** * Format a static condition as a tree-like structure, marking failed and diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 6f12ac3eb1f..0f96a1b3b09 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -36,7 +36,7 @@ public: // kludge for template.isType() DYNCAST dyncast() const override { return DYNCAST_TUPLE; } - const char *toChars() const override { return objects.toChars(); } + const char *toChars() const override; }; struct TemplatePrevious diff --git a/gcc/testsuite/gdc.test/compilable/imports/defines.c b/gcc/testsuite/gdc.test/compilable/imports/defines.c index 8a5601a2d08..6b0746f8ff9 100644 --- a/gcc/testsuite/gdc.test/compilable/imports/defines.c +++ b/gcc/testsuite/gdc.test/compilable/imports/defines.c @@ -30,3 +30,28 @@ _Static_assert(SSS[0] == 'h', "10"); #define ABC 12 #define GHI (size) abbadabba #define DEF (ABC + 5) + +#define ADD(a, b) a + b +#define SUB() 3 - 2 + +#define NO_BODY() +#define NO_BODY_PARAMS(a, b) +#define DO_WHILE() do { } while(0) + +#define pr16199_trigger(cond,func,args) _Generic (cond, default: func args) +#define pr16199_skipped1(a) (1) +#define pr16199_skipped2(b) (2) +#define pr16199_ice 0x3 + +#define M16199Ea(TYPE) (TYPE __x;) +#define M16199E(X,S,M) ({ M16199Ea(S *); }) + +#define M16199Da(TYPE,VAR) ((TYPE)(VAR)) +#define M16199D(X,S,M) ({ int *__x = (X); M16199Da(S *, __x); }) +int pr16199d() { return 7; } + +#define M16199C(X,S,M) ({ int __x; }) +int pr16199c() +{ + return 8; +} diff --git a/gcc/testsuite/gdc.test/compilable/testdefines.d b/gcc/testsuite/gdc.test/compilable/testdefines.d index 9dd8cf2af8d..060e962920a 100644 --- a/gcc/testsuite/gdc.test/compilable/testdefines.d +++ b/gcc/testsuite/gdc.test/compilable/testdefines.d @@ -15,3 +15,13 @@ static assert(SSS == "hello"); static assert(ABC == 12); static assert(DEF == 17); + +static assert(ADD(3, 4) == 7); +static assert(SUB() == 1); + +static assert(pr16199_skipped1(5) == 1); +static assert(pr16199_skipped2(6) == 2); +static assert(pr16199_ice == 3); + +static assert(pr16199d() == 7); +static assert(pr16199c() == 8); diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d index 74d45643c8d..22910390497 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d +++ b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d @@ -3,9 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/warn13679.d(15): Warning: cannot use `foreach_reverse` with an associative array -Error: warnings are treated as errors - Use -wi if you wish to treat warnings only as informational. +fail_compilation/warn13679.d(13): Error: cannot use `foreach_reverse` with an associative array --- */ diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 021149aabc7..f11c5fbfb0b 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -9471b25db9ed44d71e0e27956430c0c6a09c16db +ceff48bf7db05503117f54fdc0cefcb89b711136 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 d2fb6e218c1..f17d8beb96b 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -266,17 +266,17 @@ 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/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 \ - core/sys/freebsd/sys/elf.d core/sys/freebsd/sys/elf32.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/socket.d core/sys/freebsd/sys/sysctl.d \ - core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \ - core/sys/freebsd/unistd.d + core/sys/freebsd/net/if_.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 core/sys/freebsd/sys/elf.d \ + core/sys/freebsd/sys/elf32.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/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 \ core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 3e3ab567a82..b6d90362f0b 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -329,10 +329,10 @@ 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 \ + core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_.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 \ core/sys/freebsd/sys/_cpuset.lo core/sys/freebsd/sys/cdefs.lo \ core/sys/freebsd/sys/elf.lo core/sys/freebsd/sys/elf32.lo \ core/sys/freebsd/sys/elf64.lo \ @@ -943,17 +943,17 @@ 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/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 \ - core/sys/freebsd/sys/elf.d core/sys/freebsd/sys/elf32.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/socket.d core/sys/freebsd/sys/sysctl.d \ - core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \ - core/sys/freebsd/unistd.d + core/sys/freebsd/net/if_.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 core/sys/freebsd/sys/elf.d \ + core/sys/freebsd/sys/elf32.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/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 \ core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \ @@ -1613,6 +1613,7 @@ 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_.lo: 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 diff --git a/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d b/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d index aa39ac4bb49..a08b8edab11 100644 --- a/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d +++ b/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d @@ -3,7 +3,7 @@ /++ D header file for FreeBSD's ifaddrs.h. - Copyright: Copyright 2023 + Copyright: Copyright 2023 - 2024 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) +/ @@ -23,6 +23,7 @@ struct ifaddrs uint ifa_flags; sockaddr* ifa_addr; sockaddr* ifa_netmask; + alias ifa_broadaddr = ifa_dstaddr; sockaddr* ifa_dstaddr; void* ifa_data; } diff --git a/libphobos/libdruntime/core/sys/freebsd/net/if_.d b/libphobos/libdruntime/core/sys/freebsd/net/if_.d new file mode 100644 index 00000000000..e050f1bd418 --- /dev/null +++ b/libphobos/libdruntime/core/sys/freebsd/net/if_.d @@ -0,0 +1,493 @@ +//Written in the D programming language + +/++ + D header file for FreeBSD's net/if.h. + + Copyright: Copyright 2024 + License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) + +/ +module core.sys.freebsd.net.if_; + +public import core.sys.posix.net.if_; + +version (FreeBSD): +extern(C): +@nogc: +nothrow: + +import core.stdc.config; +import core.sys.freebsd.sys.types : caddr_t; +import core.sys.posix.sys.socket : sockaddr; +import core.sys.posix.sys.time : time_t, timeval; + +enum IF_MAXUNIT = 0x7fff; + +struct if_clonereq +{ + int ifcr_total; + int ifcr_count; + ubyte* ifcr_buffer; +} + +struct if_data +{ + ubyte ifi_type; + ubyte ifi_physical; + ubyte ifi_addrlen; + ubyte ifi_hdrlen; + ubyte ifi_link_state; + ubyte ifi_vhid; + ushort ifi_datalen; + uint ifi_mtu; + uint ifi_metric; + ulong ifi_baudrate; + + ulong ifi_ipackets; + ulong ifi_ierrors; + ulong ifi_opackets; + ulong ifi_oerrors; + ulong ifi_collisions; + ulong ifi_ibytes; + ulong ifi_obytes; + ulong ifi_imcasts; + ulong ifi_omcasts; + ulong ifi_iqdrops; + ulong ifi_oqdrops; + ulong ifi_noproto; + ulong ifi_hwassist; + + union + { + time_t ifi_epoch; + private ulong ph; + } + + union + { + timeval ifi_lastchange; + struct + { + private ulong ph1; + private ulong ph2; + } + } +} + +enum IFF_UP = 0x1; +enum IFF_BROADCAST = 0x2; +enum IFF_DEBUG = 0x4; +enum IFF_LOOPBACK = 0x8; +enum IFF_POINTOPOINT = 0x10; +enum IFF_NEEDSEPOCH = 0x20; +enum IFF_DRV_RUNNING = 0x40; +enum IFF_NOARP = 0x80; +enum IFF_PROMISC = 0x100; +enum IFF_ALLMULTI = 0x200; +enum IFF_DRV_OACTIVE = 0x400; +enum IFF_SIMPLEX = 0x800; +enum IFF_LINK0 = 0x1000; +enum IFF_LINK1 = 0x2000; +enum IFF_LINK2 = 0x4000; +enum IFF_ALTPHYS = IFF_LINK2; +enum IFF_MULTICAST = 0x8000; +enum IFF_CANTCONFIG = 0x10000; +enum IFF_PPROMISC = 0x20000; +enum IFF_MONITOR = 0x40000; +enum IFF_STATICARP = 0x80000; +enum IFF_STICKYARP = 0x100000; +enum IFF_DYING = 0x200000; +enum IFF_RENAMING = 0x400000; +enum IFF_SPARE = 0x800000; +enum IFF_NETLINK_1 = 0x1000000; + +enum IFF_RUNNING = IFF_DRV_RUNNING; +enum IFF_OACTIVE = IFF_DRV_OACTIVE; + +enum IFF_CANTCHANGE = IFF_BROADCAST | + IFF_POINTOPOINT | + IFF_DRV_RUNNING | + IFF_DRV_OACTIVE | + IFF_SIMPLEX | + IFF_MULTICAST | + IFF_ALLMULTI | + IFF_PROMISC | + IFF_DYING | + IFF_CANTCONFIG | + IFF_NEEDSEPOCH; + +enum LINK_STATE_UNKNOWN = 0; +enum LINK_STATE_DOWN = 1; +enum LINK_STATE_UP = 2; + +auto IF_Kbps(T)(T x) { return uintmax_t(x) * 1000; } +auto IF_Mbps(T)(T x) { return IF_Kbps(x * 1000); } +auto IF_Gbps(T)(T x) { return IF_Mbps(x * 1000); } + +enum IFCAP_B_RXCSUM = 0; +enum IFCAP_B_TXCSUM = 1; +enum IFCAP_B_NETCONS = 2; +enum IFCAP_B_VLAN_MTU = 3; +enum IFCAP_B_VLAN_HWTAGGING = 4; +enum IFCAP_B_JUMBO_MTU = 5; +enum IFCAP_B_POLLING = 6; +enum IFCAP_B_VLAN_HWCSUM = 7; +enum IFCAP_B_TSO4 = 8; +enum IFCAP_B_TSO6 = 9; +enum IFCAP_B_LRO = 10; +enum IFCAP_B_WOL_UCAST = 11; +enum IFCAP_B_WOL_MCAST = 12; +enum IFCAP_B_WOL_MAGIC = 13; +enum IFCAP_B_TOE4 = 14; +enum IFCAP_B_TOE6 = 15; +enum IFCAP_B_VLAN_HWFILTER = 16; +enum IFCAP_B_NV = 17; +enum IFCAP_B_VLAN_HWTSO = 18; +enum IFCAP_B_LINKSTATE = 19; +enum IFCAP_B_NETMAP = 20; +enum IFCAP_B_RXCSUM_IPV6 = 21; +enum IFCAP_B_TXCSUM_IPV6 = 22; +enum IFCAP_B_HWSTATS = 23; +enum IFCAP_B_TXRTLMT = 24; +enum IFCAP_B_HWRXTSTMP = 25; +enum IFCAP_B_MEXTPG = 26; +enum IFCAP_B_TXTLS4 = 27; +enum IFCAP_B_TXTLS6 = 28; +enum IFCAP_B_VXLAN_HWCSUM = 29; +enum IFCAP_B_VXLAN_HWTSO = 30; +enum IFCAP_B_TXTLS_RTLMT = 31; +enum IFCAP_B_RXTLS4 = 32; +enum IFCAP_B_RXTLS6 = 33; +enum __IFCAP_B_SIZE = 34; + +// IFCAP_B_MAX is defined in net/if.h, but __IFCAP_B_MAX doesn't seem to be defined anywhere. +// enum IFCAP_B_MAX = __IFCAP_B_MAX - 1; +enum IFCAP_B_SIZE = __IFCAP_B_SIZE; + +auto IFCAP_BIT(T)(T x) { return 1 << x; } + +enum IFCAP_RXCSUM = IFCAP_BIT(IFCAP_B_RXCSUM); +enum IFCAP_TXCSUM = IFCAP_BIT(IFCAP_B_TXCSUM); +enum IFCAP_NETCONS = IFCAP_BIT(IFCAP_B_NETCONS); +enum IFCAP_VLAN_MTU = IFCAP_BIT(IFCAP_B_VLAN_MTU); +enum IFCAP_VLAN_HWTAGGING = IFCAP_BIT(IFCAP_B_VLAN_HWTAGGING); +enum IFCAP_JUMBO_MTU = IFCAP_BIT(IFCAP_B_JUMBO_MTU); +enum IFCAP_POLLING = IFCAP_BIT(IFCAP_B_POLLING); +enum IFCAP_VLAN_HWCSUM = IFCAP_BIT(IFCAP_B_VLAN_HWCSUM); +enum IFCAP_TSO4 = IFCAP_BIT(IFCAP_B_TSO4); +enum IFCAP_TSO6 = IFCAP_BIT(IFCAP_B_TSO6); +enum IFCAP_LRO = IFCAP_BIT(IFCAP_B_LRO); +enum IFCAP_WOL_UCAST = IFCAP_BIT(IFCAP_B_WOL_UCAST); +enum IFCAP_WOL_MCAST = IFCAP_BIT(IFCAP_B_WOL_MCAST); +enum IFCAP_WOL_MAGIC = IFCAP_BIT(IFCAP_B_WOL_MAGIC); +enum IFCAP_TOE4 = IFCAP_BIT(IFCAP_B_TOE4); +enum IFCAP_TOE6 = IFCAP_BIT(IFCAP_B_TOE6); +enum IFCAP_VLAN_HWFILTER = IFCAP_BIT(IFCAP_B_VLAN_HWFILTER); +enum IFCAP_NV = IFCAP_BIT(IFCAP_B_NV); +enum IFCAP_VLAN_HWTSO = IFCAP_BIT(IFCAP_B_VLAN_HWTSO); +enum IFCAP_LINKSTATE = IFCAP_BIT(IFCAP_B_LINKSTATE); +enum IFCAP_NETMAP = IFCAP_BIT(IFCAP_B_NETMAP); +enum IFCAP_RXCSUM_IPV6 = IFCAP_BIT(IFCAP_B_RXCSUM_IPV6); +enum IFCAP_TXCSUM_IPV6 = IFCAP_BIT(IFCAP_B_TXCSUM_IPV6); +enum IFCAP_HWSTATS = IFCAP_BIT(IFCAP_B_HWSTATS); +enum IFCAP_TXRTLMT = IFCAP_BIT(IFCAP_B_TXRTLMT); +enum IFCAP_HWRXTSTMP = IFCAP_BIT(IFCAP_B_HWRXTSTMP); +enum IFCAP_MEXTPG = IFCAP_BIT(IFCAP_B_MEXTPG); +enum IFCAP_TXTLS4 = IFCAP_BIT(IFCAP_B_TXTLS4); +enum IFCAP_TXTLS6 = IFCAP_BIT(IFCAP_B_TXTLS6); +enum IFCAP_VXLAN_HWCSUM = IFCAP_BIT(IFCAP_B_VXLAN_HWCSUM); +enum IFCAP_VXLAN_HWTSO = IFCAP_BIT(IFCAP_B_VXLAN_HWTSO); +enum IFCAP_TXTLS_RTLMT = IFCAP_BIT(IFCAP_B_TXTLS_RTLMT); + +enum IFCAP2_RXTLS4 = IFCAP_B_RXTLS4 - 32; +enum IFCAP2_RXTLS6 = IFCAP_B_RXTLS6 - 32; + +auto IFCAP2_BIT(T)(T x) { return 1UL << x; } + +enum IFCAP_HWCSUM_IPV6 = IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6; + +enum IFCAP_HWCSUM = IFCAP_RXCSUM | IFCAP_TXCSUM; +enum IFCAP_TSO = IFCAP_TSO4 | IFCAP_TSO6; +enum IFCAP_WOL = IFCAP_WOL_UCAST | IFCAP_WOL_MCAST | IFCAP_WOL_MAGIC; +enum IFCAP_TOE = IFCAP_TOE4 | IFCAP_TOE6; +enum IFCAP_TXTLS = IFCAP_TXTLS4 | IFCAP_TXTLS6; + +enum IFCAP_CANTCHANGE = IFCAP_NETMAP | IFCAP_NV; +enum IFCAP_ALLCAPS = 0xffffffff; + +enum IFQ_MAXLEN = 50; +enum IFNET_SLOWHZ = 1; + +struct if_msghdr +{ + ushort ifm_msglen; + ubyte ifm_version; + ubyte ifm_type; + int ifm_addrs; + int ifm_flags; + ushort ifm_index; + ushort _ifm_spare1; + if_data ifm_data; +} + +auto IF_MSGHDRL_IFM_DATA(T)(T _l) { return cast(if_data*) (cast(ubyte*) _l + _l.ifm_data_off); } + +auto IF_MSGHDRL_RTA(T)(T_l) { return cast(void*) (cast(uintptr_t) _l + _l.ifm_len); } + +struct if_msghdrl +{ + ushort ifm_msglen; + ubyte ifm_version; + ubyte ifm_type; + int ifm_addrs; + int ifm_flags; + ushort ifm_index; + ushort _ifm_spare1; + ushort ifm_len; + ushort ifm_data_off; + int _ifm_spare2; + if_data ifm_data; +} + +struct ifa_msghdr +{ + ushort ifam_msglen; + ubyte ifam_version; + ubyte ifam_type; + int ifam_addrs; + int ifam_flags; + ushort ifam_index; + ushort _ifam_spare1; + int ifam_metric; +} + +auto IFA_MSGHDRL_IFAM_DATA(T)(T _l) { return cast(if_data*) (cast(ubyte*) _l + _l.ifam_data_off); } + +auto IFA_MSGHDRL_RTA(T)(T _l) { return cast(void*) (cast(uintptr_t) _l + _l.ifam_len); } + +struct ifa_msghdrl +{ + ushort ifam_msglen; + ubyte ifam_version; + ubyte ifam_type; + int ifam_addrs; + int ifam_flags; + ushort ifam_index; + ushort _ifam_spare1; + ushort ifam_len; + ushort ifam_data_off; + int ifam_metric; + if_data ifam_data; +} + +struct ifma_msghdr +{ + ushort ifmam_msglen; + ubyte ifmam_version; + ubyte ifmam_type; + int ifmam_addrs; + int ifmam_flags; + ushort ifmam_index; + ushort _ifmam_spare1; +} + +struct if_announcemsghdr +{ + ushort ifan_msglen; + ubyte ifan_version; + ubyte ifan_type; + ushort ifan_index; + char[IF_NAMESIZE] ifan_name; + ushort ifan_what; +} + +enum IFAN_ARRIVAL = 0; +enum IFAN_DEPARTURE = 1; + +struct ifreq_buffer +{ + size_t length; + void* buffer; +} + +struct ifreq_nv_req +{ + uint buf_length; + uint length; + void* buffer; +} + +enum IFR_CAP_NV_MAXBUFSIZE = 2 * 1024 * 1024; + +struct ifreq +{ + char[IF_NAMESIZE] ifr_name; + + union + { + sockaddr ifr_addr; + sockaddr ifr_dstaddr; + sockaddr ifr_broadaddr; + ifreq_buffer ifr_buffer; + private short[2] ifru_flags; + short ifr_index; + int ifr_jid; + int ifr_metric; + int ifr_mtu; + int ifr_phys; + int ifr_media; + caddr_t ifr_data; + private int[2] ifru_cap; + uint ifr_fib; + ubyte ifr_vlan_pcp; + ifreq_nv_req ifr_cap_nv; + } + + @property ref ifr_flags() { return ifru_flags[0]; } + @property ref ifr_flagshigh() { return ifru_flags[1]; } + @property ref ifr_reqcap() { return ifru_cap[0]; } + @property ref ifr_curcap() { return ifru_cap[1]; } + alias ifr_lan_pcp = ifr_vlan_pcp; +} + +auto _SIZEOF_ADDR_IFREQ(T)(T ifr) { return ifr.ifr_addr.sa_len > sockaddr.sizeof ? + ifreq.sizeof - sockaddr.sizeof + ifr.ifr_addr.sa_len : + ifreq.sizeof; } + +struct ifaliasreq +{ + char[IF_NAMESIZE] ifra_name; + sockaddr ifra_addr; + sockaddr ifra_broadaddr; + sockaddr ifra_mask; + int ifra_vhid; +} + +struct oifaliasreq +{ + char[IF_NAMESIZE] ifra_name; + sockaddr ifra_addr; + sockaddr ifra_broadaddr; + sockaddr ifra_mask; + } + +struct ifmediareq +{ + char[IF_NAMESIZE] ifm_name; + int ifm_current; + int ifm_mask; + int ifm_status; + int ifm_active; + int ifm_count; + int* ifm_ulist; +} + +struct ifdrv +{ + char[IF_NAMESIZE] ifd_name; + c_ulong ifd_cmd; + size_t ifd_len; + void* ifd_data; +} + +enum IFSTATMAX = 800; +struct ifstat +{ + char[IF_NAMESIZE] ifs_name; + char[IFSTATMAX + 1] ascii; +} + +struct ifconf +{ + int ifc_len; + union + { + caddr_t ifc_buf; + ifreq* ifc_req; + } +} + +enum IFG_ALL = "all"; +enum IFG_EGRESS = "egress"; + +struct ifg_req +{ + union + { + char[IF_NAMESIZE] ifgrq_group; + char[IF_NAMESIZE] ifgrq_member; + } +} + +struct ifgroupreq +{ + char[IF_NAMESIZE] ifgr_name; + uint ifgr_len; + union + { + char[IF_NAMESIZE] ifgr_group; + ifg_req* ifgr_groups; + } +} + +struct ifi2creq +{ + ubyte dev_addr; + ubyte offset; + ubyte len; + ubyte spare0; + uint spare1; + ubyte[8] data; +} + +enum RSS_FUNC_NONE = 0; +enum RSS_FUNC_PRIVATE = 1; +enum RSS_FUNC_TOEPLITZ = 2; + +enum RSS_TYPE_IPV4 = 0x00000001; +enum RSS_TYPE_TCP_IPV4 = 0x00000002; +enum RSS_TYPE_IPV6 = 0x00000004; +enum RSS_TYPE_IPV6_EX = 0x00000008; +enum RSS_TYPE_TCP_IPV6 = 0x00000010; +enum RSS_TYPE_TCP_IPV6_EX = 0x00000020; +enum RSS_TYPE_UDP_IPV4 = 0x00000040; +enum RSS_TYPE_UDP_IPV6 = 0x00000080; +enum RSS_TYPE_UDP_IPV6_EX = 0x00000100; + +enum RSS_KEYLEN = 128; + +struct ifrsskey +{ + char[IF_NAMESIZE] ifrk_name; + ubyte ifrk_func; + ubyte ifrk_spare0; + ushort ifrk_keylen; + ubyte[RSS_KEYLEN] ifrk_key; +} + +struct ifrsshash +{ + char[IF_NAMESIZE] ifrh_name; + ubyte ifrh_func; + ubyte ifrh_spare0; + ushort ifrh_spare1; + uint ifrh_types; +} + +enum IFNET_PCP_NONE = 0xff; + +enum IFDR_MSG_SIZE = 64; +enum IFDR_REASON_MSG = 1; +enum IFDR_REASON_VENDOR = 2; + +struct ifdownreason +{ + char[IF_NAMESIZE] ifdr_name; + uint ifdr_reason; + uint ifdr_vendor; + char[IFDR_MSG_SIZE] ifdr_msg; +} + +// FIXME It's not clear where ifnet is supposed to be coming from, so this is +// commented out for now. +//alias if_t = ifnet*; diff --git a/libphobos/libdruntime/core/sys/linux/sys/socket.d b/libphobos/libdruntime/core/sys/linux/sys/socket.d index 339a6022dc8..dc274e4d702 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/socket.d +++ b/libphobos/libdruntime/core/sys/linux/sys/socket.d @@ -71,7 +71,6 @@ enum AF_BRIDGE = PF_BRIDGE, AF_ATMPVC = PF_ATMPVC, AF_X25 = PF_X25, - AF_INET6 = PF_INET6, AF_ROSE = PF_ROSE, AF_DECnet = PF_DECnet, AF_NETBEUI = PF_NETBEUI, diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d index dd2462fbca1..48b6f9ef006 100644 --- a/libphobos/libdruntime/core/thread/fiber.d +++ b/libphobos/libdruntime/core/thread/fiber.d @@ -1393,7 +1393,7 @@ private: // At present, it is not safe to migrate fibers between threads, but if that // changes, then updating the value of R13 will also need to be handled. version (PPC64) - *cast(size_t*)(pstack + wsize) = cast(size_t) Thread.getThis().m_addr; + *cast(size_t*)(pstack + wsize) = cast(size_t) ThreadBase.getThis().m_addr; assert( (cast(size_t) pstack & 0x0f) == 0 ); } else version (AsmMIPS_O32_Posix) diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 4125fd717f4..50d71f59154 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -5478868465ae1ad743ff76ac5bb92691463ffec5 +dcbfbd43ac321e81af60afd795bd0f3c3f47cfa0 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/typecons.d b/libphobos/src/std/typecons.d index 13ae2941296..5fac1c9cca4 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -3276,7 +3276,9 @@ struct Nullable(T) { if (!_isNull) { - destroy(_value.payload); + import std.traits : Unqual; + auto ptr = () @trusted { return cast(Unqual!T*) &_value.payload; }(); + destroy!false(*ptr); } } } @@ -4319,6 +4321,37 @@ auto nullable(T)(T t) assert(b.empty); } +// https://issues.dlang.org/show_bug.cgi?id=24403 +@safe unittest +{ + static bool destroyed; + static struct S { ~this() { destroyed = true; } } + + { + Nullable!S s = S.init; + destroyed = false; + } + assert(destroyed); + + { + Nullable!(const S) s = S.init; + destroyed = false; + } + assert(destroyed); + + { + Nullable!(immutable S) s = S.init; + destroyed = false; + } + assert(destroyed); + + { + Nullable!(shared S) s = S.init; + destroyed = false; + } + assert(destroyed); +} + /** Just like `Nullable!T`, except that the null state is defined as a particular value. For example, $(D Nullable!(uint, uint.max)) is an