From patchwork Fri Feb 2 23:45:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1894816 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=GmM3mZGY; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TRXVr5yZbz1yQ0 for ; Sat, 3 Feb 2024 10:47:00 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A1DDA3857C4C for ; Fri, 2 Feb 2024 23:46:58 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [IPv6:2001:67c:2050:0:465::201]) by sourceware.org (Postfix) with ESMTPS id 622403857C75 for ; Fri, 2 Feb 2024 23:45:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 622403857C75 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 622403857C75 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:67c:2050:0:465::201 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706917557; cv=none; b=j6Xf1yMVjXliIC+TYOd9+oPywFeb68knshUeCVsrFUCoBKKWzR0c76u4VintFl5aJ4h2OV126n7QFL6iDvzTLOwoGmzLcIrvJaiKlKCOyLY0vh7xcAzs1eHICTUvzphew+YUujqtp34umJBLB0h3V+nhuGVHxJhs8AzuyrMdGHY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706917557; c=relaxed/simple; bh=p54JGTNe8q2iCyj6T3v81me8gPEaGk6fSwlLSLeVl1k=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=TPRssaLCFbX+RlHdPvhuKucwM3VY9UfDuNquXieiSTEFSICUr8uhNoFNLzy1gGi8ozmkexUyREWrymxaUNx+tmAwl+haSA7KeKlcb9i/MS7fBagBfYLgF+pYgiw+FQ3LWnxWwlX35wJNMfZafvtAUBO59at0X3HLnlyjCYvF5Ws= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp2.mailbox.org (smtp2.mailbox.org [10.196.197.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4TRXTR0HL5z9sZS; Sat, 3 Feb 2024 00:45:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gdcproject.org; s=MBO0001; t=1706917547; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Oh5YwcY90Sk00vu4fBzlYWJfM1T2HJAGFK2LEdLeSHo=; b=GmM3mZGYJ7cfS7FM8CjaRZEff2trSEdSjLc6yYnrQ1jnpF0SvhqlHQgFZWNOkvgm7O8z2z O/42kwRXVSBqM7tMDSLFl5sHoPmDcWm3ErXqEaAL2JVV6YZbccxeTnMN07su98NxPUTxj/ zIQf/0XAAbhKP7paU/EotRcqO52TrlDJCNFyYz2Ql+INIpP9uLwUBi5DUuCbqSQkze7HCE zmkBT2paN6sWQpoUx4O5BrgcG8S+7CxAkSLHd5MIAn96SNvq/VfBa7e4QPYDmOvnGe+M7K DQjUo+sIa6l/hENGkPMEs2D/uivedZVQndSU7umbrqlUllkZzhrO0Lsv/hkdEg== From: Iain Buclaw To: gcc-patches@gcc.gnu.org Cc: Iain Buclaw Subject: [committed] d: Merge dmd, druntime bce5c1f7b5, phobos e4d0dd513. Date: Sat, 3 Feb 2024 00:45:40 +0100 Message-Id: <20240202234540.97166-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP, T_FILL_THIS_FORM_SHORT, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Hi, This patch merges the D front-end and runtime library with upstream dmd dmd bce5c1f7b5, and the standard runtime library with phobos e4d0dd513. Synchronizing with the upstream beta release of v2.107.0. D front-end changes: - Import latest changes from dmd v2.107.0-beta.1. - Keywords like `__FILE__' are now always evaluated at the callsite. D runtime changes: - Import latest changes from druntime v2.107.0-beta.1. - Added `nameSig' field to TypeInfo_Class in object.d. Phobos changes: - Import latest changes from phobos v2.107.0-beta.1. Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd bce5c1f7b5. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-lang.cc (d_parse_file): Likewise. * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise. * expr.cc (build_lambda_tree): New function. (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree. (ExprVisitor::visit (SymOffExp *)): Likewise. (ExprVisitor::visit (VarExp *)): Likewise. * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal TypeInfo representation. (TypeInfoVisitor::visit (TypeInfoClassDeclaration *): Emit stub data for TypeInfo_Class.nameSig. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime bce5c1f7b5. * src/MERGE: Merge upstream phobos e4d0dd513. --- gcc/d/d-attribs.cc | 2 +- gcc/d/d-lang.cc | 5 +- gcc/d/decl.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/astenums.d | 6 + gcc/d/dmd/constfold.d | 1 + gcc/d/dmd/declaration.d | 29 + gcc/d/dmd/dinterpret.d | 132 +-- gcc/d/dmd/dmodule.d | 18 +- gcc/d/dmd/doc.d | 1 + gcc/d/dmd/dscope.d | 1 + gcc/d/dmd/dsymbolsem.d | 6 +- gcc/d/dmd/dtemplate.d | 964 +++++++++--------- gcc/d/dmd/dtoh.d | 11 + gcc/d/dmd/escape.d | 1 + gcc/d/dmd/expression.d | 33 - gcc/d/dmd/expressionsem.d | 243 ++++- gcc/d/dmd/file_manager.d | 30 +- gcc/d/dmd/func.d | 33 +- gcc/d/dmd/globals.d | 4 +- gcc/d/dmd/globals.h | 2 +- gcc/d/dmd/mtype.d | 573 +---------- gcc/d/dmd/mtype.h | 35 +- gcc/d/dmd/mustuse.d | 1 + gcc/d/dmd/ob.d | 1 + gcc/d/dmd/parse.d | 61 +- gcc/d/dmd/safe.d | 1 + gcc/d/dmd/scope.h | 1 + gcc/d/dmd/semantic3.d | 6 +- gcc/d/dmd/sideeffect.d | 1 + gcc/d/dmd/statementsem.d | 5 +- gcc/d/dmd/template.h | 2 +- gcc/d/dmd/typesem.d | 564 +++++++++- gcc/d/expr.cc | 49 +- gcc/d/typeinfo.cc | 14 +- gcc/testsuite/gdc.test/compilable/b18242.d | 2 +- .../gdc.test/compilable/issue24316.d | 13 + .../gdc.test/fail_compilation/test24295.d | 13 + .../gdc.test/runnable/imports/issue18919b.d | 250 +++++ gcc/testsuite/gdc.test/runnable/issue18919.d | 47 + gcc/testsuite/gdc.test/runnable/test18916.d | 4 +- gcc/testsuite/gdc.test/runnable/testptrref.d | 5 +- gcc/testsuite/gdc.test/runnable/xtest46.d | 28 +- libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/exception.d | 12 +- .../core/internal/container/array.d | 6 +- .../core/internal/container/common.d | 4 +- libphobos/libdruntime/core/internal/dassert.d | 7 +- .../core/internal/gc/impl/conservative/gc.d | 34 +- libphobos/libdruntime/core/internal/gc/os.d | 19 +- .../libdruntime/core/internal/spinlock.d | 4 +- libphobos/libdruntime/core/memory.d | 11 +- libphobos/libdruntime/core/stdc/assert_.d | 9 + libphobos/libdruntime/core/stdc/errno.d | 234 ++++- libphobos/libdruntime/core/stdc/fenv.d | 43 + libphobos/libdruntime/core/stdc/locale.d | 17 + libphobos/libdruntime/core/stdc/stdio.d | 150 +++ libphobos/libdruntime/core/stdc/stdlib.d | 3 + libphobos/libdruntime/core/stdc/string.d | 7 + libphobos/libdruntime/core/stdc/wchar_.d | 14 + .../libdruntime/core/sys/windows/basetsd.d | 3 - .../libdruntime/core/sys/windows/commctrl.d | 8 +- .../libdruntime/core/sys/windows/ddeml.d | 8 +- libphobos/libdruntime/core/sys/windows/dll.d | 57 +- .../libdruntime/core/sys/windows/httpext.d | 4 +- .../libdruntime/core/sys/windows/imagehlp.d | 2 +- .../libdruntime/core/sys/windows/msacm.d | 4 +- .../libdruntime/core/sys/windows/ntsecapi.d | 2 +- libphobos/libdruntime/core/sys/windows/ole.d | 2 +- .../libdruntime/core/sys/windows/prsht.d | 2 +- .../libdruntime/core/sys/windows/rpcdce.d | 4 +- .../libdruntime/core/sys/windows/rpcdcep.d | 2 +- .../libdruntime/core/sys/windows/rpcnsi.d | 2 +- .../libdruntime/core/sys/windows/setupapi.d | 2 +- .../libdruntime/core/sys/windows/shellapi.d | 2 +- .../libdruntime/core/sys/windows/shlwapi.d | 2 +- .../libdruntime/core/sys/windows/subauth.d | 2 +- libphobos/libdruntime/core/sys/windows/vfw.d | 2 +- .../libdruntime/core/sys/windows/windef.d | 68 +- .../libdruntime/core/sys/windows/wininet.d | 3 +- .../libdruntime/core/sys/windows/winsvc.d | 4 +- .../libdruntime/core/sys/windows/winuser.d | 4 +- .../libdruntime/core/sys/windows/wtypes.d | 4 +- libphobos/libdruntime/object.d | 9 +- libphobos/libdruntime/rt/cast_.d | 89 +- libphobos/libdruntime/rt/dmain2.d | 12 + libphobos/src/MERGE | 2 +- libphobos/src/std/bitmanip.d | 4 +- libphobos/src/std/complex.d | 2 +- libphobos/src/std/conv.d | 8 +- libphobos/src/std/exception.d | 6 +- libphobos/src/std/format/internal/floats.d | 14 +- libphobos/src/std/format/internal/write.d | 7 +- libphobos/src/std/math/algebraic.d | 2 +- libphobos/src/std/math/exponential.d | 44 +- libphobos/src/std/math/hardware.d | 8 - libphobos/src/std/math/operations.d | 21 +- libphobos/src/std/math/package.d | 166 --- libphobos/src/std/math/rounding.d | 4 +- libphobos/src/std/math/traits.d | 179 +++- libphobos/src/std/math/trigonometry.d | 5 +- libphobos/src/std/mmfile.d | 68 +- .../src/std/regex/internal/backtracking.d | 2 +- libphobos/src/std/regex/internal/ir.d | 4 +- libphobos/src/std/typecons.d | 56 +- 105 files changed, 2916 insertions(+), 1767 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/issue24316.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24295.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/issue18919b.d create mode 100644 gcc/testsuite/gdc.test/runnable/issue18919.d diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 8b66cf264a7..36a139b4ec4 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -327,7 +327,7 @@ build_attributes (Expressions *eattrs) for (size_t i = 0; i < eattrs->length; i++) { Expression *attr = (*eattrs)[i]; - Dsymbol *sym = attr->type->toDsymbol (0); + Dsymbol *sym = toDsymbol (attr->type, NULL); if (!sym) { diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 71f8473e0ec..aabe1ad43cb 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1344,7 +1344,10 @@ d_parse_file (void) } if (global.params.v.templates) - printTemplateStats (); + { + printTemplateStats (global.params.v.templatesListInstances, + global.errorSink); + } /* Generate JSON files. */ if (global.params.json.doOutput) diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 23749315fff..4ca85bb970d 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -782,7 +782,7 @@ public: { /* Do not store variables we cannot take the address of, but keep the values for purposes of debugging. */ - if (d->type->isscalar () && !d->type->hasPointers ()) + if (d->type->isscalar () && !hasPointers (d->type)) { tree decl = get_symbol_decl (d); d_pushdecl (decl); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 2b4400f398e..138b0b6fa7c 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce +bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa 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/astenums.d b/gcc/d/dmd/astenums.d index f19edb9e4b4..77940b80248 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -459,3 +459,9 @@ extern (C++) struct structalign_t bool isPack() const { return pack; } void setPack(bool pack) { this.pack = pack; } } + +/// Use to return D arrays from C++ functions +extern (C++) struct DArray(T) +{ + T[] data; +} diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 7bd9691a429..cee1f6364bc 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1038,6 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) else if (tb.ty == Tstruct && e1.op == EXP.int64) { // Struct = 0; + import dmd.typesem : toDsymbol; StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); assert(sd); auto elements = new Expressions(); diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 5869a220842..93ef63f7aa3 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1749,6 +1749,35 @@ extern (C++) final class SymbolDeclaration : Declaration /*********************************************************** */ +private Identifier getTypeInfoIdent(Type t) +{ + import dmd.dmangle; + import core.stdc.stdlib; + import dmd.root.rmem; + // _init_10TypeInfo_%s + OutBuffer buf; + buf.reserve(32); + mangleToBuffer(t, buf); + + const slice = buf[]; + + // Allocate buffer on stack, fail over to using malloc() + char[128] namebuf; + const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; + auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); + + const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", + cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); + //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); + assert(0 < length && length < namelen); // don't overflow the buffer + + auto id = Identifier.idPool(name[0 .. length]); + + if (name != namebuf.ptr) + free(name); + return id; +} + extern (C++) class TypeInfoDeclaration : VarDeclaration { Type tinfo; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index eda91d1ea05..a3b38d9fee3 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -1416,6 +1416,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) foreach (ca; *s.catches) { Type catype = ca.type; + import dmd.typesem : isBaseOf; if (!catype.equals(extype) && !catype.isBaseOf(extype, null)) continue; @@ -6237,6 +6238,11 @@ public: { if (soe.offset == 0 && soe.var.isFuncDeclaration()) return; + if (soe.offset == 0 && soe.var.isVarDeclaration() && soe.var.isImmutable()) + { + result = getVarExp(e.loc, istate, soe.var, CTFEGoal.RValue); + return; + } error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars()); result = CTFEExp.cantexp; return; @@ -6359,6 +6365,7 @@ public: { if (auto t = isType(ex.isTypeidExp().obj)) { + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null); if (auto ident = (sym ? sym.ident : null)) { @@ -6643,6 +6650,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) private bool stopPointersEscaping(const ref Loc loc, Expression e) { + import dmd.typesem : hasPointers; if (!e.type.hasPointers()) return true; if (isPointer(e.type)) @@ -6706,7 +6714,7 @@ Statement findGotoTarget(InterState* istate, Identifier ident) Statement target = null; if (ident) { - LabelDsymbol label = istate.fd.searchLabel(ident); + LabelDsymbol label = istate.fd.searchLabel(ident, Loc.initial); assert(label && label.statement); LabelStatement ls = label.statement; target = ls.gotoTarget ? ls.gotoTarget : ls.statement; @@ -7263,6 +7271,33 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi return eresult; } +/// Returns: equivalent `StringExp` from `ArrayLiteralExp ale` containing only `IntegerExp` elements +StringExp arrayLiteralToString(ArrayLiteralExp ale) +{ + const len = ale.elements ? ale.elements.length : 0; + const size = ale.type.nextOf().size(); + + StringExp impl(T)() + { + T[] result = new T[len]; + foreach (i; 0 .. len) + result[i] = cast(T) (*ale.elements)[i].isIntegerExp().getInteger(); + return new StringExp(ale.loc, result[], len, cast(ubyte) size); + } + + switch (size) + { + case 1: + return impl!char(); + case 2: + return impl!wchar(); + case 4: + return impl!dchar(); + default: + assert(0); + } +} + /* Decoding UTF strings for foreach loops. Duplicates the functionality of * the twelve _aApplyXXn functions in aApply.d in the runtime. */ @@ -7299,8 +7334,10 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str = resolveSlice(str, &strTmp); auto se = str.isStringExp(); - auto ale = str.isArrayLiteralExp(); - if (!se && !ale) + if (auto ale = str.isArrayLiteralExp()) + se = arrayLiteralToString(ale); + + if (!se) { error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars()); return CTFEExp.cantexp; @@ -7309,7 +7346,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression Expression eresult = null; // ded-store to prevent spurious warning - // Buffers for encoding; also used for decoding array literals + // Buffers for encoding char[4] utf8buf = void; wchar[2] utf16buf = void; @@ -7323,90 +7360,11 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression dchar rawvalue; // Holds the decoded dchar size_t currentIndex = indx; // The index of the decoded character - if (ale) - { - // If it is an array literal, copy the code points into the buffer - size_t buflen = 1; // #code points in the buffer - size_t n = 1; // #code points in this char - size_t sz = cast(size_t)ale.type.nextOf().size(); + // String literals + size_t saveindx; // used for reverse iteration - switch (sz) - { - case 1: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - while (indx > 0 && buflen < 4) - { - Expression r = (*ale.elements)[indx]; - char x = cast(char)r.isIntegerExp().getInteger(); - if ((x & 0xC0) != 0x80) - break; - --indx; - ++buflen; - } - } - else - buflen = (indx + 4 > len) ? len - indx : 4; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf8buf[i] = cast(char)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue); - break; - - case 2: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - Expression r = (*ale.elements)[indx]; - ushort x = cast(ushort)r.isIntegerExp().getInteger(); - if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) - { - --indx; - ++buflen; - } - } - else - buflen = (indx + 2 > len) ? len - indx : 2; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue); - break; - - case 4: - { - if (rvs) - --indx; - Expression r = (*ale.elements)[indx]; - rawvalue = cast(dchar)r.isIntegerExp().getInteger(); - n = 1; - } - break; - - default: - assert(0); - } - if (!rvs) - indx += n; - } - else + switch (se.sz) { - // String literals - size_t saveindx; // used for reverse iteration - - switch (se.sz) - { case 1: { if (rvs) @@ -7450,8 +7408,8 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression default: assert(0); - } } + if (errmsg) { error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr); diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 022231c1254..59d40655253 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -679,23 +679,23 @@ extern (C++) final class Module : Package /* Preprocess the file if it's a .c file */ FileName filename = srcfile; - bool ifile = false; // did we generate a .i file - scope (exit) - { - if (ifile) - File.remove(filename.toChars()); // remove generated file - } + const(ubyte)[] srctext; if (global.preprocess && FileName.equalsExt(srcfile.toString(), c_ext) && FileName.exists(srcfile.toString())) { - filename = global.preprocess(srcfile, loc, ifile, &defines); // run C preprocessor + /* Apply C preprocessor to the .c file, returning the contents + * after preprocessing + */ + srctext = global.preprocess(srcfile, loc, defines).data; } + else + srctext = global.fileManager.getFileContents(filename); + this.src = srctext; - if (auto result = global.fileManager.lookup(filename)) + if (srctext) { - this.src = result; if (global.params.makeDeps.doOutput) global.params.makeDeps.files.push(srcfile.toChars()); return true; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 810642f9f52..ec3cc91409b 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -1355,6 +1355,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum) { + import dmd.typesem : toDsymbol; if (Dsymbol s = type.toDsymbol(null)) // elaborate type prettyPrintDsymbol(s, ad.parent); else diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 7e9499fd28f..e02ba9a873b 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -97,6 +97,7 @@ extern (C++) struct Scope Dsymbol inunion; /// != null if processing members of a union bool nofree; /// true if shouldn't free it bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) + bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; /// in typeof(exp) VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init ErrorSink eSink; /// sink for error messages diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 23f0bc5b428..e9cdb945b57 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -6553,7 +6553,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TemplateStats.incInstance(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incInstance(tempdecl, tempinst, global.params.v.templatesListInstances); tempdecl.checkDeprecated(tempinst.loc, sc); @@ -6746,7 +6747,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent; //printf("parent = '%s'\n", parent.kind()); - TemplateStats.incUnique(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incUnique(tempdecl, tempinst); TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst); diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 1d84ccd0295..13cc32f73e0 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -56,6 +56,7 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -150,7 +151,7 @@ extern (C++) bool isError(const RootObject o) if (const e = isExpression(o)) return (e.op == EXP.error || !e.type || e.type.ty == Terror); if (const v = isTuple(o)) - return arrayObjectIsError(&v.objects); + return arrayObjectIsError(v.objects); const s = isDsymbol(o); assert(s); if (s.errors) @@ -161,9 +162,9 @@ extern (C++) bool isError(const RootObject o) /************************************** * Are any of the Objects an error? */ -bool arrayObjectIsError(const Objects* args) +bool arrayObjectIsError(const ref Objects args) { - foreach (const o; *args) + foreach (const o; args) { if (isError(o)) return true; @@ -187,6 +188,13 @@ inout(Type) getType(inout RootObject o) } +/*********************************** + * If oarg represents a Dsymbol, return that Dsymbol + * Params: + * oarg = argument to check + * Returns: + * Dsymbol if a symbol, null if not + */ Dsymbol getDsymbol(RootObject oarg) { //printf("getDsymbol()\n"); @@ -256,8 +264,11 @@ private Expression getExpression(RootObject o) } /****************************** - * If o1 matches o2, return true. - * Else, return false. + * See if two objects match + * Params: + * o1 = first object + * o2 = second object + * Returns: true if they match */ private bool match(RootObject o1, RootObject o2) { @@ -343,7 +354,7 @@ private bool match(RootObject o1, RootObject o2) printf("\tu1 = %s\n", u1.toChars()); printf("\tu2 = %s\n", u2.toChars()); } - if (!arrayObjectMatch(&u1.objects, &u2.objects)) + if (!arrayObjectMatch(u1.objects, u2.objects)) goto Lnomatch; goto Lmatch; @@ -362,15 +373,15 @@ Lnomatch: /************************************ * Match an array of them. */ -private bool arrayObjectMatch(Objects* oa1, Objects* oa2) +private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) { - if (oa1 == oa2) + if (&oa1 == &oa2) return true; if (oa1.length != oa2.length) return false; immutable oa1dim = oa1.length; - auto oa1d = (*oa1)[].ptr; - auto oa2d = (*oa2)[].ptr; + auto oa1d = oa1[].ptr; + auto oa2d = oa2[].ptr; foreach (j; 0 .. oa1dim) { RootObject o1 = oa1d[j]; @@ -386,12 +397,12 @@ private bool arrayObjectMatch(Objects* oa1, Objects* oa2) /************************************ * Return hash of Objects. */ -private size_t arrayObjectHash(Objects* oa1) +private size_t arrayObjectHash(ref Objects oa1) { import dmd.root.hash : mixHash; size_t hash = 0; - foreach (o1; *oa1) + foreach (o1; oa1) { /* Must follow the logic of match() */ @@ -407,7 +418,7 @@ private size_t arrayObjectHash(Objects* oa1) hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent)); } else if (auto u1 = isTuple(o1)) - hash = mixHash(hash, arrayObjectHash(&u1.objects)); + hash = mixHash(hash, arrayObjectHash(u1.objects)); } return hash; } @@ -672,7 +683,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /********************************** * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return true if successful; i.e. no conflict. + * Params: + * s = symbol to be inserted + * Return: true if successful; i.e. no conflict. */ override bool overloadInsert(Dsymbol s) { @@ -741,6 +754,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return toCharsMaybeConstraints(false); } + // Note: this function is not actually `const`, because iterating the + // function parameter list may run dsymbolsemantic on enum types const(char)* toCharsMaybeConstraints(bool includeConstraints) const { OutBuffer buf; @@ -758,15 +773,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (onemember) { - const FuncDeclaration fd = onemember.isFuncDeclaration(); - if (fd && fd.type) + if (const fd = onemember.isFuncDeclaration()) { - TypeFunction tf = cast(TypeFunction)fd.type; - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) + if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } } } } @@ -790,7 +807,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /**************************** * Check to see if constraint is satisfied. */ - extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) + private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) { /* Detect recursive attempts to instantiate this template declaration, * https://issues.dlang.org/show_bug.cgi?id=4072 @@ -807,7 +824,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol for (TemplatePrevious* p = previous; p; p = p.prev) { - if (!arrayObjectMatch(p.dedargs, dedargs)) + if (!arrayObjectMatch(*p.dedargs, *dedargs)) continue; //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive @@ -1055,7 +1072,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * dedtypes deduced arguments * Return match level. */ - extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag) + private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) { enum LOGM = 0; static if (LOGM) @@ -1151,7 +1168,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /* Any parameter left without a type gets the type of * its corresponding arg */ - foreach (i, ref dedtype; *dedtypes) + foreach (i, ref dedtype; dedtypes) { if (!dedtype) { @@ -1202,7 +1219,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } // TODO: dedtypes => ti.tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) + if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd)) return nomatch(); } @@ -1283,7 +1300,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Objects dedtypes = Objects(td2.parameters.length); // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1); + MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1); if (m > MATCH.nomatch) { /* A non-variadic template is more specialized than a @@ -1425,7 +1442,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { assert(i < parameters.length); Declaration sparam = null; - MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); + MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam); //printf("\tdeduceType m = %d\n", m); if (m == MATCH.nomatch) return nomatch(); @@ -1458,10 +1475,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol ParameterList fparameters = fd.getParameterList(); // function parameter list const nfparams = fparameters.length; // number of function parameters - const nfargs = argumentList.length; // number of function arguments if (argumentList.hasNames) return matcherror(); // TODO: resolve named args - Expressions* fargs = argumentList.arguments; // TODO: resolve named args + Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; /* Check for match of function arguments with variadic template * parameter, such as: @@ -1475,7 +1491,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // TemplateTupleParameter always makes most lesser matching. matchTiargs = MATCH.convert; - if (nfparams == 0 && nfargs != 0) // if no function parameters + if (nfparams == 0 && argumentList.length != 0) // if no function parameters { if (!declaredTuple) { @@ -1498,7 +1514,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? if (fparam.type.ty != Tident) continue; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (!tp.ident.equals(tid.ident) || tid.idents.length) continue; @@ -1527,7 +1543,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol hasttp = true; Type t = new TypeIdentifier(Loc.initial, ttp.ident); - MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); + MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes); if (m == MATCH.nomatch) return nomatch(); if (m < match) @@ -1576,7 +1592,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); size_t argi = 0; - size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs + size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs uint inoutMatch = 0; // for debugging only for (size_t parami = 0; parami < nfparams; parami++) { @@ -1592,8 +1608,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol */ if (fptupindex != IDX_NOTFOUND && parami == fptupindex) { - assert(prmtype.ty == Tident); - TypeIdentifier tid = cast(TypeIdentifier)prmtype; + TypeIdentifier tid = prmtype.isTypeIdentifier(); + assert(tid); if (!declaredTuple) { /* The types of the function arguments @@ -1606,7 +1622,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) */ size_t rem = 0; - for (size_t j = parami + 1; j < nfparams; j++) + foreach (j; parami + 1 .. nfparams) { Parameter p = fparameters[j]; if (p.defaultArg) @@ -1616,7 +1632,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length])) { Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); - rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1; + if (auto ptt = pt.isTypeTuple()) + rem += ptt.arguments.length; + else + rem += 1; } else { @@ -1627,9 +1646,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (nfargs2 - argi < rem) return nomatch(); declaredTuple.objects.setDim(nfargs2 - argi - rem); - for (size_t i = 0; i < declaredTuple.objects.length; i++) + foreach (i; 0 .. declaredTuple.objects.length) { - farg = (*fargs)[argi + i]; + farg = fargs[argi + i]; // Check invalid arguments to detect errors early. if (farg.op == EXP.error || farg.type.ty == Terror) @@ -1647,7 +1666,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } else { - m = deduceTypeHelper(farg.type, &tt, tid); + m = deduceTypeHelper(farg.type, tt, tid); } if (m == MATCH.nomatch) return nomatch(); @@ -1687,20 +1706,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // should copy prmtype to avoid affecting semantic result prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); - if (prmtype.ty == Ttuple) + if (TypeTuple tt = prmtype.isTypeTuple()) { - TypeTuple tt = cast(TypeTuple)prmtype; - size_t tt_dim = tt.arguments.length; + const tt_dim = tt.arguments.length; for (size_t j = 0; j < tt_dim; j++, ++argi) { Parameter p = (*tt.arguments)[j]; if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && - parami + 1 == nfparams && argi < nfargs) + parami + 1 == nfparams && argi < fargs.length) { prmtype = p.type; goto Lvarargs; } - if (argi >= nfargs) + if (argi >= fargs.length) { if (p.defaultArg) continue; @@ -1711,7 +1729,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return nomatch(); } - farg = (*fargs)[argi]; + farg = fargs[argi]; if (!farg.implicitConvTo(p.type)) return nomatch(); } @@ -1719,7 +1737,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (argi >= nfargs) // if not enough arguments + if (argi >= fargs.length) // if not enough arguments { if (!fparam.defaultArg) goto Lvarargs; @@ -1741,7 +1759,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * // at fparam `N start = 0`, N should be 'size_t' before * // the deduction result from fparam.defaultArg. */ - if (argi == nfargs) + if (argi == fargs.length) { foreach (ref dedtype; *dedtypes) { @@ -1769,7 +1787,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * the oded == oarg */ (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -1822,7 +1840,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } else { - farg = (*fargs)[argi]; + farg = fargs[argi]; } { // Check invalid arguments to detect errors early. @@ -1851,8 +1869,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { /* Allow expressions that have CT-known boundaries and type [] to match with [dim] */ - Type taai; - if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0)) + bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); + if (auto aaType = prmtype.isTypeAArray()) + { + if (auto indexType = aaType.index.isTypeIdentifier()) + { + inferIndexType = indexType.idents.length == 0; + } + } + if (inferIndexType) { if (StringExp se = farg.isStringExp()) { @@ -1871,7 +1896,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol oarg = argtype; } - else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0) + else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) { /* The farg passing to the prmtype always make a copy. Therefore, * we can shrink the set of the deduced type arguments for prmtype @@ -1892,11 +1917,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs) + if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) goto Lvarargs; uint im = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart); + MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart); //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); inoutMatch |= im; @@ -1984,17 +2009,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol case Taarray: { // Perhaps we can do better with this, see TypeFunction.callMatch() - if (tb.ty == Tsarray) + if (TypeSArray tsa = tb.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tb; dinteger_t sz = tsa.dim.toInteger(); - if (sz != nfargs - argi) + if (sz != fargs.length - argi) return nomatch(); } - else if (tb.ty == Taarray) + else if (TypeAArray taa = tb.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tb; - Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t); + Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); size_t i = templateParameterLookup(taa.index, parameters); if (i == IDX_NOTFOUND) @@ -2057,9 +2080,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { TypeArray ta = cast(TypeArray)tb; Type tret = fparam.isLazyArray(); - for (; argi < nfargs; argi++) + for (; argi < fargs.length; argi++) { - Expression arg = (*fargs)[argi]; + Expression arg = fargs[argi]; assert(arg); MATCH m; @@ -2085,7 +2108,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol else { uint wm = 0; - m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); + m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart); inoutMatch |= wm; } if (m == MATCH.nomatch) @@ -2112,8 +2135,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Lmatch: foreach (ref dedtype; *dedtypes) { - Type at = isType(dedtype); - if (at) + if (Type at = isType(dedtype)) { if (at.ty == Tnone) { @@ -2147,7 +2169,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * the oded == oarg */ (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -2194,7 +2216,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (tparam.specialization()) { (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -2233,7 +2255,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol sc2.minst = sc.minst; sc2.stc |= fd.storage_class & STC.deprecated_; - fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); + fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); sc2 = sc2.pop(); sc2 = sc2.pop(); @@ -2396,7 +2418,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } if (hasttp) { - tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod)); + tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction(); assert(!tf.deco); } } @@ -2602,10 +2624,10 @@ extern (C++) final class TypeDeduced : Type * tiargs = initial list of template arguments * tthis = if !NULL, the 'this' pointer argument * argumentList= arguments to function - * pMessage = address to store error message, or null + * errorHelper = delegate to send error message to if not null */ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, ArgumentList argumentList, const(char)** pMessage = null) + Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null) { version (none) { @@ -2662,7 +2684,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, return 1; } //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); int prop = tf.isproperty ? 1 : 2; if (property == 0) @@ -2711,8 +2733,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, else if (shared_this && !shared_dtor && tthis_fd !is null) tf.mod = tthis_fd.mod; } - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc); + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); //printf("test1: mfa = %d\n", mfa); + if (failMessage) + errorHelper(failMessage); if (mfa == MATCH.nomatch) return 0; @@ -2850,7 +2876,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.length); assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0); + MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match return 0; @@ -2869,7 +2895,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, // Check for recursive instantiation of tdx. for (TemplatePrevious* p = tdx.previous; p; p = p.prev) { - if (arrayObjectMatch(p.dedargs, &dedtypesX)) + if (arrayObjectMatch(*p.dedargs, dedtypesX)) { //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive @@ -2918,7 +2944,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); if (mfa < m.last) return 0; @@ -2979,7 +3005,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (isCtorCall) { // Constructor call requires additional check. - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); assert(tf.next); if (MODimplicitConv(tf.mod, tthis_fd.mod) || tf.isWild() && tf.isShared() == tthis_fd.isShared() || @@ -3175,9 +3201,8 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { - if (tparam.ty == Tident) + if (TypeIdentifier tident = tparam.isTypeIdentifier()) { - TypeIdentifier tident = cast(TypeIdentifier)tparam; //printf("\ttident = '%s'\n", tident.toChars()); return templateIdentifierLookup(tident.ident, parameters); } @@ -3267,7 +3292,7 @@ private Type rawTypeMerge(Type t1, Type t2) return null; } -private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) +private MATCH deduceTypeHelper(Type t, out Type at, Type tparam) { // 9*9 == 81 cases @@ -3297,7 +3322,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(U) shared(inout(const(T))) => shared(inout(const(T))) // foo(U) immutable(T) => immutable(T) { - *at = t; + at = t; return MATCH.exact; } case X(MODFlags.const_, MODFlags.const_): @@ -3317,7 +3342,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) shared(inout(const(T))) => T // foo(immutable(U)) immutable(T) => T { - *at = t.mutableOf().unSharedOf(); + at = t.mutableOf().unSharedOf(); return MATCH.exact; } case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_): @@ -3327,7 +3352,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(inout(U)) shared(inout(T)) => shared(T) // foo(inout(const(U))) shared(inout(const(T))) => shared(T) { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.exact; } case X(MODFlags.const_, 0): @@ -3345,13 +3370,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(const(U)) immutable(T) => T // foo(shared(const(U))) immutable(T) => T { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.constant; } case X(MODFlags.const_, MODFlags.shared_): // foo(const(U)) shared(T) => shared(T) { - *at = t; + at = t; return MATCH.constant; } case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_): @@ -3361,13 +3386,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(U)) shared(inout(T)) => inout(T) // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.exact; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_): // foo(shared(const(U))) shared(T) => T { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.constant; } case X(MODFlags.wildconst, MODFlags.immutable_): @@ -3379,13 +3404,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) immutable(T) => T // foo(shared(inout(const(U)))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): // foo(shared(const(U))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.wild, 0): @@ -3499,30 +3524,16 @@ __gshared Expression emptyArrayElement = null; * Output: * dedtypes = [ int ] // Array of Expression/Type's */ -MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) +MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) { extern (C++) final class DeduceType : Visitor { alias visit = Visitor.visit; public: - Scope* sc; - Type tparam; - TemplateParameters* parameters; - Objects* dedtypes; - uint* wm; - size_t inferStart; - bool ignoreAliasThis; MATCH result; - extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe + extern (D) this() @safe { - this.sc = sc; - this.tparam = tparam; - this.parameters = parameters; - this.dedtypes = dedtypes; - this.wm = wm; - this.inferStart = inferStart; - this.ignoreAliasThis = ignoreAliasThis; result = MATCH.nomatch; } @@ -3537,7 +3548,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (tparam.ty == Tident) { // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, parameters); + size_t i = templateParameterLookup(tparam, ¶meters); if (i == IDX_NOTFOUND) { if (!sc) @@ -3548,7 +3559,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3561,9 +3572,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateParameter tp = (*parameters)[i]; + TemplateParameter tp = parameters[i]; - TypeIdentifier tident = cast(TypeIdentifier)tparam; + TypeIdentifier tident = tparam.isTypeIdentifier(); if (tident.idents.length > 0) { //printf("matching %s to %s\n", tparam.toChars(), t.toChars()); @@ -3601,21 +3612,21 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Type tt = s.getType(); if (!tt) goto Lnomatch; - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; if (at && at.ty == Tnone) at = (cast(TypeDeduced)at).tded; if (!at || tt.equals(at)) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; goto Lexact; } } if (tp.isTemplateAliasParameter()) { - Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i]; + Dsymbol s2 = cast(Dsymbol)dedtypes[i]; if (!s2 || s == s2) { - (*dedtypes)[i] = s; + dedtypes[i] = s; goto Lexact; } } @@ -3637,7 +3648,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param +/ if (auto ta = tp.isTemplateAliasParameter()) { - (*dedtypes)[i] = t; + dedtypes[i] = t; goto Lexact; } // (23578) - ensure previous behaviour for non-alias template params @@ -3646,14 +3657,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; *wm |= wx; result = MATCH.constant; return; @@ -3662,11 +3673,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; if (result > MATCH.constant) result = MATCH.constant; // limit level for inout matches } @@ -3676,29 +3687,29 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs type if (tt.equals(at)) { - (*dedtypes)[i] = tt; // Prefer current type match + dedtypes[i] = tt; // Prefer current type match goto Lconst; } if (tt.implicitConvTo(at.constOf())) { - (*dedtypes)[i] = at.constOf().mutableOf(); + dedtypes[i] = at.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } if (at.implicitConvTo(tt.constOf())) { - (*dedtypes)[i] = tt.constOf().mutableOf(); + dedtypes[i] = tt.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } goto Lnomatch; } - else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(t, tt, tparam)) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = m; return; } @@ -3706,11 +3717,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; } return; } @@ -3740,7 +3751,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3757,9 +3768,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param MATCH m = t.implicitConvTo(tparam); if (m == MATCH.nomatch && !ignoreAliasThis) { - if (t.ty == Tclass) + if (auto tc = t.isTypeClass()) { - TypeClass tc = cast(TypeClass)t; if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3770,9 +3780,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } } - else if (t.ty == Tstruct) + else if (auto ts = t.isTypeStruct()) { - TypeStruct ts = cast(TypeStruct)t; if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3822,9 +3831,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(TypeVector t) { - if (tparam.ty == Tvector) + if (auto tp = tparam.isTypeVector()) { - TypeVector tp = cast(TypeVector)tparam; result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm); return; } @@ -3851,25 +3859,23 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateParameter tp = null; Expression edim = null; size_t i; - if (tparam.ty == Tsarray) + if (auto tsa = tparam.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tparam; if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { Identifier id = tsa.dim.isVarExp().var.ident; - i = templateIdentifierLookup(id, parameters); + i = templateIdentifierLookup(id, ¶meters); assert(i != IDX_NOTFOUND); - tp = (*parameters)[i]; + tp = parameters[i]; } else edim = tsa.dim; } - else if (tparam.ty == Taarray) + else if (auto taa = tparam.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tparam; - i = templateParameterLookup(taa.index, parameters); + i = templateParameterLookup(taa.index, ¶meters); if (i != IDX_NOTFOUND) - tp = (*parameters)[i]; + tp = parameters[i]; else { Loc loc; @@ -3878,7 +3884,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // so we use that for the resolution (better error message). if (inferStart < parameters.length) { - TemplateParameter loctp = (*parameters)[inferStart]; + TemplateParameter loctp = parameters[inferStart]; loc = loctp.loc; } @@ -3889,7 +3895,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param edim = s ? getValue(s) : getValue(e); } } - if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) + if (tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) { result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); return; @@ -3903,7 +3909,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check that index type must match if (tparam && tparam.ty == Taarray) { - TypeAArray tp = cast(TypeAArray)tparam; + TypeAArray tp = tparam.isTypeAArray(); if (!deduceType(t.index, sc, tp.index, parameters, dedtypes)) { result = MATCH.nomatch; @@ -3936,7 +3942,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // https://issues.dlang.org/show_bug.cgi?id=15243 // Resolve parameter type if it's not related with template parameters - if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length])) + if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length])) { auto tx = fparam.type.typeSemantic(Loc.initial, sc); if (tx.ty == Terror) @@ -3948,7 +3954,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - size_t nfargs = t.parameterList.length; + const size_t nfargs = t.parameterList.length; size_t nfparams = tp.parameterList.length; /* See if tuple match @@ -3963,7 +3969,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param assert(fparam.type); if (fparam.type.ty != Tident) goto L1; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (tid.idents.length) goto L1; @@ -3974,7 +3980,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param { if (tupi == parameters.length) goto L1; - TemplateParameter tx = (*parameters)[tupi]; + TemplateParameter tx = parameters[tupi]; TemplateTupleParameter tup = tx.isTemplateTupleParameter(); if (tup && tup.ident.equals(tid.ident)) break; @@ -3987,7 +3993,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* See if existing tuple, and whether it matches or not */ - RootObject o = (*dedtypes)[tupi]; + RootObject o = dedtypes[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match @@ -4016,7 +4022,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Parameter arg = t.parameterList[nfparams - 1 + i]; tup.objects[i] = arg.type; } - (*dedtypes)[tupi] = tup; + dedtypes[tupi] = tup; } nfparams--; // don't consider the last parameter for type deduction goto L2; @@ -4053,7 +4059,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tident) { - TypeIdentifier tp = cast(TypeIdentifier)tparam; + TypeIdentifier tp = tparam.isTypeIdentifier(); for (size_t i = 0; i < t.idents.length; i++) { RootObject id1 = t.idents[i]; @@ -4076,7 +4082,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TypeInstance tp = cast(TypeInstance)tparam; + TypeInstance tp = tparam.isTypeInstance(); //printf("tempinst.tempdecl = %p\n", tempdecl); //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl); @@ -4087,7 +4093,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Handle case of: * template Foo(T : sa!(T), alias sa) */ - size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); + size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking @@ -4132,15 +4138,15 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - TemplateParameter tpx = (*parameters)[i]; - if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null)) + TemplateParameter tpx = parameters[i]; + if (!tpx.matchArg(sc, tempdecl, i, ¶meters, dedtypes, null)) goto Lnomatch; } else if (tempdecl != tp.tempinst.tempdecl) goto Lnomatch; L2: - if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes)) + if (!resolveTemplateInstantiation(sc, ¶meters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes)) goto Lnomatch; } visit(cast(Type)t); @@ -4151,198 +4157,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param result = MATCH.nomatch; } - /******************** - * Match template `parameters` to the target template instance. - * Example: - * struct Temp(U, int Z) {} - * void foo(T)(Temp!(T, 3)); - * foo(Temp!(int, 3)()); - * Input: - * this.parameters = template params of foo -> [T] - * tiargs = .tiargs -> [int, 3] - * tdtypes = .tdtypes -> [int, 3] - * tempdecl = -> [T, Z] - * tp = - * Output: - * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] - */ - private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) - { - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst.tiargs[%zu]\n", i); - RootObject o1 = null; - if (i < tiargs.length) - o1 = (*tiargs)[i]; - else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) - { - // Pick up default arg - o1 = (*tdtypes)[i]; - } - else if (i >= tp.tempinst.tiargs.length) - break; - //printf("\ttest: o1 = %s\n", o1.toChars()); - if (i >= tp.tempinst.tiargs.length) - { - size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - return false; - } - - RootObject o2 = (*tp.tempinst.tiargs)[i]; - Type t2 = isType(o2); - //printf("\ttest: o2 = %s\n", o2.toChars()); - size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters.length - 1 && - (*parameters)[j].isTemplateTupleParameter()) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (is(X Y == A!(Z), Z...)) {} - * deduce that Z is a tuple(int, float) - */ - - /* Create tuple from remaining args - */ - size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; - auto vt = new Tuple(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject o; - if (k < tiargs.length) - o = (*tiargs)[i + k]; - else // Pick up default arg - o = (*tdtypes)[i + k]; - vt.objects[k] = o; - } - - Tuple v = cast(Tuple)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - return false; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type t1 = isType(o1); - Dsymbol s1 = isDsymbol(o1); - Dsymbol s2 = isDsymbol(o2); - Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression e2 = isExpression(o2); - version (none) - { - Tuple v1 = isTuple(o1); - Tuple v2 = isTuple(o2); - if (t1) - printf("t1 = %s\n", t1.toChars()); - if (t2) - printf("t2 = %s\n", t2.toChars()); - if (e1) - printf("e1 = %s\n", e1.toChars()); - if (e2) - printf("e2 = %s\n", e2.toChars()); - if (s1) - printf("s1 = %s\n", s1.toChars()); - if (s2) - printf("s2 = %s\n", s2.toChars()); - if (v1) - printf("v1 = %s\n", v1.toChars()); - if (v2) - printf("v2 = %s\n", v2.toChars()); - } - - if (t1 && t2) - { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - return false; - } - else if (e1 && e2) - { - Le: - e1 = e1.ctfeInterpret(); - - /* If it is one of the template parameters for this template, - * we should not attempt to interpret it. It already has a value. - */ - if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 - e2 = e2.ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); - //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); - if (!e1.equals(e2)) - { - if (!e2.implicitConvTo(e1.type)) - return false; - - e2 = e2.implicitCastTo(sc, e1.type); - e2 = e2.ctfeInterpret(); - if (!e1.equals(e2)) - return false; - } - } - else if (e1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (e2) - goto Le; - return false; - } - if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) - return false; - } - else if (s1 && s2) - { - Ls: - if (!s1.equals(s2)) - return false; - } - else if (s1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (s2) - goto Ls; - return false; - } - if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) - return false; - } - else - return false; - } - return true; - } - override void visit(TypeStruct t) { /* If this struct is a template struct, and we're matching @@ -4368,7 +4182,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4391,7 +4205,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tstruct) { - TypeStruct tp = cast(TypeStruct)tparam; + TypeStruct tp = tparam.isTypeStruct(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4410,7 +4224,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tenum) { - TypeEnum tp = cast(TypeEnum)tparam; + TypeEnum tp = tparam.isTypeEnum(); if (t.sym == tp.sym) visit(cast(Type)t); else @@ -4428,59 +4242,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param visit(cast(Type)t); } - /* Helper for TypeClass.deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ - static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches) - { - TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - auto tmpdedtypes = new Objects(dedtypes.length); - memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); - - auto t = new TypeInstance(Loc.initial, parti); - MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); - if (m > MATCH.nomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches == 0) - memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); - else - for (size_t k = 0; k < tmpdedtypes.length; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if ((*tmpdedtypes)[k] != (*best)[k]) - (*best)[k] = (*dedtypes)[k]; - } - ++numBaseClassMatches; - } - } - - // Now recursively test the inherited interfaces - foreach (ref bi; b.baseInterfaces) - { - deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); - } - } - override void visit(TypeClass t) { //printf("TypeClass.deduceType(this = %s)\n", t.toChars()); @@ -4509,7 +4270,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4547,12 +4308,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param while (s && s.baseclasses.length > 0) { // Test the base class - deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); // Test the interfaces inherited by the base class foreach (b; s.interfaces) { - deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); } s = (*s.baseclasses)[0].sym; } @@ -4572,7 +4333,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tclass) { - TypeClass tp = cast(TypeClass)tparam; + TypeClass tp = tparam.isTypeClass(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4589,8 +4350,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); - size_t i = templateParameterLookup(tparam, parameters); - if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0) + size_t i = templateParameterLookup(tparam, ¶meters); + if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) { @@ -4602,13 +4363,13 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter(); + TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter(); if (!tp) return; // nomatch if (e == emptyArrayElement) { - if ((*dedtypes)[i]) + if (dedtypes[i]) { result = MATCH.exact; return; @@ -4630,14 +4391,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param tb.ty == Tstruct && tb.hasPointers(); } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = deduceWildHelper(e.type, &tt, tparam)) { *wm |= wx; result = MATCH.constant; } - else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(e.type, tt, tparam)) { result = m; } @@ -4658,7 +4419,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // expression vs (none) if (!at) { - (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); + dedtypes[i] = new TypeDeduced(tt, e, tparam); return; } @@ -4716,7 +4477,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(tt, e, tparam); else - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = match1; return; } @@ -4736,7 +4497,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(t, e, tparam); else - (*dedtypes)[i] = t; + dedtypes[i] = t; pt = tt.addMod(tparam.mod); if (*wm) @@ -4870,7 +4631,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Parameter types inference from 'tof' assert(e.td._scope); - TypeFunction tf = cast(TypeFunction)e.fd.type; + TypeFunction tf = e.fd.type.isTypeFunction(); //printf("\ttof = %s\n", tof.toChars()); //printf("\ttf = %s\n", tf.toChars()); const dim = tf.parameterList.length; @@ -4895,7 +4656,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (!pto) break; Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774 - if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length])) + if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length])) return; t = t.typeSemantic(e.loc, sc); if (t.ty == Terror) @@ -4929,7 +4690,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Allow conversion from implicit function pointer to delegate if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate) { - TypeFunction tf = cast(TypeFunction)t.nextOf(); + TypeFunction tf = t.nextOf().isTypeFunction(); t = (new TypeDelegate(tf)).merge(); } //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars()); @@ -4959,7 +4720,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis); + scope DeduceType v = new DeduceType(); if (Type t = isType(o)) t.accept(v); else if (Expression e = isExpression(o)) @@ -4972,6 +4733,254 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return v.result; } + +/* Helper for TypeClass.deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches) +{ + TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + auto tmpdedtypes = new Objects(dedtypes.length); + memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); + + auto t = new TypeInstance(Loc.initial, parti); + MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes); + if (m > MATCH.nomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches == 0) + memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); + else + for (size_t k = 0; k < tmpdedtypes.length; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if ((*tmpdedtypes)[k] != best[k]) + best[k] = dedtypes[k]; + } + ++numBaseClassMatches; + } + } + + // Now recursively test the inherited interfaces + foreach (ref bi; b.baseInterfaces) + { + deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + } +} + +/******************** + * Match template `parameters` to the target template instance. + * Example: + * struct Temp(U, int Z) {} + * void foo(T)(Temp!(T, 3)); + * foo(Temp!(int, 3)()); + * Input: + * sc = context + * parameters = template params of foo -> [T] + * tiargs = .tiargs -> [int, 3] + * tdtypes = .tdtypes -> [int, 3] + * tempdecl = -> [T, Z] + * tp = + * Output: + * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] + */ +private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) +{ + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst.tiargs[%zu]\n", i); + RootObject o1 = null; + if (i < tiargs.length) + o1 = (*tiargs)[i]; + else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) + { + // Pick up default arg + o1 = (*tdtypes)[i]; + } + else if (i >= tp.tempinst.tiargs.length) + break; + //printf("\ttest: o1 = %s\n", o1.toChars()); + if (i >= tp.tempinst.tiargs.length) + { + size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); + while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) + { + i++; + } + if (i >= dim) + break; // match if all remained parameters are dependent + return false; + } + + RootObject o2 = (*tp.tempinst.tiargs)[i]; + Type t2 = isType(o2); + //printf("\ttest: o2 = %s\n", o2.toChars()); + size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) + ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; + if (j != IDX_NOTFOUND && j == parameters.length - 1 && + (*parameters)[j].isTemplateTupleParameter()) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (is(X Y == A!(Z), Z...)) {} + * deduce that Z is a tuple(int, float) + */ + + /* Create tuple from remaining args + */ + size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; + auto vt = new Tuple(vtdim); + for (size_t k = 0; k < vtdim; k++) + { + RootObject o; + if (k < tiargs.length) + o = (*tiargs)[i + k]; + else // Pick up default arg + o = (*tdtypes)[i + k]; + vt.objects[k] = o; + } + + Tuple v = cast(Tuple)(*dedtypes)[j]; + if (v) + { + if (!match(v, vt)) + return false; + } + else + (*dedtypes)[j] = vt; + break; + } + else if (!o1) + break; + + Type t1 = isType(o1); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + Expression e2 = isExpression(o2); + version (none) + { + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + if (t1) + printf("t1 = %s\n", t1.toChars()); + if (t2) + printf("t2 = %s\n", t2.toChars()); + if (e1) + printf("e1 = %s\n", e1.toChars()); + if (e2) + printf("e2 = %s\n", e2.toChars()); + if (s1) + printf("s1 = %s\n", s1.toChars()); + if (s2) + printf("s2 = %s\n", s2.toChars()); + if (v1) + printf("v1 = %s\n", v1.toChars()); + if (v2) + printf("v2 = %s\n", v2.toChars()); + } + + if (t1 && t2) + { + if (!deduceType(t1, sc, t2, *parameters, *dedtypes)) + return false; + } + else if (e1 && e2) + { + Le: + e1 = e1.ctfeInterpret(); + + /* If it is one of the template parameters for this template, + * we should not attempt to interpret it. It already has a value. + */ + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } + + e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 + e2 = e2.ctfeInterpret(); + + //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); + //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); + if (!e1.equals(e2)) + { + if (!e2.implicitConvTo(e1.type)) + return false; + + e2 = e2.implicitCastTo(sc, e1.type); + e2 = e2.ctfeInterpret(); + if (!e1.equals(e2)) + return false; + } + } + else if (e1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (e2) + goto Le; + return false; + } + if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null)) + return false; + } + else if (s1 && s2) + { + Ls: + if (!s1.equals(s2)) + return false; + } + else if (s1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (s2) + goto Ls; + return false; + } + if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null)) + return false; + } + else + return false; + } + return true; +} + + /*********************************************************** * Check whether the type t representation relies on one or more the template parameters. * Params: @@ -5625,7 +5634,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter if (e) { e = e.syntaxCopy(); - if ((e = e.expressionSemantic(sc)) is null) + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; + e = e.expressionSemantic(sc2); + sc2.pop(); + if (e is null) return null; if (auto te = e.isTemplateExp()) { @@ -6176,7 +6189,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars()); - if (!arrayObjectMatch(&tdtypes, &ti.tdtypes)) + if (!arrayObjectMatch(tdtypes, ti.tdtypes)) goto Lnotequals; /* Template functions may have different instantiations based on @@ -6221,7 +6234,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!hash) { hash = cast(size_t)cast(void*)enclosing; - hash += arrayObjectHash(&tdtypes); + hash += arrayObjectHash(tdtypes); hash += hash == 0; } return hash; @@ -6691,6 +6704,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!tiargs) return true; bool err = false; + + // The arguments are not treated as part of a default argument, + // because they are evaluated at compile time. + sc = sc.push(); + sc.inDefaultArg = false; + for (size_t j = 0; j < tiargs.length; j++) { RootObject o = (*tiargs)[j]; @@ -6716,10 +6735,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol } Ltype: - if (ta.ty == Ttuple) + if (TypeTuple tt = ta.isTypeTuple()) { // Expand tuple - TypeTuple tt = cast(TypeTuple)ta; size_t dim = tt.arguments.length; tiargs.remove(j); if (dim) @@ -6923,6 +6941,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } + sc.pop(); version (none) { printf("-TemplateInstance.semanticTiargs()\n"); @@ -6982,7 +7001,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2)) + if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2)) { .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars); return false; @@ -7032,7 +7051,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0); + MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7158,7 +7177,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol // print additional information, e.g. `foo` is not a type foreach (i, param; *tdecl.parameters) { - MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null); + MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null); auto arg = (*tiargs)[i]; auto sym = arg.isDsymbol; auto exp = arg.isExpression; @@ -7262,7 +7281,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol * to instantiate the template. */ //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); if (tf.parameterList.length) { auto tp = td.isVariadic(); @@ -7308,7 +7327,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol return 1; } } - MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0); + MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -7992,7 +8011,7 @@ struct TemplateInstanceBox * dedtypes[] deduced arguments to template instance * *psparam set to symbol declared and initialized to dedtypes[i] */ -MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8015,7 +8034,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si { assert(i < dedtypes.length); // It might have already been deduced - oarg = (*dedtypes)[i]; + oarg = dedtypes[i]; if (!oarg) return matchArgNoMatch(); } @@ -8031,7 +8050,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si assert(i + 1 == dedtypes.length); // must be the last one Tuple ovar; - if (Tuple u = isTuple((*dedtypes)[i])) + if (Tuple u = isTuple(dedtypes[i])) { // It has already been deduced ovar = u; @@ -8059,7 +8078,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si return matchArgParameter(); } -MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8087,7 +8106,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars()); - MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes); + MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes); if (m2 == MATCH.nomatch) { //printf("\tfailed deduceType\n"); @@ -8096,9 +8115,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ if (m2 < m) m = m2; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357 return matchArgNoMatch(); @@ -8113,10 +8132,10 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced type - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (!t.equals(ta)) { @@ -8130,7 +8149,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ m = MATCH.convert; } } - (*dedtypes)[i] = ta; + dedtypes[i] = ta; if (psparam) *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta); @@ -8235,15 +8254,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced value - Expression e = cast(Expression)(*dedtypes)[i]; + Expression e = cast(Expression)dedtypes[i]; if (!ei || !ei.equals(e)) return matchArgNoMatch(); } } - (*dedtypes)[i] = ei; + dedtypes[i] = ei; if (psparam) { @@ -8354,7 +8373,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); Type t = new TypeInstance(Loc.initial, ti); - MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); + MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes); if (m2 == MATCH.nomatch) return matchArgNoMatch(); } @@ -8375,14 +8394,14 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } } } - else if ((*dedtypes)[i]) + else if (dedtypes[i]) { // Must match already deduced symbol - RootObject si = (*dedtypes)[i]; + RootObject si = dedtypes[i]; if (!sa || si != sa) return matchArgNoMatch(); } - (*dedtypes)[i] = sa; + dedtypes[i] = sa; if (psparam) { @@ -8415,15 +8434,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ Tuple ovar = isTuple(oarg); if (!ovar) return MATCH.nomatch; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Tuple tup = isTuple((*dedtypes)[i]); + Tuple tup = isTuple(dedtypes[i]); if (!tup) return MATCH.nomatch; if (!match(tup, ovar)) return MATCH.nomatch; } - (*dedtypes)[i] = ovar; + dedtypes[i] = ovar; if (psparam) *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects); @@ -8457,21 +8476,24 @@ struct TemplateStats /******************************* * Add this instance + * Params: + * td = template declaration + * ti = instance of td + * listInstances = keep track of instances of templates */ static void incInstance(const TemplateDeclaration td, - const TemplateInstance ti) + const TemplateInstance ti, + bool listInstances) { void log(ref TemplateStats ts) { if (ts.allInstances is null) ts.allInstances = new TemplateInstances(); - if (global.params.v.templatesListInstances) + if (listInstances) ts.allInstances.push(cast() ti); } - // message(ti.loc, "incInstance %p %p", td, ti); - if (!global.params.v.templates) - return; + // message(ti.loc, "incInstance %p %p", td, ti); if (!td) return; assert(ti); @@ -8494,8 +8516,6 @@ struct TemplateStats const TemplateInstance ti) { // message(ti.loc, "incUnique %p %p", td, ti); - if (!global.params.v.templates) - return; if (!td) return; assert(ti); @@ -8506,7 +8526,13 @@ struct TemplateStats } } -extern (C++) void printTemplateStats() +/******************************** + * Print informational statistics on template instantiations. + * Params: + * listInstances = list instances of templates + * eSink = where the print is sent + */ +extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) { static struct TemplateDeclarationStats { @@ -8523,11 +8549,12 @@ extern (C++) void printTemplateStats() } } - if (!global.params.v.templates) - return; + const stats_length = TemplateStats.stats.length; + if (!stats_length) + return; // nothing to report Array!(TemplateDeclarationStats) sortedStats; - sortedStats.reserve(TemplateStats.stats.length); + sortedStats.reserve(stats_length); foreach (td_, ref ts; TemplateStats.stats) { sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts)); @@ -8537,10 +8564,9 @@ extern (C++) void printTemplateStats() foreach (const ref ss; sortedStats[]) { - if (global.params.v.templatesListInstances && - ss.ts.allInstances) + if (listInstances && ss.ts.allInstances) { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, @@ -8548,14 +8574,14 @@ extern (C++) void printTemplateStats() foreach (const ti; (*ss.ts.allInstances)[]) { if (ti.tinst) // if has enclosing instance - message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); else - message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); } } else { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 30991c9171a..2bfa96cf76b 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -779,6 +779,17 @@ public: } } + if (tf && tf.next) + { + // Ensure return type is declared before a function that returns that is declared. + if (auto sty = tf.next.isTypeStruct()) + ensureDeclared(sty.sym); + //else if (auto cty = tf.next.isTypeClass()) + // includeSymbol(cty.sym); // classes are returned by pointer only need to forward declare + //else if (auto ety = tf.next.isTypeEnum()) + // ensureDeclared(ety.sym); + } + writeProtection(fd.visibility.kind); if (tf && tf.linkage == LINK.c) diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 433907a17be..3e17ff4736d 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -34,6 +34,7 @@ import dmd.mtype; import dmd.printast; import dmd.rootobject; import dmd.tokens; +import dmd.typesem : hasPointers, parameterStorageClass; import dmd.visitor; import dmd.arraytypes; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 41eeff923d8..cbf01186f98 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -189,39 +189,6 @@ extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null) } } -/**************************************** - * Expand alias this tuples. - */ -TupleDeclaration isAliasThisTuple(Expression e) -{ - if (!e.type) - return null; - - Type t = e.type.toBasetype(); - while (true) - { - if (Dsymbol s = t.toDsymbol(null)) - { - if (auto ad = s.isAggregateDeclaration()) - { - s = ad.aliasthis ? ad.aliasthis.sym : null; - if (s && s.isVarDeclaration()) - { - TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); - if (td && td.isexp) - return td; - } - if (Type att = t.aliasthisOf()) - { - t = att; - continue; - } - } - } - return null; - } -} - /**************************************** * If `s` is a function template, i.e. the only member of a template * and that member is a function, return that template. diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 9ce6f4ded9d..d4645748177 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -384,7 +384,6 @@ private Expression reorderSettingAAElem(BinExp exp, Scope* sc) return Expression.combine(e0, be); } - private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) { auto e1 = binExp.e1; @@ -563,6 +562,39 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) return e0; } +/**************************************** + * Expand alias this tuples. + */ +TupleDeclaration isAliasThisTuple(Expression e) +{ + if (!e.type) + return null; + + Type t = e.type.toBasetype(); + while (true) + { + if (Dsymbol s = t.toDsymbol(null)) + { + if (auto ad = s.isAggregateDeclaration()) + { + s = ad.aliasthis ? ad.aliasthis.sym : null; + if (s && s.isVarDeclaration()) + { + TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); + if (td && td.isexp) + return td; + } + if (Type att = t.aliasthisOf()) + { + t = att; + continue; + } + } + } + return null; + } +} + /************************************** * Runs semantic on ae.arguments. Declares temporary variables * if '$' was used. @@ -5115,7 +5147,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (global.params.betterC || !sc.needsCodegen()) + if (!global.params.useGC && sc.needsCodegen()) + { + version(IN_GCC) + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars()); + else + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars()); + return setError(); + } + + if (!sc.needsCodegen()) goto LskipNewArrayLowering; /* Class types may inherit base classes that have errors. @@ -6432,8 +6473,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + void errorHelper(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6447,8 +6487,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); - return setError(); } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch) + return setError(); + // Purity and safety check should run after testing arguments matching if (exp.f) { @@ -6505,8 +6548,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + + void errorHelper2(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6527,6 +6570,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor errorSupplemental(exp.loc, "%s", failMessage); exp.f = null; } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch) + exp.f = null; } if (!exp.f || exp.f.errors) return setError(); @@ -7041,7 +7087,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc2.tinst = null; sc2.minst = null; sc2.flags |= SCOPE.fullinst; - Type t = e.targ.trySemantic(e.loc, sc2); + Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2); sc2.pop(); if (!t) // errors, so condition is false return no(); @@ -7271,7 +7317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Objects dedtypes = Objects(e.parameters.length); dedtypes.zero(); - MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); + MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal); if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) { @@ -7292,7 +7338,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TemplateParameter tp = (*e.parameters)[i]; Declaration s = null; - m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); + m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s); if (m == MATCH.nomatch) return no(); s.dsymbolSemantic(sc); @@ -7437,7 +7483,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = (cast(BinExp)e).reorderSettingAAElem(sc); } - private Expression compileIt(MixinExp exp) + private Expression compileIt(MixinExp exp, Scope *sc) { OutBuffer buf; if (expressionsToString(buf, sc, exp.exps)) @@ -7478,7 +7524,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("MixinExp::semantic('%s')\n", exp.toChars()); } - auto e = compileIt(exp); + // The expression is not treated as part of a default argument, + // because it is evaluated at compile time. + Scope* sc2 = sc.push(); + sc2.inDefaultArg = false; + + auto e = compileIt(exp, sc2); + sc2.pop(); if (!e) return setError(); result = e.expressionSemantic(sc); @@ -7575,7 +7627,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { auto fileName = FileName(resolvedNamez); - if (auto fmResult = global.fileManager.lookup(fileName)) + if (auto fmResult = global.fileManager.getFileContents(fileName)) { se = new StringExp(e.loc, fmResult); } @@ -7721,7 +7773,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // if the assert condition is a mixin expression, try to compile it if (auto ce = exp.e1.isMixinExp()) { - if (auto e1 = compileIt(ce)) + if (auto e1 = compileIt(ce, sc)) exp.e1 = e1; } @@ -13924,45 +13976,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("FileInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(LineInitExp e) { e.type = Type.tint32; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(ModuleInitExp e) { //printf("ModuleInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(FuncInitExp e) { //printf("FuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(PrettyFuncInitExp e) { //printf("PrettyFuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - - result = e; + result = e.resolveLoc(e.loc, sc); } } @@ -15047,10 +15088,21 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) */ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { + // Don't replace the special keywords, while we are inside a default + // argument. They are replaced later when copied to the call site. + if (sc.inDefaultArg) + return exp; + exp.loc = loc; Expression visit(Expression exp) { + if (auto binExp = exp.isBinExp()) + { + binExp.e1 = binExp.e1.resolveLoc(loc, sc); + binExp.e2 = binExp.e2.resolveLoc(loc, sc); + return binExp; + } if (auto unaExp = exp.isUnaExp()) { unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); @@ -15059,10 +15111,121 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return exp; } + Expression visitCond(CondExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.e2 = exp.e2.resolveLoc(loc, sc); + exp.econd = exp.econd.resolveLoc(loc, sc); + return exp; + } + Expression visitCat(CatExp exp) { exp.e1 = exp.e1.resolveLoc(loc, sc); exp.e2 = exp.e2.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + return exp; + } + + Expression visitStructLiteral(StructLiteralExp exp) + { + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitNew(NewExp exp) + { + if (exp.thisexp) + exp.thisexp = exp.thisexp.resolveLoc(loc, sc); + if (exp.argprefix) + exp.argprefix = exp.argprefix.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitCall(CallExp exp) + { + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitArray(ArrayExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitSlice(SliceExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitInterval(IntervalExp exp) + { + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitArrayLiteral(ArrayLiteralExp exp) + { + if (exp.basis) + exp.basis = exp.basis.resolveLoc(loc, sc); + + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp) + { + foreach (ref element; *exp.keys) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + foreach (ref element; *exp.values) + { + if (element) + element = element.resolveLoc(loc, sc); + } + return exp; } @@ -15079,20 +15242,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitLineInit(LineInitExp _) + Expression visitLineInit(LineInitExp exp) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); return e.expressionSemantic(sc); } - Expression visitModuleInit(ModuleInitExp _) + Expression visitModuleInit(ModuleInitExp exp) { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); return e.expressionSemantic(sc); } - Expression visitFuncInit(FuncInitExp _) + Expression visitFuncInit(FuncInitExp exp) { const(char)* s; if (sc.callsc && sc.callsc.func) @@ -15105,7 +15268,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitPrettyFunc(PrettyFuncInitExp _) + Expression visitPrettyFunc(PrettyFuncInitExp exp) { FuncDeclaration fd = (sc.callsc && sc.callsc.func) ? sc.callsc.func @@ -15133,7 +15296,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) switch(exp.op) { default: return visit(exp); + case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp()); + case EXP.new_: return visitNew(exp.isNewExp()); case EXP.concatenate: return visitCat(exp.isCatExp()); + case EXP.call: return visitCall(exp.isCallExp()); + case EXP.question: return visitCond(exp.isCondExp()); + case EXP.array: return visitArray(exp.isArrayExp()); + case EXP.slice: return visitSlice(exp.isSliceExp()); + case EXP.interval: return visitInterval(exp.isIntervalExp()); + case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp()); case EXP.file: case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp()); case EXP.line: return visitLineInit(exp.isLineInitExp); @@ -16193,7 +16365,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) em.checkDisabled(loc, sc); if (em.depdecl && !em.depdecl._scope) + { em.depdecl._scope = sc; + em.depdecl._scope.setNoFree(); + } em.checkDeprecated(loc, sc); if (em.errors) diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index eaef8d545e6..c696a5c240f 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -72,7 +72,7 @@ private struct PathStack final class FileManager { - private StringTable!(const(ubyte)[]) files; + private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name private StringTable!(bool) packageStatus; // check if the package path of the given path exists. The input path is @@ -247,35 +247,37 @@ nothrow: } /** - * Looks up the given filename from the internal file buffer table. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + * Retrieve the cached contents of the file given by `filename`. + * If the file has not been read before, read it and add the contents + * to the file cache. + * Params: + * filename = the name of the file + * Returns: + * the contents of the file, or `null` if it could not be read or was empty */ - const(ubyte)[] lookup(FileName filename) + const(ubyte)[] getFileContents(FileName filename) { const name = filename.toString; - if (auto val = files.lookup(name)) - return val.value; + if (auto val = files.lookup(name)) // if `name` is cached + return val.value; // return its contents - if (name == "__stdin.d") + if (name == "__stdin.d") // special name for reading from stdin { - auto buffer = readFromStdin().extractSlice(); + const ubyte[] buffer = readFromStdin().extractSlice(); if (this.files.insert(name, buffer) is null) + // this.files already contains the name assert(0, "stdin: Insert after lookup failure should never return `null`"); return buffer; } - if (FileName.exists(name) != 1) + if (FileName.exists(name) != 1) // if not an ordinary file return null; auto readResult = File.read(name); if (!readResult.success) return null; - auto fb = readResult.extractSlice(); + const ubyte[] fb = readResult.extractSlice(); if (files.insert(name, fb) is null) assert(0, "Insert after lookup failure should never return `null`"); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 242b4dc99f9..370da6f0ee6 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -1195,7 +1195,7 @@ extern (C++) class FuncDeclaration : Declaration * * Returns: the `LabelDsymbol` for `ident` */ - final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial) + final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc) { Dsymbol s; if (!labtab) @@ -1471,6 +1471,9 @@ extern (C++) class FuncDeclaration : Declaration final PURE isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + + import dmd.typesem : purityLevel; + TypeFunction tf = type.toTypeFunction(); if (purityInprocess) setImpure(); @@ -1782,6 +1785,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null).isStructDeclaration(); const tName = t.toChars.toDString; const entry = parentTypes.insert(tName, t); @@ -1863,6 +1867,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = tp.toDsymbol(null).isStructDeclaration(); foreach (v; sym.fields) { @@ -2727,6 +2732,7 @@ extern (C++) class FuncDeclaration : Declaration { Type t1 = fdv.type.nextOf().toBasetype(); Type t2 = this.type.nextOf().toBasetype(); + import dmd.typesem : isBaseOf; if (t1.isBaseOf(t2, null)) { /* Making temporary reference variable is necessary @@ -3294,7 +3300,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); } - if (tiargs && arrayObjectIsError(tiargs)) + if (tiargs && arrayObjectIsError(*tiargs)) return null; if (fargs !is null) foreach (arg; *fargs) @@ -3441,17 +3447,20 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + 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); - return null; + 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()); @@ -3505,10 +3514,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } } } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + + void errorHelper2(const(char)* failMessage) scope + { errorSupplemental(loc, failMessage); + } + + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2); } return null; } @@ -3624,6 +3636,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) */ Type getIndirection(Type t) { + import dmd.typesem : hasPointers; t = t.baseElemOf(); if (t.ty == Tarray || t.ty == Tpointer) return t.nextOf().toBasetype(); @@ -3670,6 +3683,7 @@ private bool traverseIndirections(Type ta, Type tb) static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass) { + import dmd.typesem : hasPointers; //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); ta = ta.baseElemOf(); tb = tb.baseElemOf(); @@ -3706,6 +3720,7 @@ private bool traverseIndirections(Type ta, Type tb) else *found = true; + import dmd.typesem : toDsymbol; AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); foreach (v; sym.fields) { diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index b60a3f8cad1..e9e73e8af66 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -15,7 +15,9 @@ import core.stdc.stdio; import core.stdc.stdint; import core.stdc.string; +import dmd.astenums; import dmd.root.array; +import dmd.root.file; import dmd.root.filename; import dmd.common.outbuffer; import dmd.errorsink; @@ -308,7 +310,7 @@ extern (C++) struct Global ErrorSink errorSink; /// where the error messages go ErrorSink errorSinkNull; /// where the error messages are ignored - extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; + extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess; nothrow: diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index c71d2f0499d..93e7c643d4c 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -307,7 +307,7 @@ struct Global ErrorSink* errorSink; // where the error messages go ErrorSink* errorSinkNull; // where the error messages disappear - FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); + DArray (*preprocess)(FileName, const Loc&, OutBuffer&); /* Start gagging. Return the current number of gagged errors */ diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 4c741cdd5cc..3d88a1dfad3 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -21,16 +21,11 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; import dmd.dclass; -import dmd.dcast; import dmd.declaration; import dmd.denum; -import dmd.dmangle; -import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; @@ -39,9 +34,7 @@ import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; -import dmd.init; import dmd.location; -import dmd.opover; import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.rmem; @@ -256,57 +249,6 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe return ty == Tchar || ty == Twchar || ty == Tdchar; } -/************************************ - * Determine mutability of indirections in (ref) t. - * - * Returns: When the type has any mutable indirections, returns 0. - * When all indirections are immutable, returns 2. - * Otherwise, when the type has const/inout indirections, returns 1. - * - * Params: - * isref = if true, check `ref t`; otherwise, check just `t` - * t = the type that is being checked - */ -int mutabilityOfType(bool isref, Type t) -{ - if (isref) - { - if (t.mod & MODFlags.immutable_) - return 2; - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - return 0; - } - - t = t.baseElemOf(); - - if (!t.hasPointers() || t.mod & MODFlags.immutable_) - return 2; - - /* Accept immutable(T)[] and immutable(T)* as being strongly pure - */ - if (t.ty == Tarray || t.ty == Tpointer) - { - Type tn = t.nextOf().toBasetype(); - if (tn.mod & MODFlags.immutable_) - return 2; - if (tn.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - } - - /* The rest of this is too strict; fix later. - * For example, the only pointer members of a struct may be immutable, - * which would maintain strong purity. - * (Just like for dynamic arrays and pointers above.) - */ - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - - /* Should catch delegates and function pointers, and fold in their purity - */ - return 0; -} - /**************** * dotExp() bit flags */ @@ -363,7 +305,7 @@ extern (C++) abstract class Type : ASTNode TypeInfoDeclaration vtinfo; // TypeInfo object for this Type - type* ctype; // for back end + void* ctype; // for back end extern (C++) __gshared Type tvoid; extern (C++) __gshared Type tint8; @@ -659,31 +601,6 @@ extern (C++) abstract class Type : ASTNode return cast(uint)size(Loc.initial); } - final Type trySemantic(const ref Loc loc, Scope* sc) - { - //printf("+trySemantic(%s) %d\n", toChars(), global.errors); - - // Needed to display any deprecations that were gagged - auto tcopy = this.syntaxCopy(); - - const errors = global.startGagging(); - Type t = typeSemantic(this, loc, sc); - if (global.endGagging(errors) || t.ty == Terror) // if any errors happened - { - t = null; - } - else - { - // If `typeSemantic` succeeded, there may have been deprecations that - // were gagged due the `startGagging` above. Run again to display - // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 - if (global.gaggedWarnings > 0) - typeSemantic(tcopy, loc, sc); - } - //printf("-trySemantic(%s) %d\n", toChars(), global.errors); - return t; - } - /************************************* * This version does a merge even if the deco is already computed. * Necessary for types that have a deco, but are not merged. @@ -1907,11 +1824,6 @@ extern (C++) abstract class Type : ASTNode return t; } - Dsymbol toDsymbol(Scope* sc) - { - return null; - } - /******************************* * If this is a shell around another type, * get that other type. @@ -1925,11 +1837,6 @@ extern (C++) abstract class Type : ASTNode return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; } - bool isBaseOf(Type t, int* poffset) - { - return 0; // assume not - } - /******************************** * Determine if 'this' can be implicitly converted * to type 'to'. @@ -2155,32 +2062,6 @@ extern (C++) abstract class Type : ASTNode return false; // assume not } - final Identifier getTypeInfoIdent() - { - // _init_10TypeInfo_%s - OutBuffer buf; - buf.reserve(32); - mangleToBuffer(this, buf); - - const slice = buf[]; - - // Allocate buffer on stack, fail over to using malloc() - char[128] namebuf; - const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; - auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); - - const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", - cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); - //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); - assert(0 < length && length < namelen); // don't overflow the buffer - - auto id = Identifier.idPool(name[0 .. length]); - - if (name != namebuf.ptr) - free(name); - return id; - } - /*************************************** * Return !=0 if the type or any of its subtypes is wild. */ @@ -2189,16 +2070,6 @@ extern (C++) abstract class Type : ASTNode return mod & MODFlags.wild; } - /*************************************** - * Return !=0 if type has pointers that need to - * be scanned by the GC during a collection cycle. - */ - bool hasPointers() - { - //printf("Type::hasPointers() %s, %d\n", toChars(), ty); - return false; - } - /************************************* * Detect if type has pointer fields that are initialized to void. * Local stack variables with such void fields can remain uninitialized, @@ -2340,76 +2211,6 @@ extern (C++) abstract class Type : ASTNode return false; } - /************************************* - * https://issues.dlang.org/show_bug.cgi?id=14488 - * Check if the inner most base type is complex or imaginary. - * Should only give alerts when set to emit transitional messages. - * Params: - * loc = The source location. - * sc = scope of the type - */ - extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) - { - if (sc.isDeprecated()) - return false; - // Don't complain if we're inside a template constraint - // https://issues.dlang.org/show_bug.cgi?id=21831 - if (sc.flags & SCOPE.constraint) - return false; - - Type t = baseElemOf(); - while (t.ty == Tpointer || t.ty == Tarray) - t = t.nextOf().baseElemOf(); - - // Basetype is an opaque enum, nothing to check. - if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) - return false; - - if (t.isimaginary() || t.iscomplex()) - { - if (sc.flags & SCOPE.Cfile) - return true; // complex/imaginary not deprecated in C code - Type rt; - switch (t.ty) - { - case Tcomplex32: - case Timaginary32: - rt = Type.tfloat32; - break; - - case Tcomplex64: - case Timaginary64: - rt = Type.tfloat64; - break; - - case Tcomplex80: - case Timaginary80: - rt = Type.tfloat80; - break; - - default: - assert(0); - } - // @@@DEPRECATED_2.117@@@ - // Deprecated in 2.097 - Can be made an error from 2.117. - // The deprecation period is longer than usual as `cfloat`, - // `cdouble`, and `creal` were quite widely used. - if (t.iscomplex()) - { - deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", - toChars(), rt.toChars()); - return true; - } - else - { - deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", - toChars(), rt.toChars()); - return true; - } - } - return false; - } - // For eliminating dynamic_cast TypeBasic isTypeBasic() { @@ -3531,24 +3332,6 @@ extern (C++) final class TypeSArray : TypeArray return ae; } - override bool hasPointers() - { - /* Don't want to do this, because: - * struct S { T* array[0]; } - * may be a variable length struct. - */ - //if (dim.toInteger() == 0) - // return false; - - if (next.ty == Tvoid) - { - // Arrays of void contain arbitrary data, which may include pointers - return true; - } - else - return next.hasPointers(); - } - override bool hasSystemFields() { return next.hasSystemFields(); @@ -3673,11 +3456,6 @@ extern (C++) final class TypeDArray : TypeArray return Type.implicitConvTo(to); } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -3734,11 +3512,6 @@ extern (C++) final class TypeAArray : TypeArray return true; } - override bool hasPointers() - { - return true; - } - override MATCH implicitConvTo(Type to) { //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); @@ -3877,11 +3650,6 @@ extern (C++) final class TypePointer : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4058,39 +3826,6 @@ extern (C++) final class TypeFunction : TypeNext return t; } - /******************************************** - * Set 'purity' field of 'this'. - * Do this lazily, as the parameter types might be forward referenced. - */ - void purityLevel() - { - TypeFunction tf = this; - if (tf.purity != PURE.fwdref) - return; - - purity = PURE.const_; // assume strong until something weakens it - - /* Evaluate what kind of purity based on the modifiers for the parameters - */ - foreach (i, fparam; tf.parameterList) - { - Type t = fparam.type; - if (!t) - continue; - - if (fparam.storageClass & (STC.lazy_ | STC.out_)) - { - purity = PURE.weak; - break; - } - const pref = (fparam.storageClass & STC.ref_) != 0; - if (mutabilityOfType(pref, t) == 0) - purity = PURE.weak; - } - - tf.purity = purity; - } - /******************************************** * Return true if there are lazy parameters. */ @@ -4115,122 +3850,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - /************************************ - * Take the specified storage class for p, - * and use the function signature to infer whether - * STC.scope_ and STC.return_ should be OR'd in. - * (This will not affect the name mangling.) - * Params: - * tthis = type of `this` parameter, null if none - * p = parameter to this function - * outerVars = context variables p could escape into, if any - * indirect = is this for an indirect or virtual function call? - * Returns: - * storage class with STC.scope_ or STC.return_ OR'd in - */ - StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null, - bool indirect = false) - { - //printf("parameterStorageClass(p: %s)\n", p.toChars()); - auto stc = p.storageClass; - - // When the preview switch is enable, `in` parameters are `scope` - if (stc & STC.constscoperef) - return stc | STC.scope_; - - if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) - return stc; - - /* If haven't inferred the return type yet, can't infer storage classes - */ - if (!nextOf() || !isnothrow()) - return stc; - - purityLevel(); - - static bool mayHavePointers(Type t) - { - if (auto ts = t.isTypeStruct()) - { - auto sym = ts.sym; - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - // struct is forward referenced, so "may have" pointers - return true; - } - return t.hasPointers(); - } - - // See if p can escape via any of the other parameters - if (purity == PURE.weak) - { - /* - * Indirect calls may escape p through a nested context - * See: - * https://issues.dlang.org/show_bug.cgi?id=24212 - * https://issues.dlang.org/show_bug.cgi?id=24213 - */ - if (indirect) - return stc; - - // Check escaping through parameters - foreach (i, fparam; parameterList) - { - Type t = fparam.type; - if (!t) - continue; - t = t.baseElemOf(); // punch thru static arrays - if (t.isMutable() && t.hasPointers()) - { - if (fparam.isReference() && fparam != p) - return stc; - - if (t.ty == Tdelegate) - return stc; // could escape thru delegate - - if (t.ty == Tclass) - return stc; - - /* if t is a pointer to mutable pointer - */ - if (auto tn = t.nextOf()) - { - if (tn.isMutable() && mayHavePointers(tn)) - return stc; // escape through pointers - } - } - } - - // Check escaping through `this` - if (tthis && tthis.isMutable()) - { - foreach (VarDeclaration v; isAggregate(tthis).fields) - { - if (v.hasPointers()) - return stc; - } - } - - // Check escaping through nested context - if (outerVars && this.isMutable()) - { - foreach (VarDeclaration v; *outerVars) - { - if (v.hasPointers()) - return stc; - } - } - } - - // Check escaping through return value - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) - { - return stc | STC.scope_ | STC.return_ | STC.returnScope; - } - else - return stc | STC.scope_; - } - override Type addStorageClass(StorageClass stc) { //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); @@ -4631,11 +4250,6 @@ extern (C++) final class TypeDelegate : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4676,20 +4290,6 @@ extern (C++) final class TypeTraits : Type return tt; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Terror) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4729,20 +4329,6 @@ extern (C++) final class TypeMixin : Type return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4867,28 +4453,6 @@ extern (C++) final class TypeIdentifier : TypeQualified return t; } - /***************************************** - * See if type resolves to a symbol, if so, - * return that symbol. - */ - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); - if (!sc) - return null; - - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tident) - s = t.toDsymbol(sc); - if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4922,18 +4486,6 @@ extern (C++) final class TypeInstance : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - //printf("TypeInstance::semantic(%s)\n", toChars()); - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tinstance) - s = t.toDsymbol(sc); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4967,16 +4519,6 @@ extern (C++) final class TypeTypeof : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override uinteger_t size(const ref Loc loc) { if (exp.type) @@ -5013,15 +4555,6 @@ extern (C++) final class TypeReturn : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5068,11 +4601,6 @@ extern (C++) final class TypeStruct : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override structalign_t alignment() { if (sym.alignment.isUnknown()) @@ -5214,15 +4742,6 @@ extern (C++) final class TypeStruct : Type return false; } - override bool hasPointers() - { - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - error(sym.loc, "no size because of forward references"); - - sym.determineTypeProperties(); - return sym.hasPointerField; - } - override bool hasVoidInitPointers() { sym.size(Loc.initial); // give error for forward references @@ -5393,9 +4912,9 @@ extern (C++) final class TypeEnum : Type return sym.getMemtype(loc).size(loc); } - Type memType(const ref Loc loc = Loc.initial) + Type memType() { - return sym.getMemtype(loc); + return sym.getMemtype(Loc.initial); } override uint alignsize() @@ -5406,11 +4925,6 @@ extern (C++) final class TypeEnum : Type return t.alignsize(); } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override bool isintegral() { return memType().isintegral(); @@ -5511,11 +5025,6 @@ extern (C++) final class TypeEnum : Type return sym.getDefaultValue(loc).toBool().hasValue(false); } - override bool hasPointers() - { - return memType().hasPointers(); - } - override bool hasVoidInitPointers() { return memType().hasVoidInitPointers(); @@ -5571,44 +5080,14 @@ extern (C++) final class TypeClass : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override inout(ClassDeclaration) isClassHandle() inout { return sym; } - override bool isBaseOf(Type t, int* poffset) - { - if (t && t.ty == Tclass) - { - ClassDeclaration cd = (cast(TypeClass)t).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - - if (sym.isBaseOf(cd, poffset)) - return true; - } - return false; - } - extern (D) MATCH implicitConvToWithoutAliasThis(Type to) { - // Run semantic before checking whether class is convertible ClassDeclaration cdto = to.isClassHandle(); - if (cdto) - { - //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); - if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) - cdto.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - } MATCH m = constConv(to); if (m > MATCH.nomatch) return m; @@ -5706,11 +5185,6 @@ extern (C++) final class TypeClass : Type return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -5952,14 +5426,6 @@ extern (C++) final class TypeNull : Type return MATCH.nomatch; } - override bool hasPointers() - { - /* Although null isn't dereferencable, treat it as a pointer type for - * attribute inference, generic code, etc. - */ - return true; - } - override bool isBoolean() { return true; @@ -6633,39 +6099,6 @@ bool isIndexableNonAggregate(Type t) t.ty == Ttuple || t.ty == Tvector); } -/*************************************************** - * Determine if type t is copyable. - * Params: - * t = type to check - * Returns: - * true if we can copy it - */ -bool isCopyable(Type t) -{ - //printf("isCopyable() %s\n", t.toChars()); - if (auto ts = t.isTypeStruct()) - { - if (ts.sym.postblit && - ts.sym.postblit.storage_class & STC.disable) - return false; - if (ts.sym.hasCopyCtor) - { - // check if there is a matching overload of the copy constructor and whether it is disabled or not - // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 - Dsymbol ctor = search_function(ts.sym, Id.ctor); - assert(ctor); - scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue - el.type = cast() ts; - Expressions* args = new Expressions(); - args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); - if (!f || f.storage_class & STC.disable) - return false; - } - } - return true; -} - /*************************************** * Computes how a parameter may be returned. * Shrinking the representation is necessary because StorageClass is so wide diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 97a7ae3c5af..c777f359da4 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -233,7 +233,6 @@ public: uinteger_t size(); virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); - Type *trySemantic(const Loc &loc, Scope *sc); Type *merge2(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -287,9 +286,7 @@ public: virtual Type *makeSharedWild(); virtual Type *makeSharedWildConst(); virtual Type *makeMutable(); - virtual Dsymbol *toDsymbol(Scope *sc); Type *toBasetype(); - virtual bool isBaseOf(Type *t, int *poffset); virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); @@ -302,9 +299,7 @@ public: virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 - Identifier *getTypeInfoIdent(); virtual int hasWild() const; - virtual bool hasPointers(); virtual bool hasVoidInitPointers(); virtual bool hasSystemFields(); virtual bool hasInvariant(); @@ -451,7 +446,6 @@ public: MATCH constConv(Type *to) override; MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; - bool hasPointers() override; bool hasSystemFields() override; bool hasVoidInitPointers() override; bool hasInvariant() override; @@ -474,7 +468,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isBoolean() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -491,7 +484,6 @@ public: uinteger_t size(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; @@ -509,7 +501,6 @@ public: MATCH constConv(Type *to) override; bool isscalar() override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -605,10 +596,8 @@ public: static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0); const char *kind() override; TypeFunction *syntaxCopy() override; - void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; - StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false); Type *addStorageClass(StorageClass stc) override; Type *substWildTo(unsigned mod) override; @@ -659,7 +648,6 @@ public: MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -675,7 +663,6 @@ class TypeTraits final : public Type const char *kind() override; TypeTraits *syntaxCopy() override; uinteger_t size(const Loc &loc) override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -687,7 +674,6 @@ class TypeMixin final : public Type const char *kind() override; TypeMixin *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -713,7 +699,6 @@ public: static TypeIdentifier *create(const Loc &loc, Identifier *ident); const char *kind() override; TypeIdentifier *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -726,7 +711,6 @@ public: const char *kind() override; TypeInstance *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -738,7 +722,6 @@ public: const char *kind() override; TypeTypeof *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -748,7 +731,6 @@ class TypeReturn final : public TypeQualified public: const char *kind() override; TypeReturn *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -776,7 +758,6 @@ public: uinteger_t size(const Loc &loc) override; unsigned alignsize() override; TypeStruct *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; structalign_t alignment() override; Expression *defaultInitLiteral(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; @@ -785,7 +766,6 @@ public: bool needsDestruction() override; bool needsCopyOrPostblit() override; bool needsNested() override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -806,8 +786,7 @@ public: TypeEnum *syntaxCopy() override; uinteger_t size(const Loc &loc) override; unsigned alignsize() override; - Type *memType(const Loc &loc = Loc()); - Dsymbol *toDsymbol(Scope *sc) override; + Type *memType(const Loc &loc); bool isintegral() override; bool isfloating() override; bool isreal() override; @@ -824,7 +803,6 @@ public: MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -843,9 +821,7 @@ public: const char *kind() override; uinteger_t size(const Loc &loc) override; TypeClass *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; ClassDeclaration *isClassHandle() override; - bool isBaseOf(Type *t, int *poffset) override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; @@ -853,7 +829,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isscope() override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -894,7 +869,6 @@ public: TypeNull *syntaxCopy() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; bool isBoolean() override; uinteger_t size(const Loc &loc) override; @@ -925,6 +899,13 @@ public: /**************************************************************/ + // If the type is a class or struct, returns the symbol for it, else null. AggregateDeclaration *isAggregate(Type *t); +bool hasPointers(Type *t); +// return the symbol to which type t resolves +Dsymbol *toDsymbol(Type *t, Scope *sc); Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); +bool isBaseOf(Type *tthis, Type *t, int *poffset); +Type *trySemantic(Type *type, const Loc &loc, Scope *sc); +void purityLevel(TypeFunction *type); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index b5601a214dc..c2fa5fbd023 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -31,6 +31,7 @@ import dmd.location; bool checkMustUse(Expression e, Scope* sc) { import dmd.id : Id; + import dmd.typesem : toDsymbol; assert(e.type); if (auto sym = e.type.toDsymbol(sc)) diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 785912e1968..0a5981589c6 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -2566,6 +2566,7 @@ void checkObErrors(ref ObState obstate) //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); if (pvs.state == PtrState.Owner) { + import dmd.typesem : hasPointers; auto v = obstate.vars[i]; if (v.type.hasPointers()) .error(v.loc, "%s `%s` is not disposed of before return", v.kind, v.toPrettyChars); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index a012e0c7c5b..268622a82fc 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = CondExpression { nextToken(); - tp_defaultvalue = parseDefaultInitExp(); + tp_defaultvalue = parseAssignExp(); } tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } @@ -2969,7 +2969,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = defaultArg { nextToken(); - ae = parseDefaultInitExp(); + ae = parseAssignExp(); } auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null); if (udas) @@ -6949,33 +6949,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } - /***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. - */ - private AST.Expression parseDefaultInitExp() - { - AST.Expression e = null; - const tv = peekNext(); - if (tv == TOK.comma || tv == TOK.rightParenthesis) - { - switch (token.value) - { - case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break; - case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break; - case TOK.line: e = new AST.LineInitExp(token.loc); break; - case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break; - case TOK.functionString: e = new AST.FuncInitExp(token.loc); break; - case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break; - default: goto LExp; - } - nextToken(); - return e; - } - LExp: - return parseAssignExp(); - } - /******************** * Parse inline assembler block. * Enters with token on the `asm`. @@ -8152,33 +8125,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; case TOK.file: - { - const(char)* s = loc.filename ? loc.filename : mod.ident.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.file); + nextToken(); + break; case TOK.fileFullPath: - { - assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location"); - const s = FileName.toAbsolute(loc.filename); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.fileFullPath); + nextToken(); + break; case TOK.line: - e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32); + e = new AST.LineInitExp(loc); nextToken(); break; case TOK.moduleString: - { - const(char)* s = md ? md.toChars() : mod.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.ModuleInitExp(loc); + nextToken(); + break; case TOK.functionString: e = new AST.FuncInitExp(loc); nextToken(); diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index af81bff0dd1..8b57f7fe249 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -26,6 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; +import dmd.typesem : hasPointers; import dmd.func : setUnsafe, setUnsafePreview; /************************************************************* diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 1535fd07755..4b157cc9ee7 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -87,6 +87,7 @@ struct Scope Dsymbol *inunion; // !=null if processing members of a union d_bool nofree; // true if shouldn't free it d_bool inLoop; // true if inside a loop (where constructor calls aren't allowed) + d_bool inDefaultArg; // true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; // in typeof(exp) VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init ErrorSink *eSink; // sink for error messages diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 520e05f4190..174d9b4dc14 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -231,8 +231,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32) return true; - return f.next.ty == Tvoid && - (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain()); + return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain()); } VarDeclaration _arguments = null; @@ -346,6 +345,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.tf = null; sc2.os = null; sc2.inLoop = false; + sc2.inDefaultArg = false; sc2.userAttribDecl = null; if (sc2.intypeof == 1) sc2.intypeof = 2; @@ -570,7 +570,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv) { - funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel); + funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel, Loc.initial); } // scope of out contract (need for vresult.semantic) diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 59398a70cb8..8038770b291 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -24,6 +24,7 @@ import dmd.init; import dmd.mtype; import dmd.postordervisitor; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /************************************************** diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 229cf17bb6a..d4827ae6aa1 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3753,7 +3753,10 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) { if (!global.params.useExceptions) { - loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); + version (IN_GCC) + loc.error("cannot use `throw` statements with `-fno-exceptions`"); + else + loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); return false; } diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 09c4912a521..153eb4eb68b 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -324,4 +324,4 @@ Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); TemplateParameter *isTemplateParameter(RootObject *o); bool isError(const RootObject *const o); -void printTemplateStats(); +void printTemplateStats(bool listInstances, ErrorSink* eSink); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 51b4ef885f1..714af8a0568 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -430,6 +430,123 @@ private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject i return sm; } +/*************************************************** + * Determine if type t is copyable. + * Params: + * t = type to check + * Returns: + * true if we can copy it + */ +bool isCopyable(Type t) +{ + //printf("isCopyable() %s\n", t.toChars()); + if (auto ts = t.isTypeStruct()) + { + if (ts.sym.postblit && + ts.sym.postblit.storage_class & STC.disable) + return false; + if (ts.sym.hasCopyCtor) + { + // check if there is a matching overload of the copy constructor and whether it is disabled or not + // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 + Dsymbol ctor = search_function(ts.sym, Id.ctor); + assert(ctor); + scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue + el.type = cast() ts; + Expressions* args = new Expressions(); + args.push(el); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); + if (!f || f.storage_class & STC.disable) + return false; + } + } + return true; +} + +/************************************ + * Determine mutability of indirections in (ref) t. + * + * Returns: When the type has any mutable indirections, returns 0. + * When all indirections are immutable, returns 2. + * Otherwise, when the type has const/inout indirections, returns 1. + * + * Params: + * isref = if true, check `ref t`; otherwise, check just `t` + * t = the type that is being checked + */ +int mutabilityOfType(bool isref, Type t) +{ + if (isref) + { + if (t.mod & MODFlags.immutable_) + return 2; + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + return 0; + } + + t = t.baseElemOf(); + + if (!t.hasPointers() || t.mod & MODFlags.immutable_) + return 2; + + /* Accept immutable(T)[] and immutable(T)* as being strongly pure + */ + if (t.ty == Tarray || t.ty == Tpointer) + { + Type tn = t.nextOf().toBasetype(); + if (tn.mod & MODFlags.immutable_) + return 2; + if (tn.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + } + + /* The rest of this is too strict; fix later. + * For example, the only pointer members of a struct may be immutable, + * which would maintain strong purity. + * (Just like for dynamic arrays and pointers above.) + */ + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + + /* Should catch delegates and function pointers, and fold in their purity + */ + return 0; +} + +/******************************************** + * Set 'purity' field of 'typeFunction'. + * Do this lazily, as the parameter types might be forward referenced. + */ +extern(C++) void purityLevel(TypeFunction typeFunction) +{ + TypeFunction tf = typeFunction; + if (tf.purity != PURE.fwdref) + return; + + typeFunction.purity = PURE.const_; // assume strong until something weakens it + + /* Evaluate what kind of purity based on the modifiers for the parameters + */ + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + + if (fparam.storageClass & (STC.lazy_ | STC.out_)) + { + typeFunction.purity = PURE.weak; + break; + } + const pref = (fparam.storageClass & STC.ref_) != 0; + if (mutabilityOfType(pref, t) == 0) + typeFunction.purity = PURE.weak; + } + + tf.purity = typeFunction.purity; +} + /****************************************** * We've mistakenly parsed `t` as a type. * Redo `t` as an Expression only if there are no type modifiers. @@ -486,6 +603,77 @@ Expression typeToExpression(Type t) } } +/************************************* + * https://issues.dlang.org/show_bug.cgi?id=14488 + * Check if the inner most base type is complex or imaginary. + * Should only give alerts when set to emit transitional messages. + * Params: + * type = type to check + * loc = The source location. + * sc = scope of the type + */ +extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc) +{ + if (sc.isDeprecated()) + return false; + // Don't complain if we're inside a template constraint + // https://issues.dlang.org/show_bug.cgi?id=21831 + if (sc.flags & SCOPE.constraint) + return false; + + Type t = type.baseElemOf(); + while (t.ty == Tpointer || t.ty == Tarray) + t = t.nextOf().baseElemOf(); + + // Basetype is an opaque enum, nothing to check. + if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) + return false; + + if (t.isimaginary() || t.iscomplex()) + { + if (sc.flags & SCOPE.Cfile) + return true; // complex/imaginary not deprecated in C code + Type rt; + switch (t.ty) + { + case Tcomplex32: + case Timaginary32: + rt = Type.tfloat32; + break; + + case Tcomplex64: + case Timaginary64: + rt = Type.tfloat64; + break; + + case Tcomplex80: + case Timaginary80: + rt = Type.tfloat80; + break; + + default: + assert(0); + } + // @@@DEPRECATED_2.117@@@ + // Deprecated in 2.097 - Can be made an error from 2.117. + // The deprecation period is longer than usual as `cfloat`, + // `cdouble`, and `creal` were quite widely used. + if (t.iscomplex()) + { + deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", + type.toChars(), rt.toChars()); + return true; + } + else + { + deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", + type.toChars(), rt.toChars()); + return true; + } + } + return false; +} + /******************************** * 'args' are being matched to function type 'tf' * Determine match level. @@ -494,12 +682,12 @@ Expression typeToExpression(Type t) * tthis = type of `this` pointer, null if not member function * argumentList = arguments to function call * flag = 1: performing a partial ordering match - * pMessage = address to store error message, or null + * errorHelper = delegate to call for error messages * sc = context * Returns: * MATCHxxxx */ -extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) +extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null) { //printf("TypeFunction::callMatch() %s\n", tf.toChars()); MATCH match = MATCH.exact; // assume exact match @@ -542,7 +730,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis { // suppress early exit if an error message is wanted, // so we can check any matching args are valid - if (!pMessage) + if (!errorHelper) return MATCH.nomatch; } // too many args; no match @@ -552,18 +740,25 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis // https://issues.dlang.org/show_bug.cgi?id=22997 if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) { - OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); - if (pMessage) - *pMessage = buf.extractChars(); + if (errorHelper) + { + OutBuffer buf; + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); + errorHelper(buf.peekChars()); + } return MATCH.nomatch; } + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage); Expression[] args; if (!resolvedArgs) { - if (!pMessage || *pMessage) + if (failMessage) + { + errorHelper(failMessage); return MATCH.nomatch; + } // if no message was provided, it was because of overflow which will be diagnosed below match = MATCH.nomatch; @@ -642,6 +837,8 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) return vmatch < match ? vmatch : match; // Error message was already generated in `matchTypeSafeVarArgs` + if (failMessage) + errorHelper(failMessage); return MATCH.nomatch; } if (pMessage && u >= args.length) @@ -651,16 +848,18 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis else if (pMessage && !*pMessage) *pMessage = tf.getParamError(args[u], p); + if (errorHelper) + errorHelper(*pMessage); return MATCH.nomatch; } if (m < match) match = m; // pick worst match } - if (pMessage && !parameterList.varargs && args.length > nparams) + if (errorHelper && !parameterList.varargs && args.length > nparams) { // all parameters had a match, but there are surplus args - *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length); + errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length)); return MATCH.nomatch; } //printf("match = %d\n", match); @@ -687,7 +886,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, Expression e = new DotIdExp(arg.loc, ve, Id.ctor); e = new CallExp(arg.loc, e, arg); //printf("e = %s\n", e.toChars()); - if (.trySemantic(e, sc)) + if (dmd.expressionsem.trySemantic(e, sc)) return true; if (pMessage) @@ -1017,6 +1216,70 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, } } +/*************************************** + * Return !=0 if type has pointers that need to + * be scanned by the GC during a collection cycle. + */ +extern(C++) bool hasPointers(Type t) +{ + bool visitType(Type _) { return false; } + bool visitDArray(TypeDArray _) { return true; } + bool visitAArray(TypeAArray _) { return true; } + bool visitPointer(TypePointer _) { return true; } + bool visitDelegate(TypeDelegate _) { return true; } + bool visitClass(TypeClass _) { return true; } + bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); } + + /* Although null isn't dereferencable, treat it as a pointer type for + * attribute inference, generic code, etc. + */ + bool visitNull(TypeNull _) { return true; } + + bool visitSArray(TypeSArray t) + { + /* Don't want to do this, because: + * struct S { T* array[0]; } + * may be a variable length struct. + */ + //if (dim.toInteger() == 0) + // return false; + + if (t.next.ty == Tvoid) + { + // Arrays of void contain arbitrary data, which may include pointers + return true; + } + else + return t.next.hasPointers(); + } + + bool visitStruct(TypeStruct t) + { + StructDeclaration sym = t.sym; + + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + error(sym.loc, "no size because of forward references"); + + sym.determineTypeProperties(); + return sym.hasPointerField; + } + + + switch(t.ty) + { + default: return visitType(t); + case Tsarray: return visitSArray(t.isTypeSArray()); + case Tarray: return visitDArray(t.isTypeDArray()); + case Taarray: return visitAArray(t.isTypeAArray()); + case Tpointer: return visitPointer(t.isTypePointer()); + case Tdelegate: return visitDelegate(t.isTypeDelegate()); + case Tstruct: return visitStruct(t.isTypeStruct()); + case Tenum: return visitEnum(t.isTypeEnum()); + case Tclass: return visitClass(t.isTypeClass()); + case Tnull: return visitNull(t.isTypeNull()); + } +} + /****************************************** * Perform semantic analysis on a type. * Params: @@ -1661,9 +1924,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { e = inferType(e, fparam.type); + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; Initializer iz = new ExpInitializer(e.loc, e); - iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret); + iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret); e = iz.initializerToExpression(); + sc2.pop(); } if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { @@ -2553,6 +2819,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } } +extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc) +{ + //printf("+trySemantic(%s) %d\n", toChars(), global.errors); + + // Needed to display any deprecations that were gagged + auto tcopy = type.syntaxCopy(); + + const errors = global.startGagging(); + Type t = typeSemantic(type, loc, sc); + if (global.endGagging(errors) || t.ty == Terror) // if any errors happened + { + t = null; + } + else + { + // If `typeSemantic` succeeded, there may have been deprecations that + // were gagged due the `startGagging` above. Run again to display + // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 + if (global.gaggedWarnings > 0) + typeSemantic(tcopy, loc, sc); + } + //printf("-trySemantic(%s) %d\n", toChars(), global.errors); + return t; +} + /************************************ * If an identical type to `type` is in `type.stringtable`, return * the latter one. Otherwise, add it to `type.stringtable`. @@ -5216,6 +5507,117 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi } } +/* +If `type` resolves to a dsymbol, then that +dsymbol is returned. + +Params: + type = the type that is checked + sc = the scope where the type is used + +Returns: + The dsymbol to which the type resolve or `null` + if the type does resolve to any symbol (for example, + in the case of basic types). +*/ +extern(C++) Dsymbol toDsymbol(Type type, Scope* sc) +{ + Dsymbol visitType(Type _) { return null; } + Dsymbol visitStruct(TypeStruct type) { return type.sym; } + Dsymbol visitEnum(TypeEnum type) { return type.sym; } + Dsymbol visitClass(TypeClass type) { return type.sym; } + + Dsymbol visitTraits(TypeTraits type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Terror) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitMixin(TypeMixin type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitIdentifier(TypeIdentifier type) + { + //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); + if (!sc) + return null; + + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tident) + s = t.toDsymbol(sc); + if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitInstance(TypeInstance type) + { + Type t; + Expression e; + Dsymbol s; + //printf("TypeInstance::semantic(%s)\n", toChars()); + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tinstance) + s = t.toDsymbol(sc); + return s; + } + + Dsymbol visitTypeof(TypeTypeof type) + { + //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + Dsymbol visitReturn(TypeReturn type) + { + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + switch(type.ty) + { + default: return visitType(type); + case Ttraits: return visitTraits(type.isTypeTraits()); + case Tmixin: return visitMixin(type.isTypeMixin()); + case Tident: return visitIdentifier(type.isTypeIdentifier()); + case Tinstance: return visitInstance(type.isTypeInstance()); + case Ttypeof: return visitTypeof(type.isTypeTypeof()); + case Treturn: return visitReturn(type.isTypeReturn()); + case Tstruct: return visitStruct(type.isTypeStruct()); + case Tenum: return visitEnum(type.isTypeEnum()); + case Tclass: return visitClass(type.isTypeClass()); + } +} /********************************************** * Extract complex type from core.stdc.config @@ -5541,6 +5943,144 @@ Lnotcovariant: return Covariant.no; } +/************************************ + * Take the specified storage class for p, + * and use the function signature to infer whether + * STC.scope_ and STC.return_ should be OR'd in. + * (This will not affect the name mangling.) + * Params: + * tf = TypeFunction to use to get the signature from + * tthis = type of `this` parameter, null if none + * p = parameter to this function + * outerVars = context variables p could escape into, if any + * indirect = is this for an indirect or virtual function call? + * Returns: + * storage class with STC.scope_ or STC.return_ OR'd in + */ +StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null, + bool indirect = false) +{ + //printf("parameterStorageClass(p: %s)\n", p.toChars()); + auto stc = p.storageClass; + + // When the preview switch is enable, `in` parameters are `scope` + if (stc & STC.constscoperef) + return stc | STC.scope_; + + if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure) + return stc; + + /* If haven't inferred the return type yet, can't infer storage classes + */ + if (!tf.nextOf() || !tf.isnothrow()) + return stc; + + tf.purityLevel(); + + static bool mayHavePointers(Type t) + { + if (auto ts = t.isTypeStruct()) + { + auto sym = ts.sym; + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + // struct is forward referenced, so "may have" pointers + return true; + } + return t.hasPointers(); + } + + // See if p can escape via any of the other parameters + if (tf.purity == PURE.weak) + { + /* + * Indirect calls may escape p through a nested context + * See: + * https://issues.dlang.org/show_bug.cgi?id=24212 + * https://issues.dlang.org/show_bug.cgi?id=24213 + */ + if (indirect) + return stc; + + // Check escaping through parameters + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + t = t.baseElemOf(); // punch thru static arrays + if (t.isMutable() && t.hasPointers()) + { + if (fparam.isReference() && fparam != p) + return stc; + + if (t.ty == Tdelegate) + return stc; // could escape thru delegate + + if (t.ty == Tclass) + return stc; + + /* if t is a pointer to mutable pointer + */ + if (auto tn = t.nextOf()) + { + if (tn.isMutable() && mayHavePointers(tn)) + return stc; // escape through pointers + } + } + } + + // Check escaping through `this` + if (tthis && tthis.isMutable()) + { + foreach (VarDeclaration v; isAggregate(tthis).fields) + { + if (v.hasPointers()) + return stc; + } + } + + // Check escaping through nested context + if (outerVars && tf.isMutable()) + { + foreach (VarDeclaration v; *outerVars) + { + if (v.hasPointers()) + return stc; + } + } + } + + // Check escaping through return value + Type tret = tf.nextOf().toBasetype(); + if (tf.isref || tret.hasPointers()) + { + return stc | STC.scope_ | STC.return_ | STC.returnScope; + } + else + return stc | STC.scope_; +} + +extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset) +{ + auto tc = tthis.isTypeClass(); + if (!tc) + return false; + + if (!t || t.ty != Tclass) + return false; + + ClassDeclaration cd = t.isTypeClass().sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete()) + tc.sym.dsymbolSemantic(null); + + if (tc.sym.isBaseOf(cd, poffset)) + return true; + + return false; +} + /******************************* Private *****************************************/ private: diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 7e63b0ba890..6f596c5ac20 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -204,6 +204,22 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2) return compound_expr (lexpr, expr); } +/* Compile the function literal body. */ + +static void +build_lambda_tree (FuncLiteralDeclaration *fld, Type *type = NULL) +{ + /* This check is for lambda's, remove `vthis' as function isn't nested. */ + if (fld->tok == TOK::reserved && (type == NULL || type->ty == TY::Tpointer)) + { + fld->tok = TOK::function_; + fld->vthis = NULL; + } + + /* Compile the function literal body. */ + build_decl_tree (fld); +} + /* Implements the visitor interface to build the GCC trees of all Expression AST classes emitted from the D Front-end. All visit methods accept one parameter E, which holds the frontend AST @@ -2012,17 +2028,8 @@ public: void visit (FuncExp *e) final override { - Type *ftype = e->type->toBasetype (); - - /* This check is for lambda's, remove `vthis' as function isn't nested. */ - if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer) - { - e->fd->tok = TOK::function_; - e->fd->vthis = NULL; - } - - /* Compile the function literal body. */ - build_decl_tree (e->fd); + /* Compile the declaration. */ + build_lambda_tree (e->fd, e->type->toBasetype ()); /* If nested, this will be a trampoline. */ if (e->fd->isNested ()) @@ -2071,6 +2078,10 @@ public: if (e->var->isFuncDeclaration ()) result = maybe_reject_intrinsic (result); + /* Emit lambdas, same as is done in FuncExp. */ + if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ()) + build_lambda_tree (fld); + if (declaration_reference_p (e->var)) gcc_assert (POINTER_TYPE_P (TREE_TYPE (result))); else @@ -2105,19 +2116,9 @@ public: return; } - /* This check is same as is done in FuncExp for lambdas. */ - FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration (); - if (fld != NULL) - { - if (fld->tok == TOK::reserved) - { - fld->tok = TOK::function_; - fld->vthis = NULL; - } - - /* Compiler the function literal body. */ - build_decl_tree (fld); - } + /* Emit lambdas, same as is done in FuncExp. */ + if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ()) + build_lambda_tree (fld); if (this->constp_) { diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 257a2abe5d7..dfab0e651b9 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -259,7 +259,8 @@ create_tinfo_types (Module *mod) array_type_node, array_type_node, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node, - array_type_node, ptr_type_node, ptr_type_node, NULL); + array_type_node, ptr_type_node, d_ulong_type, + d_ulong_type, ptr_type_node, NULL); object_module = mod; } @@ -814,6 +815,7 @@ public: void *deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; + ulong[2] nameSig immutable(void)* m_RTInfo; Information relating to interfaces, and their vtables are laid out @@ -932,6 +934,10 @@ public: else this->layout_field (null_pointer_node); + /* ulong[2] nameSig; */ + this->layout_field (build_zero_cst (d_ulong_type)); + this->layout_field (build_zero_cst (d_ulong_type)); + /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); @@ -979,6 +985,10 @@ public: this->layout_field (null_array_node); this->layout_field (null_pointer_node); + /* ulong[2] nameSig; */ + this->layout_field (build_zero_cst (d_ulong_type)); + this->layout_field (build_zero_cst (d_ulong_type)); + /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); @@ -1084,7 +1094,7 @@ public: /* StructFlags m_flags; */ int m_flags = StructFlags::none; - if (ti->hasPointers ()) + if (hasPointers (ti)) m_flags |= StructFlags::hasPointers; this->layout_field (build_integer_cst (m_flags, d_uint_type)); diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d index 3bc699aa7da..9909620ae3f 100644 --- a/gcc/testsuite/gdc.test/compilable/b18242.d +++ b/gcc/testsuite/gdc.test/compilable/b18242.d @@ -7,7 +7,7 @@ class Object { } class TypeInfo { } class TypeInfo_Class : TypeInfo { - version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; } + version(D_LP64) { ubyte[136+16] _x; } else { ubyte[68+16] _x; } } class Throwable { } diff --git a/gcc/testsuite/gdc.test/compilable/issue24316.d b/gcc/testsuite/gdc.test/compilable/issue24316.d new file mode 100644 index 00000000000..16d8a8b09b7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue24316.d @@ -0,0 +1,13 @@ +struct S +{ + int i; +} + +int f(immutable S *s) +{ + return s.i; +} + +immutable S globalS = S(5); + +static assert (f(&globalS) == 5); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24295.d b/gcc/testsuite/gdc.test/fail_compilation/test24295.d new file mode 100644 index 00000000000..58b6e92df8f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24295.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -betterC + +/* +TEST_OUTPUT: +--- +fail_compilation/test24295.d(12): Error: expression `new int[](1$?:32=u|64=LU$)` allocates with the GC and cannot be used with switch `-betterC` +--- +*/ + +void f() +{ + int[] overlaps = new int[1]; +} diff --git a/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d new file mode 100644 index 00000000000..4278f7f5cde --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d @@ -0,0 +1,250 @@ +module imports.issue18919b; + +import core.stdc.stdio; + +// Remove directories from paths. Used to make the output platform-independent. +string baseName(string path) +{ + foreach_reverse (i, char c; path) + { + if (c == '/' || c == '\\') + return path[i + 1 .. $]; + } + return path; +} +const(char)* baseName(const(char)* path) +{ + for (const(char)* ptr = path; *ptr; ptr++) + { + if (*ptr == '/' || *ptr == '\\') + path = ptr + 1; + } + return path; +} + +void func1(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + file = baseName(file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, cast(int) line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +// https://issues.dlang.org/show_bug.cgi?id=21211 +void func2(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + file = baseName(file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + file, cast(int) line, func, pfunc, mod); +} + +// https://issues.dlang.org/show_bug.cgi?id=18919 +struct Loc3 +{ + string file; + size_t line; + string func; + string pfunc; + string mod; +} +void func3(Loc3 loc = Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +Loc3 defaultLoc3(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + return Loc3(file, line, func, pfunc, mod); +} +void func3b(Loc3 loc = defaultLoc3) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +enum Loc3Mixin = q{Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)}; +void func3c(Loc3 loc = mixin(Loc3Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +void func3d(Loc3* loc = new Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +struct Loc4 +{ + const(char)* file; + size_t line; + const(char)* func; + const(char)* pfunc; + const(char)* mod; +} +void func4(Loc4 loc = Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +Loc4 defaultLoc4(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + return Loc4(file, line, func, pfunc, mod); +} +void func4b(Loc4 loc = defaultLoc4) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +enum Loc4Mixin = q{Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)}; +void func4c(Loc4 loc = mixin(Loc4Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +void func4d(Loc4* loc = new Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} + +void func5(string file = baseName(__FILE__), int line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__)() +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +void func6(string file = baseName(__FILE__), int line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr)() +{ + printf("%s: %.*s:%d %s %s %s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, func, pfunc, mod); +} + +void func7(int expr1 = 1000 + __LINE__ * 2, + string expr2 = "file=" ~ baseName(__FILE__) ~ " func=" ~ __FUNCTION__, + int expr3 = __LINE__ > 5 ? 1 : 2) +{ + printf("%s: expr1=%d, %.*s, expr3=%d\n", __FUNCTION__.ptr, expr1, cast(int) expr2.length, expr2.ptr, expr3); +} + +immutable string[2] constants = ["constant1", "constant2"]; +void func8(int[] expr1 = [__LINE__, __LINE__ + 1000], + int[string] expr2 = [baseName(__FILE__): __LINE__], + string expr3 = constants[__LINE__ > 5], + string expr4 = __FILE__[0 .. __FILE__.length - 2]) +{ + expr4 = baseName(expr4); + printf("%s: expr1=[", __FUNCTION__.ptr); + foreach (i, x; expr1) + printf("%d, ", x); + printf("], expr2=["); + foreach (k, v; expr2) + printf("%.*s: %d, ", cast(int) k.length, k.ptr, v); + printf("], expr3=%.*s", cast(int) expr3.length, expr3.ptr); + printf(", expr4=%.*s\n", cast(int) expr4.length, expr4.ptr); +} + +void func9(void function(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__) + fp = (string file, size_t line, string mod) + { + file = baseName(file); + printf("imports.issue18919b.func9.fp: %.*s:%d %.*s\n", + cast(int) file.length, file.ptr, cast(int) line, + cast(int) mod.length, mod.ptr); + }) +{ + fp(); +} + +void func10(string expr1 = mixin(() { return "\"expr1=" ~ __MODULE__ ~ "\""; } ()), + string expr2 = mixin("\"expr2=" ~ __MODULE__ ~ "\"")) +{ + printf("%s: %.*s, %.*s\n", __FUNCTION__.ptr, + cast(int) expr1.length, expr1.ptr, + cast(int) expr2.length, expr2.ptr); +} + +template ctLoc3(string file, int line, + string func, string pfunc, string mod) +{ + enum Loc3 ctLoc3 = Loc3(file, line, func, pfunc, mod); +} + +void func11(Loc3 loc = ctLoc3!(baseName(__FILE__), __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +void func12(const(char)*[] args = [baseName(__FILE__.ptr), + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr]) +{ + printf("%s:", __FUNCTION__.ptr); + foreach (arg; args) + printf(" %s", arg); + printf("\n"); +} diff --git a/gcc/testsuite/gdc.test/runnable/issue18919.d b/gcc/testsuite/gdc.test/runnable/issue18919.d new file mode 100644 index 00000000000..815e018d649 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/issue18919.d @@ -0,0 +1,47 @@ +/* +EXTRA_SOURCES: imports/issue18919b.d +RUN_OUTPUT: +--- +imports.issue18919b.func1: issue18919.d:29 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func2: issue18919.d:30 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3: issue18919.d:31 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3b: issue18919.d:32 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3c: issue18919.d:33 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3d: issue18919.d:34 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4: issue18919.d:35 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4b: issue18919.d:36 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4c: issue18919.d:37 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4d: issue18919.d:38 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func5!("issue18919.d", 39, "issue18919.main", "void issue18919.main()", "issue18919").func5: issue18919.d:39 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func6!("issue18919.d", 40, "issue18919.main", "void issue18919.main()", "issue18919").func6: issue18919.d:40 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func7: expr1=1082, file=issue18919.d func=issue18919.main, expr3=1 +imports.issue18919b.func8: expr1=[42, 1042, ], expr2=[issue18919.d: 42, ], expr3=constant2, expr4=issue18919 +imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b +imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b +imports.issue18919b.func11: issue18919b.d:233 imports.issue18919b +imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919 +--- +*/ +import imports.issue18919b; + +void main() +{ + func1(); + func2(); + func3(); + func3b(); + func3c(); + func3d(); + func4(); + func4b(); + func4c(); + func4d(); + func5(); + func6(); + func7(); + func8(); + func9(); + func10(); + func11(); + func12(); +} diff --git a/gcc/testsuite/gdc.test/runnable/test18916.d b/gcc/testsuite/gdc.test/runnable/test18916.d index 0e844ada15a..f14f32c31eb 100644 --- a/gcc/testsuite/gdc.test/runnable/test18916.d +++ b/gcc/testsuite/gdc.test/runnable/test18916.d @@ -11,9 +11,9 @@ struct Line void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__)) { - assert(line1 == 12); + assert(line1 == 21); assert(line2 == 21); - assert(line3 == 12); + assert(line3 == 21); } void main() diff --git a/gcc/testsuite/gdc.test/runnable/testptrref.d b/gcc/testsuite/gdc.test/runnable/testptrref.d index 7255595cb57..af101b92464 100644 --- a/gcc/testsuite/gdc.test/runnable/testptrref.d +++ b/gcc/testsuite/gdc.test/runnable/testptrref.d @@ -3,6 +3,7 @@ version(CRuntime_Microsoft) { extern(C) { + extern __gshared void* __ImageBase; extern __gshared uint _DP_beg; extern __gshared uint _DP_end; extern __gshared uint _TP_beg; @@ -18,8 +19,8 @@ version(CRuntime_Microsoft) { import core.internal.traits : externDFunc; alias findImageSection = externDFunc!("rt.sections_win64.findImageSection", - void[] function(string name) nothrow @nogc); - dataSection = findImageSection(".data"); + void[] function(void* handle, string name) nothrow @nogc); + dataSection = findImageSection(&__ImageBase, ".data"); } void[] tlsRange; diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index aeb2aab8336..cbcbd1a97f1 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -179,7 +179,7 @@ void test7() void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__) { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -192,7 +192,7 @@ void test8() void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)() { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -8031,6 +8031,29 @@ void test18232() assert(u.method() == Canary.init); } +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24332 + +void test24332() +{ + class A {} + final class B : A {} + + auto foo(A a) { + return cast(B) a; + } + + auto a = new A(); + auto n = cast(B) a; + assert(n is null); + auto b = cast(A) new B(); + auto c = cast(B) b; + assert(c); + B e; + auto d = cast(B) cast(A) e; + assert(d is null); +} + /***************************************************/ int main() @@ -8352,6 +8375,7 @@ int main() test17349(); test17915(); test18232(); + test24332(); printf("Success\n"); return 0; diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 2b4400f398e..138b0b6fa7c 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce +bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/core/exception.d b/libphobos/libdruntime/core/exception.d index d2016b115f1..959ce83f02e 100644 --- a/libphobos/libdruntime/core/exception.d +++ b/libphobos/libdruntime/core/exception.d @@ -697,17 +697,17 @@ else * Throws: * $(LREF OutOfMemoryError). */ - extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ + extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ { // NOTE: Since an out of memory condition exists, no allocation must occur // while generating this object. - throw staticError!OutOfMemoryError(); + throw staticError!OutOfMemoryError(file, line); } - extern (C) noreturn onOutOfMemoryErrorNoGC() @trusted nothrow @nogc + extern (C) noreturn onOutOfMemoryErrorNoGC(string file = __FILE__, size_t line = __LINE__) @trusted nothrow @nogc { // suppress stacktrace until they are @nogc - throw staticError!OutOfMemoryError(false); + throw staticError!OutOfMemoryError(false, file, line); } } @@ -718,11 +718,11 @@ else * Throws: * $(LREF InvalidMemoryOperationError). */ -extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ +extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ { // The same restriction applies as for onOutOfMemoryError. The GC is in an // undefined state, thus no allocation must occur while generating this object. - throw staticError!InvalidMemoryOperationError(); + throw staticError!InvalidMemoryOperationError(file, line); } diff --git a/libphobos/libdruntime/core/internal/container/array.d b/libphobos/libdruntime/core/internal/container/array.d index 27292cdb1c3..b583341d06b 100644 --- a/libphobos/libdruntime/core/internal/container/array.d +++ b/libphobos/libdruntime/core/internal/container/array.d @@ -9,7 +9,7 @@ module core.internal.container.array; static import common = core.internal.container.common; -import core.exception : onOutOfMemoryErrorNoGC; +import core.exception : onOutOfMemoryError; struct Array(T) { @@ -47,7 +47,7 @@ nothrow: _length = nlength; } else - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); } @@ -103,7 +103,7 @@ nothrow: back = val; } else - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); } void popBack() diff --git a/libphobos/libdruntime/core/internal/container/common.d b/libphobos/libdruntime/core/internal/container/common.d index 582d63ba2a2..659b2b5e49c 100644 --- a/libphobos/libdruntime/core/internal/container/common.d +++ b/libphobos/libdruntime/core/internal/container/common.d @@ -18,7 +18,7 @@ void* xrealloc(void* ptr, size_t sz) nothrow @nogc if (!sz) { .free(ptr); return null; } if (auto nptr = .realloc(ptr, sz)) return nptr; - .free(ptr); onOutOfMemoryErrorNoGC(); + .free(ptr); onOutOfMemoryError(); assert(0); } @@ -27,7 +27,7 @@ void* xmalloc(size_t sz) nothrow @nogc import core.exception; if (auto nptr = .malloc(sz)) return nptr; - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); assert(0); } diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d index dbad0e6064f..76948c8bde8 100644 --- a/libphobos/libdruntime/core/internal/dassert.d +++ b/libphobos/libdruntime/core/internal/dassert.d @@ -180,6 +180,8 @@ private string miniFormat(V)(const scope ref V v) /// `shared` values are formatted as their base type static if (is(V == shared T, T)) { + import core.atomic : atomicLoad; + // Use atomics to avoid race conditions whenever possible static if (__traits(compiles, atomicLoad(v))) { @@ -472,11 +474,6 @@ private bool[] calcFieldOverlap(const scope size_t[] offsets) return overlaps; } -// This should be a local import in miniFormat but fails with a cyclic dependency error -// core.thread.osthread -> core.time -> object -> core.internal.array.capacity -// -> core.atomic -> core.thread -> core.thread.osthread -import core.atomic : atomicLoad; - /// Negates a comparison token, e.g. `==` is mapped to `!=` private string invertCompToken(scope string comp) pure nothrow @nogc @safe { diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d index 6f194126e7e..ca4577f0195 100644 --- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d +++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d @@ -94,8 +94,8 @@ private // Declared as an extern instead of importing core.exception // to avoid inlining - see https://issues.dlang.org/show_bug.cgi?id=13725. - void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; - void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc; + void onInvalidMemoryOperationError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc; + void onOutOfMemoryError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted nothrow @nogc; version (COLLECT_FORK) version (OSX) @@ -141,7 +141,7 @@ private GC initialize() auto gc = cast(ConservativeGC) cstdlib.malloc(__traits(classInstanceSize, ConservativeGC)); if (!gc) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); return emplace(gc); } @@ -160,7 +160,7 @@ class ConservativeGC : GC Gcx *gcx; // implementation - static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.lengthy); + static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.brief); static bool _inFinalizer; __gshared bool isPrecise = false; @@ -188,7 +188,7 @@ class ConservativeGC : GC gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof); if (!gcx) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); gcx.initialize(); if (config.initReserve) @@ -509,7 +509,7 @@ class ConservativeGC : GC auto p = gcx.alloc(size + SENTINEL_EXTRA, alloc_size, bits, ti); if (!p) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); debug (SENTINEL) { @@ -1968,7 +1968,7 @@ struct Gcx // tryAlloc will succeed if a new pool was allocated above, if it fails allocate a new pool now if (!tryAlloc() && (!newPool(1, false) || !tryAlloc())) // out of luck or memory - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); } assert(p !is null); L_hasBin: @@ -2008,7 +2008,7 @@ struct Gcx size_t pn; immutable npages = LargeObjectPool.numPages(size); if (npages == size_t.max) - onOutOfMemoryErrorNoGC(); // size just below size_t.max requested + onOutOfMemoryError(); // size just below size_t.max requested bool tryAlloc() nothrow { @@ -2248,7 +2248,7 @@ struct Gcx enum initSize = 64 * 1024; // Windows VirtualAlloc granularity immutable ncap = _cap ? 2 * _cap : initSize / RANGE.sizeof; auto p = cast(RANGE*)os_mem_map(ncap * RANGE.sizeof); - if (p is null) onOutOfMemoryErrorNoGC(); + if (p is null) onOutOfMemoryError(); debug (VALGRIND) makeMemUndefined(p[0..ncap]); if (_p !is null) { @@ -3394,7 +3394,7 @@ Lmark: scanThreadData = cast(ScanThreadData*) cstdlib.calloc(numScanThreads, ScanThreadData.sizeof); if (!scanThreadData) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); evStart.initialize(false, false); evDone.initialize(false, false); @@ -3610,7 +3610,7 @@ struct Pool { rtinfo = cast(immutable(size_t)**)cstdlib.malloc(npages * (size_t*).sizeof); if (!rtinfo) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); memset(rtinfo, 0, npages * (size_t*).sizeof); } else @@ -3633,13 +3633,13 @@ struct Pool pagetable = cast(Bins*)cstdlib.malloc(npages * Bins.sizeof); if (!pagetable) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); if (npages > 0) { bPageOffsets = cast(uint*)cstdlib.malloc(npages * uint.sizeof); if (!bPageOffsets) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); if (isLargeObject) { @@ -4643,14 +4643,14 @@ debug (LOGGING) { data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof); if (!data && allocdim) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); } else { Log *newdata; newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof); if (!newdata && allocdim) - onOutOfMemoryErrorNoGC(); + onOutOfMemoryError(); memcpy(newdata, data, dim * Log.sizeof); cstdlib.free(data); data = newdata; @@ -4989,8 +4989,8 @@ version (D_LP64) unittest // only run if the system has enough physical memory size_t sz = 2L^^32; //import core.stdc.stdio; - //printf("availphys = %lld", os_physical_mem()); - if (os_physical_mem() > sz) + //printf("availphys = %lld", os_physical_mem(true)); + if (os_physical_mem(true) > sz) { import core.memory; GC.collect(); diff --git a/libphobos/libdruntime/core/internal/gc/os.d b/libphobos/libdruntime/core/internal/gc/os.d index 38b60cbbcc4..0db1753575b 100644 --- a/libphobos/libdruntime/core/internal/gc/os.d +++ b/libphobos/libdruntime/core/internal/gc/os.d @@ -254,23 +254,26 @@ bool isLowOnMem(size_t mapped) nothrow @nogc /** Get the size of available physical memory + Params: + avail = if supported on the current platform, return the currently unused memory + rather than the installed physical memory Returns: size of installed physical RAM */ version (Windows) { - ulong os_physical_mem() nothrow @nogc + ulong os_physical_mem(bool avail) nothrow @nogc { import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS; MEMORYSTATUS stat; GlobalMemoryStatus(&stat); - return stat.dwTotalPhys; // limited to 4GB for Win32 + return avail ? stat.dwAvailPhys : stat.dwTotalPhys; // limited to 4GB for Win32 } } else version (Darwin) { extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow; - ulong os_physical_mem() nothrow @nogc + ulong os_physical_mem(bool avail) nothrow @nogc { enum { @@ -287,11 +290,15 @@ else version (Darwin) } else version (Posix) { - ulong os_physical_mem() nothrow @nogc + ulong os_physical_mem(bool avail) nothrow @nogc { - import core.sys.posix.unistd : sysconf, _SC_PAGESIZE, _SC_PHYS_PAGES; + import core.sys.posix.unistd; const pageSize = sysconf(_SC_PAGESIZE); - const pages = sysconf(_SC_PHYS_PAGES); + static if (__traits(compiles, _SC_AVPHYS_PAGES)) // not available on all platforms + const sc = avail ? _SC_AVPHYS_PAGES : _SC_PHYS_PAGES; + else + const sc = _SC_PHYS_PAGES; + const pages = sysconf(sc); return pageSize * pages; } } diff --git a/libphobos/libdruntime/core/internal/spinlock.d b/libphobos/libdruntime/core/internal/spinlock.d index 36d806ad014..b0ea8f6c902 100644 --- a/libphobos/libdruntime/core/internal/spinlock.d +++ b/libphobos/libdruntime/core/internal/spinlock.d @@ -53,9 +53,9 @@ shared struct SpinLock import core.time; if (k < pauseThresh) return core.atomic.pause(); - else if (k < 32) + else // if (k < 32) return Thread.yield(); - Thread.sleep(1.msecs); + // Thread.sleep(1.msecs); } private: diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d index 4f44b604c45..f2a48f9a3ae 100644 --- a/libphobos/libdruntime/core/memory.d +++ b/libphobos/libdruntime/core/memory.d @@ -266,8 +266,8 @@ extern(C): /** * Enables automatic garbage collection behavior if collections have - * previously been suspended by a call to disable. This function is - * reentrant, and must be called once for every call to disable before + * previously been suspended by a call to `GC.disable()`. This function is + * reentrant, and must be called once for every call to `GC.disable()` before * automatic collections are enabled. */ pragma(mangle, "gc_enable") static void enable() @safe nothrow pure; @@ -278,7 +278,12 @@ extern(C): * process footprint. Collections may continue to occur in instances * where the implementation deems necessary for correct program behavior, * such as during an out of memory condition. This function is reentrant, - * but enable must be called once for each call to disable. + * but `GC.enable()` must be called once for each call to `GC.disable()`. + * Unlike the + * $(LINK2 https://dlang.org/spec/function.html#nogc-functions, `@nogc` attribute), + * `GC.disable()` halts + * collections across all threads, yet still allows GC allocations. + * Disabling collections eliminates GC pauses. */ pragma(mangle, "gc_disable") static void disable() @safe nothrow pure; diff --git a/libphobos/libdruntime/core/stdc/assert_.d b/libphobos/libdruntime/core/stdc/assert_.d index d6cb8a608a0..c6d9d9f6cc2 100644 --- a/libphobos/libdruntime/core/stdc/assert_.d +++ b/libphobos/libdruntime/core/stdc/assert_.d @@ -113,6 +113,15 @@ else version (CRuntime_Musl) */ noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); } +else version (CRuntime_Newlib) +{ + /*** + * Assert failure function in the Newlib library. + */ + noreturn __assert(const(char)* file, int line, const(char)* exp); + /// + noreturn __assert_func(const(char)* file, int line, const(char)* func, const(char)* exp); +} else version (CRuntime_UClibc) { noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* func); diff --git a/libphobos/libdruntime/core/stdc/errno.d b/libphobos/libdruntime/core/stdc/errno.d index e503dd96195..ddec70f7af3 100644 --- a/libphobos/libdruntime/core/stdc/errno.d +++ b/libphobos/libdruntime/core/stdc/errno.d @@ -75,6 +75,14 @@ else version (CRuntime_Musl) alias errno = __errno_location; } } +else version (CRuntime_Newlib) +{ + extern (C) + { + ref int __errno(); + alias errno = __errno; + } +} else version (OpenBSD) { // https://github.com/openbsd/src/blob/master/include/errno.h @@ -164,7 +172,7 @@ else extern (C): -version (Windows) +version (CRuntime_DigitalMars) { enum EPERM = 1; /// Operation not permitted enum ENOENT = 2; /// No such file or directory @@ -250,6 +258,230 @@ version (Windows) enum ETXTBSY = 139; enum EWOULDBLOCK = 140; } +else version (CRuntime_Microsoft) +{ + enum EPERM = 1; /// Operation not permitted + enum ENOENT = 2; /// No such file or directory + enum ESRCH = 3; /// No such process + enum EINTR = 4; /// Interrupted system call + enum EIO = 5; /// I/O error + enum ENXIO = 6; /// No such device or address + enum E2BIG = 7; /// Argument list too long + enum ENOEXEC = 8; /// Exec format error + enum EBADF = 9; /// Bad file number + enum ECHILD = 10; /// No child processes + enum EAGAIN = 11; /// Try again + enum ENOMEM = 12; /// Out of memory + enum EACCES = 13; /// Permission denied + enum EFAULT = 14; /// Bad address + enum EBUSY = 16; /// Device or resource busy + enum EEXIST = 17; /// File exists + enum EXDEV = 18; /// Cross-device link + enum ENODEV = 19; /// No such device + enum ENOTDIR = 20; /// Not a directory + enum EISDIR = 21; /// Is a directory + enum EINVAL = 22; /// Invalid argument + enum ENFILE = 23; /// File table overflow + enum EMFILE = 24; /// Too many open files + enum ENOTTY = 25; /// Not a typewriter + enum EFBIG = 27; /// File too large + enum ENOSPC = 28; /// No space left on device + enum ESPIPE = 29; /// Illegal seek + enum EROFS = 30; /// Read-only file system + enum EMLINK = 31; /// Too many links + enum EPIPE = 32; /// Broken pipe + enum EDOM = 33; /// Math argument out of domain of func + enum ERANGE = 34; /// Math result not representable + enum EDEADLK = 36; /// Resource deadlock would occur + enum ENAMETOOLONG = 38; /// File name too long + enum ENOLCK = 39; /// No record locks available + enum ENOSYS = 40; /// Function not implemented + enum ENOTEMPTY = 41; /// Directory not empty + enum EILSEQ = 42; /// Illegal byte sequence + enum EDEADLOCK = EDEADLK; /// Resource deadlock would occur + + // POSIX compatibility + // See_Also: https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants + enum EADDRINUSE = 100; + enum EADDRNOTAVAIL = 101; + enum EAFNOSUPPORT = 102; + enum EALREADY = 103; + enum EBADMSG = 104; + enum ECANCELED = 105; + enum ECONNABORTED = 106; + enum ECONNREFUSED = 107; + enum ECONNRESET = 108; + enum EDESTADDRREQ = 109; + enum EHOSTUNREACH = 110; + enum EIDRM = 111; + enum EINPROGRESS = 112; + enum EISCONN = 113; + enum ELOOP = 114; + enum EMSGSIZE = 115; + enum ENETDOWN = 116; + enum ENETRESET = 117; + enum ENETUNREACH = 118; + enum ENOBUFS = 119; + enum ENODATA = 120; + enum ENOLINK = 121; + enum ENOMSG = 122; + enum ENOPROTOOPT = 123; + enum ENOSR = 124; + enum ENOSTR = 125; + enum ENOTCONN = 126; + enum ENOTRECOVERABLE = 127; + enum ENOTSOCK = 128; + enum ENOTSUP = 129; + enum EOPNOTSUPP = 130; + enum EOTHER = 131; + enum EOVERFLOW = 132; + enum EOWNERDEAD = 133; + enum EPROTO = 134; + enum EPROTONOSUPPORT = 135; + enum EPROTOTYPE = 136; + enum ETIME = 137; + enum ETIMEDOUT = 138; + enum ETXTBSY = 139; + enum EWOULDBLOCK = 140; +} +else version (CRuntime_Newlib) +{ + enum EPERM = 1; + enum ENOENT = 2; + enum ESRCH = 3; + enum EINTR = 4; + enum EIO = 5; + enum ENXIO = 6; + enum E2BIG = 7; + enum ENOEXEC = 8; + enum EBADF = 9; + enum ECHILD = 10; + enum EAGAIN = 11; + enum ENOMEM = 12; + enum EACCES = 13; + enum EFAULT = 14; + enum EBUSY = 16; + enum EEXIST = 17; + enum EXDEV = 18; + enum ENODEV = 19; + enum ENOTDIR = 20; + enum EISDIR = 21; + enum EINVAL = 22; + enum ENFILE = 23; + enum EMFILE = 24; + enum ENOTTY = 25; + enum ETXTBSY = 26; + enum EFBIG = 27; + enum ENOSPC = 28; + enum ESPIPE = 29; + enum EROFS = 30; + enum EMLINK = 31; + enum EPIPE = 32; + enum EDOM = 33; + enum ERANGE = 34; + enum ENOMSG = 35; + enum EIDRM = 36; + enum EDEADLK = 45; + enum ENOLCK = 46; + enum ENOSTR = 60; + enum ENODATA = 61; + enum ETIME = 62; + enum ENOSR = 63; + enum ENOLINK = 67; + enum EPROTO = 71; + enum EMULTIHOP = 74; + enum EBADMSG = 77; + enum EFTYPE = 79; + enum ENOSYS = 88; + enum ENOTEMPTY = 90; + enum ENAMETOOLONG = 91; + enum ELOOP = 92; + enum EOPNOTSUPP = 95; + enum EPFNOSUPPORT = 96; + enum ECONNRESET = 104; + enum ENOBUFS = 105; + enum EAFNOSUPPORT = 106; + enum EPROTOTYPE = 107; + enum ENOTSOCK = 108; + enum ENOPROTOOPT = 109; + enum ECONNREFUSED = 111; + enum EADDRINUSE = 112; + enum ECONNABORTED = 113; + enum ENETUNREACH = 114; + enum ENETDOWN = 115; + enum ETIMEDOUT = 116; + enum EHOSTDOWN = 117; + enum EHOSTUNREACH = 118; + enum EINPROGRESS = 119; + enum EALREADY = 120; + enum EDESTADDRREQ = 121; + enum EMSGSIZE = 122; + enum EPROTONOSUPPORT = 123; + enum EADDRNOTAVAIL = 125; + enum ENETRESET = 126; + enum EISCONN = 127; + enum ENOTCONN = 128; + enum ETOOMANYREFS = 129; + enum EDQUOT = 132; + enum ESTALE = 133; + enum ENOTSUP = 134; + enum EILSEQ = 138; + enum EOVERFLOW = 139; + enum ECANCELED = 140; + enum ENOTRECOVERABLE = 141; + enum EOWNERDEAD = 142; + + enum EWOULDBLOCK = EAGAIN; + + enum __ELASTERROR = 2000; + + // Linux errno extensions + version (Cygwin) + { + enum ENOTBLK = 15; + enum ECHRNG = 37; + enum EL2NSYNC = 38; + enum EL3HLT = 39; + enum EL3RST = 40; + enum ELNRNG = 41; + enum EUNATCH = 42; + enum ENOCSI = 43; + enum EL2HLT = 44; + enum EBADE = 50; + enum EBADR = 51; + enum EXFULL = 52; + enum ENOANO = 53; + enum EBADRQC = 54; + enum EBADSLT = 55; + enum EDEADLOCK = 56; + enum EBFONT = 57; + enum ENONET = 64; + enum ENOPKG = 65; + enum EREMOTE = 66; + enum EADV = 68; + enum ESRMNT = 69; + enum ECOMM = 70; + enum ELBIN = 75; + enum EDOTDOT = 76; + enum ENOTUNIQ = 80; + enum EBADFD = 81; + enum EREMCHG = 82; + enum ELIBACC = 83; + enum ELIBBAD = 84; + enum ELIBSCN = 85; + enum ELIBMAX = 86; + enum ELIBEXEC = 87; + enum ENMFILE = 89; + enum ESHUTDOWN = 110; + enum ESOCKTNOSUPPORT = 124; + enum EPROCLIM = 130; + enum EUSERS = 131; + enum ENOMEDIUM = 135; + enum ENOSHARE = 136; + enum ECASECLASH = 137; + enum ESTRPIPE = 143; + } +} else version (linux) { enum EPERM = 1; /// diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d index 0051ecdb7c9..a7364c0a211 100644 --- a/libphobos/libdruntime/core/stdc/fenv.d +++ b/libphobos/libdruntime/core/stdc/fenv.d @@ -448,6 +448,49 @@ else version (CRuntime_Musl) static assert(false, "Architecture not supported."); } } +else version (CRuntime_Newlib) +{ + version (AArch64) + { + alias fenv_t = ulong; + alias fexcept_t = ulong; + } + else version (RISCV_Any) + { + alias fenv_t = size_t; + alias fexcept_t = size_t; + } + else version (X86_Any) + { + struct fenv_t + { + uint _fpu_cw; + uint _fpu_sw; + uint _fpu_tagw; + uint _fpu_ipoff; + uint _fpu_ipsel; + uint _fpu_opoff; + uint _fpu_opsel; + uint _sse_mxcsr; + } + alias fexcept_t = uint; + } + else version (SPARC64) + { + alias fenv_t = ulong; + alias fexcept_t = ulong; + } + else version (SPARC) + { + alias fenv_t = uint; + alias fexcept_t = uint; + } + else + { + alias fenv_t = int; + alias fexcept_t = int; + } +} else version (CRuntime_UClibc) { version (X86) diff --git a/libphobos/libdruntime/core/stdc/locale.d b/libphobos/libdruntime/core/stdc/locale.d index 4b8d5c82e02..357d75e9589 100644 --- a/libphobos/libdruntime/core/stdc/locale.d +++ b/libphobos/libdruntime/core/stdc/locale.d @@ -252,6 +252,23 @@ else version (CRuntime_Musl) /// enum LC_ALL = 6; } +else version (CRuntime_Newlib) +{ + /// + enum LC_ALL = 0; + /// + enum LC_COLLATE = 1; + /// + enum LC_CTYPE = 2; + /// + enum LC_MONETARY = 3; + /// + enum LC_NUMERIC = 4; + /// + enum LC_TIME = 5; + /// + enum LC_MESSAGES = 6; +} else version (CRuntime_UClibc) { /// diff --git a/libphobos/libdruntime/core/stdc/stdio.d b/libphobos/libdruntime/core/stdc/stdio.d index ee37da1a5dd..1fc046163ee 100644 --- a/libphobos/libdruntime/core/stdc/stdio.d +++ b/libphobos/libdruntime/core/stdc/stdio.d @@ -328,6 +328,30 @@ else version (CRuntime_Bionic) int _size; } } +else version (CRuntime_Newlib) +{ + enum + { + /// + BUFSIZ = 1024, + /// + EOF = -1, + /// + FOPEN_MAX = 20, + /// + FILENAME_MAX = 1024, + /// + TMP_MAX = 26, + /// + L_tmpnam = 1024 + } + + struct __sbuf + { + ubyte* _base; + int _size; + } +} else version (CRuntime_UClibc) { enum @@ -769,6 +793,57 @@ else version (CRuntime_Bionic) /// alias shared(__sFILE) FILE; } +else version (CRuntime_Newlib) +{ + import core.sys.posix.sys.types : ssize_t; + import core.stdc.wchar_ : mbstate_t; + + /// + alias fpos_t = c_long; + + /// + struct __sFILE + { + ubyte* _p; + int _r; + int _w; + short _flags; + short _file; + __sbuf _bf; + int _lbfsize; + + void* _data; + void* _cookie; + + ssize_t function(void*, void*, scope char*, size_t) _read; + ssize_t function(void*, void*, scope const char*, size_t) _write; + fpos_t function(void*, void*, fpos_t, int) _seek; + int function(void*, void*) _close; + + __sbuf _ub; + ubyte* _up; + int _ur; + + ubyte[3] _ubuf; + ubyte[1] _nbuf; + + __sbuf _lb; + + int _blksize; + int _flags2; + + long _offset; + void* _unused; + + void* _lock; + mbstate_t _mbstate; + } + + /// + alias __sFILE _iobuf; // needed for phobos + /// + alias shared(__sFILE) FILE; +} else version (CRuntime_UClibc) { import core.stdc.wchar_ : mbstate_t; @@ -1137,6 +1212,40 @@ else version (CRuntime_Musl) _IONBF = 2, } } +else version (CRuntime_Newlib) +{ + enum + { + /// + _IOFBF = 0, + /// + _IOLBF = 1, + /// + _IONBF = 2, + } + + private + { + shared struct _reent + { + int _errno; + __sFILE* _stdin; + __sFILE* _stdout; + __sFILE* _stderr; + } + _reent* __getreent(); + } + + pragma(inline, true) + { + /// + @property auto stdin()() { return __getreent()._stdin; } + /// + @property auto stdout()() { return __getreent()._stdout; } + /// + @property auto stderr()() { return __getreent()._stderr; } + } +} else version (CRuntime_UClibc) { enum @@ -1869,6 +1978,47 @@ else version (CRuntime_Musl) pragma(printf) int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg); } +else version (CRuntime_Newlib) +{ + // No unsafe pointer manipulation. + @trusted + { + /// + void rewind(FILE* stream); + /// + pure void clearerr(FILE* stream); + /// + pure int feof(FILE* stream); + /// + pure int ferror(FILE* stream); + /// + int fileno(FILE *); + } + + /// + pragma(printf) + int snprintf(scope char* s, size_t n, scope const char* format, scope const ...); + /// + pragma(printf) + int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg); + + // + // Gnu under-the-hood C I/O functions. Uses _iobuf* for the unshared + // version of FILE*, usable when the FILE is locked. + // See http://gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html + // + import core.stdc.wchar_ : wint_t; + import core.stdc.stddef : wchar_t; + + /// + int fputc_unlocked(int c, _iobuf* stream); + /// + int fgetc_unlocked(_iobuf* stream); + /// + wint_t fputwc_unlocked(wchar_t wc, _iobuf* stream); + /// + wint_t fgetwc_unlocked(_iobuf* stream); +} else version (CRuntime_UClibc) { // No unsafe pointer manipulation. diff --git a/libphobos/libdruntime/core/stdc/stdlib.d b/libphobos/libdruntime/core/stdc/stdlib.d index 0b42de8ec3b..bd5fc2b15ea 100644 --- a/libphobos/libdruntime/core/stdc/stdlib.d +++ b/libphobos/libdruntime/core/stdc/stdlib.d @@ -28,6 +28,8 @@ else version (WatchOS) version (CRuntime_Glibc) version = AlignedAllocSupported; +else version (CRuntime_Newlib) + version = AlignedAllocSupported; else {} extern (C): @@ -97,6 +99,7 @@ else version (DragonFlyBSD) enum RAND_MAX = 0x7fffffff; else version (Solaris) enum RAND_MAX = 0x7fff; else version (CRuntime_Bionic) enum RAND_MAX = 0x7fffffff; else version (CRuntime_Musl) enum RAND_MAX = 0x7fffffff; +else version (CRuntime_Newlib) enum RAND_MAX = 0x7fffffff; else version (CRuntime_UClibc) enum RAND_MAX = 0x7fffffff; else version (WASI) enum RAND_MAX = 0x7fffffff; else static assert( false, "Unsupported platform" ); diff --git a/libphobos/libdruntime/core/stdc/string.d b/libphobos/libdruntime/core/stdc/string.d index 3591a6d2d77..b9e3bb7568c 100644 --- a/libphobos/libdruntime/core/stdc/string.d +++ b/libphobos/libdruntime/core/stdc/string.d @@ -72,8 +72,15 @@ version (ReturnStrerrorR) const(char)* strerror_r(int errnum, return scope char* buf, size_t buflen); } // This one is +else version (CRuntime_Newlib) +{ + /// + pragma(mangle, "__xpg_strerror_r") + int strerror_r(int errnum, scope char* buf, size_t buflen); +} else { + /// int strerror_r(int errnum, scope char* buf, size_t buflen); } /// diff --git a/libphobos/libdruntime/core/stdc/wchar_.d b/libphobos/libdruntime/core/stdc/wchar_.d index 2d01e2634dc..6ed2dfe8318 100644 --- a/libphobos/libdruntime/core/stdc/wchar_.d +++ b/libphobos/libdruntime/core/stdc/wchar_.d @@ -106,6 +106,20 @@ else version (Solaris) /// alias mbstate_t = __mbstate_t; } +else version (CRuntime_Newlib) +{ + /// + struct mbstate_t + { + int __count; + union ___value + { + wint_t __wch = 0; + char[4] __wchb; + } + ___value __value; + } +} else version (CRuntime_UClibc) { /// diff --git a/libphobos/libdruntime/core/sys/windows/basetsd.d b/libphobos/libdruntime/core/sys/windows/basetsd.d index e70dbdc6c22..1e5a45427c7 100644 --- a/libphobos/libdruntime/core/sys/windows/basetsd.d +++ b/libphobos/libdruntime/core/sys/windows/basetsd.d @@ -15,9 +15,6 @@ version (Windows): // import. alias HANDLE = void*; -package template DECLARE_HANDLE(string name, base = HANDLE) { - mixin ("alias " ~ base.stringof ~ " " ~ name ~ ";"); -} alias HANDLE* PHANDLE, LPHANDLE; // helper for aligned structs diff --git a/libphobos/libdruntime/core/sys/windows/commctrl.d b/libphobos/libdruntime/core/sys/windows/commctrl.d index dabee5672b9..fe4ebbc75d8 100644 --- a/libphobos/libdruntime/core/sys/windows/commctrl.d +++ b/libphobos/libdruntime/core/sys/windows/commctrl.d @@ -1740,8 +1740,8 @@ enum { I_CHILDRENCALLBACK = -1 } -mixin DECLARE_HANDLE!("HTREEITEM"); -mixin DECLARE_HANDLE!("HIMAGELIST"); +alias HTREEITEM = HANDLE; +alias HIMAGELIST = HANDLE; version (Win64) { @@ -4482,8 +4482,8 @@ static if (_WIN32_IE >= 0x400) { alias RBHITTESTINFO* LPRBHITTESTINFO; } -mixin DECLARE_HANDLE!("HDSA"); -mixin DECLARE_HANDLE!("HDPA"); +alias HDSA = HANDLE; +alias HDPA = HANDLE; version (Unicode) { alias HDITEMW HDITEM; diff --git a/libphobos/libdruntime/core/sys/windows/ddeml.d b/libphobos/libdruntime/core/sys/windows/ddeml.d index 00bad1d300d..2e8e3ee25d6 100644 --- a/libphobos/libdruntime/core/sys/windows/ddeml.d +++ b/libphobos/libdruntime/core/sys/windows/ddeml.d @@ -15,10 +15,10 @@ pragma(lib, "user32"); import core.sys.windows.basetsd, core.sys.windows.windef, core.sys.windows.winnt; -mixin DECLARE_HANDLE!("HCONVLIST"); -mixin DECLARE_HANDLE!("HCONV"); -mixin DECLARE_HANDLE!("HSZ"); -mixin DECLARE_HANDLE!("HDDEDATA"); +alias HCONVLIST = HANDLE; +alias HCONV = HANDLE; +alias HSZ = HANDLE; +alias HDDEDATA = HANDLE; enum : int { CP_WINANSI = 1004, diff --git a/libphobos/libdruntime/core/sys/windows/dll.d b/libphobos/libdruntime/core/sys/windows/dll.d index 5b02fb55801..77141d5deb3 100644 --- a/libphobos/libdruntime/core/sys/windows/dll.d +++ b/libphobos/libdruntime/core/sys/windows/dll.d @@ -487,10 +487,20 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads, }, null ); } -/** same as above, but only usable if druntime is linked statically +version (Shared) version (DigitalMars) private extern(C) extern __gshared void* __ImageBase; + +/** same as above, but checking for shared runtime */ +pragma(inline, false) // version (Shared) only set when compiling druntime bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true ) { + version (Shared) version (DigitalMars) + { + // cannot declare rt_initSharedModule globally as it then conflicts with the definition in sections_win64.d + pragma(mangle, "rt_initSharedModule") extern(C) bool rt_initSharedModule( void* handle ); + if ( hInstance != &__ImageBase ) + return rt_initSharedModule( hInstance ); + } version (Win64) { return dll_process_attach( hInstance, attach_threads, @@ -506,8 +516,16 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true ) /** * to be called from DllMain with reason DLL_PROCESS_DETACH */ +pragma(inline, false) // version (Shared) only set when compiling druntime void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true ) { + version (Shared) version (DigitalMars) + { + // cannot declare rt_termSharedModule globally as it then conflicts with the definition in sections_win64.d + pragma(mangle, "rt_termSharedModule") extern(C) bool rt_termSharedModule( void* handle ); + if ( hInstance != &__ImageBase ) + return cast(void) rt_termSharedModule( hInstance ); + } // notify core.thread.joinLowLevelThread that the DLL is about to be unloaded thread_DLLProcessDetaching = true; @@ -531,6 +549,21 @@ void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true ) Runtime.terminate(); } +/***************************** +* Check whether the D runtime is built as a DLL or linked statically +* +* Returns: +* true = DLL, false = static library +*/ +pragma(inline, false) // version (Shared) only set when compiling druntime +bool isSharedDRuntime() +{ + version (Shared) + return true; + else + return false; +} + /* Make sure that tlsCtorRun is itself a tls variable */ static bool tlsCtorRun; @@ -542,8 +575,15 @@ static ~this() { tlsCtorRun = false; } * Returns: * true for success, false for failure */ -bool dll_thread_attach( bool attach_thread = true, bool initTls = true ) +pragma(inline, false) // version (Shared) only set when compiling druntime +bool dll_thread_attach( bool attach_thread = true, bool initTls = true, HINSTANCE hInstance = null ) { + version (Shared) version (DigitalMars) + { + if ( hInstance && hInstance != &__ImageBase ) + return true; + } + // if the OS has not prepared TLS for us, don't attach to the thread // (happened when running under x64 OS) auto tid = GetCurrentThreadId(); @@ -565,8 +605,15 @@ bool dll_thread_attach( bool attach_thread = true, bool initTls = true ) * Returns: * true for success, false for failure */ -bool dll_thread_detach( bool detach_thread = true, bool exitTls = true ) +pragma(inline, false) // version (Shared) only set when compiling druntime +bool dll_thread_detach( bool detach_thread = true, bool exitTls = true, HINSTANCE hInstance = null ) { + version (Shared) version (DigitalMars) + { + if ( hInstance && hInstance != &__ImageBase ) + return true; + } + // if the OS has not prepared TLS for us, we did not attach to the thread if ( !GetTlsDataAddress( GetCurrentThreadId() ) ) return false; @@ -613,10 +660,10 @@ mixin template SimpleDllMain() return true; case DLL_THREAD_ATTACH: - return dll_thread_attach( true, true ); + return dll_thread_attach( true, true, hInstance ); case DLL_THREAD_DETACH: - return dll_thread_detach( true, true ); + return dll_thread_detach( true, true, hInstance ); } } } diff --git a/libphobos/libdruntime/core/sys/windows/httpext.d b/libphobos/libdruntime/core/sys/windows/httpext.d index 6973879abf3..200b2843c4d 100644 --- a/libphobos/libdruntime/core/sys/windows/httpext.d +++ b/libphobos/libdruntime/core/sys/windows/httpext.d @@ -19,7 +19,7 @@ version (Windows): MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ -import core.sys.windows.basetsd /+: DECLARE_HANDLE, HANDLE+/; +import core.sys.windows.basetsd /+: HANDLE+/; import core.sys.windows.windef /+: BOOL, CHAR, DWORD, LPBYTE, LPDWORD+/; import core.sys.windows.winnt /+: LPCSTR, LPSTR, LPVOID, PVOID, VOID+/; @@ -47,7 +47,7 @@ enum { HSE_IO_SEND_HEADERS = 0x00000008 } -mixin DECLARE_HANDLE!("HCONN"); +alias HCONN = HANDLE; struct HSE_VERSION_INFO { DWORD dwExtensionVersion; diff --git a/libphobos/libdruntime/core/sys/windows/imagehlp.d b/libphobos/libdruntime/core/sys/windows/imagehlp.d index 399c0b2b1af..68d88d78780 100644 --- a/libphobos/libdruntime/core/sys/windows/imagehlp.d +++ b/libphobos/libdruntime/core/sys/windows/imagehlp.d @@ -275,7 +275,7 @@ struct IMAGEHLP_DUPLICATE_SYMBOL { } alias IMAGEHLP_DUPLICATE_SYMBOL* PIMAGEHLP_DUPLICATE_SYMBOL; -mixin DECLARE_HANDLE!("DIGEST_HANDLE"); +alias DIGEST_HANDLE = HANDLE; extern (Windows) { alias BOOL function(IMAGEHLP_STATUS_REASON, LPSTR, LPSTR, ULONG_PTR, ULONG_PTR) diff --git a/libphobos/libdruntime/core/sys/windows/msacm.d b/libphobos/libdruntime/core/sys/windows/msacm.d index 645e40d4ecb..df4d6c4fc92 100644 --- a/libphobos/libdruntime/core/sys/windows/msacm.d +++ b/libphobos/libdruntime/core/sys/windows/msacm.d @@ -14,8 +14,8 @@ version (ANSI) {} else version = Unicode; import core.sys.windows.basetsd, core.sys.windows.mmsystem, core.sys.windows.windef; -mixin DECLARE_HANDLE!("HACMDRIVERID"); -mixin DECLARE_HANDLE!("HACMDRIVER"); +alias HACMDRIVERID = HANDLE; +alias HACMDRIVER = HANDLE; alias HACMDRIVER* LPHACMDRIVER; enum size_t diff --git a/libphobos/libdruntime/core/sys/windows/ntsecapi.d b/libphobos/libdruntime/core/sys/windows/ntsecapi.d index fbc6b7f6b99..fa08a74ee5b 100644 --- a/libphobos/libdruntime/core/sys/windows/ntsecapi.d +++ b/libphobos/libdruntime/core/sys/windows/ntsecapi.d @@ -666,7 +666,7 @@ struct POLICY_DOMAIN_KERBEROS_TICKET_INFO { } alias POLICY_DOMAIN_KERBEROS_TICKET_INFO* PPOLICY_DOMAIN_KERBEROS_TICKET_INFO; -mixin DECLARE_HANDLE!("LSA_HANDLE"); +alias LSA_HANDLE = HANDLE; alias LSA_HANDLE* PLSA_HANDLE; struct TRUSTED_DOMAIN_NAME_INFO { diff --git a/libphobos/libdruntime/core/sys/windows/ole.d b/libphobos/libdruntime/core/sys/windows/ole.d index a844124bdb7..b9e55a3b129 100644 --- a/libphobos/libdruntime/core/sys/windows/ole.d +++ b/libphobos/libdruntime/core/sys/windows/ole.d @@ -155,7 +155,7 @@ enum OLEOPT_UPDATE { // #endif } -mixin DECLARE_HANDLE!("HOBJECT"); +alias HOBJECT = HANDLE; alias LONG_PTR LHSERVER, LHCLIENTDOC, LHSERVERDOC; struct OLEOBJECTVTBL { diff --git a/libphobos/libdruntime/core/sys/windows/prsht.d b/libphobos/libdruntime/core/sys/windows/prsht.d index 92596b5b548..053b1fa2ac9 100644 --- a/libphobos/libdruntime/core/sys/windows/prsht.d +++ b/libphobos/libdruntime/core/sys/windows/prsht.d @@ -247,7 +247,7 @@ struct PROPSHEETPAGEW { alias PROPSHEETPAGEW* LPPROPSHEETPAGEW; alias const(PROPSHEETPAGEW)* LPCPROPSHEETPAGEW; -mixin DECLARE_HANDLE!("HPROPSHEETPAGE"); +alias HPROPSHEETPAGE = HANDLE; struct PROPSHEETHEADERA { DWORD dwSize = PROPSHEETHEADERA.sizeof; diff --git a/libphobos/libdruntime/core/sys/windows/rpcdce.d b/libphobos/libdruntime/core/sys/windows/rpcdce.d index 4f3f3cc1f66..951480b955d 100644 --- a/libphobos/libdruntime/core/sys/windows/rpcdce.d +++ b/libphobos/libdruntime/core/sys/windows/rpcdce.d @@ -160,8 +160,8 @@ struct RPC_IF_ID_VECTOR { uint Count; RPC_IF_ID*[1] IfId; } -mixin DECLARE_HANDLE!("RPC_AUTH_IDENTITY_HANDLE"); -mixin DECLARE_HANDLE!("RPC_AUTHZ_HANDLE"); +alias RPC_AUTH_IDENTITY_HANDLE = HANDLE; +alias RPC_AUTHZ_HANDLE = HANDLE; struct RPC_SECURITY_QOS { uint Version; diff --git a/libphobos/libdruntime/core/sys/windows/rpcdcep.d b/libphobos/libdruntime/core/sys/windows/rpcdcep.d index 71b82be7a7f..421c2752b1c 100644 --- a/libphobos/libdruntime/core/sys/windows/rpcdcep.d +++ b/libphobos/libdruntime/core/sys/windows/rpcdcep.d @@ -15,7 +15,7 @@ import core.sys.windows.basetyps; import core.sys.windows.w32api; import core.sys.windows.windef; -mixin DECLARE_HANDLE!("I_RPC_HANDLE"); +alias I_RPC_HANDLE = HANDLE; alias long RPC_STATUS; enum RPC_NCA_FLAGS_DEFAULT=0; diff --git a/libphobos/libdruntime/core/sys/windows/rpcnsi.d b/libphobos/libdruntime/core/sys/windows/rpcnsi.d index 1294d0dc08c..60c7b0972af 100644 --- a/libphobos/libdruntime/core/sys/windows/rpcnsi.d +++ b/libphobos/libdruntime/core/sys/windows/rpcnsi.d @@ -18,7 +18,7 @@ import core.sys.windows.basetyps, core.sys.windows.rpcdcep, core.sys.windows.rpc core.sys.windows.w32api; import core.sys.windows.windef; // for HANDLE -mixin DECLARE_HANDLE!("RPC_NS_HANDLE"); +alias RPC_NS_HANDLE = HANDLE; enum RPC_C_NS_SYNTAX_DEFAULT=0; enum RPC_C_NS_SYNTAX_DCE=3; diff --git a/libphobos/libdruntime/core/sys/windows/setupapi.d b/libphobos/libdruntime/core/sys/windows/setupapi.d index 7a052cde2b4..da503864787 100644 --- a/libphobos/libdruntime/core/sys/windows/setupapi.d +++ b/libphobos/libdruntime/core/sys/windows/setupapi.d @@ -858,7 +858,7 @@ enum : DWORD { alias PVOID HINF; alias PVOID HDSKSPC; -mixin DECLARE_HANDLE!("HDEVINFO"); +alias HDEVINFO = HANDLE; alias PVOID HSPFILEQ; alias PVOID HSPFILELOG; diff --git a/libphobos/libdruntime/core/sys/windows/shellapi.d b/libphobos/libdruntime/core/sys/windows/shellapi.d index fdd9938d908..2ddf680e1f0 100644 --- a/libphobos/libdruntime/core/sys/windows/shellapi.d +++ b/libphobos/libdruntime/core/sys/windows/shellapi.d @@ -188,7 +188,7 @@ enum SHERB_NOPROGRESSUI = 2; enum SHERB_NOSOUND = 4; alias WORD FILEOP_FLAGS, PRINTEROP_FLAGS; -mixin DECLARE_HANDLE!("HDROP"); +alias HDROP = HANDLE; //align(2): // 1 in Win32, default in Win64 diff --git a/libphobos/libdruntime/core/sys/windows/shlwapi.d b/libphobos/libdruntime/core/sys/windows/shlwapi.d index cfabbada223..3562003a41f 100644 --- a/libphobos/libdruntime/core/sys/windows/shlwapi.d +++ b/libphobos/libdruntime/core/sys/windows/shlwapi.d @@ -120,7 +120,7 @@ enum URLIS URLIS_HASQUERY } -mixin DECLARE_HANDLE!("HUSKEY"); +alias HUSKEY = HANDLE; alias HUSKEY* PHUSKEY; extern (Windows) diff --git a/libphobos/libdruntime/core/sys/windows/subauth.d b/libphobos/libdruntime/core/sys/windows/subauth.d index a48fb9955c4..8240d9f4781 100644 --- a/libphobos/libdruntime/core/sys/windows/subauth.d +++ b/libphobos/libdruntime/core/sys/windows/subauth.d @@ -106,7 +106,7 @@ struct STRING { alias STRING* PSTRING; +/ -mixin DECLARE_HANDLE!("SAM_HANDLE"); +alias SAM_HANDLE = HANDLE; alias SAM_HANDLE* PSAM_HANDLE; struct OLD_LARGE_INTEGER { diff --git a/libphobos/libdruntime/core/sys/windows/vfw.d b/libphobos/libdruntime/core/sys/windows/vfw.d index e8ca74e888d..c0f22a9fb5b 100644 --- a/libphobos/libdruntime/core/sys/windows/vfw.d +++ b/libphobos/libdruntime/core/sys/windows/vfw.d @@ -678,7 +678,7 @@ extern (Windows) { void ICCompressorFree(PCOMPVARS pc); } -mixin DECLARE_HANDLE!("HDRAWDIB"); +alias HDRAWDIB = HANDLE; enum { DDF_0001 = 0x0001, diff --git a/libphobos/libdruntime/core/sys/windows/windef.d b/libphobos/libdruntime/core/sys/windows/windef.d index 4e951f3ddac..105be44c5b6 100644 --- a/libphobos/libdruntime/core/sys/windows/windef.d +++ b/libphobos/libdruntime/core/sys/windows/windef.d @@ -74,43 +74,43 @@ alias const(void)* PCVOID, LPCVOID; alias UINT_PTR WPARAM; alias LONG_PTR LPARAM, LRESULT; -mixin DECLARE_HANDLE!("HHOOK"); -mixin DECLARE_HANDLE!("HGLOBAL"); -mixin DECLARE_HANDLE!("HLOCAL"); -mixin DECLARE_HANDLE!("GLOBALHANDLE"); -mixin DECLARE_HANDLE!("LOCALHANDLE"); -mixin DECLARE_HANDLE!("HGDIOBJ"); -mixin DECLARE_HANDLE!("HACCEL"); -mixin DECLARE_HANDLE!("HBITMAP", HGDIOBJ); -mixin DECLARE_HANDLE!("HBRUSH", HGDIOBJ); -mixin DECLARE_HANDLE!("HCOLORSPACE"); -mixin DECLARE_HANDLE!("HDC"); -mixin DECLARE_HANDLE!("HGLRC"); -mixin DECLARE_HANDLE!("HDESK"); -mixin DECLARE_HANDLE!("HENHMETAFILE"); -mixin DECLARE_HANDLE!("HFONT", HGDIOBJ); -mixin DECLARE_HANDLE!("HICON"); -mixin DECLARE_HANDLE!("HINSTANCE"); -mixin DECLARE_HANDLE!("HKEY"); -mixin DECLARE_HANDLE!("HMENU"); -mixin DECLARE_HANDLE!("HMETAFILE"); -mixin DECLARE_HANDLE!("HMODULE"); -mixin DECLARE_HANDLE!("HMONITOR"); -mixin DECLARE_HANDLE!("HPALETTE"); -mixin DECLARE_HANDLE!("HPEN", HGDIOBJ); -mixin DECLARE_HANDLE!("HRGN", HGDIOBJ); -mixin DECLARE_HANDLE!("HRSRC"); -mixin DECLARE_HANDLE!("HSTR"); -mixin DECLARE_HANDLE!("HTASK"); -mixin DECLARE_HANDLE!("HWND"); -mixin DECLARE_HANDLE!("HWINSTA"); -mixin DECLARE_HANDLE!("HKL"); -mixin DECLARE_HANDLE!("HCURSOR"); +alias HHOOK = HANDLE; +alias HGLOBAL = HANDLE; +alias HLOCAL = HANDLE; +alias GLOBALHANDLE = HANDLE; +alias LOCALHANDLE = HANDLE; +alias HGDIOBJ = HANDLE; +alias HACCEL = HANDLE; +alias HBITMAP = HGDIOBJ; +alias HBRUSH = HGDIOBJ; +alias HCOLORSPACE = HANDLE; +alias HDC = HANDLE; +alias HGLRC = HANDLE; +alias HDESK = HANDLE; +alias HENHMETAFILE = HANDLE; +alias HFONT = HGDIOBJ; +alias HICON = HANDLE; +alias HINSTANCE = HANDLE; +alias HKEY = HANDLE; +alias HMENU = HANDLE; +alias HMETAFILE = HANDLE; +alias HMODULE = HANDLE; +alias HMONITOR = HANDLE; +alias HPALETTE = HANDLE; +alias HPEN = HGDIOBJ; +alias HRGN = HGDIOBJ; +alias HRSRC = HANDLE; +alias HSTR = HANDLE; +alias HTASK = HANDLE; +alias HWND = HANDLE; +alias HWINSTA = HANDLE; +alias HKL = HANDLE; +alias HCURSOR = HANDLE; alias HKEY* PHKEY; static if (_WIN32_WINNT >= 0x500) { - mixin DECLARE_HANDLE!("HTERMINAL"); - mixin DECLARE_HANDLE!("HWINEVENTHOOK"); + alias HTERMINAL = HANDLE; + alias HWINEVENTHOOK = HANDLE; } alias extern (Windows) INT_PTR function() nothrow FARPROC, NEARPROC, PROC; diff --git a/libphobos/libdruntime/core/sys/windows/wininet.d b/libphobos/libdruntime/core/sys/windows/wininet.d index 328af503a4c..790d4d01dcb 100644 --- a/libphobos/libdruntime/core/sys/windows/wininet.d +++ b/libphobos/libdruntime/core/sys/windows/wininet.d @@ -740,7 +740,8 @@ enum { INTERNET_CACHE_GROUP_REMOVE = 1 } -mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug +alias HINTERNET = HANDLE; +// mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug /*struct HINTERNET { HANDLE h; alias h this; diff --git a/libphobos/libdruntime/core/sys/windows/winsvc.d b/libphobos/libdruntime/core/sys/windows/winsvc.d index f7f2fa7d27d..e6418ac8ac6 100644 --- a/libphobos/libdruntime/core/sys/windows/winsvc.d +++ b/libphobos/libdruntime/core/sys/windows/winsvc.d @@ -184,10 +184,10 @@ struct SERVICE_TABLE_ENTRYW { } alias SERVICE_TABLE_ENTRYW* LPSERVICE_TABLE_ENTRYW; -mixin DECLARE_HANDLE!("SC_HANDLE"); +alias SC_HANDLE = HANDLE; alias SC_HANDLE* LPSC_HANDLE; alias void* SC_LOCK; -mixin DECLARE_HANDLE!("SERVICE_STATUS_HANDLE"); +alias SERVICE_STATUS_HANDLE = HANDLE; extern (Windows) { alias void function(DWORD) LPHANDLER_FUNCTION; diff --git a/libphobos/libdruntime/core/sys/windows/winuser.d b/libphobos/libdruntime/core/sys/windows/winuser.d index 829952dfdb5..469e68e6668 100644 --- a/libphobos/libdruntime/core/sys/windows/winuser.d +++ b/libphobos/libdruntime/core/sys/windows/winuser.d @@ -2495,8 +2495,8 @@ extern (Windows) nothrow { alias NAMEENUMPROCW WINSTAENUMPROCW; } -mixin DECLARE_HANDLE!("HDWP"); -mixin DECLARE_HANDLE!("HDEVNOTIFY"); +alias HDWP = HANDLE; +alias HDEVNOTIFY = HANDLE; struct MENUGETOBJECTINFO { DWORD dwFlags; diff --git a/libphobos/libdruntime/core/sys/windows/wtypes.d b/libphobos/libdruntime/core/sys/windows/wtypes.d index 0206839ebf2..881f05a650c 100644 --- a/libphobos/libdruntime/core/sys/windows/wtypes.d +++ b/libphobos/libdruntime/core/sys/windows/wtypes.d @@ -96,8 +96,8 @@ alias OLECHAR* BSTR; alias FLAGGED_WORD_BLOB* wireBSTR; alias BSTR* LPBSTR; //alias LONG SCODE; // also in winerror -mixin DECLARE_HANDLE!("HCONTEXT"); -mixin DECLARE_HANDLE!("HMETAFILEPICT"); +alias HCONTEXT = HANDLE; +alias HMETAFILEPICT = HANDLE; union CY { struct { diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 1b39a27c102..710f4cc90d1 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -1646,10 +1646,10 @@ class TypeInfo_Class : TypeInfo string name; /// class name void*[] vtbl; /// virtual function pointer table Interface[] interfaces; /// interfaces this class implements - TypeInfo_Class base; /// base class + TypeInfo_Class base; /// base class void* destructor; void function(Object) classInvariant; - enum ClassFlags : uint + enum ClassFlags : ushort { isCOMclass = 0x1, noPointers = 0x2, @@ -1660,11 +1660,14 @@ class TypeInfo_Class : TypeInfo isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100, + hasNameSig = 0x200, } ClassFlags m_flags; - void* deallocator; + ushort depth; /// inheritance distance from Object + void* deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; // default Constructor + ulong[2] nameSig; /// unique signature for `name` immutable(void)* m_RTInfo; // data for precise GC override @property immutable(void)* rtInfo() const { return m_RTInfo; } diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d index 925599e0159..44e0f7a9ccc 100644 --- a/libphobos/libdruntime/rt/cast_.d +++ b/libphobos/libdruntime/rt/cast_.d @@ -23,10 +23,12 @@ pure: // but we are trying to implement dynamic cast. extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) @safe { - if (a is b) - return true; - // take care of potential duplicates across binaries - return a.name == b.name; + // same class if signatures match, works with potential duplicates across binaries + return a is b || + (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig + ? (a.nameSig[0] == b.nameSig[0] && + a.nameSig[1] == b.nameSig[1]) // new fast way + : (a is b || a.name == b.name)); // old slow way for temporary binary compatibility } /****************************************** @@ -58,7 +60,7 @@ Object _d_toObject(return scope void* p) } /************************************* - * Attempts to cast Object o to class c. + * Attempts to cast interface Object o to class c. * Returns o if successful, null if not. */ void* _d_interface_cast(void* p, ClassInfo c) @@ -70,9 +72,26 @@ void* _d_interface_cast(void* p, ClassInfo c) Interface* pi = **cast(Interface***) p; debug(cast_) printf("\tpi.offset = %d\n", pi.offset); - return _d_dynamic_cast(cast(Object)(p - pi.offset), c); + Object o2 = cast(Object)(p - pi.offset); + void* res = null; + size_t offset = 0; + if (o2 && _d_isbaseof2(typeid(o2), c, offset)) + { + debug(cast_) printf("\toffset = %d\n", offset); + res = cast(void*) o2 + offset; + } + debug(cast_) printf("\tresult = %p\n", res); + return res; } +/***** + * Dynamic cast from a class object `o` to class or interface `c`, where `c` is a subtype of `o`. + * Params: + * o = instance of class + * c = a subclass of o + * Returns: + * null if o is null or c is not a subclass of o. Otherwise, return o. + */ void* _d_dynamic_cast(Object o, ClassInfo c) { debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name); @@ -88,6 +107,64 @@ void* _d_dynamic_cast(Object o, ClassInfo c) return res; } +/***** + * Dynamic cast from a class object o to class c, where c is a subclass of o. + * Params: + * o = instance of class + * c = a subclass of o + * Returns: + * null if o is null or c is not a subclass of o. Otherwise, return o. + */ +void* _d_class_cast(Object o, ClassInfo c) +{ + debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s', level %d)\n", o, c.name, level); + + if (!o) + return null; + + ClassInfo oc = typeid(o); + int delta = oc.depth; + + if (delta && c.depth) + { + delta -= c.depth; + if (delta < 0) + return null; + + while (delta--) + oc = oc.base; + if (areClassInfosEqual(oc, c)) + return cast(void*)o; + return null; + } + + // no depth data - support the old way + do + { + if (areClassInfosEqual(oc, c)) + return cast(void*)o; + oc = oc.base; + } while (oc); + return null; +} + +/** + * Dynamic cast `o` to final class `c` only one level down + * Params: + * o = object that is instance of a class + * c = class to cast it to + * Returns: + * o if it succeeds, null if it fails + */ +void* _d_paint_cast(Object o, ClassInfo c) +{ + /* If o is really an instance of c, just do a paint + */ + auto p = (o && cast(void*)(areClassInfosEqual(typeid(o), c)) ? o : null); + debug assert(cast(void*)p is cast(void*)_d_dynamic_cast(o, c)); + return cast(void*)p; +} + int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe { if (areClassInfosEqual(oc, c)) diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d index 8a10aac8fcb..5ac053cef15 100644 --- a/libphobos/libdruntime/rt/dmain2.d +++ b/libphobos/libdruntime/rt/dmain2.d @@ -496,6 +496,13 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF { if (rt_init()) { + version(Shared) version(CRuntime_Microsoft) version (DigitalMars) + { + auto exeHandle = handleForAddr(mainFunc); + if (exeHandle) + if (!rt_initSharedModule(exeHandle)) + exeHandle = null; + } auto utResult = runModuleUnitTests(); assert(utResult.passed <= utResult.executed); if (utResult.passed == utResult.executed) @@ -521,6 +528,11 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF cast(int)utResult.executed); result = EXIT_FAILURE; } + version(Shared) version(CRuntime_Microsoft) version (DigitalMars) + { + if (exeHandle) + rt_termSharedModule(exeHandle); + } } else result = EXIT_FAILURE; diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 103a93f5ad6..b29da3b4ce7 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -7a6e9568862f5a0d9eb34707d85dcf7ff889c26f +e4d0dd5136be3c539a02cc2f1618cb989a685837 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/bitmanip.d b/libphobos/src/std/bitmanip.d index b84a6762d19..e9f61919b0d 100644 --- a/libphobos/src/std/bitmanip.d +++ b/libphobos/src/std/bitmanip.d @@ -279,10 +279,8 @@ See_Also: $(REF BitFlags, std,typecons) */ string bitfields(T...)() { - import std.conv : to; - static assert(T.length % 3 == 0, - "Wrong number of arguments (" ~ to!string(T.length) ~ "): Must be a multiple of 3"); + "Wrong number of arguments (" ~ T.length.stringof ~ "): Must be a multiple of 3"); static foreach (i, ARG; T) { diff --git a/libphobos/src/std/complex.d b/libphobos/src/std/complex.d index 347e351c26a..60746f98ef7 100644 --- a/libphobos/src/std/complex.d +++ b/libphobos/src/std/complex.d @@ -1892,7 +1892,7 @@ Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc @safe pure nothrow @nogc unittest { import std.meta : AliasSeq; - import std.math : RealFormat, floatTraits; + import std.math.traits : floatTraits, RealFormat; static foreach (T; AliasSeq!(float, double, real)) {{ static if (floatTraits!T.realFormat == RealFormat.ibmExtended) diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 23b33c4d78c..5d02df08bf9 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -1804,7 +1804,7 @@ if (!is(S : T) && isAssociativeArray!S && } static void testFloatingToIntegral(Floating, Integral)() { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; bool convFails(Source, Target, E)(Source src) { @@ -3430,7 +3430,7 @@ if (isFloatingPoint!Target && !is(Target == enum) && Target result = cast(Target) (sign ? -ldval : ldval); // if overflow occurred - import std.math : isFinite; + import std.math.traits : isFinite; enforce(isFinite(result), new ConvException("Range error")); advanceSource(); @@ -3598,7 +3598,7 @@ if (isFloatingPoint!Target && !is(Target == enum) && @system unittest { // @system because strtod is not @safe. - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; static if (floatTraits!real.realFormat == RealFormat.ieeeDouble) { @@ -3682,7 +3682,7 @@ if (isFloatingPoint!Target && !is(Target == enum) && { import core.stdc.errno; import core.stdc.stdlib; - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; errno = 0; // In case it was set by another unittest in a different module. struct longdouble diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d index 5c786859c8e..58a667c1d85 100644 --- a/libphobos/src/std/exception.d +++ b/libphobos/src/std/exception.d @@ -1632,6 +1632,9 @@ class ErrnoException : Exception /// Operating system error code. final @property uint errno() nothrow pure scope @nogc @safe { return _errno; } private uint _errno; + /// Localized error message generated through $(REF strerror_r, core,stdc,string) or $(REF strerror, core,stdc,string). + final @property string errnoMsg() nothrow pure scope @nogc @safe { return _errnoMsg; } + private string _errnoMsg; /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code. this(string msg, string file = null, size_t line = 0) @safe { @@ -1642,7 +1645,8 @@ class ErrnoException : Exception this(string msg, int errno, string file = null, size_t line = 0) @safe { _errno = errno; - super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line); + _errnoMsg = errnoString(errno); + super(msg ~ " (" ~ errnoMsg ~ ")", file, line); } } diff --git a/libphobos/src/std/format/internal/floats.d b/libphobos/src/std/format/internal/floats.d index afe0bfa3cb5..88b9d22d7d9 100644 --- a/libphobos/src/std/format/internal/floats.d +++ b/libphobos/src/std/format/internal/floats.d @@ -28,6 +28,15 @@ if (is(T == float) || is(T == double) return w.data; } +/// Returns: whether `c` is a supported format specifier for floats +package(std.format) bool isFloatSpec(char c) nothrow @nogc pure @safe +{ + return c == 'a' || c == 'A' + || c == 'e' || c == 'E' + || c == 'f' || c == 'F' + || c == 'g' || c == 'G'; +} + package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f) if (is(T == float) || is(T == double) || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) @@ -43,10 +52,7 @@ if (is(T == float) || is(T == double) if (sgn == "" && f.flPlus) sgn = "+"; if (sgn == "" && f.flSpace) sgn = " "; - assert(f.spec == 'a' || f.spec == 'A' - || f.spec == 'e' || f.spec == 'E' - || f.spec == 'f' || f.spec == 'F' - || f.spec == 'g' || f.spec == 'G', "unsupported format specifier"); + assert(isFloatSpec(f.spec), "unsupported format specifier"); bool is_upper = f.spec == 'A' || f.spec == 'E' || f.spec=='F' || f.spec=='G'; // special treatment for nan and inf diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d index 85954faa35e..16c7a51d8c6 100644 --- a/libphobos/src/std/format/internal/write.d +++ b/libphobos/src/std/format/internal/write.d @@ -570,9 +570,9 @@ void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f) if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { - import std.algorithm.searching : find; import std.format : enforceFmt; import std.range.primitives : put; + import std.format.internal.floats : printFloat, isFloatSpec; FloatingPointTypeOf!T val = obj; const char spec = f.spec; @@ -597,11 +597,9 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) return; } - enforceFmt(find("fgFGaAeEs", spec).length, - "incompatible format character for floating point argument: %" ~ spec); - FormatSpec!Char fs = f; // fs is copy for change its values. fs.spec = spec == 's' ? 'g' : spec; + enforceFmt(isFloatSpec(fs.spec), "incompatible format character for floating point argument: %" ~ spec); static if (is(T == float) || is(T == double) || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) @@ -631,7 +629,6 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) tval = -doubleLowest; } - import std.format.internal.floats : printFloat; printFloat(w, tval, fs); } diff --git a/libphobos/src/std/math/algebraic.d b/libphobos/src/std/math/algebraic.d index 99990716460..fd305231d08 100644 --- a/libphobos/src/std/math/algebraic.d +++ b/libphobos/src/std/math/algebraic.d @@ -308,7 +308,7 @@ if (isFloatingPoint!T) // If both are huge, avoid overflow by scaling by 2^^-N. // If both are tiny, avoid underflow by scaling by 2^^N. import core.math : fabs, sqrt; - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; alias F = floatTraits!T; diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d index 8290479248d..5e90f0de897 100644 --- a/libphobos/src/std/math/exponential.d +++ b/libphobos/src/std/math/exponential.d @@ -1002,8 +1002,7 @@ float exp(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) exp(ca private T expImpl(T)(T x) @safe pure nothrow @nogc { - import std.math : floatTraits, RealFormat; - import std.math.traits : isNaN; + import std.math.traits : floatTraits, RealFormat, isNaN; import std.math.rounding : floor; import std.math.algebraic : poly; import std.math.constants : LOG2E; @@ -1143,7 +1142,7 @@ private T expImpl(T)(T x) @safe pure nothrow @nogc @safe @nogc nothrow unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.math.operations : NaN, feqrel, isClose; import std.math.constants : E; import std.math.traits : isIdentical; @@ -1517,7 +1516,7 @@ L_largenegative: private T expm1Impl(T)(T x) @safe pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.math.rounding : floor; import std.math.algebraic : poly; import std.math.constants : LN2; @@ -1909,8 +1908,7 @@ L_was_nan: private T exp2Impl(T)(T x) @nogc @safe pure nothrow { - import std.math : floatTraits, RealFormat; - import std.math.traits : isNaN; + import std.math.traits : floatTraits, RealFormat, isNaN; import std.math.rounding : floor; import std.math.algebraic : poly; @@ -2098,8 +2096,7 @@ private T exp2Impl(T)(T x) @nogc @safe pure nothrow T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc if (isFloatingPoint!T) { - import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; - import std.math.traits : isSubnormal; + import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB, isSubnormal; if (__ctfe) { @@ -2353,8 +2350,7 @@ if (isFloatingPoint!T) @safe unittest { - import std.math : floatTraits, RealFormat; - import std.math.traits : isIdentical; + import std.math.traits : floatTraits, RealFormat, isIdentical; import std.meta : AliasSeq; import std.typecons : tuple, Tuple; @@ -2486,7 +2482,7 @@ if (isFloatingPoint!T) int ilogb(T)(const T x) @trusted pure nothrow @nogc if (isFloatingPoint!T) { - import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; + import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; import core.bitop : bsr; alias F = floatTraits!T; @@ -2681,7 +2677,7 @@ alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN; @safe nothrow @nogc unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.math.operations : nextUp; import std.meta : AliasSeq; import std.typecons : Tuple; @@ -2778,7 +2774,7 @@ float ldexp(float n, int exp) @safe pure nothrow @nogc { return core.math.ldex @safe pure nothrow @nogc unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended || floatTraits!(real).realFormat == RealFormat.ieeeExtended53 || @@ -2866,7 +2862,7 @@ private // Coefficients shared across log(), log2(), log10(), log1p(). template LogCoeffs(T) { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple) { @@ -3179,8 +3175,7 @@ private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc { import std.math.constants : SQRT1_2; import std.math.algebraic : poly; - import std.math.traits : isInfinity, isNaN, signbit; - import std.math : floatTraits, RealFormat; + import std.math.traits : isInfinity, isNaN, signbit, floatTraits, RealFormat; alias coeffs = LogCoeffs!T; alias F = floatTraits!T; @@ -3306,7 +3301,7 @@ private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc @safe @nogc nothrow unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.meta : AliasSeq; static void testLog(T)(T[2][] vals) @@ -3452,8 +3447,7 @@ private T log10Impl(T)(T x) @safe pure nothrow @nogc { import std.math.constants : SQRT1_2; import std.math.algebraic : poly; - import std.math.traits : isNaN, isInfinity, signbit; - import std.math : floatTraits, RealFormat; + import std.math.traits : isNaN, isInfinity, signbit, floatTraits, RealFormat; alias coeffs = LogCoeffs!T; alias F = floatTraits!T; @@ -3558,7 +3552,7 @@ Ldone: @safe @nogc nothrow unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.meta : AliasSeq; static void testLog10(T)(T[2][] vals) @@ -3710,7 +3704,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc import std.math.traits : isNaN, isInfinity, signbit; import std.math.algebraic : poly; import std.math.constants : SQRT1_2, SQRT2; - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; // Special cases. if (isNaN(x) || x == 0.0) @@ -3746,7 +3740,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc @safe @nogc nothrow unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.meta : AliasSeq; static void testLog1p(T)(T[2][] vals) @@ -3891,7 +3885,7 @@ private T log2Impl(T)(T x) @safe pure nothrow @nogc import std.math.traits : isNaN, isInfinity, signbit; import std.math.constants : SQRT1_2, LOG2E; import std.math.algebraic : poly; - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; alias coeffs = LogCoeffs!T; alias F = floatTraits!T; @@ -3972,7 +3966,7 @@ Ldone: @safe @nogc nothrow unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.meta : AliasSeq; static void testLog2(T)(T[2][] vals) @@ -4172,7 +4166,7 @@ private T logbImpl(T)(T x) @trusted pure nothrow @nogc @safe @nogc nothrow unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.meta : AliasSeq; static void testLogb(T)(T[2][] vals) diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d index cb6cb87845c..c7c5d6ee1fc 100644 --- a/libphobos/src/std/math/hardware.d +++ b/libphobos/src/std/math/hardware.d @@ -210,14 +210,12 @@ private: } else version (RISCV_Any) { - mixin(` uint result = void; asm pure nothrow @nogc { "frflags %0" : "=r" (result); } return result; - `); } else version (LoongArch_Any) { @@ -307,13 +305,11 @@ private: } else version (RISCV_Any) { - mixin(` uint newValues = 0x0; asm pure nothrow @nogc { "fsflags %0" : : "r" (newValues); } - `); } else version (LoongArch_Any) { @@ -1039,14 +1035,12 @@ private: } else version (RISCV_Any) { - mixin(` ControlState cont; asm pure nothrow @nogc { "frcsr %0" : "=r" (cont); } return cont; - `); } else version (LoongArch_Any) { @@ -1163,12 +1157,10 @@ private: } else version (RISCV_Any) { - mixin(` asm pure nothrow @nogc { "fscsr %0" : : "r" (newState); } - `); } else version (LoongArch_Any) { diff --git a/libphobos/src/std/math/operations.d b/libphobos/src/std/math/operations.d index 4bf19ee3da9..d456e29adb6 100644 --- a/libphobos/src/std/math/operations.d +++ b/libphobos/src/std/math/operations.d @@ -44,7 +44,7 @@ import std.traits : CommonType, isFloatingPoint, isIntegral, Unqual; */ real NaN(ulong payload) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeExtended || @@ -136,7 +136,7 @@ real NaN(ulong payload) @trusted pure nothrow @nogc @system pure nothrow @nogc unittest // not @safe because taking address of local. { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) { @@ -159,7 +159,7 @@ real NaN(ulong payload) @trusted pure nothrow @nogc */ ulong getNaNPayload(real x) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; // assert(isNaN(x)); alias F = floatTraits!(real); @@ -283,7 +283,7 @@ debug(UnitTest) */ real nextUp(real x) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; + import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; alias F = floatTraits!(real); static if (F.realFormat != RealFormat.ieeeDouble) @@ -522,8 +522,7 @@ float nextDown(float x) @safe pure nothrow @nogc @safe pure nothrow @nogc unittest { - import std.math : floatTraits, RealFormat; - import std.math.traits : isIdentical; + import std.math.traits : floatTraits, RealFormat, isIdentical; static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended || floatTraits!(real).realFormat == RealFormat.ieeeDouble || @@ -865,7 +864,7 @@ real fma(real x, real y, real z) @safe pure nothrow @nogc { return (x * y) + z; int feqrel(X)(const X x, const X y) @trusted pure nothrow @nogc if (isFloatingPoint!(X)) { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import core.math : fabs; /* Public Domain. Author: Don Clugston, 18 Aug 2005. @@ -1495,7 +1494,7 @@ private template FloatingPointBaseType(T) int cmp(T)(const(T) x, const(T) y) @nogc @trusted pure nothrow if (isFloatingPoint!T) { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; alias F = floatTraits!T; @@ -1723,7 +1722,7 @@ if (isFloatingPoint!T) FloatingPointBitpattern!T extractBitpattern(T)(const(T) value) @trusted if (isFloatingPoint!T) { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; T val = value; FloatingPointBitpattern!T ret; @@ -1895,7 +1894,7 @@ if (isFloatingPoint!T) @safe pure unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; alias F = floatTraits!real; static if (F.realFormat == RealFormat.ieeeExtended) @@ -1946,7 +1945,7 @@ if (isFloatingPoint!T) @safe pure unittest { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.math.exponential : log2; alias F = floatTraits!real; diff --git a/libphobos/src/std/math/package.d b/libphobos/src/std/math/package.d index 614f4d36fbb..0d1ecc35642 100644 --- a/libphobos/src/std/math/package.d +++ b/libphobos/src/std/math/package.d @@ -321,169 +321,3 @@ else static assert(real.mant_dig == 53 || real.mant_dig == 113, "Only 64-bit and 128-bit reals are supported for BigEndian CPUs."); } - -// Underlying format exposed through floatTraits -enum RealFormat -{ - ieeeHalf, - ieeeSingle, - ieeeDouble, - ieeeExtended, // x87 80-bit real - ieeeExtended53, // x87 real rounded to precision of double. - ibmExtended, // IBM 128-bit extended - ieeeQuadruple, -} - -// Constants used for extracting the components of the representation. -// They supplement the built-in floating point properties. -template floatTraits(T) -{ - import std.traits : Unqual; - - // EXPMASK is a ushort mask to select the exponent portion (without sign) - // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort - // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1). - // EXPPOS_SHORT is the index of the exponent when represented as a ushort array. - // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. - // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal - enum Unqual!T RECIP_EPSILON = (1/T.epsilon); - static if (T.mant_dig == 24) - { - // Single precision float - enum ushort EXPMASK = 0x7F80; - enum ushort EXPSHIFT = 7; - enum ushort EXPBIAS = 0x3F00; - enum uint EXPMASK_INT = 0x7F80_0000; - enum uint MANTISSAMASK_INT = 0x007F_FFFF; - enum realFormat = RealFormat.ieeeSingle; - version (LittleEndian) - { - enum EXPPOS_SHORT = 1; - enum SIGNPOS_BYTE = 3; - } - else - { - enum EXPPOS_SHORT = 0; - enum SIGNPOS_BYTE = 0; - } - } - else static if (T.mant_dig == 53) - { - static if (T.sizeof == 8) - { - // Double precision float, or real == double - enum ushort EXPMASK = 0x7FF0; - enum ushort EXPSHIFT = 4; - enum ushort EXPBIAS = 0x3FE0; - enum uint EXPMASK_INT = 0x7FF0_0000; - enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only - enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF; - enum realFormat = RealFormat.ieeeDouble; - version (LittleEndian) - { - enum EXPPOS_SHORT = 3; - enum SIGNPOS_BYTE = 7; - } - else - { - enum EXPPOS_SHORT = 0; - enum SIGNPOS_BYTE = 0; - } - } - else static if (T.sizeof == 12) - { - // Intel extended real80 rounded to double - enum ushort EXPMASK = 0x7FFF; - enum ushort EXPSHIFT = 0; - enum ushort EXPBIAS = 0x3FFE; - enum realFormat = RealFormat.ieeeExtended53; - version (LittleEndian) - { - enum EXPPOS_SHORT = 4; - enum SIGNPOS_BYTE = 9; - } - else - { - enum EXPPOS_SHORT = 0; - enum SIGNPOS_BYTE = 0; - } - } - else - static assert(false, "No traits support for " ~ T.stringof); - } - else static if (T.mant_dig == 64) - { - // Intel extended real80 - enum ushort EXPMASK = 0x7FFF; - enum ushort EXPSHIFT = 0; - enum ushort EXPBIAS = 0x3FFE; - enum realFormat = RealFormat.ieeeExtended; - version (LittleEndian) - { - enum EXPPOS_SHORT = 4; - enum SIGNPOS_BYTE = 9; - } - else - { - enum EXPPOS_SHORT = 0; - enum SIGNPOS_BYTE = 0; - } - } - else static if (T.mant_dig == 113) - { - // Quadruple precision float - enum ushort EXPMASK = 0x7FFF; - enum ushort EXPSHIFT = 0; - enum ushort EXPBIAS = 0x3FFE; - enum realFormat = RealFormat.ieeeQuadruple; - version (LittleEndian) - { - enum EXPPOS_SHORT = 7; - enum SIGNPOS_BYTE = 15; - } - else - { - enum EXPPOS_SHORT = 0; - enum SIGNPOS_BYTE = 0; - } - } - else static if (T.mant_dig == 106) - { - // IBM Extended doubledouble - enum ushort EXPMASK = 0x7FF0; - enum ushort EXPSHIFT = 4; - enum realFormat = RealFormat.ibmExtended; - - // For IBM doubledouble the larger magnitude double comes first. - // It's really a double[2] and arrays don't index differently - // between little and big-endian targets. - enum DOUBLEPAIR_MSB = 0; - enum DOUBLEPAIR_LSB = 1; - - // The exponent/sign byte is for most significant part. - version (LittleEndian) - { - enum EXPPOS_SHORT = 3; - enum SIGNPOS_BYTE = 7; - } - else - { - enum EXPPOS_SHORT = 0; - enum SIGNPOS_BYTE = 0; - } - } - else - static assert(false, "No traits support for " ~ T.stringof); -} - -// These apply to all floating-point types -version (LittleEndian) -{ - enum MANTISSA_LSB = 0; - enum MANTISSA_MSB = 1; -} -else -{ - enum MANTISSA_LSB = 1; - enum MANTISSA_MSB = 0; -} diff --git a/libphobos/src/std/math/rounding.d b/libphobos/src/std/math/rounding.d index 7dbe89b2dee..f6654fc115a 100644 --- a/libphobos/src/std/math/rounding.d +++ b/libphobos/src/std/math/rounding.d @@ -551,7 +551,7 @@ long lrint(real x) @trusted pure nothrow @nogc } else { - import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; + import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeDouble) @@ -896,7 +896,7 @@ long rndtol(float x) @safe pure nothrow @nogc { return rndtol(cast(real) x); } // Helper for floor/ceil T floorImpl(T)(const T x) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; alias F = floatTraits!(T); // Take care not to trigger library calls from the compiler, diff --git a/libphobos/src/std/math/traits.d b/libphobos/src/std/math/traits.d index 2841bad219f..81ab1b789db 100644 --- a/libphobos/src/std/math/traits.d +++ b/libphobos/src/std/math/traits.d @@ -137,7 +137,7 @@ if (isFloatingPoint!(X)) */ bool isFinite(X)(X x) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; static if (__traits(isFloating, X)) if (__ctfe) @@ -202,7 +202,7 @@ bool isFinite(X)(X x) @trusted pure nothrow @nogc */ bool isNormal(X)(X x) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; static if (__traits(isFloating, X)) if (__ctfe) @@ -264,7 +264,7 @@ bool isNormal(X)(X x) @trusted pure nothrow @nogc */ bool isSubnormal(X)(X x) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; + import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; static if (__traits(isFloating, X)) if (__ctfe) @@ -344,7 +344,7 @@ bool isSubnormal(X)(X x) @trusted pure nothrow @nogc bool isInfinity(X)(X x) @nogc @trusted pure nothrow if (isFloatingPoint!(X)) { - import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; + import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; alias F = floatTraits!(X); static if (F.realFormat == RealFormat.ieeeSingle) @@ -466,7 +466,7 @@ if (isFloatingPoint!(X)) */ bool isIdentical(real x, real y) @trusted pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; // We're doing a bitwise comparison so the endianness is irrelevant. long* pxs = cast(long *)&x; @@ -510,7 +510,7 @@ bool isIdentical(real x, real y) @trusted pure nothrow @nogc */ int signbit(X)(X x) @nogc @trusted pure nothrow { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; if (__ctfe) { @@ -594,7 +594,7 @@ Returns: R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc if (isFloatingPoint!(R) && isFloatingPoint!(X)) { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; if (__ctfe) { @@ -851,3 +851,168 @@ if (isNumeric!X) }} } +// Underlying format exposed through floatTraits +enum RealFormat +{ + ieeeHalf, + ieeeSingle, + ieeeDouble, + ieeeExtended, // x87 80-bit real + ieeeExtended53, // x87 real rounded to precision of double. + ibmExtended, // IBM 128-bit extended + ieeeQuadruple, +} + +// Constants used for extracting the components of the representation. +// They supplement the built-in floating point properties. +template floatTraits(T) +{ + import std.traits : Unqual; + + // EXPMASK is a ushort mask to select the exponent portion (without sign) + // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort + // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1). + // EXPPOS_SHORT is the index of the exponent when represented as a ushort array. + // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. + // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal + enum Unqual!T RECIP_EPSILON = (1/T.epsilon); + static if (T.mant_dig == 24) + { + // Single precision float + enum ushort EXPMASK = 0x7F80; + enum ushort EXPSHIFT = 7; + enum ushort EXPBIAS = 0x3F00; + enum uint EXPMASK_INT = 0x7F80_0000; + enum uint MANTISSAMASK_INT = 0x007F_FFFF; + enum realFormat = RealFormat.ieeeSingle; + version (LittleEndian) + { + enum EXPPOS_SHORT = 1; + enum SIGNPOS_BYTE = 3; + } + else + { + enum EXPPOS_SHORT = 0; + enum SIGNPOS_BYTE = 0; + } + } + else static if (T.mant_dig == 53) + { + static if (T.sizeof == 8) + { + // Double precision float, or real == double + enum ushort EXPMASK = 0x7FF0; + enum ushort EXPSHIFT = 4; + enum ushort EXPBIAS = 0x3FE0; + enum uint EXPMASK_INT = 0x7FF0_0000; + enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only + enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF; + enum realFormat = RealFormat.ieeeDouble; + version (LittleEndian) + { + enum EXPPOS_SHORT = 3; + enum SIGNPOS_BYTE = 7; + } + else + { + enum EXPPOS_SHORT = 0; + enum SIGNPOS_BYTE = 0; + } + } + else static if (T.sizeof == 12) + { + // Intel extended real80 rounded to double + enum ushort EXPMASK = 0x7FFF; + enum ushort EXPSHIFT = 0; + enum ushort EXPBIAS = 0x3FFE; + enum realFormat = RealFormat.ieeeExtended53; + version (LittleEndian) + { + enum EXPPOS_SHORT = 4; + enum SIGNPOS_BYTE = 9; + } + else + { + enum EXPPOS_SHORT = 0; + enum SIGNPOS_BYTE = 0; + } + } + else + static assert(false, "No traits support for " ~ T.stringof); + } + else static if (T.mant_dig == 64) + { + // Intel extended real80 + enum ushort EXPMASK = 0x7FFF; + enum ushort EXPSHIFT = 0; + enum ushort EXPBIAS = 0x3FFE; + enum realFormat = RealFormat.ieeeExtended; + version (LittleEndian) + { + enum EXPPOS_SHORT = 4; + enum SIGNPOS_BYTE = 9; + } + else + { + enum EXPPOS_SHORT = 0; + enum SIGNPOS_BYTE = 0; + } + } + else static if (T.mant_dig == 113) + { + // Quadruple precision float + enum ushort EXPMASK = 0x7FFF; + enum ushort EXPSHIFT = 0; + enum ushort EXPBIAS = 0x3FFE; + enum realFormat = RealFormat.ieeeQuadruple; + version (LittleEndian) + { + enum EXPPOS_SHORT = 7; + enum SIGNPOS_BYTE = 15; + } + else + { + enum EXPPOS_SHORT = 0; + enum SIGNPOS_BYTE = 0; + } + } + else static if (T.mant_dig == 106) + { + // IBM Extended doubledouble + enum ushort EXPMASK = 0x7FF0; + enum ushort EXPSHIFT = 4; + enum realFormat = RealFormat.ibmExtended; + + // For IBM doubledouble the larger magnitude double comes first. + // It's really a double[2] and arrays don't index differently + // between little and big-endian targets. + enum DOUBLEPAIR_MSB = 0; + enum DOUBLEPAIR_LSB = 1; + + // The exponent/sign byte is for most significant part. + version (LittleEndian) + { + enum EXPPOS_SHORT = 3; + enum SIGNPOS_BYTE = 7; + } + else + { + enum EXPPOS_SHORT = 0; + enum SIGNPOS_BYTE = 0; + } + } + else + static assert(false, "No traits support for " ~ T.stringof); +} + +// These apply to all floating-point types +version (LittleEndian) +{ + enum MANTISSA_LSB = 0; + enum MANTISSA_MSB = 1; +} +else +{ + enum MANTISSA_LSB = 1; + enum MANTISSA_MSB = 0; +} diff --git a/libphobos/src/std/math/trigonometry.d b/libphobos/src/std/math/trigonometry.d index a3d04c60402..4f5f5c50e55 100644 --- a/libphobos/src/std/math/trigonometry.d +++ b/libphobos/src/std/math/trigonometry.d @@ -307,7 +307,7 @@ Lret: private T tanImpl(T)(T x) @safe pure nothrow @nogc { - import std.math : floatTraits, RealFormat; + import std.math.traits : floatTraits, RealFormat; import std.math.constants : PI, PI_4; import std.math.rounding : floor; import std.math.algebraic : poly; @@ -675,8 +675,7 @@ float atan(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) atan( private T atanImpl(T)(T x) @safe pure nothrow @nogc { - import std.math : floatTraits, RealFormat; - import std.math.traits : copysign, isInfinity, signbit; + import std.math.traits : floatTraits, RealFormat, copysign, isInfinity, signbit; import std.math.constants : PI_2, PI_4; import std.math.algebraic : poly; diff --git a/libphobos/src/std/mmfile.d b/libphobos/src/std/mmfile.d index f8f8a9088b6..b2cab3157d0 100644 --- a/libphobos/src/std/mmfile.d +++ b/libphobos/src/std/mmfile.d @@ -2,10 +2,22 @@ /** * Read and write memory mapped files. + * + * Memory mapped files are a mechanism in operating systems that allows + * file access through virtual memory. After opening a file with `MmFile`, + * the contents can be read from or written to with standard slice / pointer operations. + * Changes to the memory are automatically reflected in the underlying file. + * + * Memory mapping can increase I/O performance of large files, compared to buffered + * read / write operations from `std.file` and `std.stdio`. However, I/O errors are + * not handled as safely: when for example the disk that the file is on gets removed, + * reading from it may result in a segfault. + * * Copyright: Copyright The D Language Foundation 2004 - 2009. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(HTTP digitalmars.com, Walter Bright), * Matthew Wilson + * References: $(LINK https://en.wikipedia.org/wiki/Memory-mapped_file) * Source: $(PHOBOSSRC std/mmfile.d) * * $(SCRIPT inhibitQuickIndex = 1;) @@ -612,23 +624,47 @@ private: { static assert(0); } +} + +/// Read an existing file +@system unittest +{ + import std.file; + std.file.write(deleteme, "hello"); // deleteme is a temporary filename + scope(exit) remove(deleteme); + + // Use a scope class so the file will be closed at the end of this function + scope mmfile = new MmFile(deleteme); + + assert(mmfile.length == "hello".length); + + // Access file contents with the slice operator + // This is typed as `void[]`, so cast to `char[]` or `ubyte[]` to use it + const data = cast(const(char)[]) mmfile[]; + + // At this point, the file content may not have been read yet. + // In that case, the following memory access will intentionally + // trigger a page fault, causing the kernel to load the file contents + assert(data[0 .. 5] == "hello"); +} + +/// Write a new file +@system unittest +{ + import std.file; + scope(exit) remove(deleteme); + + scope mmfile = new MmFile(deleteme, MmFile.Mode.readWriteNew, 5, null); + assert(mmfile.length == 5); + + auto data = cast(ubyte[]) mmfile[]; + + // This write to memory will be reflected in the file contents + data[] = '\n'; + + mmfile.flush(); - // Report error, where errno gives the error number - // void errNo() - // { - // version (Windows) - // { - // throw new FileException(filename, GetLastError()); - // } - // else version (linux) - // { - // throw new FileException(filename, errno); - // } - // else - // { - // static assert(0); - // } - // } + assert(std.file.read(deleteme) == "\n\n\n\n\n"); } @system unittest diff --git a/libphobos/src/std/regex/internal/backtracking.d b/libphobos/src/std/regex/internal/backtracking.d index ac73f70f0f3..a488e0660d0 100644 --- a/libphobos/src/std/regex/internal/backtracking.d +++ b/libphobos/src/std/regex/internal/backtracking.d @@ -682,7 +682,7 @@ final: while (prevStack()) {} return re.ir[pc].data; default: - debug printBytecode(re.ir[0..$]); + debug(std_regex_debug) printBytecode(re.ir[0..$]); assert(0); L_backtrack: if (!popState()) diff --git a/libphobos/src/std/regex/internal/ir.d b/libphobos/src/std/regex/internal/ir.d index 069d75f8822..04b902fc39d 100644 --- a/libphobos/src/std/regex/internal/ir.d +++ b/libphobos/src/std/regex/internal/ir.d @@ -403,7 +403,7 @@ struct Group(DataIndex) } //debugging tool, prints out instruction along with opcodes -@trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[]) +debug(std_regex_parser) @trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[]) { import std.array : appender; import std.format.write : formattedWrite; @@ -467,7 +467,7 @@ struct Group(DataIndex) } //disassemble the whole chunk -@trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[]) +debug(std_regex_parser) @trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[]) { import std.stdio : writeln; for (uint pc=0; pc= dim[0]) { @@ -4088,16 +4097,12 @@ auto nullable(T)(T t) struct Test { - bool b; - - nothrow invariant { assert(b == true); } - SysTime _st; static bool destroyed; @disable this(); - this(bool b) { this.b = b; } + this(int _dummy) {} ~this() @safe { destroyed = true; } // mustn't call opAssign on Test.init in Nullable!Test, because the invariant @@ -4109,7 +4114,7 @@ auto nullable(T)(T t) { Nullable!Test nt; - nt = Test(true); + nt = Test(1); // destroy value Test.destroyed = false; @@ -10676,6 +10681,21 @@ unittest assert(s2.get().b == 3); } +// https://issues.dlang.org/show_bug.cgi?id=24318 +@system unittest +{ + static struct S + { + @disable this(this); + int i; + } + + Nullable!S s = S(1); + assert(s.get().i == 1); + s = S(2); + assert(s.get().i == 2); +} + /// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed. /// Old code may be relying on `@safe`ty of some of the member functions which /// cannot be safe in the new scheme, and