From patchwork Sun Mar 13 13:12:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1604773 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=van5u/zP; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from 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 RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KGg8Z0cnJz9sGQ for ; Mon, 14 Mar 2022 00:13:16 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2A0A93858C3A for ; Sun, 13 Mar 2022 13:13:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2A0A93858C3A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1647177193; bh=By+Ep7yg4jKS3ajdBybBZRaaMInH/KipeUZCLn6FihM=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=van5u/zP14MABIb7mSZ9adsiiTw+8O/dey73mEiT2YJPlJumhVOlfvl23/19T+v6g IAh3AyZk5aGHKB4gVBxnixpbNDr5I4YrF3m6M5Gntv3XAaYyV2aHK76rZm6rXIOg85 kFHeEiYQGs06C+rlJjO2jpiXwKlx43+fpKwBiF6w= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [80.241.56.152]) by sourceware.org (Postfix) with ESMTPS id 50B5A3858C78 for ; Sun, 13 Mar 2022 13:12:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 50B5A3858C78 Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:105:465:1:3:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4KGg7j3KRkz9sTH; Sun, 13 Mar 2022 14:12:33 +0100 (CET) To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd 02a3fafc6, druntime 26b58167, phobos 16cb085b5. Date: Sun, 13 Mar 2022 14:12:16 +0100 Message-Id: <20220313131216.1137773-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Iain Buclaw via Gcc-patches From: Iain Buclaw Reply-To: Iain Buclaw Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Hi, This patch merges the D front-end implementation with upstream dmd 02a3fafc6, as well as the D runtime libraries with druntime 26b58167, and phobos 16cb085b5, synchronizing with the release of 2.099.0. D front-end changes: - Import dmd v2.099.0. - The deprecation period for D1-style operators has ended, any use of the D1 overload operators will now result in a compiler error. - `scope' as a type constraint on class, struct, union, and enum declarations has been deprecated. - Fix segmentation fault when emplacing a new front-end Expression node during CTFE (PR104835). D runtime changes: - Import druntime v2.099.0. - Fix C bindings for stdint types (PR104738). - Fix bus error when allocating new array on the GC (PR104742). - Fix bus error when allocating new pointer on the GC (PR104745). Phobos changes: - Import phobos v2.099.0. - New function `bind' in `std.functional'. Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, with further bootstrap testing on mips64el-linux-gnu and sparc64-linux-gnu to verify found issues are fixed. Committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 02a3fafc6. * dmd/VERSION: Update version to v2.099.0. * imports.cc (ImportVisitor::visit (EnumDeclaration *)): Don't cache decl in front-end AST node. (ImportVisitor::visit (AggregateDeclaration *)): Likewise. (ImportVisitor::visit (ClassDeclaration *)): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 26b58167. * src/MERGE: Merge upstream phobos 16cb085b5. --- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/common/outbuffer.d | 35 ++ gcc/d/dmd/constfold.d | 5 +- gcc/d/dmd/cparse.d | 265 ++++++++++++- gcc/d/dmd/dcast.d | 8 +- gcc/d/dmd/dclass.d | 44 +-- gcc/d/dmd/declaration.d | 7 +- gcc/d/dmd/declaration.h | 1 + gcc/d/dmd/dmodule.d | 26 +- gcc/d/dmd/dsymbol.d | 80 +++- gcc/d/dmd/dsymbol.h | 7 +- gcc/d/dmd/dsymbolsem.d | 49 ++- gcc/d/dmd/dtemplate.d | 6 +- gcc/d/dmd/dtoh.d | 9 + gcc/d/dmd/escape.d | 23 +- gcc/d/dmd/expression.d | 16 +- gcc/d/dmd/expressionsem.d | 81 +++- gcc/d/dmd/importc.d | 5 +- gcc/d/dmd/lexer.d | 344 +++-------------- gcc/d/dmd/mtype.d | 20 +- gcc/d/dmd/mtype.h | 2 + gcc/d/dmd/opover.d | 45 ++- gcc/d/dmd/optimize.d | 53 +-- gcc/d/dmd/parse.d | 6 +- gcc/d/dmd/statementsem.d | 105 +++--- gcc/d/dmd/tokens.d | 21 -- gcc/d/dmd/tokens.h | 1 - gcc/d/dmd/typesem.d | 16 +- gcc/d/imports.cc | 6 +- .../gdc.test/compilable/commontype.d | 9 +- gcc/testsuite/gdc.test/compilable/test7172.d | 5 + .../gdc.test/fail_compilation/dep_d1_ops.d | 82 ++-- .../gdc.test/fail_compilation/dephexstrings.d | 3 +- .../fail_compilation/deprecateopdot.d | 6 +- .../gdc.test/fail_compilation/fail136.d | 2 +- .../gdc.test/fail_compilation/fail18.d | 2 +- .../gdc.test/fail_compilation/fail22780.d | 3 +- .../gdc.test/fail_compilation/fail22827.d | 9 + .../gdc.test/fail_compilation/issue22820.d | 68 ++++ .../gdc.test/fail_compilation/lexer1.d | 4 +- .../gdc.test/fail_compilation/lexer2.d | 8 +- .../gdc.test/fail_compilation/opapplyscope.d | 27 ++ .../gdc.test/fail_compilation/scope_class.d | 3 +- .../gdc.test/fail_compilation/scope_type.d | 8 +- .../gdc.test/fail_compilation/test15191.d | 28 +- .../gdc.test/fail_compilation/test19097.d | 44 ++- .../gdc.test/fail_compilation/test21008.d | 41 ++ .../fail_compilation/test_switch_error.d | 78 ++++ .../gdc.test/fail_compilation/typeerrors.d | 31 +- gcc/testsuite/gdc.test/runnable/auto1.d | 8 +- gcc/testsuite/gdc.test/runnable/interpret.d | 2 +- gcc/testsuite/gdc.test/runnable/opover.d | 352 ++++++++---------- gcc/testsuite/gdc.test/runnable/sctor2.d | 7 +- gcc/testsuite/gdc.test/runnable/test22136.d | 25 -- gcc/testsuite/gdc.test/runnable/testconst.d | 4 +- gcc/testsuite/gdc.test/runnable/xtest46.d | 18 +- gcc/testsuite/gdc.test/runnable/xtest46_gc.d | 8 - libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/internal/gc/bits.d | 4 +- libphobos/libdruntime/core/stdc/config.d | 2 +- libphobos/libdruntime/core/stdc/fenv.d | 2 + libphobos/libdruntime/core/stdc/stdint.d | 314 +++++++++++++--- libphobos/libdruntime/core/stdcpp/new_.d | 2 +- libphobos/libdruntime/core/sys/windows/stat.d | 61 ++- libphobos/libdruntime/rt/lifetime.d | 11 +- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/setops.d | 2 +- libphobos/src/std/bitmanip.d | 3 +- libphobos/src/std/datetime/interval.d | 4 +- libphobos/src/std/datetime/systime.d | 4 +- .../std/experimental/allocator/mallocator.d | 1 + libphobos/src/std/functional.d | 165 ++++++++ libphobos/src/std/sumtype.d | 1 + libphobos/src/std/utf.d | 12 +- 75 files changed, 1792 insertions(+), 975 deletions(-) create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22827.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/issue22820.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test21008.d delete mode 100644 gcc/testsuite/gdc.test/runnable/test22136.d diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 71dc2b0a155..220088969c5 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -423f19b41089f627808bf16ff21c60c0791712ba +cbba5f41a32cfed7f22a213d537f8e2dee0b92f7 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 4bb69df8e2c..17724c661f7 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.099.0-rc.1 +v2.099.0 diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index fafe90e5357..0705c1880c0 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -662,6 +662,8 @@ struct OutBuffer return cast(char)data[i]; } + alias opDollar = length; + /*********************************** * Extract the data as a slice and take ownership of it. * @@ -879,3 +881,36 @@ unittest s = unsignedToTempString(29, buf[], 16); assert(s == "1d"); } + +unittest +{ + OutBuffer buf; + buf.writeUTF8(0x0000_0011); + buf.writeUTF8(0x0000_0111); + buf.writeUTF8(0x0000_1111); + buf.writeUTF8(0x0001_1111); + buf.writeUTF8(0x0010_0000); + assert(buf[] == "\x11\U00000111\U00001111\U00011111\U00100000"); + + buf.reset(); + buf.writeUTF16(0x0000_0011); + buf.writeUTF16(0x0010_FFFF); + assert(buf[] == cast(string) "\u0011\U0010FFFF"w); +} + +unittest +{ + OutBuffer buf; + buf.doindent = true; + + const(char)[] s = "abc"; + buf.writestring(s); + buf.level += 1; + buf.indent(); + buf.writestring("abs"); + + assert(buf[] == "abc\tabs"); + + buf.setsize(4); + assert(buf.length == 4); +} diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 7bc890f9ae2..96ca5207511 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1230,7 +1230,7 @@ UnionExp ArrayLength(Type type, Expression e1) /* Also return EXP.cantExpression if this fails */ -UnionExp Index(Type type, Expression e1, Expression e2) +UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) { UnionExp ue = void; Loc loc = e1.loc; @@ -1255,8 +1255,9 @@ UnionExp Index(Type type, Expression e1, Expression e2) TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype(); uinteger_t length = tsa.dim.toInteger(); uinteger_t i = e2.toInteger(); - if (i >= length) + if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds)) { + // C code only checks bounds if an ArrayLiteralExp e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length); emplaceExp!(ErrorExp)(&ue); } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 3ded10a7346..2edab14c2a4 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -22,6 +22,7 @@ import dmd.identifier; import dmd.lexer; import dmd.parse; import dmd.errors; +import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; @@ -38,6 +39,24 @@ final class CParser(AST) : Parser!AST bool addFuncName; /// add declaration of __func__ to function symbol table bool importBuiltins; /// seen use of C compiler builtins, so import __builtins; + private + { + structalign_t packalign; // current state of #pragma pack alignment + + // #pragma pack stack + Array!Identifier* records; // identifers (or null) + Array!structalign_t* packs; // parallel alignment values + } + + /** C allows declaring a function with a typedef: + * typedef int (myfunc)(); myfunc fun; + * but we need to distinguish `fun` being a function as opposed to a variable in the + * parse pass. This is accomplished by having a simple symbol table of typedefs + * where we know, by syntax, if they are function types or non-function types. + * funcTypeIds is the symbol table, of the identifiers of typedefs of function types. + */ + AST.Identifiers funcTypeIds; /// Identifiers in this are typedefs of function types + extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, const ref TARGET target) { @@ -47,6 +66,7 @@ final class CParser(AST) : Parser!AST mod = _module; linkage = LINK.c; Ccompile = true; + this.packalign.setDefault(); // Configure sizes for C `long`, `long double`, `wchar_t`, ... this.boolsize = target.boolsize; @@ -130,6 +150,7 @@ final class CParser(AST) : Parser!AST //printf("cparseStatement()\n"); + const funcTypeIdsLengthSave = funcTypeIds.length; auto symbolsSave = symbols; if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))) symbols = new AST.Dsymbols(); @@ -572,6 +593,7 @@ final class CParser(AST) : Parser!AST if (pEndloc) *pEndloc = prevloc; symbols = symbolsSave; + funcTypeIds.setDim(funcTypeIdsLengthSave); return s; } @@ -1551,6 +1573,7 @@ final class CParser(AST) : Parser!AST return; } + const funcTypeIdsLengthSave = funcTypeIds.length; auto symbolsSave = symbols; Specifier specifier; specifier.packalign = this.packalign; @@ -1660,11 +1683,13 @@ final class CParser(AST) : Parser!AST t.value == TOK.leftCurly) // start of compound-statement { auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier); + funcTypeIds.setDim(funcTypeIdsLengthSave); symbols = symbolsSave; symbols.push(s); return; } AST.Dsymbol s = null; + funcTypeIds.setDim(funcTypeIdsLengthSave); symbols = symbolsSave; if (!symbols) symbols = new AST.Dsymbols; // lazilly create it @@ -1722,6 +1747,10 @@ final class CParser(AST) : Parser!AST } } } + else if (isFunctionTypedef(dt)) + { + funcTypeIds.push(id); // remember function typedefs + } if (isalias) s = new AST.AliasDeclaration(token.loc, id, dt); } @@ -1743,7 +1772,8 @@ final class CParser(AST) : Parser!AST } // declare the symbol assert(id); - if (dt.isTypeFunction()) + + if (isFunctionTypedef(dt)) { if (hasInitializer) error("no initializer for function declaration"); @@ -4546,5 +4576,238 @@ final class CParser(AST) : Parser!AST return s; } + /******************************** + * Determines if type t is a function type. + * Make this work without needing semantic analysis. + * Params: + * t = type to test + * Returns: + * true if it represents a function + */ + bool isFunctionTypedef(AST.Type t) + { + //printf("isFunctionTypedef() %s\n", t.toChars()); + if (t.isTypeFunction()) + return true; + if (auto tid = t.isTypeIdentifier()) + { + /* Scan array of typedef identifiers that are an alias for + * a function type + */ + foreach (ftid; funcTypeIds[]) + { + if (tid.ident == ftid) + { + return true; + } + } + } + return false; + } + + //} + + /******************************************************************************/ + /********************************* Directive Parser ***************************/ + //{ + + override bool parseSpecialTokenSequence() + { + Token n; + scan(&n); + if (n.value == TOK.int32Literal) + { + poundLine(n, true); + return true; + } + if (n.value == TOK.identifier) + { + if (n.ident == Id.line) + { + poundLine(n, false); + return true; + } + else if (n.ident == Id.__pragma) + { + pragmaDirective(scanloc); + return true; + } + } + error("C preprocessor directive `#%s` is not supported", n.toChars()); + return false; + } + + /********************************************* + * C11 6.10.6 Pragma directive + * # pragma pp-tokens(opt) new-line + * The C preprocessor sometimes leaves pragma directives in + * the preprocessed output. Ignore them. + * Upon return, p is at start of next line. + */ + private void pragmaDirective(const ref Loc loc) + { + Token n; + scan(&n); + if (n.value == TOK.identifier && n.ident == Id.pack) + return pragmaPack(loc); + skipToNextLine(); + } + + /********* + * # pragma pack + * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html + * https://docs.microsoft.com/en-us/cpp/preprocessor/pack + * Scanner is on the `pack` + * Params: + * startloc = location to use for error messages + */ + private void pragmaPack(const ref Loc startloc) + { + const loc = startloc; + Token n; + scan(&n); + if (n.value != TOK.leftParenthesis) + { + error(loc, "left parenthesis expected to follow `#pragma pack`"); + skipToNextLine(); + return; + } + + void closingParen() + { + if (n.value != TOK.rightParenthesis) + { + error(loc, "right parenthesis expected to close `#pragma pack(`"); + } + skipToNextLine(); + } + + void setPackAlign(ref const Token t) + { + const n = t.unsvalue; + if (n < 1 || n & (n - 1) || ushort.max < n) + error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n); + packalign.set(cast(uint)n); + packalign.setPack(true); + } + + scan(&n); + + if (!records) + { + records = new Array!Identifier; + packs = new Array!structalign_t; + } + + /* # pragma pack ( show ) + */ + if (n.value == TOK.identifier && n.ident == Id.show) + { + if (packalign.isDefault()) + warning(startloc, "current pack attribute is default"); + else + warning(startloc, "current pack attribute is %d", packalign.get()); + scan(&n); + return closingParen(); + } + /* # pragma pack ( push ) + * # pragma pack ( push , identifier ) + * # pragma pack ( push , integer ) + * # pragma pack ( push , identifier , integer ) + */ + if (n.value == TOK.identifier && n.ident == Id.push) + { + scan(&n); + Identifier record = null; + if (n.value == TOK.comma) + { + scan(&n); + if (n.value == TOK.identifier) + { + record = n.ident; + scan(&n); + if (n.value == TOK.comma) + { + scan(&n); + if (n.value == TOK.int32Literal) + { + setPackAlign(n); + scan(&n); + } + else + error(loc, "alignment value expected, not `%s`", n.toChars()); + } + } + else if (n.value == TOK.int32Literal) + { + setPackAlign(n); + scan(&n); + } + else + error(loc, "alignment value expected, not `%s`", n.toChars()); + } + this.records.push(record); + this.packs.push(packalign); + return closingParen(); + } + /* # pragma pack ( pop ) + * # pragma pack ( pop PopList ) + * PopList : + * , IdentifierOrInteger + * , IdentifierOrInteger PopList + * IdentifierOrInteger: + * identifier + * integer + */ + if (n.value == TOK.identifier && n.ident == Id.pop) + { + scan(&n); + while (n.value == TOK.comma) + { + scan(&n); + if (n.value == TOK.identifier) + { + for (size_t len = this.records.length; len; --len) + { + if ((*this.records)[len - 1] == n.ident) + { + packalign = (*this.packs)[len - 1]; + this.records.setDim(len - 1); + this.packs.setDim(len - 1); + break; + } + } + scan(&n); + } + else if (n.value == TOK.int32Literal) + { + setPackAlign(n); + this.records.push(null); + this.packs.push(packalign); + scan(&n); + } + } + return closingParen(); + } + /* # pragma pack ( integer ) + */ + if (n.value == TOK.int32Literal) + { + setPackAlign(n); + scan(&n); + return closingParen(); + } + /* # pragma pack ( ) + */ + if (n.value == TOK.rightParenthesis) + { + packalign.setDefault(); + return closingParen(); + } + + error(loc, "unrecognized `#pragma pack(%s)`", n.toChars()); + skipToNextLine(); + } + //} } diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index f1afa76e53b..69036ada483 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -2443,7 +2443,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } - __gshared const(char)* msg = "cannot form delegate due to covariant return type"; + static immutable msg = "cannot form delegate due to covariant return type"; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); @@ -2453,7 +2453,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) int offset; e.func.tookAddressOf++; if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) - e.error("%s", msg); + e.error("%s", msg.ptr); auto result = e.copy(); result.type = t; return result; @@ -2469,7 +2469,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { int offset; if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) - e.error("%s", msg); + e.error("%s", msg.ptr); if (f != e.func) // if address not already marked as taken f.tookAddressOf++; auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2); @@ -2477,7 +2477,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) return result; } if (e.func.tintro) - e.error("%s", msg); + e.error("%s", msg.ptr); } } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index ce463c023f0..15ac8d91735 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -205,7 +205,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration super(loc, id); - __gshared const(char)* msg = "only object.d can define this reserved class name"; + static immutable msg = "only object.d can define this reserved class name"; if (baseclasses) { @@ -232,37 +232,37 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (id == Id.TypeInfo) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.dtypeinfo = this; } if (id == Id.TypeInfo_Class) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoclass = this; } if (id == Id.TypeInfo_Interface) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfointerface = this; } if (id == Id.TypeInfo_Struct) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfostruct = this; } if (id == Id.TypeInfo_Pointer) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfopointer = this; } if (id == Id.TypeInfo_Array) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoarray = this; } if (id == Id.TypeInfo_StaticArray) @@ -274,61 +274,61 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (id == Id.TypeInfo_AssociativeArray) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoassociativearray = this; } if (id == Id.TypeInfo_Enum) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoenum = this; } if (id == Id.TypeInfo_Function) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfofunction = this; } if (id == Id.TypeInfo_Delegate) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfodelegate = this; } if (id == Id.TypeInfo_Tuple) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfotypelist = this; } if (id == Id.TypeInfo_Const) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoconst = this; } if (id == Id.TypeInfo_Invariant) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoinvariant = this; } if (id == Id.TypeInfo_Shared) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoshared = this; } if (id == Id.TypeInfo_Wild) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfowild = this; } if (id == Id.TypeInfo_Vector) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfovector = this; } } @@ -336,32 +336,32 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (id == Id.Object) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); object = this; } if (id == Id.Throwable) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); throwable = this; } if (id == Id.Exception) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); exception = this; } if (id == Id.Error) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); errorException = this; } if (id == Id.cpp_type_info_ptr) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); cpp_type_info_ptr = this; } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index cdf9355e94c..585ac2f0b60 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -29,6 +29,7 @@ import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; +import dmd.gluelayer; import dmd.id; import dmd.identifier; import dmd.init; @@ -227,6 +228,8 @@ extern (C++) abstract class Declaration : Dsymbol enum wasRead = 1; // set if AliasDeclaration was read enum ignoreRead = 2; // ignore any reads of AliasDeclaration + Symbol* isym; // import version of csym + // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; @@ -679,10 +682,12 @@ extern (C++) final class TupleDeclaration : Declaration } /*********************************************************** + * https://dlang.org/spec/declaration.html#AliasDeclaration */ extern (C++) final class AliasDeclaration : Declaration { - Dsymbol aliassym; + Dsymbol aliassym; // alias ident = aliassym; + Dsymbol overnext; // next in overload list Dsymbol _import; // !=null if unresolved internal alias for selective import diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index e30acb41b2a..93e3a5a0b5d 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -119,6 +119,7 @@ public: LINK linkage; short inuse; // used to detect cycles uint8_t adFlags; + Symbol* isym; // import version of csym DString mangleOverride; // overridden symbol with pragma(mangle, "...") const char *kind() const; diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 6568442c17a..00fa031397c 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -675,24 +675,28 @@ extern (C++) final class Module : Package //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); - if (global.params.emitMakeDeps) - { - global.params.makeDeps.push(srcfile.toChars()); - } + + bool success; if (auto readResult = FileManager.fileManager.lookup(srcfile)) { srcBuffer = readResult; - return true; + success = true; } - - auto readResult = File.read(srcfile.toChars()); - if (loadSourceBuffer(loc, readResult)) + else { - FileManager.fileManager.add(srcfile, srcBuffer); - return true; + auto readResult = File.read(srcfile.toChars()); + if (loadSourceBuffer(loc, readResult)) + { + FileManager.fileManager.add(srcfile, srcBuffer); + success = true; + } } - return false; + if (success && global.params.emitMakeDeps) + { + global.params.makeDeps.push(srcfile.toChars()); + } + return success; } /// syntactic parse diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 200cb7639c7..f8ada2b1ea1 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -245,8 +245,6 @@ extern (C++) class Dsymbol : ASTNode /// C++ namespace this symbol belongs to CPPNamespaceDeclaration cppnamespace; Symbol* csym; // symbol for code generator - Symbol* isym; // import version of csym - const(char)* comment; // documentation comment for this Dsymbol const Loc loc; // where defined Scope* _scope; // !=null means context to use for semantic() const(char)* prettystring; // cached value of toPrettyChars() @@ -257,10 +255,6 @@ extern (C++) class Dsymbol : ASTNode DeprecatedDeclaration depdecl; // customized deprecation message UserAttributeDeclaration userAttribDecl; // user defined attributes - // !=null means there's a ddoc unittest associated with this symbol - // (only use this with ddoc) - UnitTestDeclaration ddocUnittest; - final extern (D) this() { //printf("Dsymbol::Dsymbol(%p)\n", this); @@ -811,7 +805,7 @@ extern (C++) class Dsymbol : ASTNode Dsymbol s2 = sds.symtabLookup(this,ident); // If using C tag/prototype/forward declaration rules - if (sc.flags & SCOPE.Cfile) + if (sc.flags & SCOPE.Cfile && !this.isImport()) { if (handleTagSymbols(*sc, this, s2, sds)) return; @@ -1214,17 +1208,65 @@ extern (C++) class Dsymbol : ASTNode */ void addComment(const(char)* comment) { - //if (comment) - // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - if (!this.comment) - this.comment = comment; - else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0) + if (!comment || !*comment) + return; + + //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars()); + void* h = cast(void*)this; // just the pointer is the key + auto p = h in commentHashTable; + if (!p) + { + commentHashTable[h] = comment; + return; + } + if (strcmp(*p, comment) != 0) { // Concatenate the two - this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true); + *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true); } } + /// get documentation comment for this Dsymbol + final const(char)* comment() + { + //printf("getcomment: %p '%s'\n", this, this.toChars()); + if (auto p = cast(void*)this in commentHashTable) + { + //printf("comment: '%s'\n", *p); + return *p; + } + return null; + } + + /* Shell around addComment() to avoid disruption for the moment */ + final void comment(const(char)* comment) { addComment(comment); } + + private extern (D) __gshared const(char)*[void*] commentHashTable; + + + /********************************** + * Get ddoc unittest associated with this symbol. + * (only use this with ddoc) + * Returns: ddoc unittest, null if none + */ + final UnitTestDeclaration ddocUnittest() + { + if (auto p = cast(void*)this in ddocUnittestHashTable) + return *p; + return null; + } + + /********************************** + * Set ddoc unittest associated with this symbol. + */ + final void ddocUnittest(UnitTestDeclaration utd) + { + ddocUnittestHashTable[cast(void*)this] = utd; + } + + private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable; + + /**************************************** * Returns true if this symbol is defined in a non-root module without instantiation. */ @@ -1247,6 +1289,18 @@ extern (C++) class Dsymbol : ASTNode return false; } + /** + * Deinitializes the global state of the compiler. + * + * This can be used to restore the state set by `_init` to its original + * state. + */ + static void deinitialize() + { + commentHashTable = commentHashTable.init; + ddocUnittestHashTable = ddocUnittestHashTable.init; + } + /************ */ override void accept(Visitor v) diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 03d5c3d2e98..c5af06eb4cd 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -175,8 +175,6 @@ public: /// C++ namespace this symbol belongs to CPPNamespaceDeclaration *namespace_; Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym - const utf8_t *comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope *_scope; // !=NULL means context to use for semantic() const utf8_t *prettystring; @@ -185,7 +183,6 @@ public: unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab DeprecatedDeclaration *depdecl; // customized deprecation message UserAttributeDeclaration *userAttribDecl; // user defined attributes - UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc) static Dsymbol *create(Identifier *); const char *toChars() const; @@ -252,6 +249,10 @@ public: virtual void checkCtorConstInit() { } virtual void addComment(const utf8_t *comment); + const utf8_t *comment(); // current value of comment + + UnitTestDeclaration *ddocUnittest(); + void ddocUnittest(UnitTestDeclaration *); bool inNonRoot(); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index ef25717e79f..b68d840c396 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2140,6 +2140,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Module.dprogress++; + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + Scope* sce; if (ed.isAnonymous()) sce = sc; @@ -3085,6 +3091,25 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return null; } + if (sc.flags & SCOPE.Cfile) + { + /* C11 allows a function to be declared with a typedef, D does not. + */ + if (auto ti = funcdecl.type.isTypeIdentifier()) + { + auto tj = ti.typeSemantic(funcdecl.loc, sc); + if (auto tjf = tj.isTypeFunction()) + { + /* Copy the type instead of just pointing to it, + * as we don't merge function types + */ + auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); + funcdecl.type = tjf2; + funcdecl.originalType = tjf2; + } + } + } + if (!getFunctionType(funcdecl)) return; @@ -3550,6 +3575,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor default: { + if (vi >= cd.vtbl.length) + { + /* the derived class cd doesn't have its vtbl[] allocated yet. + * https://issues.dlang.org/show_bug.cgi?id=21008 + */ + funcdecl.error("circular reference to class `%s`", cd.toChars()); + funcdecl.errors = true; + return; + } FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); // This function is covariant with fdv @@ -4625,6 +4659,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sd.deferred.semantic2(sc); sd.deferred.semantic3(sc); } + + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sd.storage_class & STC.scope_) + deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); } void interfaceSemantic(ClassDeclaration cd) @@ -5283,12 +5323,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.087 - // Make an error in 2.091 + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 - if (0 && // deprecation disabled for now to accommodate existing extensive use - cldec.storage_class & STC.scope_) + if (cldec.storage_class & STC.scope_) deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); } diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 6abe69a9c4f..adb91edec78 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -7806,10 +7806,10 @@ struct TemplateInstanceBox /* Used when a proposed instance is used to see if there's * an existing instance. */ - static if (__VERSION__ >= 2099) - res = (cast()ti).equalsx(cast()s.ti); - else // https://issues.dlang.org/show_bug.cgi?id=22717 + static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717 res = (cast()s.ti).equalsx(cast()ti); + else + res = (cast()ti).equalsx(cast()s.ti); } debug (FindExistingInstance) ++(res ? nHits : nCollisions); diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index a34e2ccae28..285b834f468 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -180,6 +180,15 @@ struct _d_dynamicArray final `); } + // prevent trailing newlines + version (Windows) + while (buf.length >= 4 && buf[$-4..$] == "\r\n\r\n") + buf.remove(buf.length - 2, 2); + else + while (buf.length >= 2 && buf[$-2..$] == "\n\n") + buf.remove(buf.length - 1, 1); + + if (global.params.cxxhdrname is null) { // Write to stdout; assume it succeeds diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 35c1f76e600..be11f26b04a 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -497,7 +497,7 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) { Expression arg = (*ce.arguments)[i]; if (!arg.type.hasPointers()) - return false; + continue; //printf("\targ[%d]: %s\n", i, arg.toChars()); @@ -620,7 +620,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) return false; if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter return true; - if (fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter + if (!fd.vthis && fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter return true; } return false; @@ -1029,7 +1029,6 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) */ !(p.parent == sc.func)) { - // Only look for errors if in module listed on command line if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029 && sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868 { @@ -1095,7 +1094,6 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) continue; // https://dlang.org/spec/function.html#return-ref-parameters - // Only look for errors if in module listed on command line if (p == sc.func) { //printf("escaping reference to local ref variable %s\n", v.toChars()); @@ -1246,7 +1244,6 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0) ) { - // Only look for errors if in module listed on command line // https://issues.dlang.org/show_bug.cgi?id=17029 if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) { @@ -1278,11 +1275,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { if (log) { - printf("byref `%s`\n", v.toChars()); - if (v.storage_class & STC.return_) printf(" return"); - if (v.storage_class & STC.ref_) printf(" ref"); - if (v.storage_class & STC.scope_) printf(" scope"); - printf("\n"); + printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class))); } // 'featureState' tells us whether to emit an error or a deprecation, @@ -1714,9 +1707,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { Parameter p = tf.parameterList[i - j]; const stc = tf.parameterStorageClass(null, p); - if ((stc & (STC.scope_)) && (stc & STC.return_)) + ScopeRef psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) arg.accept(this); - else if ((stc & (STC.ref_)) && (stc & STC.return_)) + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) { if (tf.isref) { @@ -1974,9 +1968,10 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) { Parameter p = tf.parameterList[i - j]; const stc = tf.parameterStorageClass(null, p); - if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_)) + ScopeRef psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) arg.accept(this); - else if ((stc & STC.scope_) && (stc & STC.return_)) + else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) { if (auto de = arg.isDelegateExp()) { diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 2b41219846a..45fefc03dea 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -72,10 +72,15 @@ import dmd.typesem; import dmd.visitor; enum LOGSEMANTIC = false; + void emplaceExp(T : Expression, Args...)(void* p, Args args) { - scope tmp = new T(args); - memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T)); + static if (__VERSION__ < 2099) + const init = typeid(T).initializer; + else + const init = __traits(initSymbol, T); + p[0 .. __traits(classInstanceSize, T)] = init[]; + (cast(T)p).__ctor(args); } void emplaceExp(T : UnionExp)(T* p, Expression e) @@ -5831,6 +5836,13 @@ extern (C++) final class IndexExp : BinExp //printf("IndexExp::IndexExp('%s')\n", toChars()); } + extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) + { + super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2); + this.indexIsInBounds = indexIsInBounds; + //printf("IndexExp::IndexExp('%s')\n", toChars()); + } + override IndexExp syntaxCopy() { auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy()); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 6692fb9717e..f8e5af4ac95 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -5279,6 +5279,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // The mangling change only works for D mangling } + if (!(sc.flags & SCOPE.Cfile)) { /* https://issues.dlang.org/show_bug.cgi?id=21272 * If we are in a foreach body we need to extract the @@ -7057,19 +7058,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (exp.e1.op == EXP.call) + else if (auto ce = exp.e1.isCallExp()) { - CallExp ce = cast(CallExp)exp.e1; - if (ce.e1.type.ty == Tfunction) - { - TypeFunction tf = cast(TypeFunction)ce.e1.type; - if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) - && tf.next.hasPointers() && sc.func.setUnsafe()) - { - exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`", - ce.e1.toChars(), sc.func.toChars()); - } - } + if (!checkAddressCall(sc, ce, "take address of")) + return setError(); } else if (exp.e1.op == EXP.index) { @@ -7800,7 +7792,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); Type t1b = exp.e1.type.toBasetype(); - if (t1b.ty == Tpointer) + if (auto tp = t1b.isTypePointer()) { if (t1b.isPtrToFunction()) { @@ -7809,7 +7801,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (!exp.lwr || !exp.upr) { - exp.error("need upper and lower bound to slice pointer"); + exp.error("upper and lower bounds are needed to slice a pointer"); + if (auto ad = isAggregate(tp.next.toBasetype())) + { + auto s = search_function(ad, Id.index); + if (!s) s = search_function(ad, Id.slice); + if (s) + { + auto fd = s.isFuncDeclaration(); + if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration()) + { + exp.errorSupplemental( + "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`", + exp.e1.toChars(), + s.ident.toChars(), + exp.e1.toChars() + ); + } + + } + } + return setError(); } if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) @@ -7844,6 +7856,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (v && !checkAddressVar(sc, exp.e1, v)) return setError(); } + // https://issues.dlang.org/show_bug.cgi?id=22539 + if (auto ce = exp.e1.isCallExp()) + { + if (!checkAddressCall(sc, ce, "slice static array of")) + return setError(); + } } } else if (t1b.ty == Ttuple) @@ -8446,7 +8464,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (length) { auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); - exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2)); + // OR it in, because it might already be set for C array indexing + exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2)); } } } @@ -12943,6 +12962,38 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) return true; } +/**************************************************** + * Determine if the address of a `ref return` value of + * a function call with type `tf` can be taken safely. + * + * This is currently stricter than necessary: it can be safe to take the + * address of a `ref` with pointer type when the pointer isn't `scope`, but + * that involves inspecting the function arguments and parameter types, which + * is left as a future enhancement. + * + * Params: + * sc = context + * ce = function call in question + * action = for the error message, how the pointer is taken, e.g. "slice static array of" + * Returns: + * `true` if ok, `false` for error + */ +private bool checkAddressCall(Scope* sc, CallExp ce, const(char)* action) +{ + if (auto tf = ce.e1.type.isTypeFunction()) + { + if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) + && tf.next.hasPointers() && sc.func.setUnsafe()) + { + ce.error("cannot %s `ref return` of `%s()` in `@safe` function `%s`", + action, ce.e1.toChars(), sc.func.toChars()); + ce.errorSupplemental("return type `%s` has pointers that may be `scope`", tf.next.toChars()); + return false; + } + } + return true; +} + /******************************* * Checks the attributes of a function. * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`) diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index a48b339bf50..72e0e1a93a5 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -159,7 +159,8 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) if (t1.isTypeDArray() || t1.isTypeSArray()) { e2 = e2.expressionSemantic(sc).arrayFuncConv(sc); - return new IndexExp(ae.loc, e1, e2).expressionSemantic(sc); + // C doesn't do array bounds checking, so `true` turns it off + return new IndexExp(ae.loc, e1, e2, true).expressionSemantic(sc); } e1 = e1.arrayFuncConv(sc); // e1 might still be a function call @@ -167,7 +168,7 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) auto t2 = e2.type.toBasetype(); if (t2.isTypeDArray() || t2.isTypeSArray()) { - return new IndexExp(ae.loc, e2, e1).expressionSemantic(sc); // swap operands + return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands } e2 = e2.arrayFuncConv(sc); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 965b3b45f87..dbdf6a503d1 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -68,8 +68,6 @@ class Lexer ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof ubyte wchar_tsize; /// size of C wchar_t, 2 or 4 - structalign_t packalign; /// current state of #pragma pack alignment (ImportC) - private { const(char)* base; // pointer to start of buffer @@ -89,10 +87,6 @@ class Lexer int lastDocLine; // last line of previous doc comment Token* tokenFreelist; - - // ImportC #pragma pack stack - Array!Identifier* records; // identifers (or null) - Array!structalign_t* packs; // parallel alignment values } nothrow: @@ -124,7 +118,6 @@ class Lexer this.commentToken = commentToken; this.inTokenStringConstant = 0; this.lastDocLine = 0; - this.packalign.setDefault(); //initKeywords(); /* If first line starts with '#!', ignore the line */ @@ -381,24 +374,18 @@ class Lexer goto case_ident; case 'r': - if (p[1] != '"') + if (Ccompile || p[1] != '"') goto case_ident; p++; goto case '`'; case '`': + if (Ccompile) + goto default; wysiwygStringConstant(t); return; - case 'x': - if (p[1] != '"') - goto case_ident; - p++; - auto start = p; - OutBuffer hexString; - t.value = hexStringConstant(t); - hexString.write(start[0 .. p - start]); - error("Built-in hex string literals are obsolete, use `std.conv.hexString!%s` instead.", hexString.extractChars()); - return; case 'q': + if (Ccompile) + goto case_ident; if (p[1] == '"') { p++; @@ -438,7 +425,7 @@ class Lexer //case 'u': case 'v': case 'w': - /*case 'x':*/ + case 'x': case 'y': case 'z': case 'A': @@ -676,6 +663,7 @@ class Lexer endOfLine(); continue; case '+': + if (!Ccompile) { int nest; startLoc = loc(); @@ -745,6 +733,7 @@ class Lexer } continue; } + break; default: break; } @@ -1051,35 +1040,8 @@ class Lexer case '#': { p++; - Token n; - scan(&n); - if (Ccompile && n.value == TOK.int32Literal) - { - poundLine(n, true); + if (parseSpecialTokenSequence()) continue; - } - if (n.value == TOK.identifier) - { - if (n.ident == Id.line) - { - poundLine(n, false); - continue; - } - else if (n.ident == Id.__pragma && Ccompile) - { - pragmaDirective(scanloc); - continue; - } - else - { - const locx = loc(); - warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); - } - } - else if (n.value == TOK.if_) - { - error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); - } t.value = TOK.pound; return; } @@ -1388,84 +1350,6 @@ class Lexer } } - /************************************** - * Lex hex strings: - * x"0A ae 34FE BD" - */ - private TOK hexStringConstant(Token* t) - { - Loc start = loc(); - uint n = 0; - uint v = ~0; // dead assignment, needed to suppress warning - p++; - stringbuffer.setsize(0); - while (1) - { - dchar c = *p++; - switch (c) - { - case ' ': - case '\t': - case '\v': - case '\f': - continue; // skip white space - case '\r': - if (*p == '\n') - continue; // ignore '\r' if followed by '\n' - // Treat isolated '\r' as if it were a '\n' - goto case '\n'; - case '\n': - endOfLine(); - continue; - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t.setString(); - // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). - p--; - return TOK.hexadecimalString; - case '"': - if (n & 1) - { - error("odd number (%d) of hex characters in hex string", n); - stringbuffer.writeByte(v); - } - t.setString(stringbuffer); - stringPostfix(t); - return TOK.hexadecimalString; - default: - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c & 0x80) - { - p--; - const u = decodeUTF(); - p++; - if (u == PS || u == LS) - endOfLine(); - else - error("non-hex character \\u%04x in hex string", u); - } - else - error("non-hex character '%c' in hex string", c); - if (n & 1) - { - v = (v << 4) | c; - stringbuffer.writeByte(v); - } - else - v = c; - n++; - break; - } - } - assert(0); // see bug 15731 - } - /** Lex a delimited string. Some examples of delimited strings are: --- @@ -2666,6 +2550,37 @@ class Lexer va_end(args); } + /*************************************** + * Parse special token sequence: + * Returns: + * true if the special token sequence was handled + * References: + * https://dlang.org/spec/lex.html#special-token-sequence + */ + bool parseSpecialTokenSequence() + { + Token n; + scan(&n); + if (n.value == TOK.identifier) + { + if (n.ident == Id.line) + { + poundLine(n, false); + return true; + } + else + { + const locx = loc(); + warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); + } + } + else if (n.value == TOK.if_) + { + error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); + } + return false; + } + /********************************************* * Parse line/file preprocessor directive: * #line linnum [filespec] @@ -2680,7 +2595,7 @@ class Lexer * References: * linemarker https://gcc.gnu.org/onlinedocs/gcc-11.1.0/cpp/Preprocessor-Output.html */ - private void poundLine(ref Token tok, bool linemarker) + final void poundLine(ref Token tok, bool linemarker) { auto linnum = this.scanloc.linnum; const(char)* filespec = null; @@ -2806,183 +2721,10 @@ class Lexer error(loc, "#line integer [\"filespec\"]\\n expected"); } - /********************************************* - * C11 6.10.6 Pragma directive - * # pragma pp-tokens(opt) new-line - * The C preprocessor sometimes leaves pragma directives in - * the preprocessed output. Ignore them. - * Upon return, p is at start of next line. - */ - private void pragmaDirective(const ref Loc loc) - { - Token n; - scan(&n); - if (n.value == TOK.identifier && n.ident == Id.pack) - return pragmaPack(loc); - skipToNextLine(); - } - - /********* - * ImportC - * # pragma pack - * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html - * https://docs.microsoft.com/en-us/cpp/preprocessor/pack - * Scanner is on the `pack` - * Params: - * startloc = location to use for error messages - */ - private void pragmaPack(const ref Loc startloc) - { - const loc = startloc; - Token n; - scan(&n); - if (n.value != TOK.leftParenthesis) - { - error(loc, "left parenthesis expected to follow `#pragma pack`"); - skipToNextLine(); - return; - } - - void closingParen() - { - if (n.value != TOK.rightParenthesis) - { - error(loc, "right parenthesis expected to close `#pragma pack(`"); - } - skipToNextLine(); - } - - void setPackAlign(ref const Token t) - { - const n = t.unsvalue; - if (n < 1 || n & (n - 1) || ushort.max < n) - error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n); - packalign.set(cast(uint)n); - packalign.setPack(true); - } - - scan(&n); - - if (!records) - { - records = new Array!Identifier; - packs = new Array!structalign_t; - } - - /* # pragma pack ( show ) - */ - if (n.value == TOK.identifier && n.ident == Id.show) - { - if (packalign.isDefault()) - warning(startloc, "current pack attribute is default"); - else - warning(startloc, "current pack attribute is %d", packalign.get()); - scan(&n); - return closingParen(); - } - /* # pragma pack ( push ) - * # pragma pack ( push , identifier ) - * # pragma pack ( push , integer ) - * # pragma pack ( push , identifier , integer ) - */ - if (n.value == TOK.identifier && n.ident == Id.push) - { - scan(&n); - Identifier record = null; - if (n.value == TOK.comma) - { - scan(&n); - if (n.value == TOK.identifier) - { - record = n.ident; - scan(&n); - if (n.value == TOK.comma) - { - scan(&n); - if (n.value == TOK.int32Literal) - { - setPackAlign(n); - scan(&n); - } - else - error(loc, "alignment value expected, not `%s`", n.toChars()); - } - } - else if (n.value == TOK.int32Literal) - { - setPackAlign(n); - scan(&n); - } - else - error(loc, "alignment value expected, not `%s`", n.toChars()); - } - this.records.push(record); - this.packs.push(packalign); - return closingParen(); - } - /* # pragma pack ( pop ) - * # pragma pack ( pop PopList ) - * PopList : - * , IdentifierOrInteger - * , IdentifierOrInteger PopList - * IdentifierOrInteger: - * identifier - * integer - */ - if (n.value == TOK.identifier && n.ident == Id.pop) - { - scan(&n); - while (n.value == TOK.comma) - { - scan(&n); - if (n.value == TOK.identifier) - { - for (size_t len = this.records.length; len; --len) - { - if ((*this.records)[len - 1] == n.ident) - { - packalign = (*this.packs)[len - 1]; - this.records.setDim(len - 1); - this.packs.setDim(len - 1); - break; - } - } - scan(&n); - } - else if (n.value == TOK.int32Literal) - { - setPackAlign(n); - this.records.push(null); - this.packs.push(packalign); - scan(&n); - } - } - return closingParen(); - } - /* # pragma pack ( integer ) - */ - if (n.value == TOK.int32Literal) - { - setPackAlign(n); - scan(&n); - return closingParen(); - } - /* # pragma pack ( ) - */ - if (n.value == TOK.rightParenthesis) - { - packalign.setDefault(); - return closingParen(); - } - - error(loc, "unrecognized `#pragma pack(%s)`", n.toChars()); - skipToNextLine(); - } - /*************************************** * Scan forward to start of next line. */ - private void skipToNextLine() + final void skipToNextLine() { while (1) { @@ -3557,5 +3299,3 @@ unittest assert(tok == TOK.endOfFile); } } - - diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 9297ad9dd03..18af7721df1 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4214,6 +4214,7 @@ extern (C++) final class TypeFunction : TypeNext inoutParam = 0x0400, // inout on the parameters inoutQual = 0x0800, // inout on the qualifier isctor = 0x1000, // the function is a constructor + isreturnscope = 0x2000, // `this` is returned by value } LINK linkage; // calling convention @@ -4247,6 +4248,8 @@ extern (C++) final class TypeFunction : TypeNext this.isref = true; if (stc & STC.return_) this.isreturn = true; + if (stc & STC.returnScope) + this.isreturnscope = true; if (stc & STC.returninferred) this.isreturninferred = true; if (stc & STC.scope_) @@ -4285,6 +4288,7 @@ extern (C++) final class TypeFunction : TypeNext t.isproperty = isproperty; t.isref = isref; t.isreturn = isreturn; + t.isreturnscope = isreturnscope; t.isScopeQual = isScopeQual; t.isreturninferred = isreturninferred; t.isscopeinferred = isscopeinferred; @@ -4507,6 +4511,7 @@ extern (C++) final class TypeFunction : TypeNext tf.isproperty = t.isproperty; tf.isref = t.isref; tf.isreturn = t.isreturn; + tf.isreturnscope = t.isreturnscope; tf.isScopeQual = t.isScopeQual; tf.isreturninferred = t.isreturninferred; tf.isscopeinferred = t.isscopeinferred; @@ -4573,6 +4578,7 @@ extern (C++) final class TypeFunction : TypeNext t.isproperty = isproperty; t.isref = isref; t.isreturn = isreturn; + t.isreturnscope = isreturnscope; t.isScopeQual = isScopeQual; t.isreturninferred = isreturninferred; t.isscopeinferred = isscopeinferred; @@ -5136,6 +5142,18 @@ extern (C++) final class TypeFunction : TypeNext else funcFlags &= ~FunctionFlag.isreturn; } + /// set or get if the function has the `returnscope` attribute + bool isreturnscope() const pure nothrow @safe @nogc + { + return (funcFlags & FunctionFlag.isreturnscope) != 0; + } + /// ditto + void isreturnscope(bool v) pure nothrow @safe @nogc + { + if (v) funcFlags |= FunctionFlag.isreturnscope; + else funcFlags &= ~FunctionFlag.isreturnscope; + } + /// set or get if the function has the `scope` attribute bool isScopeQual() const pure nothrow @safe @nogc { @@ -6384,7 +6402,7 @@ extern (C++) final class TypeClass : Type /* Conversion derived to const(base) */ int offset = 0; - if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod)) + if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod)) { // Disallow: // derived to base diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index cb6023696ee..3f085b06091 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -625,6 +625,8 @@ public: void isref(bool v); bool isreturn() const; void isreturn(bool v); + bool isreturnscope() const; + void isreturnscope(bool v); bool isScopeQual() const; void isScopeQual(bool v); bool isreturninferred() const; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 01708d65655..fc643776edd 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -396,13 +396,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) fd = search_function(ad, id); if (fd) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 - e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); - // Rewrite +e1 as e1.add() - result = build_overload(e.loc, sc, e.e1, null, fd); - return result; + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 + e.error("`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + return ErrorExp.get(); } } // Didn't find it. Forward to aliasthis @@ -670,13 +667,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) s = search_function(ad1, id); if (s && id != Id.assign) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 if (id == Id.postinc || id == Id.postdec) - e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + e.error("`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); else - e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + e.error("`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + return ErrorExp.get(); } } if (ad2 && id_r) @@ -689,10 +686,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) s_r = null; if (s_r) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 - e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 + e.error("`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); + return ErrorExp.get(); } } } @@ -1232,12 +1229,12 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) s = search_function(ad1, id); if (s) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 scope char[] op = EXPtoString(e.op).dup; op[$-1] = '\0'; // remove trailing `=` - e.deprecation("`%s` is deprecated. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr); + e.error("`%s` is obsolete. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr); + return ErrorExp.get(); } } @@ -1552,7 +1549,8 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out * Params: * fes = the foreach statement * sc = context - * sapply = null or opApply or delegate + * sapply = null or opApply or delegate, overload resolution has not been done. + * Do overload resolution on sapply. * Returns: * false for errors */ @@ -1588,8 +1586,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) */ if (FuncDeclaration fd = sapply.isFuncDeclaration()) { - auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters); - if (fdapply) + if (auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters)) { // Fill in any missing types on foreach parameters[] matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true); @@ -1598,7 +1595,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) } return false; } - return sapply !is null; + return true; // shouldn't this be false? } Parameter p = (*fes.parameters)[0]; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 10c265f600b..cc02bd9ea7c 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -338,9 +338,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) void visitTuple(TupleExp e) { expOptimize(e.e0, WANTvalue); - for (size_t i = 0; i < e.exps.dim; i++) + foreach (ref ex; (*e.exps)[]) { - expOptimize((*e.exps)[i], WANTvalue); + expOptimize(ex, WANTvalue); } } @@ -349,9 +349,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.elements) { expOptimize(e.basis, result & WANTexpand); - for (size_t i = 0; i < e.elements.dim; i++) + foreach (ref ex; (*e.elements)[]) { - expOptimize((*e.elements)[i], result & WANTexpand); + expOptimize(ex, result & WANTexpand); } } } @@ -359,9 +359,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) void visitAssocArrayLiteral(AssocArrayLiteralExp e) { assert(e.keys.dim == e.values.dim); - for (size_t i = 0; i < e.keys.dim; i++) + foreach (i, ref ekey; (*e.keys)[]) { - expOptimize((*e.keys)[i], result & WANTexpand); + expOptimize(ekey, result & WANTexpand); expOptimize((*e.values)[i], result & WANTexpand); } } @@ -374,9 +374,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) e.stageflags |= stageOptimize; if (e.elements) { - for (size_t i = 0; i < e.elements.dim; i++) + foreach (ref ex; (*e.elements)[]) { - expOptimize((*e.elements)[i], result & WANTexpand); + expOptimize(ex, result & WANTexpand); } } e.stageflags = old; @@ -647,9 +647,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) // Optimize parameters if (e.arguments) { - for (size_t i = 0; i < e.arguments.dim; i++) + foreach (ref arg; (*e.arguments)[]) { - expOptimize((*e.arguments)[i], WANTvalue); + expOptimize(arg, WANTvalue); } } } @@ -663,16 +663,16 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.arguments) { Type t1 = e.e1.type.toBasetype(); - if (t1.ty == Tdelegate) - t1 = t1.nextOf(); + if (auto td = t1.isTypeDelegate()) + t1 = td.next; // t1 can apparently be void for __ArrayDtor(T) calls if (auto tf = t1.isTypeFunction()) { - for (size_t i = 0; i < e.arguments.dim; i++) + foreach (i, ref arg; (*e.arguments)[]) { Parameter p = tf.parameterList[i]; bool keep = p && p.isReference(); - expOptimize((*e.arguments)[i], WANTvalue, keep); + expOptimize(arg, WANTvalue, keep); } } } @@ -719,14 +719,17 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) } } - if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) + // Returning e.e1 with changing its type + void returnE_e1() { - //printf(" returning2 %s\n", e.e1.toChars()); - L1: - // Returning e1 with changing its type ret = (e1old == e.e1 ? e.e1.copy() : e.e1); ret.type = e.type; - return; + } + + if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) + { + //printf(" returning2 %s\n", e.e1.toChars()); + return returnE_e1(); } /* The first test here is to prevent infinite loops */ @@ -738,7 +741,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray)) { //printf(" returning3 %s\n", e.e1.toChars()); - goto L1; + return returnE_e1(); } if (e.type.ty == Tclass && e.e1.type.ty == Tclass) { @@ -750,7 +753,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (cdfrom.errors || cdto.errors) return error(); if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration()) - goto L1; // can always convert a class to Object + return returnE_e1(); // can always convert a class to Object // Need to determine correct offset before optimizing away the cast. // https://issues.dlang.org/show_bug.cgi?id=16980 cdfrom.size(e.loc); @@ -760,13 +763,13 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (cdto.isBaseOf(cdfrom, &offset) && offset == 0) { //printf(" returning4 %s\n", e.e1.toChars()); - goto L1; + return returnE_e1(); } } if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf())) { //printf(" returning5 %s\n", e.e1.toChars()); - goto L1; + return returnE_e1(); } if (e.e1.isConst()) { @@ -781,7 +784,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return error(); if (esz == e1sz) - goto L1; + return returnE_e1(); } return; } @@ -1065,7 +1068,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) // Don't optimize to an array literal element directly in case an lvalue is requested if (keepLvalue && ex.op == EXP.arrayLiteral) return; - ret = Index(e.type, ex, e.e2).copy(); + ret = Index(e.type, ex, e.e2, e.indexIsInBounds).copy(); if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue())) ret = e; } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index e83b326c7e3..480a96c25db 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1971,7 +1971,6 @@ class Parser(AST) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: - case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: @@ -5623,7 +5622,6 @@ LagainStc: case TOK.true_: case TOK.false_: case TOK.string_: - case TOK.hexadecimalString: case TOK.leftParenthesis: case TOK.cast_: case TOK.mul: @@ -7106,7 +7104,6 @@ LagainStc: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: - case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: @@ -7987,7 +7984,6 @@ LagainStc: break; case TOK.string_: - case TOK.hexadecimalString: { // cat adjacent strings auto s = token.ustring; @@ -7997,7 +7993,7 @@ LagainStc: { const prev = token; nextToken(); - if (token.value == TOK.string_ || token.value == TOK.hexadecimalString) + if (token.value == TOK.string_) { if (token.postfix) { diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 88520e85c24..f229918d899 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -866,7 +866,6 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor assert(t.ty == Tdelegate); tfld = cast(TypeFunction)t.nextOf(); } - //printf("tfld = %s\n", tfld.toChars()); } } } @@ -1442,12 +1441,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor /* Call: * _aApply(aggr, flde) */ - __gshared const(char)** fntab = + static immutable fntab = [ "cc", "cw", "cd", "wc", "cc", "wd", "dc", "dw", "dd" - ]; + ]; const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1; char[BUFFER_LEN] fdname; @@ -1470,7 +1469,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor assert(0); } const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : ""; - int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag], cast(ulong)dim); + int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim); assert(j < BUFFER_LEN); FuncDeclaration fdapply; @@ -2475,68 +2474,66 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor Expression initialExp = cs.exp; // The switch'ed value has errors and doesn't provide the actual type - // Don't touch the case to not replace it with an `ErrorExp` even if it is valid + // Omit the cast to enable further semantic (exluding the check for matching types) if (sw.condition.type && !sw.condition.type.isTypeError()) - { cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type); - cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); + cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); + + Expression e = cs.exp; + // Remove all the casts the user and/or implicitCastTo may introduce + // otherwise we'd sometimes fail the check below. + while (e.op == EXP.cast_) + e = (cast(CastExp)e).e1; + + /* This is where variables are allowed as case expressions. + */ + if (e.op == EXP.variable) + { + VarExp ve = cast(VarExp)e; + VarDeclaration v = ve.var.isVarDeclaration(); + Type t = cs.exp.type.toBasetype(); + if (v && (t.isintegral() || t.ty == Tclass)) + { + /* Flag that we need to do special code generation + * for this, i.e. generate a sequence of if-then-else + */ + sw.hasVars = 1; + + /* TODO check if v can be uninitialized at that point. + */ + if (!v.isConst() && !v.isImmutable()) + { + cs.error("`case` variables have to be `const` or `immutable`"); + } - Expression e = cs.exp; - // Remove all the casts the user and/or implicitCastTo may introduce - // otherwise we'd sometimes fail the check below. - while (e.op == EXP.cast_) - e = (cast(CastExp)e).e1; + if (sw.isFinal) + { + cs.error("`case` variables not allowed in `final switch` statements"); + errors = true; + } - /* This is where variables are allowed as case expressions. - */ - if (e.op == EXP.variable) - { - VarExp ve = cast(VarExp)e; - VarDeclaration v = ve.var.isVarDeclaration(); - Type t = cs.exp.type.toBasetype(); - if (v && (t.isintegral() || t.ty == Tclass)) + /* Find the outermost scope `scx` that set `sw`. + * Then search scope `scx` for a declaration of `v`. + */ + for (Scope* scx = sc; scx; scx = scx.enclosing) { - /* Flag that we need to do special code generation - * for this, i.e. generate a sequence of if-then-else - */ - sw.hasVars = 1; - - /* TODO check if v can be uninitialized at that point. - */ - if (!v.isConst() && !v.isImmutable()) - { - cs.error("`case` variables have to be `const` or `immutable`"); - } + if (scx.enclosing && scx.enclosing.sw == sw) + continue; + assert(scx.sw == sw); - if (sw.isFinal) + if (!scx.search(cs.exp.loc, v.ident, null)) { - cs.error("`case` variables not allowed in `final switch` statements"); + cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", + v.toChars(), v.loc.toChars()); errors = true; } - - /* Find the outermost scope `scx` that set `sw`. - * Then search scope `scx` for a declaration of `v`. - */ - for (Scope* scx = sc; scx; scx = scx.enclosing) - { - if (scx.enclosing && scx.enclosing.sw == sw) - continue; - assert(scx.sw == sw); - - if (!scx.search(cs.exp.loc, v.ident, null)) - { - cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", - v.toChars(), v.loc.toChars()); - errors = true; - } - break; - } - goto L1; + break; } + goto L1; } - else - cs.exp = cs.exp.ctfeInterpret(); } + else + cs.exp = cs.exp.ctfeInterpret(); if (StringExp se = cs.exp.toStringExp()) cs.exp = se; diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 0b1d1583a55..6e56eb25474 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -124,7 +124,6 @@ enum TOK : ubyte // Leaf operators identifier, string_, - hexadecimalString, this_, super_, error, @@ -854,8 +853,6 @@ extern (C++) struct Token TOK.wchar_tLiteral: "wchar_tv", TOK.whitespace: "whitespace", - TOK.hexadecimalString: "xstring", - // C only keywords TOK.inline : "inline", TOK.register : "register", @@ -1008,24 +1005,6 @@ nothrow: p = buf.extractSlice().ptr; } break; - case TOK.hexadecimalString: - { - OutBuffer buf; - buf.writeByte('x'); - buf.writeByte('"'); - foreach (size_t i; 0 .. len) - { - if (i) - buf.writeByte(' '); - buf.printf("%02x", ustring[i]); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractSlice().ptr; - break; - } case TOK.identifier: case TOK.enum_: case TOK.struct_: diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 6dfd0ce3333..c404cab2ad5 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -133,7 +133,6 @@ enum class TOK : unsigned char // Leaf operators identifier, string_, - hexadecimalString, this_, super_, error, diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 1f038363dfe..57188af90d6 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -666,9 +666,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type visitType(Type t) { + // @@@DEPRECATED_2.110@@@ + // Use of `cent` and `ucent` has always been an error. + // Starting from 2.100, recommend core.int128 as a replace for the + // lack of compiler support. if (t.ty == Tint128 || t.ty == Tuns128) { - .error(loc, "`cent` and `ucent` types not implemented"); + .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead"); return error(); } @@ -1188,6 +1192,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) tf.isref = true; if (sc.stc & STC.return_) tf.isreturn = true; + if (sc.stc & STC.returnScope) + tf.isreturnscope = true; if (sc.stc & STC.returninferred) tf.isreturninferred = true; if (sc.stc & STC.scope_) @@ -3828,10 +3834,10 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) * e.opDot().ident */ e = build_overload(e.loc, sc, e, null, fd); - // @@@DEPRECATED_2.092@@@. - e.deprecation("`opDot` is deprecated. Use `alias this`"); - e = new DotIdExp(e.loc, e, ident); - return returnExp(e.expressionSemantic(sc)); + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.082, made an error in 2.100. + e.error("`opDot` is obsolete. Use `alias this`"); + return ErrorExp.get(); } /* Look for overloaded opDispatch to see if we should forward request diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc index 29c0fbfe6d2..6747ee5df27 100644 --- a/gcc/d/imports.cc +++ b/gcc/d/imports.cc @@ -106,20 +106,20 @@ public: tree type = build_ctype (d->type); /* Not all kinds of D enums create a TYPE_DECL. */ if (TREE_CODE (type) == ENUMERAL_TYPE) - d->isym = this->make_import (TYPE_STUB_DECL (type)); + this->result_ = this->make_import (TYPE_STUB_DECL (type)); } void visit (AggregateDeclaration *d) { tree type = build_ctype (d->type); - d->isym = this->make_import (TYPE_STUB_DECL (type)); + this->result_ = this->make_import (TYPE_STUB_DECL (type)); } void visit (ClassDeclaration *d) { /* Want the RECORD_TYPE, not POINTER_TYPE. */ tree type = TREE_TYPE (build_ctype (d->type)); - d->isym = this->make_import (TYPE_STUB_DECL (type)); + this->result_ = this->make_import (TYPE_STUB_DECL (type)); } /* For now, ignore importing other kinds of dsymbols. */ diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d index a740994d7b5..076e29baece 100644 --- a/gcc/testsuite/gdc.test/compilable/commontype.d +++ b/gcc/testsuite/gdc.test/compilable/commontype.d @@ -196,8 +196,7 @@ static assert(is( X!( C***, B*** ) == const(B**)* )); // `B***` static assert(is( X!( C*, I* ) == I* )); static assert(is( X!( I*, C* ) == I* )); -//static assert(Error!( C**, I** )); -static assert(is( X!( C**, I** ) == const(I*)* )); +static assert(Error!( C**, I** )); static assert(Error!( C*, D* )); // should work @@ -304,15 +303,13 @@ static assert(is( X!(C[4], B[4]) )); static assert(Error!( C[4], I[4] )); static assert(Error!( C[4], D[4] )); static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] )); -//static assert(Error!( C[4], const(I)[4] )); -static assert(is( X!( C[4], const(I)[4] ) == const(I)[] )); +static assert(Error!( C[4], const(I)[4] )); static assert(Error!( C[4], const(D)[4] )); static assert(Error!( C*[4], B*[4] )); static assert(Error!( C*[4], I*[4] )); static assert(Error!( C*[4], D*[4] )); static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !? -//static assert(Error!( C*[4], const(I*)[4] )); -static assert(is( X!( C*[4], const(I*)[4] ) == const(I*)[] )); +static assert(Error!( C*[4], const(I*)[4] )); static assert(Error!( C*[4], const(D*)[4] )); static assert(Error!( C*[4], B**[4] )); static assert(Error!( C*[4], const(B*)*[4] )); diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d index a4cf663066e..013630bd483 100644 --- a/gcc/testsuite/gdc.test/compilable/test7172.d +++ b/gcc/testsuite/gdc.test/compilable/test7172.d @@ -1,3 +1,8 @@ +/* TEST_OUTPUT: +--- +compilable/test7172.d(14): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +--- +*/ void main() { abstract class AbstractC{} diff --git a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d index 230fc4bae3e..19c64752aaf 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d @@ -2,47 +2,47 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/dep_d1_ops.d(105): Deprecation: `opAdd` is deprecated. Use `opBinary(string op)(...) if (op == "+")` instead. -fail_compilation/dep_d1_ops.d(106): Deprecation: `opAdd_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "+")` instead. -fail_compilation/dep_d1_ops.d(107): Deprecation: `opSub` is deprecated. Use `opBinary(string op)(...) if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(108): Deprecation: `opSub_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(109): Deprecation: `opMul` is deprecated. Use `opBinary(string op)(...) if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(110): Deprecation: `opMul_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(111): Deprecation: `opDiv` is deprecated. Use `opBinary(string op)(...) if (op == "/")` instead. -fail_compilation/dep_d1_ops.d(112): Deprecation: `opDiv_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "/")` instead. -fail_compilation/dep_d1_ops.d(113): Deprecation: `opMod` is deprecated. Use `opBinary(string op)(...) if (op == "%")` instead. -fail_compilation/dep_d1_ops.d(114): Deprecation: `opMod_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "%")` instead. -fail_compilation/dep_d1_ops.d(116): Deprecation: `opAnd` is deprecated. Use `opBinary(string op)(...) if (op == "&")` instead. -fail_compilation/dep_d1_ops.d(117): Deprecation: `opOr` is deprecated. Use `opBinary(string op)(...) if (op == "|")` instead. -fail_compilation/dep_d1_ops.d(118): Deprecation: `opXor` is deprecated. Use `opBinary(string op)(...) if (op == "^")` instead. -fail_compilation/dep_d1_ops.d(120): Deprecation: `opShl` is deprecated. Use `opBinary(string op)(...) if (op == "<<")` instead. -fail_compilation/dep_d1_ops.d(121): Deprecation: `opShl_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "<<")` instead. -fail_compilation/dep_d1_ops.d(122): Deprecation: `opShr` is deprecated. Use `opBinary(string op)(...) if (op == ">>")` instead. -fail_compilation/dep_d1_ops.d(123): Deprecation: `opShr_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == ">>")` instead. -fail_compilation/dep_d1_ops.d(124): Deprecation: `opUShr` is deprecated. Use `opBinary(string op)(...) if (op == ">>>")` instead. -fail_compilation/dep_d1_ops.d(125): Deprecation: `opUShr_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == ">>>")` instead. -fail_compilation/dep_d1_ops.d(127): Deprecation: `opCat` is deprecated. Use `opBinary(string op)(...) if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(128): Deprecation: `opCat_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(130): Deprecation: `opNeg` is deprecated. Use `opUnary(string op)() if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(131): Deprecation: `opCom` is deprecated. Use `opUnary(string op)() if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(132): Deprecation: `opPostInc` is deprecated. Use `opUnary(string op)() if (op == "++")` instead. -fail_compilation/dep_d1_ops.d(133): Deprecation: `opPostDec` is deprecated. Use `opUnary(string op)() if (op == "--")` instead. -fail_compilation/dep_d1_ops.d(134): Deprecation: `opStar` is deprecated. Use `opUnary(string op)() if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(136): Deprecation: `opIn` is deprecated. Use `opBinary(string op)(...) if (op == "in")` instead. -fail_compilation/dep_d1_ops.d(137): Deprecation: `opIn_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "in")` instead. -fail_compilation/dep_d1_ops.d(139): Deprecation: `opAddAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "+")` instead. -fail_compilation/dep_d1_ops.d(140): Deprecation: `opSubAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(141): Deprecation: `opMulAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(142): Deprecation: `opDivAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "/")` instead. -fail_compilation/dep_d1_ops.d(143): Deprecation: `opModAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "%")` instead. -fail_compilation/dep_d1_ops.d(144): Deprecation: `opAndAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "&")` instead. -fail_compilation/dep_d1_ops.d(145): Deprecation: `opOrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "|")` instead. -fail_compilation/dep_d1_ops.d(146): Deprecation: `opXorAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "^")` instead. -fail_compilation/dep_d1_ops.d(147): Deprecation: `opShlAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "<<")` instead. -fail_compilation/dep_d1_ops.d(148): Deprecation: `opShrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == ">>")` instead. -fail_compilation/dep_d1_ops.d(149): Deprecation: `opUShrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == ">>>")` instead. -fail_compilation/dep_d1_ops.d(150): Deprecation: `opCatAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(158): Deprecation: `opCom` is deprecated. Use `opUnary(string op)() if (op == "~")` instead. +fail_compilation/dep_d1_ops.d(105): Error: `opAdd` is obsolete. Use `opBinary(string op)(...) if (op == "+")` instead. +fail_compilation/dep_d1_ops.d(106): Error: `opAdd_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "+")` instead. +fail_compilation/dep_d1_ops.d(107): Error: `opSub` is obsolete. Use `opBinary(string op)(...) if (op == "-")` instead. +fail_compilation/dep_d1_ops.d(108): Error: `opSub_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "-")` instead. +fail_compilation/dep_d1_ops.d(109): Error: `opMul` is obsolete. Use `opBinary(string op)(...) if (op == "*")` instead. +fail_compilation/dep_d1_ops.d(110): Error: `opMul_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "*")` instead. +fail_compilation/dep_d1_ops.d(111): Error: `opDiv` is obsolete. Use `opBinary(string op)(...) if (op == "/")` instead. +fail_compilation/dep_d1_ops.d(112): Error: `opDiv_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "/")` instead. +fail_compilation/dep_d1_ops.d(113): Error: `opMod` is obsolete. Use `opBinary(string op)(...) if (op == "%")` instead. +fail_compilation/dep_d1_ops.d(114): Error: `opMod_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "%")` instead. +fail_compilation/dep_d1_ops.d(116): Error: `opAnd` is obsolete. Use `opBinary(string op)(...) if (op == "&")` instead. +fail_compilation/dep_d1_ops.d(117): Error: `opOr` is obsolete. Use `opBinary(string op)(...) if (op == "|")` instead. +fail_compilation/dep_d1_ops.d(118): Error: `opXor` is obsolete. Use `opBinary(string op)(...) if (op == "^")` instead. +fail_compilation/dep_d1_ops.d(120): Error: `opShl` is obsolete. Use `opBinary(string op)(...) if (op == "<<")` instead. +fail_compilation/dep_d1_ops.d(121): Error: `opShl_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "<<")` instead. +fail_compilation/dep_d1_ops.d(122): Error: `opShr` is obsolete. Use `opBinary(string op)(...) if (op == ">>")` instead. +fail_compilation/dep_d1_ops.d(123): Error: `opShr_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == ">>")` instead. +fail_compilation/dep_d1_ops.d(124): Error: `opUShr` is obsolete. Use `opBinary(string op)(...) if (op == ">>>")` instead. +fail_compilation/dep_d1_ops.d(125): Error: `opUShr_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == ">>>")` instead. +fail_compilation/dep_d1_ops.d(127): Error: `opCat` is obsolete. Use `opBinary(string op)(...) if (op == "~")` instead. +fail_compilation/dep_d1_ops.d(128): Error: `opCat_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "~")` instead. +fail_compilation/dep_d1_ops.d(130): Error: `opNeg` is obsolete. Use `opUnary(string op)() if (op == "-")` instead. +fail_compilation/dep_d1_ops.d(131): Error: `opCom` is obsolete. Use `opUnary(string op)() if (op == "~")` instead. +fail_compilation/dep_d1_ops.d(132): Error: `opPostInc` is obsolete. Use `opUnary(string op)() if (op == "++")` instead. +fail_compilation/dep_d1_ops.d(133): Error: `opPostDec` is obsolete. Use `opUnary(string op)() if (op == "--")` instead. +fail_compilation/dep_d1_ops.d(134): Error: `opStar` is obsolete. Use `opUnary(string op)() if (op == "*")` instead. +fail_compilation/dep_d1_ops.d(136): Error: `opIn` is obsolete. Use `opBinary(string op)(...) if (op == "in")` instead. +fail_compilation/dep_d1_ops.d(137): Error: `opIn_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "in")` instead. +fail_compilation/dep_d1_ops.d(139): Error: `opAddAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "+")` instead. +fail_compilation/dep_d1_ops.d(140): Error: `opSubAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "-")` instead. +fail_compilation/dep_d1_ops.d(141): Error: `opMulAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "*")` instead. +fail_compilation/dep_d1_ops.d(142): Error: `opDivAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "/")` instead. +fail_compilation/dep_d1_ops.d(143): Error: `opModAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "%")` instead. +fail_compilation/dep_d1_ops.d(144): Error: `opAndAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "&")` instead. +fail_compilation/dep_d1_ops.d(145): Error: `opOrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "|")` instead. +fail_compilation/dep_d1_ops.d(146): Error: `opXorAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "^")` instead. +fail_compilation/dep_d1_ops.d(147): Error: `opShlAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "<<")` instead. +fail_compilation/dep_d1_ops.d(148): Error: `opShrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == ">>")` instead. +fail_compilation/dep_d1_ops.d(149): Error: `opUShrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == ">>>")` instead. +fail_compilation/dep_d1_ops.d(150): Error: `opCatAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "~")` instead. +fail_compilation/dep_d1_ops.d(158): Error: `opCom` is obsolete. Use `opUnary(string op)() if (op == "~")` instead. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d b/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d index a97afdcdf75..2ce37959e11 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d @@ -2,7 +2,8 @@ /* TEST_OUTPUT: --- -fail_compilation/dephexstrings.d(8): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"60"` instead. +fail_compilation/dephexstrings.d(9): Error: semicolon expected following auto declaration, not `"60"` +fail_compilation/dephexstrings.d(9): Error: declaration expected, not `"60"` --- */ enum xstr = x"60"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d index 5aaab6a2b17..46c949376e3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d @@ -2,9 +2,9 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/deprecateopdot.d(27): Deprecation: `opDot` is deprecated. Use `alias this` -fail_compilation/deprecateopdot.d(28): Deprecation: `opDot` is deprecated. Use `alias this` -fail_compilation/deprecateopdot.d(29): Deprecation: `opDot` is deprecated. Use `alias this` +fail_compilation/deprecateopdot.d(27): Error: `opDot` is obsolete. Use `alias this` +fail_compilation/deprecateopdot.d(28): Error: `opDot` is obsolete. Use `alias this` +fail_compilation/deprecateopdot.d(29): Error: `opDot` is obsolete. Use `alias this` --- */ struct S6 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d index 299b994d919..16659b5fdc1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail136.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail136.d(10): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"EF BB BF"` instead. +fail_compilation/fail136.d(10): Error: found `"EF BB BF"` when expecting `;` following statement --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18.d b/gcc/testsuite/gdc.test/fail_compilation/fail18.d index 55a4af1f45d..848b65116f1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail18.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail18.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail18.d(14): Error: need upper and lower bound to slice pointer +fail_compilation/fail18.d(14): Error: upper and lower bounds are needed to slice a pointer --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d index dd83f75e9c2..e22be9fe047 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d @@ -1,7 +1,8 @@ // https://issues.dlang.org/show_bug.cgi?id=22780 /* TEST_OUTPUT: --- -fail_compilation/fail22780.d(11): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope` +fail_compilation/fail22780.d(8): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +fail_compilation/fail22780.d(12): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope` --- */ scope class C10717 { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22827.d b/gcc/testsuite/gdc.test/fail_compilation/fail22827.d new file mode 100644 index 00000000000..ee031ae1906 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22827.d @@ -0,0 +1,9 @@ +// https://issues.dlang.org/show_bug.cgi?id=22827 +/* TEST_OUTPUT: +--- +fail_compilation/fail22827.d(8): Error: `cent` and `ucent` types are obsolete, use `core.int128.Cent` instead +fail_compilation/fail22827.d(9): Error: `cent` and `ucent` types are obsolete, use `core.int128.Cent` instead +--- +*/ +cent i22827; +ucent j22827; diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue22820.d b/gcc/testsuite/gdc.test/fail_compilation/issue22820.d new file mode 100644 index 00000000000..af42b46d524 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/issue22820.d @@ -0,0 +1,68 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/issue22820.d(138): Error: upper and lower bounds are needed to slice a pointer +fail_compilation/issue22820.d(138): pointer `s1` points to an aggregate that defines an `opIndex`, perhaps you meant `(*s1)[]` +fail_compilation/issue22820.d(139): Error: upper and lower bounds are needed to slice a pointer +fail_compilation/issue22820.d(139): pointer `s2` points to an aggregate that defines an `opSlice`, perhaps you meant `(*s2)[]` +fail_compilation/issue22820.d(140): Error: upper and lower bounds are needed to slice a pointer +fail_compilation/issue22820.d(140): pointer `s3` points to an aggregate that defines an `opIndex`, perhaps you meant `(*s3)[]` +fail_compilation/issue22820.d(141): Error: upper and lower bounds are needed to slice a pointer +fail_compilation/issue22820.d(141): pointer `cp` points to an aggregate that defines an `opIndex`, perhaps you meant `(*cp)[]` +fail_compilation/issue22820.d(142): Error: upper and lower bounds are needed to slice a pointer +fail_compilation/issue22820.d(142): pointer `e` points to an aggregate that defines an `opIndex`, perhaps you meant `(*e)[]` +--- +*/ + +#line 100 + +// normal functions +struct S1 { + int[] opIndex() { return a; } + int[] a; +} + +// opSlice alternative +struct S2 { + int[] opSlice() { return a; } + int[] a; +} + +// templates +struct S3 { + int[] opIndex()() { return a; } + int[] a; +} + +class C { + int[] opIndex()() { return a; } + int[] a; +} + +enum E : S1 +{ + a = S1([1]) +} + +void main() { + S1* s1 = new S1; + S2* s2 = new S2; + S3* s3 = new S3; + C c = new C; + C* cp = &c; + E* e = new E; + int* p; + + p = s1[].ptr; + p = s2[].ptr; + p = s3[].ptr; + p = cp[].ptr; + p = e[].ptr; + + p = (*s1)[].ptr; + p = (*s2)[].ptr; + p = (*s3)[].ptr; + p = (*cp)[].ptr; + p = (*e)[].ptr; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d index 6569d4c2239..115f1366dce 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/lexer1.d(30): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"01 02 03"w` instead. -fail_compilation/lexer1.d(30): Error: declaration expected, not `x"01 02 03"w` +fail_compilation/lexer1.d(30): Error: no identifier for declarator `x` +fail_compilation/lexer1.d(30): Error: declaration expected, not `"01 02 03"w` fail_compilation/lexer1.d(31): Error: declaration expected, not `2147483649U` fail_compilation/lexer1.d(32): Error: declaration expected, not `0.1` fail_compilation/lexer1.d(33): Error: declaration expected, not `0.1f` diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d index 2386da597a8..f895e644c44 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/lexer2.d(16): Error: odd number (3) of hex characters in hex string -fail_compilation/lexer2.d(16): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123"` instead. -fail_compilation/lexer2.d(17): Error: non-hex character 'G' in hex string -fail_compilation/lexer2.d(17): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123G"` instead. +fail_compilation/lexer2.d(16): Error: semicolon expected following auto declaration, not `"123"` +fail_compilation/lexer2.d(16): Error: declaration expected, not `"123"` +fail_compilation/lexer2.d(17): Error: semicolon expected following auto declaration, not `"123G"` +fail_compilation/lexer2.d(17): Error: declaration expected, not `"123G"` fail_compilation/lexer2.d(18): Error: heredoc rest of line should be blank fail_compilation/lexer2.d(20): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(20) fail_compilation/lexer2.d(22): Error: semicolon expected following auto declaration, not `End of File` diff --git a/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d b/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d new file mode 100644 index 00000000000..b15d6e49b18 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d @@ -0,0 +1,27 @@ +/* TEST_OUTPUT: +--- +fail_compilation/opapplyscope.d(113): Error: function `opapplyscope.S.opApply(scope int delegate(scope int* ptr) @safe dg)` is not callable using argument types `(int delegate(int* x) nothrow @nogc @safe)` +fail_compilation/opapplyscope.d(113): cannot pass argument `__foreachbody3` of type `int delegate(int* x) nothrow @nogc @safe` to parameter `scope int delegate(scope int* ptr) @safe dg` +--- + */ + +#line 100 + +struct S +{ + int opApply(scope int delegate (scope int* ptr) @safe dg) @safe + { + return 0; + } +} + +void test() @safe +{ + static int* global; + S s; + foreach (/*scope*/ int* x; s) + { + global = x; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d index b70e3eb8c5a..bba14908833 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d +++ b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/scope_class.d(11): Error: functions cannot return `scope scope_class.C` +fail_compilation/scope_class.d(10): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +fail_compilation/scope_class.d(12): Error: functions cannot return `scope scope_class.C` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d index 1e152f54d14..e0550138b7e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d +++ b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d @@ -2,11 +2,15 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/scope_type.d(11): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site. +fail_compilation/scope_type.d(13): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +fail_compilation/scope_type.d(14): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site. +fail_compilation/scope_type.d(15): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +fail_compilation/scope_type.d(16): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. --- */ scope class C { } scope interface I { } -//scope struct S { } +scope struct S { } +scope enum E { e } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d index fea9fb7958c..2ac3b562198 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d @@ -1,15 +1,19 @@ /* TEST_OUTPUT: -PERMUTE_ARGS: -dip1000 +REQUIRED_ARGS: -preview=dip1000 --- -fail_compilation/test15191.d(31): Error: returning `&identity(x)` escapes a reference to local variable `x` -fail_compilation/test15191.d(37): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` -fail_compilation/test15191.d(43): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive` -fail_compilation/test15191.d(43): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(35): Error: returning `&identity(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(41): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(47): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive` +fail_compilation/test15191.d(47): return type `int*` has pointers that may be `scope` +fail_compilation/test15191.d(68): Error: cannot slice static array of `ref return` of `identityArr()` in `@safe` function `sliceOfRefEscape` +fail_compilation/test15191.d(68): return type `int*[1]` has pointers that may be `scope` --- */ +// Test taking the address of a `ref return` using & and [] operators // https://issues.dlang.org/show_bug.cgi?id=15191 // https://issues.dlang.org/show_bug.cgi?id=22519 +// https://issues.dlang.org/show_bug.cgi?id=22539 @safe: ref int foo(return ref int s) @@ -50,3 +54,17 @@ int* addrOfRefGlobal() { return &getGlobalInt(); } + +// Slice: +ref int*[1] identityArr(ref return scope int*[1] x) +{ + return x; +} + +int* sliceOfRefEscape() +{ + int stackVar = 0xFF; + scope int*[1] x = [&stackVar]; + int*[] y = identityArr(x)[]; + return y[0]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19097.d b/gcc/testsuite/gdc.test/fail_compilation/test19097.d index b5560f0b27b..034813b5316 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19097.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19097.d @@ -1,7 +1,9 @@ /* REQUIRED_ARGS: -preview=dip1000 * TEST_OUTPUT: --- -fail_compilation/test19097.d(35): Error: scope variable `s` may not be returned +fail_compilation/test19097.d(37): Error: scope variable `s` may not be returned +fail_compilation/test19097.d(66): Error: scope variable `z` assigned to `refPtr` with longer lifetime +fail_compilation/test19097.d(97): Error: scope variable `s` may not be returned --- */ @@ -54,3 +56,43 @@ struct S2(T) S2!int s2; +/************************/ +struct S3 +{ + int* ptr; + void assign(ref int* refPtr, return scope int* z) scope @safe + { + this.ptr = z; // allowed, first ref + refPtr = z; // should not be allowed + } +} + +int* escape() @safe +{ + int local; + + S3 escapeThis; + int* escapeRef; + + escapeThis.assign(escapeRef, &local); + + return escapeRef; +} + +/************************/ +// https://issues.dlang.org/show_bug.cgi?id=22837 +struct S4 +{ + int* p; + this(int dummy, return scope int* p) @safe + { + this.p = p; + } +} + +int* escape2() +{ + int x; + auto s = S4(0, &x); + return s.p; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21008.d b/gcc/testsuite/gdc.test/fail_compilation/test21008.d new file mode 100644 index 00000000000..d5cf96a6c3a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test21008.d @@ -0,0 +1,41 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular reference to class `C` +fail_compilation/test21008.d(117): Error: need `this` for `toString` of type `string()` +fail_compilation/test21008.d(117): Error: need `this` for `toHash` of type `nothrow @trusted $?:32=uint|64=ulong$()` +fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()` +fail_compilation/test21008.d(117): missing argument for parameter #1: `Object o` +fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()` +fail_compilation/test21008.d(117): missing argument for parameter #1: `Object o` +fail_compilation/test21008.d(117): Error: `Monitor` has no effect +fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()` +fail_compilation/test21008.d(117): missing argument for parameter #1: `string classname` +fail_compilation/test21008.d(105): called from here: `handleMiddlewareAnnotation()` +fail_compilation/test21008.d(108): Error: class `test21008.C` no size because of forward reference +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=21008 + +#line 100 + +class Base +{ + bool after(); + + mixin(handleMiddlewareAnnotation); +} + +class C : Base +{ + override bool after(); +} + +string handleMiddlewareAnnotation() +{ + foreach (member; __traits(allMembers, C)) + { + __traits(getMember, C, member); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d index a0d1d122e63..bfd8803d2f2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d @@ -99,3 +99,81 @@ void test5(int i) } } + +/++ +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(513): Error: undefined identifier `undefinedFunc` +fail_compilation/test_switch_error.d(517): Error: `case` must be a `string` or an integral constant, not `Strukt(1)` +fail_compilation/test_switch_error.d(518): Error: `case` variables have to be `const` or `immutable` +fail_compilation/test_switch_error.d(518): Error: `case` variables not allowed in `final switch` statements +fail_compilation/test_switch_error.d(519): Error: `case` variables not allowed in `final switch` statements +fail_compilation/test_switch_error.d(522): Error: undefined identifier `undefinedFunc2` +--- +++/ +#line 500 + +enum Foo +{ + one, two +} + +struct Strukt +{ + int i; +} + +void errorsWithErrors(int param, immutable int constant) +{ + final switch(undefinedFunc()) + { + case Foo.one: break; + case Foo.two: break; + case Strukt(1): break; + case param: break; + case constant: break; + } + + switch (undefinedFunc2()) + { + case constant: break; + } +} + +/++ +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(622): Error: undefined identifier `undefinedFunc` +fail_compilation/test_switch_error.d(624): Error: `case` must be a `string` or an integral constant, not `SubtypeOfInt(2)` +fail_compilation/test_switch_error.d(625): Error: `case` must be a `string` or an integral constant, not `SubtypeOfIntMethod()` +--- +++/ +#line 600 + +struct SubtypeOfInt +{ + int i; + alias i this; +} + +struct SubtypeOfIntMethod +{ + int getI() { return 0; } + alias getI this; +} + +void errorsWithErrors2(int param) +{ + final switch(param) + { + case SubtypeOfInt(1): break; + case SubtypeOfIntMethod(): break; + } + + // This snippet causes somewhat misleading error messages + final switch(undefinedFunc()) + { + case SubtypeOfInt(2): break; + case SubtypeOfIntMethod(): break; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d index a93a49fdc18..37395d4b897 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d +++ b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d @@ -1,22 +1,23 @@ /* TEST_OUTPUT: --- -fail_compilation/typeerrors.d(36): Error: tuple index 4 exceeds 4 -fail_compilation/typeerrors.d(38): Error: variable `x` cannot be read at compile time -fail_compilation/typeerrors.d(39): Error: cannot have array of `void()` -fail_compilation/typeerrors.d(40): Error: cannot have array of scope `typeerrors.C` +fail_compilation/typeerrors.d(32): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +fail_compilation/typeerrors.d(37): Error: tuple index 4 exceeds 4 +fail_compilation/typeerrors.d(39): Error: variable `x` cannot be read at compile time +fail_compilation/typeerrors.d(40): Error: cannot have array of `void()` fail_compilation/typeerrors.d(41): Error: cannot have array of scope `typeerrors.C` -fail_compilation/typeerrors.d(44): Error: `int[5]` is not an expression -fail_compilation/typeerrors.d(46): Error: variable `x` is used as a type -fail_compilation/typeerrors.d(37): variable `x` is declared here -fail_compilation/typeerrors.d(47): Error: cannot have associative array key of `void()` -fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void` -fail_compilation/typeerrors.d(49): Error: cannot have array of scope `typeerrors.C` -fail_compilation/typeerrors.d(50): Error: cannot have associative array of `void` -fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void()` -fail_compilation/typeerrors.d(53): Error: cannot have parameter of type `void` -fail_compilation/typeerrors.d(55): Error: slice `[1..5]` is out of range of [0..4] -fail_compilation/typeerrors.d(56): Error: slice `[2..1]` is out of range of [0..4] +fail_compilation/typeerrors.d(42): Error: cannot have array of scope `typeerrors.C` +fail_compilation/typeerrors.d(45): Error: `int[5]` is not an expression +fail_compilation/typeerrors.d(47): Error: variable `x` is used as a type +fail_compilation/typeerrors.d(38): variable `x` is declared here +fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void()` +fail_compilation/typeerrors.d(49): Error: cannot have associative array key of `void` +fail_compilation/typeerrors.d(50): Error: cannot have array of scope `typeerrors.C` +fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void` +fail_compilation/typeerrors.d(52): Error: cannot have associative array of `void()` +fail_compilation/typeerrors.d(54): Error: cannot have parameter of type `void` +fail_compilation/typeerrors.d(56): Error: slice `[1..5]` is out of range of [0..4] +fail_compilation/typeerrors.d(57): Error: slice `[2..1]` is out of range of [0..4] --- */ diff --git a/gcc/testsuite/gdc.test/runnable/auto1.d b/gcc/testsuite/gdc.test/runnable/auto1.d index ea023836bf2..6ee075089d1 100644 --- a/gcc/testsuite/gdc.test/runnable/auto1.d +++ b/gcc/testsuite/gdc.test/runnable/auto1.d @@ -16,7 +16,7 @@ import core.stdc.stdio; /******************************************/ -scope class Foo +class Foo { static int x; @@ -65,7 +65,7 @@ void test1() int ax; -scope class A2 +class A2 { this() { @@ -96,11 +96,11 @@ void test2() int status3; -scope class Parent3 +class Parent3 { } -scope class Child3 : Parent3 +class Child3 : Parent3 { this(){ assert(status3==0); diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d index 4d02a924a21..6b1e89b65ff 100644 --- a/gcc/testsuite/gdc.test/runnable/interpret.d +++ b/gcc/testsuite/gdc.test/runnable/interpret.d @@ -3246,7 +3246,7 @@ int test6907() } { S1* p = new S1(); - if (__ctfe) + if (__ctfe) { (*p).__dtor(); destroy(p); diff --git a/gcc/testsuite/gdc.test/runnable/opover.d b/gcc/testsuite/gdc.test/runnable/opover.d index 633981e4cbb..253a7a54ceb 100644 --- a/gcc/testsuite/gdc.test/runnable/opover.d +++ b/gcc/testsuite/gdc.test/runnable/opover.d @@ -31,7 +31,8 @@ import core.stdc.stdio; class A1 { - int opAdd(int i) { return 7 + i; } + int opBinary(string op)(int i) if (op == "+") { return 7 + i; } + alias opBinaryRight = opBinary; } void test1() @@ -50,8 +51,8 @@ void test1() class A2 { - int opDiv(int i) { return 9 + i; } - int opDiv_r(int i) { return 17 + i; } + int opBinary(string op)(int i) if (op == "/") { return 9 + i; } + int opBinaryRight(string op)(int i) if (op == "/") { return 17 + i; } } void test2() @@ -74,31 +75,31 @@ class C1 class C2 { - int opAdd(D1 d) { return 1; } - int opAdd(D2 d) { return 2; } - int opAdd(D3 d) { return 3; } - int opAdd(D4 d) { return 4; } + int opBinary(string op)(D1 d) if (op == "+") { return 1; } + int opBinary(string op)(D2 d) if (op == "+") { return 2; } + int opBinary(string op)(D3 d) if (op == "+") { return 3; } + int opBinary(string op)(D4 d) if (op == "+") { return 4; } } class C3 { - int opAdd_r(D1 d) { return 5; } - int opAdd_r(D2 d) { return 6; } - int opAdd_r(D3 d) { return 7; } - int opAdd_r(D4 d) { return 8; } + int opBinaryRight(string op)(D1 d) if (op == "+") { return 5; } + int opBinaryRight(string op)(D2 d) if (op == "+") { return 6; } + int opBinaryRight(string op)(D3 d) if (op == "+") { return 7; } + int opBinaryRight(string op)(D4 d) if (op == "+") { return 8; } } class C4 { - int opAdd(D1 d) { return 9; } - int opAdd(D2 d) { return 10; } - int opAdd(D3 d) { return 11; } - int opAdd(D4 d) { return 12; } + int opBinary(string op)(D1 d) if (op == "+") { return 9; } + int opBinary(string op)(D2 d) if (op == "+") { return 10; } + int opBinary(string op)(D3 d) if (op == "+") { return 11; } + int opBinary(string op)(D4 d) if (op == "+") { return 12; } - int opAdd_r(D1 d) { return 13; } - int opAdd_r(D2 d) { return 14; } - int opAdd_r(D3 d) { return 15; } - int opAdd_r(D4 d) { return 16; } + int opBinaryRight(string op)(D1 d) if (op == "+") { return 13; } + int opBinaryRight(string op)(D2 d) if (op == "+") { return 14; } + int opBinaryRight(string op)(D3 d) if (op == "+") { return 15; } + int opBinaryRight(string op)(D4 d) if (op == "+") { return 16; } } class D1 @@ -107,31 +108,31 @@ class D1 class D2 { - int opAdd(C1 c) { return 17; } - int opAdd(C2 d) { return 18; } - int opAdd(C3 d) { return 19; } - int opAdd(C4 d) { return 20; } + int opBinary(string op)(C1 d) if (op == "+") { return 17; } + int opBinary(string op)(C2 d) if (op == "+") { return 18; } + int opBinary(string op)(C3 d) if (op == "+") { return 19; } + int opBinary(string op)(C4 d) if (op == "+") { return 20; } } class D3 { - int opAdd_r(C1 d) { return 21; } - int opAdd_r(C2 d) { return 22; } - int opAdd_r(C3 d) { return 23; } - int opAdd_r(C4 d) { return 24; } + int opBinaryRight(string op)(C1 d) if (op == "+") { return 21; } + int opBinaryRight(string op)(C2 d) if (op == "+") { return 22; } + int opBinaryRight(string op)(C3 d) if (op == "+") { return 23; } + int opBinaryRight(string op)(C4 d) if (op == "+") { return 24; } } class D4 { - int opAdd(C1 d) { return 25; } - int opAdd(C2 d) { return 26; } - int opAdd(C3 d) { return 27; } - int opAdd(C4 d) { return 28; } + int opBinary(string op)(C1 d) if (op == "+") { return 25; } + int opBinary(string op)(C2 d) if (op == "+") { return 26; } + int opBinary(string op)(C3 d) if (op == "+") { return 27; } + int opBinary(string op)(C4 d) if (op == "+") { return 28; } - int opAdd_r(C1 d) { return 29; } - int opAdd_r(C2 d) { return 30; } - int opAdd_r(C3 d) { return 31; } - int opAdd_r(C4 d) { return 32; } + int opBinaryRight(string op)(C1 d) if (op == "+") { return 29; } + int opBinaryRight(string op)(C2 d) if (op == "+") { return 30; } + int opBinaryRight(string op)(C3 d) if (op == "+") { return 31; } + int opBinaryRight(string op)(C4 d) if (op == "+") { return 32; } } @@ -149,90 +150,45 @@ void test3() int i; - version (ADD_R) - { //i = c1 + d1; assert(i == ); - i = c1 + d2; assert(i == 17); + //i = c1 + d2; assert(i == ); i = c1 + d3; assert(i == 21); i = c1 + d4; assert(i == 29); i = c2 + d1; assert(i == 1); i = c2 + d2; assert(i == 2); - i = c2 + d3; assert(i == 3); - i = c2 + d4; assert(i == 4); + i = c2 + d3; assert(i == 22); + i = c2 + d4; assert(i == 30); //i = c3 + d1; assert(i == ); - i = c3 + d2; assert(i == 19); + //i = c3 + d2; assert(i == ); i = c3 + d3; assert(i == 23); i = c3 + d4; assert(i == 31); i = c4 + d1; assert(i == 9); i = c4 + d2; assert(i == 10); - i = c4 + d3; assert(i == 11); - i = c4 + d4; assert(i == 12); + i = c4 + d3; assert(i == 24); + i = c4 + d4; assert(i == 32); //i = d1 + c1; assert(i == ); - i = d1 + c2; assert(i == 1); + //i = d1 + c2; assert(i == ); i = d1 + c3; assert(i == 5); i = d1 + c4; assert(i == 13); i = d2 + c1; assert(i == 17); i = d2 + c2; assert(i == 18); - i = d2 + c3; assert(i == 19); - i = d2 + c4; assert(i == 20); + i = d2 + c3; assert(i == 6); + i = d2 + c4; assert(i == 14); //i = d3 + c1; assert(i == ); - i = d3 + c2; assert(i == 3); + //i = d3 + c2; assert(i == ); i = d3 + c3; assert(i == 7); i = d3 + c4; assert(i == 15); i = d4 + c1; assert(i == 25); i = d4 + c2; assert(i == 26); - i = d4 + c3; assert(i == 27); - i = d4 + c4; assert(i == 28); - } - else - { - //i = c1 + d1; assert(i == ); - i = c1 + d2; assert(i == 17); -// i = c1 + d3; assert(i == 21); - i = c1 + d4; assert(i == 29); - - i = c2 + d1; assert(i == 1); - i = c2 + d2; assert(i == 2); -// i = c2 + d3; assert(i == 3); -// i = c2 + d4; assert(i == 4); - - //i = c3 + d1; assert(i == ); -// i = c3 + d2; printf("i = %d\n", i); assert(i == 19); -// i = c3 + d3; assert(i == 23); - i = c3 + d4; assert(i == 31); - - i = c4 + d1; assert(i == 9); - i = c4 + d2; assert(i == 10); -// i = c4 + d3; assert(i == 11); -// i = c4 + d4; assert(i == 12); - - //i = d1 + c1; assert(i == ); - i = d1 + c2; assert(i == 1); -// i = d1 + c3; assert(i == 5); - i = d1 + c4; assert(i == 13); - - i = d2 + c1; assert(i == 17); - i = d2 + c2; assert(i == 18); -// i = d2 + c3; assert(i == 19); -// i = d2 + c4; assert(i == 20); - - //i = d3 + c1; assert(i == ); -// i = d3 + c2; assert(i == 3); -// i = d3 + c3; assert(i == 7); - i = d3 + c4; assert(i == 15); - - i = d4 + c1; assert(i == 25); - i = d4 + c2; assert(i == 26); -// i = d4 + c3; assert(i == 27); -// i = d4 + c4; assert(i == 28); - } + i = d4 + c3; assert(i == 8); + i = d4 + c4; assert(i == 16); } /**************************************/ @@ -258,44 +214,45 @@ void test4() class A5 { - int opNeg() { return 10; } - int opCom() { return 11; } - int opPostInc() { return 12; } - int opPostDec() { return 13; } - - int opAdd(int j) { return 14; } - int opSub(int j) { return 15; } - int opSub_r(int j) { return 16; } - int opMul(int j) { return 17; } - int opDiv(int j) { return 18; } - int opDiv_r(int j) { return 19; } - int opMod(int j) { return 20; } - int opMod_r(int j) { return 21; } - int opAnd(int j) { return 22; } - int opOr(int j) { return 23; } - int opXor(int j) { return 24; } - int opShl(int j) { return 25; } - int opShl_r(int j) { return 26; } - int opShr(int j) { return 27; } - int opShr_r(int j) { return 28; } - int opUShr(int j) { return 29; } - int opUShr_r(int j) { return 30; } - int opCat(int j) { return 31; } - int opCat_r(int j) { return 32; } + int opUnary(string op)() if (op == "-") { return 10; } + int opUnary(string op)() if (op == "~") { return 11; } + int opUnary(string op)() if (op == "++") { return 12; } + int opUnary(string op)() if (op == "--") { return 13; } + + + int opBinary(string op)(int j) if (op == "+") { return 14; } + int opBinary(string op)(int j) if (op == "-") { return 15; } + int opBinaryRight(string op)(int j) if (op == "-") { return 16; } + int opBinary(string op)(int j) if (op == "*") { return 17; } + int opBinary(string op)(int j) if (op == "/") { return 18; } + int opBinaryRight(string op)(int j) if (op == "/") { return 19; } + int opBinary(string op)(int j) if (op == "%") { return 20; } + int opBinaryRight(string op)(int j) if (op == "%") { return 21; } + int opBinary(string op)(int j) if (op == "&") { return 22; } + int opBinary(string op)(int j) if (op == "|") { return 23; } + int opBinary(string op)(int j) if (op == "^") { return 24; } + int opBinary(string op)(int j) if (op == "<<") { return 25; } + int opBinaryRight(string op)(int j) if (op == "<<") { return 26; } + int opBinary(string op)(int j) if (op == ">>") { return 27; } + int opBinaryRight(string op)(int j) if (op == ">>") { return 28; } + int opBinary(string op)(int j) if (op == ">>>") { return 29; } + int opBinaryRight(string op)(int j) if (op == ">>>") { return 30; } + int opBinary(string op)(int j) if (op == "~") { return 31; } + int opBinaryRight(string op)(int j) if (op == "~") { return 32; } int opEquals(int j) { return 33; } int opCmp(int j) { return 34; } - int opAddAssign(int j) { return 35; } - int opSubAssign(int j) { return 36; } - int opMulAssign(int j) { return 37; } - int opDivAssign(int j) { return 38; } - int opModAssign(int j) { return 39; } - int opAndAssign(int j) { return 40; } - int opOrAssign(int j) { return 41; } - int opXorAssign(int j) { return 42; } - int opShlAssign(int j) { return 43; } - int opShrAssign(int j) { return 44; } - int opUShrAssign(int j) { return 45; } - int opCatAssign(int j) { return 46; } + int opOpAssign(string op)(int j) if (op == "+") { return 35; } + int opOpAssign(string op)(int j) if (op == "-") { return 36; } + int opOpAssign(string op)(int j) if (op == "*") { return 37; } + int opOpAssign(string op)(int j) if (op == "/") { return 38; } + int opOpAssign(string op)(int j) if (op == "%") { return 39; } + int opOpAssign(string op)(int j) if (op == "&") { return 40; } + int opOpAssign(string op)(int j) if (op == "|") { return 41; } + int opOpAssign(string op)(int j) if (op == "^") { return 42; } + int opOpAssign(string op)(int j) if (op == "<<") { return 43; } + int opOpAssign(string op)(int j) if (op == ">>") { return 44; } + int opOpAssign(string op)(int j) if (op == ">>>") { return 45; } + int opOpAssign(string op)(int j) if (op == "~") { return 46; } } void test5() @@ -309,10 +266,10 @@ void test5() i = ~a; assert(i == 11); - i = a++; + i = ++a; assert(i == 12); - i = a--; + i = --a; assert(i == 13); i = a + 1; @@ -402,13 +359,9 @@ printf("i = %d\n", i); i = (a += 1); assert(i == 35); - i = ++a; - assert(i == 35); i = (a -= 1); assert(i == 36); - i = --a; - assert(i == 36); i = (a *= 1); assert(i == 37); @@ -445,45 +398,45 @@ printf("i = %d\n", i); struct A6 { - int opNeg() { return 10; } - int opCom() { return 11; } - int opPostInc() { return 12; } - int opPostDec() { return 13; } - - int opAdd(int j) { return 14; } - int opSub(int j) { return 15; } - int opSub_r(int j) { return 16; } - int opMul(int j) { return 17; } - int opDiv(int j) { return 18; } - int opDiv_r(int j) { return 19; } - int opMod(int j) { return 20; } - int opMod_r(int j) { return 21; } - int opAnd(int j) { return 22; } - int opOr(int j) { return 23; } - int opXor(int j) { return 24; } - int opShl(int j) { return 25; } - int opShl_r(int j) { return 26; } - int opShr(int j) { return 27; } - int opShr_r(int j) { return 28; } - int opUShr(int j) { return 29; } - int opUShr_r(int j) { return 30; } - int opCat(int j) { return 31; } - int opCat_r(int j) { return 32; } - int opEquals(int j) { return 33; } + int opUnary(string op)() if (op == "-") { return 10; } + int opUnary(string op)() if (op == "~") { return 11; } + int opUnary(string op)() if (op == "++") { return 12; } + int opUnary(string op)() if (op == "--") { return 13; } + + int opBinary(string op)(int j) if (op == "+") { return 14; } + int opBinary(string op)(int j) if (op == "-") { return 15; } + int opBinaryRight(string op)(int j) if (op == "-") { return 16; } + int opBinary(string op)(int j) if (op == "*") { return 17; } + int opBinary(string op)(int j) if (op == "/") { return 18; } + int opBinaryRight(string op)(int j) if (op == "/") { return 19; } + int opBinary(string op)(int j) if (op == "%") { return 20; } + int opBinaryRight(string op)(int j) if (op == "%") { return 21; } + int opBinary(string op)(int j) if (op == "&") { return 22; } + int opBinary(string op)(int j) if (op == "|") { return 23; } + int opBinary(string op)(int j) if (op == "^") { return 24; } + int opBinary(string op)(int j) if (op == "<<") { return 25; } + int opBinaryRight(string op)(int j) if (op == "<<") { return 26; } + int opBinary(string op)(int j) if (op == ">>") { return 27; } + int opBinaryRight(string op)(int j) if (op == ">>") { return 28; } + int opBinary(string op)(int j) if (op == ">>>") { return 29; } + int opBinaryRight(string op)(int j) if (op == ">>>") { return 30; } + int opBinary(string op)(int j) if (op == "~") { return 31; } + int opBinaryRight(string op)(int j) if (op == "~") { return 32; } + int opEquals(int j) { return 33; } const bool opEquals(const ref A6) { return false; } int opCmp(int j) { return 34; } - int opAddAssign(int j) { return 35; } - int opSubAssign(int j) { return 36; } - int opMulAssign(int j) { return 37; } - int opDivAssign(int j) { return 38; } - int opModAssign(int j) { return 39; } - int opAndAssign(int j) { return 40; } - int opOrAssign(int j) { return 41; } - int opXorAssign(int j) { return 42; } - int opShlAssign(int j) { return 43; } - int opShrAssign(int j) { return 44; } - int opUShrAssign(int j) { return 45; } - int opCatAssign(int j) { return 46; } + int opOpAssign(string op)(int j) if (op == "+") { return 35; } + int opOpAssign(string op)(int j) if (op == "-") { return 36; } + int opOpAssign(string op)(int j) if (op == "*") { return 37; } + int opOpAssign(string op)(int j) if (op == "/") { return 38; } + int opOpAssign(string op)(int j) if (op == "%") { return 39; } + int opOpAssign(string op)(int j) if (op == "&") { return 40; } + int opOpAssign(string op)(int j) if (op == "|") { return 41; } + int opOpAssign(string op)(int j) if (op == "^") { return 42; } + int opOpAssign(string op)(int j) if (op == "<<") { return 43; } + int opOpAssign(string op)(int j) if (op == ">>") { return 44; } + int opOpAssign(string op)(int j) if (op == ">>>") { return 45; } + int opOpAssign(string op)(int j) if (op == "~") { return 46; } } void test6() @@ -497,10 +450,10 @@ void test6() i = ~a; assert(i == 11); - i = a++; + i = ++a; assert(i == 12); - i = a--; + i = --a; assert(i == 13); i = a + 1; @@ -589,13 +542,9 @@ void test6() i = (a += 1); assert(i == 35); - i = ++a; - assert(i == 35); i = (a -= 1); assert(i == 36); - i = --a; - assert(i == 36); i = (a *= 1); assert(i == 37); @@ -652,19 +601,19 @@ void test7() interface IWriter { - int opShl (string i); - int opShl (int i); + int opBinary(string op)(string i) if (op == "<<"); + int opBinary(string op)(int i) if (op == "<<"); } class Writer : IWriter { - int opShl (string i) + int opBinary(string op)(string i) if (op == "<<") { printf("Writer.opShl(char[])\n"); return 1; } - int opShl (int i) + int opBinary(string op)(int i) if (op == "<<") { printf("Writer.opShl(int)\n"); return 2; @@ -673,9 +622,13 @@ class Writer : IWriter class BinaryWriter : Writer { - alias Writer.opShl opShl; + int opBinary(string op)(string i) if (op == "<<") + { + printf("Writer.opShl(char[])\n"); + return 1; + } - override int opShl (int i) + int opBinary(string op)(int i) if (op == "<<") { printf("BinaryWriter.opShl(int)\n"); return 3; @@ -712,12 +665,14 @@ void test9() class A10 { - int opAdd(int i) { return i + 1; } + int opBinary(string op)(int i) if (op == "+") { return i + 1; } + alias opBinaryRight = opBinary; } class B10 { - int opAdd_r(A10 a) { return 3; } + int opBinaryRight(string op)(A10 a) if (op == "+") { return 3; } + alias opBinary = opBinaryRight; } void test10() @@ -791,13 +746,13 @@ void test12() class A13 { - A13 opShl(int x) + A13 opBinary(string op)(int x) if (op == "<<") { printf("A::opShl(int %d)\n", x); printf("%d",x); return this; } - A13 opShl(string x) + A13 opBinary(string op)(string x) if (op == "<<") { printf("A::opShl(char[])\n"); printf("%.*s", cast(int)x.length, x.ptr); @@ -807,7 +762,7 @@ class A13 class B13 { - A13 opShl_r(A13 a) + A13 opBinaryRight(string op)(A13 a) if (op == "<<") { printf("B::opShl_r(A)\n"); return a; @@ -829,7 +784,7 @@ void test13() class Foo14 { int a; - int opIn(int x) + int opBinary(string op)(int x) if (op == "in") { return a + x; } @@ -999,18 +954,6 @@ struct Vec12778X float x = 0, y = 0; } -struct Vec12778Y -{ - Vec12778Y opAdd()(Vec12778Y b) const - { - enum op = "+"; - mixin("return Vec12778Y(this.x " ~ op ~ " b.x, this.y " ~ op ~ " b.y);"); - } - alias opAdd_r = opAdd; - - float x = 0, y = 0; -} - void test12778() { struct S @@ -1018,17 +961,14 @@ void test12778() void test1() { Vec12778X vx = vx1 + vx2; // ok - Vec12778Y vy = vy1 + vy2; // ok } void test2() const { Vec12778X vx = vx1 + vx2; // ok <- error - Vec12778Y vy = vy1 + vy2; // ok <- error } Vec12778X vx1, vx2; - Vec12778Y vy1, vy2; } } @@ -1049,8 +989,8 @@ struct S14343b int i; immutable(Object) o; - void opAddAssign(int j) { i += j; } - S14343b opPostInc() { ++i; return this; } + void opOpAssign(string op)(int j) if (op == "+") { i += j; } + S14343b opUnary(string op)() if (op == "++") { ++i; return this; } void opAssign(S14343b other) {} } diff --git a/gcc/testsuite/gdc.test/runnable/sctor2.d b/gcc/testsuite/gdc.test/runnable/sctor2.d index a2367cf7999..bd820e498f4 100644 --- a/gcc/testsuite/gdc.test/runnable/sctor2.d +++ b/gcc/testsuite/gdc.test/runnable/sctor2.d @@ -1,5 +1,10 @@ -// REQUIRED_ARGS: -w -de +// REQUIRED_ARGS: -w -dw // PERMUTE_ARGS: +/* TEST_OUTPUT: +--- +runnable/sctor2.d(12): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. +--- +*/ /***************************************************/ // 15665 diff --git a/gcc/testsuite/gdc.test/runnable/test22136.d b/gcc/testsuite/gdc.test/runnable/test22136.d deleted file mode 100644 index 8b5af24396e..00000000000 --- a/gcc/testsuite/gdc.test/runnable/test22136.d +++ /dev/null @@ -1,25 +0,0 @@ - -interface IObject -{ - size_t toHash() @trusted nothrow; -} - -interface Dummy {} -interface Bug(E) : Dummy, IObject {} -interface OK(E) : IObject, Dummy {} - -void main() -{ - - { - Bug!string s; - size_t t = hashOf(s); - } - { - OK!string s; - size_t t = hashOf(s); - } - - static assert(is(immutable Bug!string* : immutable IObject*)); - static assert(is(immutable OK!string* : immutable IObject*)); -} diff --git a/gcc/testsuite/gdc.test/runnable/testconst.d b/gcc/testsuite/gdc.test/runnable/testconst.d index 191ddadc9f2..17e3236f80f 100644 --- a/gcc/testsuite/gdc.test/runnable/testconst.d +++ b/gcc/testsuite/gdc.test/runnable/testconst.d @@ -2175,13 +2175,13 @@ void test4251b() // derived class to const(base interface) in tail interface I {} class X : I {} - static assert(is( X[] : const(I)[] )); + static assert(!is( X[] : const(I)[] )); // interface to const(base interface) in tail interface J {} interface K : I, J {} static assert( is( K[] : const(I)[] )); // OK, runtime offset is same - static assert(is( K[] : const(J)[] )); // !? NG, runtime offset is different + static assert(!is( K[] : const(J)[] )); // NG, runtime offset is different } /************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index a66e00f0c5d..eeaa1dbe72d 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -14,14 +14,6 @@ tuple(height) tuple(get, get) tuple(clear) tuple(draw, draw) -runnable/xtest46.d(149): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(151): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(152): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(154): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(181): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(183): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(184): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46.d(186): Deprecation: `opDot` is deprecated. Use `alias this` const(int) string[] double[] @@ -137,10 +129,7 @@ struct T6 S6 s; int b = 7; - S6* opDot() return - { - return &s; - } + alias s this; } void test6() @@ -169,10 +158,7 @@ class C7 S7 s; int b = 7; - S7* opDot() - { - return &s; - } + alias s this; } void test7() diff --git a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d index 14b82a00cd3..348c05bd09d 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d @@ -15,14 +15,6 @@ tuple(height) tuple(get, get) tuple(clear) tuple(draw, draw) -runnable/xtest46_gc.d-mixin-$n$(185): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(187): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(188): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(190): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(217): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(219): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(220): Deprecation: `opDot` is deprecated. Use `alias this` -runnable/xtest46_gc.d-mixin-$n$(222): Deprecation: `opDot` is deprecated. Use `alias this` const(int) string[] double[] diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index c4b1538b3a4..77b6ad00173 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -0316b981e5f2fa1525e893c5d94c59c847a8c386 +26b581670ef6e2643d74078f200d1cd21fa40e90 The first line of this file holds the git revision number of the last merge done from the dlang/druntime repository. diff --git a/libphobos/libdruntime/core/internal/gc/bits.d b/libphobos/libdruntime/core/internal/gc/bits.d index 3c1bb543460..aa94e407642 100644 --- a/libphobos/libdruntime/core/internal/gc/bits.d +++ b/libphobos/libdruntime/core/internal/gc/bits.d @@ -239,7 +239,9 @@ struct GCBits size_t cntWords = lastWord - firstWord; copyWordsShifted(firstWord, cntWords, firstOff, source); - wordtype src = (source[cntWords - 1] >> (BITS_PER_WORD - firstOff)) | (source[cntWords] << firstOff); + wordtype src = (source[cntWords - 1] >> (BITS_PER_WORD - firstOff)); + if (lastOff >= firstOff) // prevent buffer overread + src |= (source[cntWords] << firstOff); wordtype mask = (BITS_2 << lastOff) - 1; data[lastWord] = (data[lastWord] & ~mask) | (src & mask); } diff --git a/libphobos/libdruntime/core/stdc/config.d b/libphobos/libdruntime/core/stdc/config.d index 44bb7077b59..037af25a675 100644 --- a/libphobos/libdruntime/core/stdc/config.d +++ b/libphobos/libdruntime/core/stdc/config.d @@ -34,7 +34,7 @@ version (StdDdoc) alias ddoc_long = int; alias ddoc_ulong = uint; } - struct ddoc_complex(T) { T re; T im; }; + struct ddoc_complex(T) { T re; T im; } } /*** diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d index 3002c022613..88123fb16a6 100644 --- a/libphobos/libdruntime/core/stdc/fenv.d +++ b/libphobos/libdruntime/core/stdc/fenv.d @@ -151,6 +151,8 @@ version (GNUFP) // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/sparc/fpu/bits/fenv.h else version (SPARC_Any) { + import core.stdc.config : c_ulong; + alias fenv_t = c_ulong; alias fexcept_t = c_ulong; } diff --git a/libphobos/libdruntime/core/stdc/stdint.d b/libphobos/libdruntime/core/stdc/stdint.d index 9db2fdaa691..556ac019eeb 100644 --- a/libphobos/libdruntime/core/stdc/stdint.d +++ b/libphobos/libdruntime/core/stdc/stdint.d @@ -36,20 +36,7 @@ extern (C): nothrow: @nogc: -// These are defined the same way as D basic types, so the definition is -// platform-independant -alias int8_t = byte; /// -alias int16_t = short; /// -alias uint8_t = ubyte; /// -alias uint16_t = ushort; /// - -// 32 bit types and need to be defined on-platform basis, because -// they might have C++ binary mangling of `int` or `long`. -// 64-bit types respectively might be mangled as `long` or `long long` - -// It would seem correct to define intmax_t and uintmax_t here, but C and C++ -// compilers don't in practice always set them to the maximum supported value. -// See https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/ + static if (is(ucent)) { alias int128_t = cent; /// @@ -58,6 +45,10 @@ static if (is(ucent)) version (Windows) { + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// version (CRuntime_DigitalMars) { alias int32_t = cpp_long; /// @@ -71,23 +62,31 @@ version (Windows) alias int64_t = long; /// alias uint64_t = ulong; /// - alias int_least8_t = byte; /// - alias uint_least8_t = ubyte; /// - alias int_least16_t = short; /// - alias uint_least16_t = ushort; /// - alias int_least32_t = int32_t; /// + alias int_least8_t = byte; /// + alias uint_least8_t = ubyte; /// + alias int_least16_t = short; /// + alias uint_least16_t = ushort; /// + alias int_least32_t = int32_t; /// alias uint_least32_t = uint32_t; /// - alias int_least64_t = long; /// - alias uint_least64_t = ulong; /// + alias int_least64_t = long; /// + alias uint_least64_t = ulong; /// - alias int_fast8_t = byte; /// - alias uint_fast8_t = ubyte; /// - alias int_fast16_t = int; /// - alias uint_fast16_t = uint; /// - alias int_fast32_t = int32_t; /// + alias int_fast8_t = byte; /// + alias uint_fast8_t = ubyte; /// + version (MinGW) + { + alias int_fast16_t = short; /// + alias uint_fast16_t = ushort; /// + } + else + { + alias int_fast16_t = int; /// + alias uint_fast16_t = uint; /// + } + alias int_fast32_t = int32_t; /// alias uint_fast32_t = uint32_t; /// - alias int_fast64_t = long; /// - alias uint_fast64_t = ulong; /// + alias int_fast64_t = long; /// + alias uint_fast64_t = ulong; /// alias intptr_t = ptrdiff_t; /// alias uintptr_t = size_t; /// @@ -96,6 +95,10 @@ version (Windows) } else version (Darwin) { + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// alias int32_t = int; /// alias uint32_t = uint; /// alias int64_t = cpp_longlong; /// @@ -124,32 +127,27 @@ else version (Darwin) alias intmax_t = long; /// alias uintmax_t = ulong; /// } -else version (Posix) +else version (linux) { - alias int32_t = int; /// - alias uint32_t = uint; /// - alias int64_t = long; /// - alias uint64_t = ulong; /// - - alias int_least8_t = byte; /// - alias uint_least8_t = ubyte; /// - alias int_least16_t = short; /// + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = long; /// + alias uint64_t = ulong; /// + + alias int_least8_t = byte; /// + alias uint_least8_t = ubyte; /// + alias int_least16_t = short; /// alias uint_least16_t = ushort; /// - alias int_least32_t = int; /// - alias uint_least32_t = uint; /// - alias int_least64_t = long; /// - alias uint_least64_t = ulong;/// + alias int_least32_t = int; /// + alias uint_least32_t = uint; /// + alias int_least64_t = long; /// + alias uint_least64_t = ulong; /// - version (FreeBSD) - { - alias int_fast8_t = int; /// - alias uint_fast8_t = uint; /// - alias int_fast16_t = int; /// - alias uint_fast16_t = uint; /// - alias int_fast32_t = int; /// - alias uint_fast32_t = uint; /// - } - else version (CRuntime_Musl) + version (CRuntime_Musl) { alias int_fast8_t = byte; /// alias uint_fast8_t = ubyte; /// @@ -167,17 +165,221 @@ else version (Posix) alias int_fast32_t = ptrdiff_t; /// alias uint_fast32_t = size_t; /// } - alias int_fast64_t = long; /// + alias int_fast64_t = long; /// + alias uint_fast64_t = ulong; /// + + alias intptr_t = ptrdiff_t; /// + alias uintptr_t = size_t; /// + alias intmax_t = long; /// + alias uintmax_t = ulong; /// +} +else version (CRuntime_Glibc) +{ + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = long; /// + alias uint64_t = ulong; /// + + alias int_least8_t = byte; /// + alias uint_least8_t = ubyte; /// + alias int_least16_t = short; /// + alias uint_least16_t = ushort; /// + alias int_least32_t = int; /// + alias uint_least32_t = uint; /// + alias int_least64_t = long; /// + alias uint_least64_t = ulong; /// + + alias int_fast8_t = byte; /// + alias uint_fast8_t = ubyte; /// + alias int_fast16_t = ptrdiff_t; /// + alias uint_fast16_t = size_t; /// + alias int_fast32_t = ptrdiff_t; /// + alias uint_fast32_t = size_t; /// + alias int_fast64_t = long; /// + alias uint_fast64_t = ulong; /// + + alias intptr_t = ptrdiff_t; /// + alias uintptr_t = size_t; /// + alias intmax_t = long; /// + alias uintmax_t = ulong; /// +} +else version (DragonFlyBSD) +{ + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = long; /// + alias uint64_t = ulong; /// + + alias int_least8_t = int8_t; /// + alias uint_least8_t = uint8_t; /// + alias int_least16_t = int16_t; /// + alias uint_least16_t = uint16_t; /// + alias int_least32_t = int32_t; /// + alias uint_least32_t = uint32_t; /// + alias int_least64_t = int64_t; /// + alias uint_least64_t = uint64_t; /// + + alias int_fast8_t = int32_t; /// + alias uint_fast8_t = uint32_t; /// + alias int_fast16_t = int32_t; /// + alias uint_fast16_t = uint32_t; /// + alias int_fast32_t = int32_t; /// + alias uint_fast32_t = uint32_t; /// + alias int_fast64_t = int64_t; /// + alias uint_fast64_t = uint64_t; /// + + alias intptr_t = ptrdiff_t; /// + alias uintptr_t = size_t; /// + alias intmax_t = long; /// + alias uintmax_t = ulong; /// +} +else version (FreeBSD) +{ + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = long; /// + alias uint64_t = ulong; /// + + alias int_least8_t = byte; /// + alias uint_least8_t = ubyte; /// + alias int_least16_t = short; /// + alias uint_least16_t = ushort; /// + alias int_least32_t = int; /// + alias uint_least32_t = uint; /// + alias int_least64_t = long; /// + alias uint_least64_t = ulong; /// + + alias int_fast8_t = int; /// + alias uint_fast8_t = uint; /// + alias int_fast16_t = int; /// + alias uint_fast16_t = uint; /// + alias int_fast32_t = int; /// + alias uint_fast32_t = uint; /// + alias int_fast64_t = long; /// alias uint_fast64_t = ulong; /// alias intptr_t = ptrdiff_t; /// - alias uintptr_t = size_t; /// - alias intmax_t = long; /// - alias uintmax_t = ulong; /// + alias uintptr_t = size_t; /// + alias intmax_t = long; /// + alias uintmax_t = ulong; /// +} +else version (NetBSD) +{ + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = long; /// + alias uint64_t = ulong; /// + + alias int_least8_t = int8_t; /// + alias uint_least8_t = uint8_t; /// + alias int_least16_t = int16_t; /// + alias uint_least16_t = uint16_t; /// + alias int_least32_t = int32_t; /// + alias uint_least32_t = uint32_t; /// + alias int_least64_t = int64_t; /// + alias uint_least64_t = uint64_t; /// + + alias int_fast8_t = int32_t; /// + alias uint_fast8_t = uint32_t; /// + alias int_fast16_t = int32_t; /// + alias uint_fast16_t = uint32_t; /// + alias int_fast32_t = int32_t; /// + alias uint_fast32_t = uint32_t; /// + alias int_fast64_t = int64_t; /// + alias uint_fast64_t = uint64_t; /// + + alias intptr_t = ptrdiff_t; /// + alias uintptr_t = size_t; /// + alias intmax_t = long; /// + alias uintmax_t = ulong; /// +} +else version (OpenBSD) +{ + alias int8_t = byte; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = cpp_longlong; /// + alias uint64_t = cpp_ulonglong; /// + + alias int_least8_t = byte; /// + alias uint_least8_t = ubyte; /// + alias int_least16_t = short; /// + alias uint_least16_t = ushort; /// + alias int_least32_t = int; /// + alias uint_least32_t = uint; /// + alias int_least64_t = cpp_longlong; /// + alias uint_least64_t = cpp_ulonglong; /// + + alias int_fast8_t = int; /// + alias uint_fast8_t = uint; /// + alias int_fast16_t = int; /// + alias uint_fast16_t = uint; /// + alias int_fast32_t = int; /// + alias uint_fast32_t = uint; /// + alias int_fast64_t = cpp_longlong; /// + alias uint_fast64_t = cpp_ulonglong; /// + + alias intptr_t = cpp_long; /// + alias uintptr_t = cpp_ulong; /// + alias intmax_t = cpp_longlong; /// + alias uintmax_t = cpp_ulonglong; /// +} +else version (Solaris) +{ + alias int8_t = char; /// + alias int16_t = short; /// + alias uint8_t = ubyte; /// + alias uint16_t = ushort; /// + alias int32_t = int; /// + alias uint32_t = uint; /// + alias int64_t = long; /// + alias uint64_t = ulong; /// + + alias int_least8_t = char; /// + alias uint_least8_t = ubyte; /// + alias int_least16_t = short; /// + alias uint_least16_t = ushort; /// + alias int_least32_t = int; /// + alias uint_least32_t = uint; /// + alias int_least64_t = long; /// + alias uint_least64_t = ulong; /// + + alias int_fast8_t = char; /// + alias uint_fast8_t = ubyte; /// + alias int_fast16_t = int; /// + alias uint_fast16_t = uint; /// + alias int_fast32_t = int; /// + alias uint_fast32_t = uint; /// + alias int_fast64_t = long; /// + alias uint_fast64_t = ulong; /// + + alias intptr_t = ptrdiff_t; /// + alias uintptr_t = size_t; /// + alias intmax_t = long; /// + alias uintmax_t = ulong; /// } else { - static assert(0); + static assert(false, "Unsupported architecture."); } diff --git a/libphobos/libdruntime/core/stdcpp/new_.d b/libphobos/libdruntime/core/stdcpp/new_.d index 77c179ce962..6a598baec28 100644 --- a/libphobos/libdruntime/core/stdcpp/new_.d +++ b/libphobos/libdruntime/core/stdcpp/new_.d @@ -26,7 +26,7 @@ extern (C++, "std") struct nothrow_t {} /// - enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ }; + enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ } /// class bad_alloc : exception diff --git a/libphobos/libdruntime/core/sys/windows/stat.d b/libphobos/libdruntime/core/sys/windows/stat.d index c9ee6ce5ca8..16f66e1287e 100644 --- a/libphobos/libdruntime/core/sys/windows/stat.d +++ b/libphobos/libdruntime/core/sys/windows/stat.d @@ -8,6 +8,8 @@ version (Windows): extern (C) nothrow @nogc: @system: +import core.sys.windows.stdc.time; + // Posix version is in core.sys.posix.sys.stat enum S_IFMT = 0xF000; @@ -30,22 +32,49 @@ int S_ISDIR(int m) { return (m & S_IFMT) == S_IFDIR; } int S_ISCHR(int m) { return (m & S_IFMT) == S_IFCHR; } } -struct struct_stat +version (CRuntime_DigitalMars) { - short st_dev; - ushort st_ino; - ushort st_mode; - short st_nlink; - ushort st_uid; - ushort st_gid; - short st_rdev; - short dummy; - int st_size; - int st_atime; - int st_mtime; - int st_ctime; + struct struct_stat + { + short st_dev; + ushort st_ino; + ushort st_mode; + short st_nlink; + ushort st_uid; + ushort st_gid; + short st_rdev; + short dummy; + int st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + } + + int stat(const(char)*, struct_stat *); + int fstat(int, struct_stat *) @trusted; + int _wstat(const(wchar)*, struct_stat *); } +else version (CRuntime_Microsoft) +{ + struct struct_stat + { + uint st_dev; + ushort st_ino; + ushort st_mode; + short st_nlink; + short st_uid; + short st_gid; + uint st_rdev; + int st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + } -int stat(const(char)*, struct_stat *); -int fstat(int, struct_stat *) @trusted; -int _wstat(const(wchar)*, struct_stat *); + // These assume time_t is 32 bits (which druntime's definition currently is) + // Add pragma(mangle) to use _stat64 etc. when time_t is made 64-bit + // See also: https://issues.dlang.org/show_bug.cgi?id=21134 + int stat(const(char)*, struct_stat *); + int fstat(int, struct_stat *) @trusted; + int _wstat(const(wchar)*, struct_stat *); +} diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index 1f7a81de80f..b0e25b57054 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -1011,8 +1011,12 @@ extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @ foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) { case T.sizeof: - (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr; - return result; + if (tinext.talign % T.alignof == 0) + { + (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr; + return result; + } + goto default; } default: @@ -1118,7 +1122,8 @@ extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak if (tiSize) { - *cast(TypeInfo*)(p + itemSize) = null; // the GC might not have cleared this area + // the GC might not have cleared the padding area in the block + *cast(TypeInfo*)(p + (itemSize & ~(size_t.sizeof - 1))) = null; *cast(TypeInfo*)(p + blkInf.size - tiSize) = cast() ti; } diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 5fd357c534a..963ffe020de 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -a1f8c4c0700ce4e256f4130ad7883c6ea3890901 +16cb085b584f100fa677e2e64ff6b6dbb4921ad1 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/setops.d b/libphobos/src/std/algorithm/setops.d index ede1831028e..cc6f5b77db7 100644 --- a/libphobos/src/std/algorithm/setops.d +++ b/libphobos/src/std/algorithm/setops.d @@ -404,7 +404,7 @@ if (ranges.length >= 2 && r = ranges[i].save; // rollover } } - @property Result save() scope return + @property Result save() return scope { Result copy = this; foreach (i, r; ranges) diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d index 9af9d721230..de2e0fb262f 100644 --- a/libphobos/src/std/bitmanip.d +++ b/libphobos/src/std/bitmanip.d @@ -1447,7 +1447,8 @@ public: size_t bitCount; foreach (i; 0 .. fullWords) bitCount += countBitsSet(_ptr[i]); - bitCount += countBitsSet(_ptr[fullWords] & endMask); + if (endBits) + bitCount += countBitsSet(_ptr[fullWords] & endMask); return bitCount; } else diff --git a/libphobos/src/std/datetime/interval.d b/libphobos/src/std/datetime/interval.d index ba2a21056c7..d787e3a8080 100644 --- a/libphobos/src/std/datetime/interval.d +++ b/libphobos/src/std/datetime/interval.d @@ -7848,12 +7848,12 @@ if (isTimePoint!TP && duration = The duration which separates each successive time point in the range. +/ -TP delegate(scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow +TP delegate(return scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow if (isTimePoint!TP && __traits(compiles, TP.init + duration) && (dir == Direction.fwd || dir == Direction.bwd)) { - TP func(scope const TP tp) + TP func(return scope const TP tp) { static if (dir == Direction.fwd) return tp + duration; diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d index db325f727e8..949ad7d75cc 100644 --- a/libphobos/src/std/datetime/systime.d +++ b/libphobos/src/std/datetime/systime.d @@ -6269,7 +6269,7 @@ public: duration = The $(REF Duration, core,time) to add to or subtract from this $(LREF SysTime). +/ - SysTime opBinary(string op)(Duration duration) @safe const pure nothrow scope + SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope if (op == "+" || op == "-") { SysTime retval = SysTime(this._stdTime, this._timezone); @@ -7668,7 +7668,7 @@ public: $(LREF SysTime) for the last day in the month that this Date is in. The time portion of endOfMonth is always 23:59:59.9999999. +/ - @property SysTime endOfMonth() @safe const nothrow scope + @property SysTime endOfMonth() @safe const nothrow return scope { immutable hnsecs = adjTime; immutable days = getUnitsFromHNSecs!"days"(hnsecs); diff --git a/libphobos/src/std/experimental/allocator/mallocator.d b/libphobos/src/std/experimental/allocator/mallocator.d index 895d5883f52..de9afbbf7d5 100644 --- a/libphobos/src/std/experimental/allocator/mallocator.d +++ b/libphobos/src/std/experimental/allocator/mallocator.d @@ -392,6 +392,7 @@ version (Posix) AlignedMallocator.instance.alignedReallocate(c, 32, 32); assert(c.ptr); + version (LDC_AddressSanitizer) {} else // AddressSanitizer does not support such large memory allocations (0x10000000000 max) version (DragonFlyBSD) {} else /* FIXME: Malloc on DragonFly does not return NULL when allocating more than UINTPTR_MAX * $(LINK: https://bugs.dragonflybsd.org/issues/3114, dragonfly bug report) * $(LINK: https://github.com/dlang/druntime/pull/1999#discussion_r157536030, PR Discussion) */ diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d index da698e045fe..90b0f91ecce 100644 --- a/libphobos/src/std/functional.d +++ b/libphobos/src/std/functional.d @@ -1847,3 +1847,168 @@ if (isCallable!(F)) static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD))); } } + +// Converts an unsigned integer to a compile-time string constant. +private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length]; + +// Check that .stringof does what we expect, since it's not guaranteed by the +// language spec. +@safe unittest +{ + assert(toCtString!0 == "0"); + assert(toCtString!123456 == "123456"); +} + +/** + * Passes the fields of a struct as arguments to a function. + * + * Can be used with a $(LINK2 https://dlang.org/spec/expression.html#function_literals, + * function literal) to give temporary names to the fields of a struct or + * tuple. + * + * Params: + * fun = Callable that the struct's fields will be passed to. + * + * Returns: + * A function that accepts a single struct as an argument and passes its + * fields to `fun` when called. + */ +template bind(alias fun) +{ + /** + * Params: + * args = The struct or tuple whose fields will be used as arguments. + * + * Returns: `fun(args.tupleof)` + */ + auto ref bind(T)(auto ref T args) + if (is(T == struct)) + { + import std.meta : Map = staticMap; + import core.lifetime : move; + + // Forwards the i'th member of `args` + // Needed because core.lifetime.forward doesn't work on struct members + template forwardArg(size_t i) + { + static if (__traits(isRef, args) || !is(typeof(move(args.tupleof[i])))) + enum forwardArg = "args.tupleof[" ~ toCtString!i ~ "], "; + else + enum forwardArg = "move(args.tupleof[" ~ toCtString!i ~ "]), "; + } + + static if (args.tupleof.length == 0) + enum argList = ""; + else + alias argList = Map!(forwardArg, Iota!(args.tupleof.length)); + + return mixin("fun(", argList, ")"); + } +} + +/// Giving names to tuple elements +@safe unittest +{ + import std.typecons : tuple; + + auto name = tuple("John", "Doe"); + string full = name.bind!((first, last) => first ~ " " ~ last); + assert(full == "John Doe"); +} + +/// Passing struct fields to a function +@safe unittest +{ + import std.algorithm.comparison : min, max; + + struct Pair + { + int a; + int b; + } + + auto p = Pair(123, 456); + assert(p.bind!min == 123); // min(p.a, p.b) + assert(p.bind!max == 456); // max(p.a, p.b) +} + +/// In a range pipeline +@safe unittest +{ + import std.algorithm.iteration : map, filter; + import std.algorithm.comparison : equal; + import std.typecons : tuple; + + auto ages = [ + tuple("Alice", 35), + tuple("Bob", 64), + tuple("Carol", 21), + tuple("David", 39), + tuple("Eve", 50) + ]; + + auto overForty = ages + .filter!(bind!((name, age) => age > 40)) + .map!(bind!((name, age) => name)); + + assert(overForty.equal(["Bob", "Eve"])); +} + +// Zero arguments +@safe unittest +{ + struct Empty {} + + assert(Empty().bind!(() => 123) == 123); +} + +// Non-copyable arguments +@safe unittest +{ + import std.typecons : tuple; + + static struct NoCopy + { + int n; + @disable this(this); + } + + static struct Pair + { + NoCopy a, b; + } + + static auto fun(NoCopy a, NoCopy b) + { + return tuple(a.n, b.n); + } + + auto expected = fun(NoCopy(1), NoCopy(2)); + assert(Pair(NoCopy(1), NoCopy(2)).bind!fun == expected); +} + +// ref arguments +@safe unittest +{ + import std.typecons : tuple; + + auto t = tuple(123, 456); + t.bind!((ref int a, int b) { a = 789; b = 1011; }); + + assert(t[0] == 789); + assert(t[1] == 456); +} + +// auto ref arguments +@safe unittest +{ + import std.typecons : tuple; + + auto t = tuple(123); + t.bind!((auto ref x) { + static assert(__traits(isRef, x)); + }); + tuple(123).bind!((auto ref x) { + static assert(!__traits(isRef, x)); + }); +} diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 3833c84243c..8da38bdb4e6 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -13,6 +13,7 @@ include: License: Boost License 1.0 Authors: Paul Backus +Source: $(PHOBOSSRC std/sumtype.d) +/ module std.sumtype; diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index 5c23684b9ae..f0200ce7052 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -1209,6 +1209,15 @@ do assert("ë"w.decode(i) == 'ë' && i == 1); } +@safe pure unittest // https://issues.dlang.org/show_bug.cgi?id=22867 +{ + import std.conv : hexString; + string data = hexString!"f787a598"; + size_t offset = 0; + try data.decode(offset); + catch (UTFException ex) assert(offset == 0); +} + /++ `decodeFront` is a variant of $(LREF decode) which specifically decodes the first code point. Unlike $(LREF decode), `decodeFront` accepts any @@ -1671,7 +1680,6 @@ if ( } } - index += i + 1; static if (i == 3) { if (d > dchar.max) @@ -1682,6 +1690,8 @@ if ( throw invalidUTF(); } } + + index += i + 1; return d; } }