From patchwork Thu Apr 21 19:47:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1620440 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=US0wy0dC; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4Kkp4C6RQLz9s2R for ; Fri, 22 Apr 2022 05:48:10 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D4B23385734C for ; Thu, 21 Apr 2022 19:48:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D4B23385734C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1650570487; bh=+RaeGzSClAawdPzRBI/MoRRI+yyoCJYMM9/dqZRFpXY=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=US0wy0dCbmaqF4yRgR1AL7Gf/4HZTa2ql2/75tu+9z1Me0m6qoFXSStaBkksl+6IE BGuzfAydWywSvSlQQw0uzJWl1Q9mmEBuTsxV2TxpDUTrujz5mFsJt1A/REjfV14j/l OG4QFYVPEIGkWzXKErj00TrgLyxTr8w8ltFI36Ok= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-202.mailbox.org (mout-p-202.mailbox.org [80.241.56.172]) by sourceware.org (Postfix) with ESMTPS id DA7AF3858430 for ; Thu, 21 Apr 2022 19:47:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DA7AF3858430 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-202.mailbox.org (Postfix) with ESMTPS id 4Kkp3367fnz9sSb; Thu, 21 Apr 2022 21:47:11 +0200 (CEST) To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd eb7bee331, druntime 27834edb, phobos ac296f80c. Date: Thu, 21 Apr 2022 20:47:03 +0100 Message-Id: <20220421194703.1247797-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_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP 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 with upstream dmd eb7bee331, and the standard library with druntime 27834edb and phobos ac296f80c. D front-end changes: - Import dmd v2.100.0-beta.1. - Print deprecation messages for scope violations unless `-frevert=dip1000' is used. - Fixed a missed case of switch case fallthrough not being caught by the compiler. D runtime changes: - Import druntime v2.100.0-beta.1. Phobos changes: - Import phobos v2.100.0-beta.1. Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd eb7bee331. * dmd/VERSION: Update version to v2.100.0-beta.1. * d-lang.cc (d_handle_option): Handle OPT_frevert_dip1000. * lang.opt (frevert=dip1000): New option. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 27834edb. * src/MERGE: Merge upstream phobos ac296f80c. * src/Makefile.am (PHOBOS_DSOURCES): Add std/int128.d. * src/Makefile.in: Regenerate. --- gcc/d/d-lang.cc | 5 + gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/aggregate.d | 22 ++ gcc/d/dmd/astenums.d | 1 + gcc/d/dmd/blockexit.d | 15 +- gcc/d/dmd/clone.d | 6 +- gcc/d/dmd/cparse.d | 22 +- gcc/d/dmd/declaration.d | 18 +- gcc/d/dmd/dmodule.d | 6 +- gcc/d/dmd/dsymbol.d | 4 +- gcc/d/dmd/dsymbolsem.d | 9 +- gcc/d/dmd/errors.d | 16 +- gcc/d/dmd/escape.d | 61 ++- gcc/d/dmd/expression.d | 11 +- gcc/d/dmd/expression.h | 2 - gcc/d/dmd/expressionsem.d | 29 +- gcc/d/dmd/initsem.d | 8 +- gcc/d/dmd/lexer.d | 55 ++- gcc/d/dmd/mtype.d | 92 ++--- gcc/d/dmd/mtype.h | 2 +- gcc/d/dmd/optimize.d | 13 +- gcc/d/dmd/parse.d | 98 +++-- gcc/d/dmd/statement.d | 8 + gcc/d/dmd/transitivevisitor.d | 4 +- gcc/d/dmd/typesem.d | 11 +- gcc/d/dmd/utils.d | 2 +- gcc/d/lang.opt | 4 + .../gdc.test/compilable/betterCarray.d | 7 + gcc/testsuite/gdc.test/compilable/test18216.d | 40 ++ gcc/testsuite/gdc.test/compilable/test22635.d | 13 + .../gdc.test/fail_compilation/diag11198.d | 12 +- .../gdc.test/fail_compilation/fail22202.d | 22 ++ .../gdc.test/fail_compilation/fail23036.d | 22 ++ .../gdc.test/fail_compilation/fail_scope.d | 30 +- .../gdc.test/fail_compilation/retscope6.d | 48 ++- .../gdc.test/fail_compilation/test22999.d | 27 ++ .../gdc.test/fail_compilation/test23017.d | 20 + gcc/testsuite/gdc.test/runnable/testscope.d | 16 - libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/exception.d | 84 ++-- libphobos/libdruntime/object.d | 4 +- libphobos/libdruntime/rt/aaA.d | 4 +- libphobos/src/MERGE | 2 +- libphobos/src/Makefile.am | 2 +- libphobos/src/Makefile.in | 4 +- libphobos/src/std/base64.d | 20 +- libphobos/src/std/int128.d | 374 ++++++++++++++++++ libphobos/src/std/path.d | 2 +- libphobos/src/std/traits.d | 21 +- 50 files changed, 1002 insertions(+), 302 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/test18216.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22635.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22202.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail23036.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test22999.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test23017.d create mode 100644 libphobos/src/std/int128.d diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 69571628336..9adcabdf7cf 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -637,12 +637,17 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_frevert_all: + global.params.useDIP1000 = FeatureState::disabled; global.params.useDIP25 = FeatureState::disabled; global.params.dtorFields = FeatureState::disabled; global.params.fix16997 = !value; global.params.markdown = !value; break; + case OPT_frevert_dip1000: + global.params.useDIP1000 = FeatureState::disabled; + break; + case OPT_frevert_dip25: global.params.useDIP25 = FeatureState::disabled; break; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index f36d65e7d84..2bc9b95b5e2 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -4d1bfcf142928cf1c097b0a2689485c1b14f4f53 +eb7bee331a13026eeb4dcbf9d43d5d4e744a4d26 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 28a360921ab..2450fd55ef8 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.099.1 +v2.100.0-beta.1 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 8895aa5e2bd..f4b5e8af7ff 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -57,6 +57,28 @@ enum ClassKind : ubyte c, } +/** + * Give a nice string for a class kind for error messages + * Params: + * c = class kind + * Returns: + * 0-terminated string for `c` + */ +const(char)* toChars(ClassKind c) +{ + final switch (c) + { + case ClassKind.d: + return "D"; + case ClassKind.cpp: + return "C++"; + case ClassKind.objc: + return "Objective-C"; + case ClassKind.c: + return "C"; + } +} + /** * If an aggregate has a pargma(mangle, ...) this holds the information * to mangle. diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 1a2cf8b0641..bf196934aed 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -28,6 +28,7 @@ enum Baseok : ubyte enum MODFlags : int { + none = 0, // default (mutable) const_ = 1, // type is const immutable_ = 4, // type is immutable shared_ = 2, // type is shared diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index afd7ac052ad..22c9dde5f7e 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -139,16 +139,21 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) // Allow if last case/default was empty CaseStatement sc = slast.isCaseStatement(); DefaultStatement sd = slast.isDefaultStatement(); - if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement())) - { - } - else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement())) + auto sl = (sc ? sc.statement : (sd ? sd.statement : null)); + + if (sl && (!sl.hasCode() || sl.isErrorStatement())) { } else if (func.getModule().filetype != FileType.c) { const(char)* gototype = s.isCaseStatement() ? "case" : "default"; - s.error("switch case fallthrough - use 'goto %s;' if intended", gototype); + // @@@DEPRECATED_2.110@@@ https://issues.dlang.org/show_bug.cgi?id=22999 + // Deprecated in 2.100 + // Make an error in 2.110 + if (sl && sl.isCaseStatement()) + s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype); + else + s.error("switch case fallthrough - use 'goto %s;' if intended", gototype); } } } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 2ed0dc7bdd1..9c8c1c316bf 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -912,8 +912,8 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) ex = new DotVarExp(loc, ex, v); // This is a hack so we can call destructors on const/immutable objects. - // Do it as a type 'paint'. - ex = new CastExp(loc, ex, v.type.mutableOf()); + // Do it as a type 'paint', `cast()` + ex = new CastExp(loc, ex, MODFlags.none); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; @@ -1588,7 +1588,7 @@ private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) auto tf = ctorDecl.type.toTypeFunction(); const dim = tf.parameterList.length; - if (dim == 1) + if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)) { auto param = tf.parameterList[0]; if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index bb12aa7c995..53bf26ec927 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -259,6 +259,7 @@ final class CParser(AST) : Parser!AST case TOK.plusPlus: case TOK.minusMinus: case TOK.sizeof_: + case TOK._Generic: Lexp: auto exp = cparseExpression(); if (token.value == TOK.identifier && exp.op == EXP.identifier) @@ -2399,15 +2400,13 @@ final class CParser(AST) : Parser!AST if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore importBuiltins = true; // probably one of those compiler extensions t = null; - if (scw & SCW.xtypedef) - { - /* Punch through to what the typedef is, to support things like: - * typedef T* T; - */ - auto pt = lookupTypedef(previd); - if (pt && *pt) // if previd is a known typedef - t = *pt; - } + + /* Punch through to what the typedef is, to support things like: + * typedef T* T; + */ + auto pt = lookupTypedef(previd); + if (pt && *pt) // if previd is a known typedef + t = *pt; if (!t) t = new AST.TypeIdentifier(loc, previd); @@ -2745,6 +2744,11 @@ final class CParser(AST) : Parser!AST Specifier specifier; specifier.packalign.setDefault(); auto tspec = cparseSpecifierQualifierList(LVL.global, specifier); + if (tspec && specifier.mod & MOD.xconst) + { + tspec = toConst(tspec); + specifier.mod = MOD.xnone; // 'used' it + } Identifier id; return cparseDeclarator(DTR.xabstract, tspec, id, specifier); } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 45eb582745a..a533d30ca80 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -379,7 +379,7 @@ extern (C++) abstract class Declaration : Dsymbol if (e1 && e1.op == EXP.this_ && isField()) { - VarDeclaration vthis = (cast(ThisExp)e1).var; + VarDeclaration vthis = e1.isThisExp().var; for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx.func == vthis.parent && (scx.flags & SCOPE.contract)) @@ -656,9 +656,8 @@ extern (C++) final class TupleDeclaration : Declaration if (o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; - if (e.op == EXP.dSymbol) + if (DsymbolExp ve = e.isDsymbolExp()) { - DsymbolExp ve = cast(DsymbolExp)e; Declaration d = ve.s.isDeclaration(); if (d && d.needThis()) { @@ -1143,7 +1142,7 @@ extern (C++) class VarDeclaration : Declaration assert(o.dyncast() == DYNCAST.expression); Expression e = cast(Expression)o; assert(e.op == EXP.dSymbol); - DsymbolExp se = cast(DsymbolExp)e; + DsymbolExp se = e.isDsymbolExp(); se.s.setFieldOffset(ad, fieldState, isunion); } return; @@ -1441,16 +1440,17 @@ extern (C++) class VarDeclaration : Declaration const sdsz = sd.type.size(); assert(sdsz != SIZE_INVALID && sdsz != 0); const n = sz / sdsz; - e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t)); + SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), + new IntegerExp(loc, n, Type.tsize_t)); // Prevent redundant bounds check - (cast(SliceExp)e).upperIsInBounds = true; - (cast(SliceExp)e).lowerIsLessThanUpper = true; + se.upperIsInBounds = true; + se.lowerIsLessThanUpper = true; // This is a hack so we can call destructors on const/immutable objects. - e.type = sd.type.arrayOf(); + se.type = sd.type.arrayOf(); - e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e); + e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se); } return e; } diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index e9c4c954efd..2d9f6510ba5 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -1133,8 +1133,10 @@ extern (C++) final class Module : Package // If it isn't there, some compiler rewrites, like // classinst == classinst -> .object.opEquals(classinst, classinst) // would fail inside object.d. - if (members.dim == 0 || (*members)[0].ident != Id.object || - (*members)[0].isImport() is null) + if (filetype != FileType.c && + (members.dim == 0 || + (*members)[0].ident != Id.object || + (*members)[0].isImport() is null)) { auto im = new Import(Loc.initial, null, Id.object, null, 0); members.shift(im); diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 2021e2afd8e..74eaa1d8d7a 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -838,7 +838,8 @@ extern (C++) class Dsymbol : ASTNode } if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) { - if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof) + if (ident == Id.__sizeof || + !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof)) { error("`.%s` property cannot be redefined", ident.toChars()); errors = true; @@ -2523,6 +2524,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (i1) // vd is the definition { + vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it sds.symtab.update(vd); // replace vd2 with the definition return vd; } diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 1ccaab56da6..5415401e0e4 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2874,7 +2874,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc = sc.endCTFE(); resolved = resolved.ctfeInterpret(); StringExp name = resolved.toStringExp(); - TupleExp tup = name ? null : resolved.toTupleExp(); + TupleExp tup = name ? null : resolved.isTupleExp(); if (!tup && !name) { error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars()); @@ -4621,7 +4621,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor buildOpAssign(sd, sc2); buildOpEquals(sd, sc2); - if (global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo + if (!(sc2.flags & SCOPE.Cfile) && + global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo { sd.xeq = buildXopEquals(sd, sc2); sd.xcmp = buildXopCmp(sd, sc2); @@ -5023,6 +5024,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.com = true; if (cldec.baseClass.isCPPclass()) cldec.classKind = ClassKind.cpp; + if (cldec.classKind != cldec.baseClass.classKind) + cldec.error("with %s linkage cannot inherit from class `%s` with %s linkage", + cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars()); + if (cldec.baseClass.stack) cldec.stack = true; cldec.enclosing = cldec.baseClass.enclosing; diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index 114bd44e32c..62e86a1163c 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -434,8 +434,20 @@ else pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap); /** - * Call this after printing out fatal error messages to clean up and exit - * the compiler. + * The type of the fatal error handler + * Returns: true if error handling is done, false to do exit(EXIT_FAILURE) + */ +alias FatalErrorHandler = bool delegate(); + +/** + * The fatal error handler. + * If non-null it will be called for every fatal() call issued by the compiler. + */ +__gshared FatalErrorHandler fatalErrorHandler; + +/** + * Call this after printing out fatal error messages to clean up and exit the + * compiler. You can also set a fatalErrorHandler to override this behaviour. */ extern (C++) void fatal(); diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 78b9a07f3a3..44c3757248b 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -316,24 +316,27 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp */ void unsafeAssign(VarDeclaration v, const char* desc) { - if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) + if (setUnsafeDIP1000(sc.func)) { if (!gag) { if (assertmsg) { - error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`", + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`", desc, v.toChars()); } else { - error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s", + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s", desc, v.toChars(), par ? par.toChars() : "this", fdc ? fdc.toPrettyChars() : "indirectly"); } } - result = true; + if (global.params.useDIP1000 == FeatureState.enabled) + result = true; } } @@ -774,7 +777,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (v.isDataseg()) continue; - if (global.params.useDIP1000 == FeatureState.enabled) + if (global.params.useDIP1000 != FeatureState.disabled) { if (va && va.isScope() && !v.isReference()) { @@ -782,12 +785,18 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) { va.doNotInferReturn = true; } - else if (fd.setUnsafe()) + else if (setUnsafeDIP1000(fd)) { if (!gag) - error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); - result = true; - continue; + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); + + + if (global.params.useDIP1000 == FeatureState.enabled) + { + result = true; + continue; + } } } } @@ -976,12 +985,11 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag) if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown // despite being `scope` { + if (!gag) + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (e.loc, "scope variable `%s` may not be thrown", v.toChars()); if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029 - { - if (!gag) - error(e.loc, "scope variable `%s` may not be thrown", v.toChars()); result = true; - } continue; } else @@ -1042,13 +1050,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) */ !(p.parent == sc.func)) { - 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 + if (setUnsafeDIP1000(sc.func)) // https://issues.dlang.org/show_bug.cgi?id=20868 { + // Only look for errors if in module listed on command line if (!gag) - error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars()); - result = true; + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars()); + if (global.params.useDIP1000 == FeatureState.enabled) + result = true; } + continue; } } @@ -1258,11 +1269,13 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) ) { // https://issues.dlang.org/show_bug.cgi?id=17029 - if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) + if (setUnsafeDIP1000(sc.func)) { if (!gag) - error(e.loc, "scope variable `%s` may not be returned", v.toChars()); - result = true; + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (e.loc, "scope variable `%s` may not be returned", v.toChars()); + if (global.params.useDIP1000 == FeatureState.enabled) + result = true; } continue; } @@ -2341,3 +2354,11 @@ private void addMaybe(VarDeclaration va, VarDeclaration v) va.maybes = new VarDeclarations(); va.maybes.push(v); } + + +private bool setUnsafeDIP1000(FuncDeclaration f) +{ + return global.params.useDIP1000 == FeatureState.enabled + ? f.setUnsafe() + : f.isSafeBypassingInference(); +} diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 24030eb42d0..107e85b0793 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -967,11 +967,6 @@ extern (C++) abstract class Expression : ASTNode return null; } - TupleExp toTupleExp() - { - return null; - } - /*************************************** * Return !=0 if expression is an lvalue. */ @@ -1746,6 +1741,7 @@ extern (C++) abstract class Expression : ASTNode inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; } inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; } inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; } + inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; } inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; } inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; } @@ -2888,11 +2884,6 @@ extern (C++) final class TupleExp : Expression return new TupleExp(loc, exps); } - override TupleExp toTupleExp() - { - return this; - } - override TupleExp syntaxCopy() { return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps)); diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 9522b23a3b1..a0d63e0023d 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -103,7 +103,6 @@ public: virtual real_t toImaginary(); virtual complex_t toComplex(); virtual StringExp *toStringExp(); - virtual TupleExp *toTupleExp(); virtual bool isLvalue(); virtual Expression *toLvalue(Scope *sc, Expression *e); virtual Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -406,7 +405,6 @@ public: Expressions *exps; static TupleExp *create(const Loc &loc, Expressions *exps); - TupleExp *toTupleExp(); TupleExp *syntaxCopy(); bool equals(const RootObject *o) const; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 64cd7ab849c..22a1f45f4e8 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -2028,7 +2028,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc, //printf("type: %s\n", arg.type.toChars()); //printf("param: %s\n", p.toChars()); - if (firstArg && p.storageClass & STC.return_) + const pStc = tf.parameterStorageClass(tthis, p); + + if (firstArg && (pStc & STC.return_)) { /* Argument value can be assigned to firstArg. * Check arg to see if it matters. @@ -2036,7 +2038,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc, if (global.params.useDIP1000 == FeatureState.enabled) err |= checkParamArgumentReturn(sc, firstArg, arg, p, false); } - else if (tf.parameterEscapes(tthis, p)) + // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along + // as lazy parameters to the next function, but that isn't escaping. + else if (!(pStc & (STC.scope_ | STC.lazy_))) { /* Argument value can escape from the called function. * Check arg to see if it matters. @@ -2044,7 +2048,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, if (global.params.useDIP1000 == FeatureState.enabled) err |= checkParamArgumentEscape(sc, fd, p, arg, false, false); } - else if (!(p.storageClass & STC.return_)) + else if (!(pStc & STC.return_)) { /* Argument value cannot escape from the called function. */ @@ -3229,7 +3233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Type t = cle.type.typeSemantic(cle.loc, sc); auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret); - auto e = initializerToExpression(init, t); + auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0); if (!e) { error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars()); @@ -12195,7 +12199,7 @@ Expression semanticX(DotIdExp exp, Scope* sc) if (Expression ex = unaSemantic(exp, sc)) return ex; - if (exp.ident == Id._mangleof) + if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof) { // symbol.mangleof @@ -12304,6 +12308,8 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } + const cfile = (sc.flags & SCOPE.Cfile) != 0; + /* Special case: rewrite this.id and super.id * to be classtype.id and baseclasstype.id * if we have no this pointer. @@ -12555,7 +12561,16 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars()); return ErrorExp.get(); } - else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof) + else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && + !( + exp.ident == Id.__sizeof || + exp.ident == Id.__xalignof || + !cfile && + (exp.ident == Id._mangleof || + exp.ident == Id.offsetof || + exp.ident == Id._init || + exp.ident == Id.stringof) + )) { Type t1bn = t1b.nextOf(); if (flag) @@ -12590,7 +12605,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); return e; } - else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp()) + else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp()) { // Sizeof string literal includes the terminating 0 auto se = exp.e1.isStringExp(); diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 616712b463d..c84a9f69ffa 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -695,7 +695,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ assert(sc); auto tm = vd.type.addMod(ts.mod); auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret); - auto ex = iz.initializerToExpression(); + auto ex = iz.initializerToExpression(null, true); if (ex.op == EXP.error) { errors = true; @@ -1100,6 +1100,8 @@ Initializer inferType(Initializer init, Scope* sc) */ extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false) { + //printf("initializerToExpression() isCfile: %d\n", isCfile); + Expression visitVoid(VoidInitializer) { return null; @@ -1197,7 +1199,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n assert(j < edim); if (Initializer iz = init.value[i]) { - if (Expression ex = iz.initializerToExpression()) + if (Expression ex = iz.initializerToExpression(null, isCfile)) { (*elements)[j] = ex; ++j; @@ -1285,7 +1287,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n Expression visitC(CInitializer i) { - //printf("CInitializer.initializerToExpression()\n"); + //printf("CInitializer.initializerToExpression(null, true)\n"); return null; } diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index b778bc82d77..5945da32259 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -1236,28 +1236,47 @@ class Lexer { uint v = 0; int n = 0; - while (1) + if (Ccompile && ndigits == 2) { - if (isdigit(cast(char)c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - v = v * 16 + c; - c = *++p; - if (++n == ndigits) - break; - if (!ishex(cast(char)c)) + /* C11 6.4.4.4-7 one to infinity hex digits + */ + do { - .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); - break; - } + if (isdigit(cast(char)c)) + c -= '0'; + else if (islower(c)) + c -= 'a' - 10; + else + c -= 'A' - 10; + v = v * 16 + c; + c = *++p; + } while (ishex(cast(char)c)); } - if (ndigits != 2 && !utf_isValidDchar(v)) + else { - .error(loc, "invalid UTF character \\U%08x", v); - v = '?'; // recover with valid UTF character + while (1) + { + if (isdigit(cast(char)c)) + c -= '0'; + else if (islower(c)) + c -= 'a' - 10; + else + c -= 'A' - 10; + v = v * 16 + c; + c = *++p; + if (++n == ndigits) + break; + if (!ishex(cast(char)c)) + { + .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); + break; + } + } + if (ndigits != 2 && !utf_isValidDchar(v)) + { + .error(loc, "invalid UTF character \\U%08x", v); + v = '?'; // recover with valid UTF character + } } c = v; } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 50dd20b70b9..13df0d71f3f 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4360,29 +4360,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - /*************************** - * Examine function signature for parameter p and see if - * the value of p can 'escape' the scope of the function. - * This is useful to minimize the needed annotations for the parameters. - * Params: - * tthis = type of `this` parameter, null if none - * p = parameter to this function - * Returns: - * true if escapes via assignment to global or through a parameter - */ - bool parameterEscapes(Type tthis, Parameter p) - { - /* Scope parameters do not escape. - * Allow 'lazy' to imply 'scope' - - * lazy parameters can be passed along - * as lazy parameters to the next function, but that isn't - * escaping. - */ - if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_)) - return false; - return true; - } - /************************************ * Take the specified storage class for p, * and use the function signature to infer whether @@ -4410,7 +4387,7 @@ extern (C++) final class TypeFunction : TypeNext /* If haven't inferred the return type yet, can't infer storage classes */ - if (!nextOf()) + if (!nextOf() || !isnothrow()) return stc; purityLevel(); @@ -4461,37 +4438,12 @@ extern (C++) final class TypeFunction : TypeNext } } - /* Inferring STC.return_ here has false positives - * for pure functions, producing spurious error messages - * about escaping references. - * Give up on it for now. - */ - version (none) - { - stc |= STC.scope_; - - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) - { - /* The result has references, so p could be escaping - * that way. - */ - stc |= STC.return_; - } - } + // Check escaping through return value + Type tret = nextOf().toBasetype(); + if (isref || tret.hasPointers()) + return stc | STC.scope_ | STC.return_ | STC.returnScope; else - { - // Check escaping through return value - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers() || !isnothrow()) - { - return stc; - } - - stc |= STC.scope_; - } - - return stc; + return stc | STC.scope_; } override Type addStorageClass(StorageClass stc) @@ -4791,14 +4743,40 @@ extern (C++) final class TypeFunction : TypeNext m = MATCH.exact; else { - m = MATCH.nomatch; if (pMessage) { + /* https://issues.dlang.org/show_bug.cgi?id=22202 + * + * If a function was deduced by semantic on the CallExp, + * it means that resolveFuncCall completed succesfully. + * Therefore, there exists a callable copy constructor, + * however, it cannot be called because scope constraints + * such as purity, safety or nogc. + */ OutBuffer buf; - buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", - argStruct.toChars(), targ.toChars(), tprm.toChars()); + auto callExp = e.isCallExp(); + if (auto f = callExp.f) + { + char[] s; + if (!f.isPure && sc.func.setImpure()) + s ~= "pure "; + if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe()) + s ~= "@safe "; + if (!f.isNogc && sc.func.setGC()) + s ~= "nogc "; + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + + } + else + { + buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", + argStruct.toChars(), targ.toChars(), tprm.toChars()); + } + *pMessage = buf.extractChars(); } + m = MATCH.nomatch; goto Nomatch; } } diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index e0b6339bf23..6ba47dfa34e 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -109,6 +109,7 @@ enum class TY : uint8_t */ enum MODFlags { + MODnone = 0, // default (mutable) MODconst = 1, // type is const MODimmutable = 4, // type is immutable MODshared = 2, // type is shared @@ -608,7 +609,6 @@ public: void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; - bool parameterEscapes(Parameter *p); StorageClass parameterStorageClass(Parameter *p); Type *addStorageClass(StorageClass stc); diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 3b8b1b6fa6c..3cc36b49e01 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -593,7 +593,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return; } } - // Convert &((a.b)[n]) to (&a.b)+n + // Convert &((a.b)[index]) to (&a.b)+index*elementsize else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp()) { sinteger_t index = ae.e2.toInteger(); @@ -614,9 +614,18 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) } } + import core.checkedint : mulu; + bool overflow; + const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // index*elementsize + if (overflow) + { + e.error("array offset overflow"); + return error(); + } + auto pe = new AddrExp(e.loc, ve); pe.type = e.type; - ret = new AddExp(e.loc, pe, ae.e2); + ret = new AddExp(e.loc, pe, new IntegerExp(e.loc, offset, Type.tsize_t)); ret.type = e.type; return; } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 7b1b63cba82..4b9c0f2119f 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -987,23 +987,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); if (token.value == TOK.assign) { - nextToken(); - if (token.value == TOK.identifier) - s = new AST.DebugSymbol(token.loc, token.ident); - else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) - s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue); - else - { - error("identifier or integer expected, not `%s`", token.toChars()); - s = null; - } - nextToken(); - if (token.value != TOK.semicolon) - error("semicolon expected"); - nextToken(); + s = parseDebugSpecification(); break; } - condition = parseDebugCondition(); goto Lcondition; @@ -1012,20 +998,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); if (token.value == TOK.assign) { - nextToken(); - if (token.value == TOK.identifier) - s = new AST.VersionSymbol(token.loc, token.ident); - else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) - s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue); - else - { - error("identifier or integer expected, not `%s`", token.toChars()); - s = null; - } - nextToken(); - if (token.value != TOK.semicolon) - error("semicolon expected"); - nextToken(); + s = parseVersionSpecification(); break; } condition = parseVersionCondition(); @@ -2197,6 +2170,26 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return qualified; } + private AST.DebugSymbol parseDebugSpecification() + { + AST.DebugSymbol s; + nextToken(); + if (token.value == TOK.identifier) + s = new AST.DebugSymbol(token.loc, token.ident); + else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue); + else + { + error("identifier or integer expected, not `%s`", token.toChars()); + s = null; + } + nextToken(); + if (token.value != TOK.semicolon) + error("semicolon expected"); + nextToken(); + return s; + } + /************************************** * Parse a debug conditional */ @@ -2223,6 +2216,29 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return new AST.DebugCondition(loc, mod, level, id); } + /************************************** + * Parse a version specification + */ + private AST.VersionSymbol parseVersionSpecification() + { + AST.VersionSymbol s; + nextToken(); + if (token.value == TOK.identifier) + s = new AST.VersionSymbol(token.loc, token.ident); + else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue); + else + { + error("identifier or integer expected, not `%s`", token.toChars()); + s = null; + } + nextToken(); + if (token.value != TOK.semicolon) + error("semicolon expected"); + nextToken(); + return s; + } + /************************************** * Parse a version conditional */ @@ -6053,10 +6069,14 @@ LagainStc: nextToken(); if (token.value == TOK.assign) { - error("debug conditions can only be declared at module scope"); - nextToken(); - nextToken(); - goto Lerror; + if (auto ds = parseDebugSpecification()) + { + if (ds.ident) + ds.error("declaration must be at module level"); + else + ds.error("level declaration must be at module level"); + } + break; } cond = parseDebugCondition(); goto Lcondition; @@ -6065,10 +6085,14 @@ LagainStc: nextToken(); if (token.value == TOK.assign) { - error("version conditions can only be declared at module scope"); - nextToken(); - nextToken(); - goto Lerror; + if (auto vs = parseVersionSpecification()) + { + if (vs.ident) + vs.error("declaration must be at module level"); + else + vs.error("level declaration must be at module level"); + } + break; } cond = parseVersionCondition(); goto Lcondition; diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index ae03b8a4c52..71713249009 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -315,6 +315,14 @@ extern (C++) abstract class Statement : ASTNode override void visit(ImportStatement s) { } + + override void visit(CaseStatement s) + { + } + + override void visit(DefaultStatement s) + { + } } scope HasCode hc = new HasCode(); diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 615c49fd623..0acad6ae14a 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -17,7 +17,9 @@ import core.stdc.stdio; extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST { alias visit = PermissiveVisitor!AST.visit; - mixin ParseVisitMethods!AST; + + mixin ParseVisitMethods!AST __methods; + alias visit = __methods.visit; } /* This mixin implements the AST traversal logic for parse time AST nodes. The same code diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index b26741242f9..f63b17752ed 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1843,7 +1843,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) mtype.sym = e.isScopeExp().sds; break; case EXP.tuple: - TupleExp te = e.toTupleExp(); + TupleExp te = e.isTupleExp(); Objects* elems = new Objects(te.exps.dim); foreach (i; 0 .. elems.dim) { @@ -2306,7 +2306,8 @@ extern (C++) Type merge(Type type) case Tident: case Tinstance: case Tmixin: - return type; + case Ttag: + return type; // don't merge placeholder types case Tsarray: // prevents generating the mangle if the array dim is not yet known @@ -3904,7 +3905,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) assert(e.op != EXP.dot); // https://issues.dlang.org/show_bug.cgi?id=14010 - if (ident == Id._mangleof) + if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof) { return mt.getProperty(sc, e.loc, ident, flag & 1); } @@ -4656,7 +4657,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi { static if (LOGDEFAULTINIT) { - printf("TypeBasic::defaultInit() '%s'\n", mt.toChars()); + printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile); } dinteger_t value = 0; @@ -4714,7 +4715,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi { static if (LOGDEFAULTINIT) { - printf("TypeSArray::defaultInit() '%s'\n", mt.toChars()); + printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile); } if (mt.next.ty == Tvoid) return mt.tuns8.defaultInit(loc, isCfile); diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index cdfe3cb61aa..7f3fb64842d 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -84,7 +84,7 @@ extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data) ensurePathToNameExists(Loc.initial, filename); if (!File.update(filename, data)) { - error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr); + error(loc, "Error writing file '%.*s'", cast(int) filename.length, filename.ptr); fatal(); } } diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index 51e8e5c7e00..b4b81523c14 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -396,6 +396,10 @@ frevert=all D RejectNegative Turn off all revertable D language features. +frevert=dip1000 +D RejectNegative +Revert DIP1000: Scoped pointers. + frevert=dip25 D RejectNegative Revert DIP25: Sealed references. diff --git a/gcc/testsuite/gdc.test/compilable/betterCarray.d b/gcc/testsuite/gdc.test/compilable/betterCarray.d index 3e9a881c3d6..72dcc6b5ee3 100644 --- a/gcc/testsuite/gdc.test/compilable/betterCarray.d +++ b/gcc/testsuite/gdc.test/compilable/betterCarray.d @@ -26,3 +26,10 @@ void issue19234() A[10] b; b[] = a[]; } + +/**********************************************/ +// https://issues.dlang.org/show_bug.cgi?id=22922 +void issue22922() +{ + int[] x = []; +} diff --git a/gcc/testsuite/gdc.test/compilable/test18216.d b/gcc/testsuite/gdc.test/compilable/test18216.d new file mode 100644 index 00000000000..43f5629a3c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test18216.d @@ -0,0 +1,40 @@ +// https://issues.dlang.org/show_bug.cgi?id=18216 + +struct Node +{ + mixin Type!(); + Pointer left; +} + +mixin template Type() +{ + alias Base = typeof(this); + + static struct Proxy + { + struct Node + { + Base m_payload; + } + static immutable default_value = Base.init; // just remove this will work + } + + alias pNode = shared(Proxy.Node)*; + + static struct Pointer + { + Base* _ptr; + auto ptr() + { + return cast(pNode) _ptr; + } + + void opAssign(ref Pointer other) {} // just remove this will work + + alias getThis this; // just remove this will work + ref auto getThis() return + { + return ptr.m_payload; + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test22635.d b/gcc/testsuite/gdc.test/compilable/test22635.d new file mode 100644 index 00000000000..c2abc837956 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22635.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=22635 +// opCast prevent calling destructor for const this + +struct Foo +{ + bool opCast(T : bool)() const { assert(0); } + ~this() {} +} + +struct Bar +{ + const Foo foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d index ebefa4dc6af..279d62a5496 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d @@ -1,8 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11198.d(11): Error: version conditions can only be declared at module scope -fail_compilation/diag11198.d(12): Error: debug conditions can only be declared at module scope +fail_compilation/diag11198.d(15): Error: version `blah` declaration must be at module level +fail_compilation/diag11198.d(16): Error: debug `blah` declaration must be at module level +fail_compilation/diag11198.d(17): Error: version `1` level declaration must be at module level +fail_compilation/diag11198.d(18): Error: debug `2` level declaration must be at module level +fail_compilation/diag11198.d(19): Error: identifier or integer expected, not `""` +fail_compilation/diag11198.d(20): Error: identifier or integer expected, not `""` --- */ @@ -10,4 +14,8 @@ void main() { version = blah; debug = blah; + version = 1; + debug = 2; + version = ""; + debug = ""; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d new file mode 100644 index 00000000000..167d3624879 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=22202 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy _param_0)` is not callable using argument types `(SystemCopy)` +fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +--- +*/ + +struct SystemCopy +{ + this(ref inout SystemCopy other) inout {} +} + +void fun(SystemCopy) @safe pure @nogc {} + +void main() @safe pure @nogc +{ + SystemCopy s; + fun(s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23036.d b/gcc/testsuite/gdc.test/fail_compilation/fail23036.d new file mode 100644 index 00000000000..8920586c67a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23036.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=23036 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23036.d(12): Error: `struct S` may not define both a rvalue constructor and a copy constructor +fail_compilation/fail23036.d(15): rvalue constructor defined here +fail_compilation/fail23036.d(14): copy constructor defined here +--- +*/ + +struct S +{ + this(ref S) {} + this(S, int a = 2) {} +} + +void main() +{ + S a; + S b = a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d index 41a8c2d85e3..07c3766d490 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d @@ -2,6 +2,13 @@ REQUIRED_ARGS: TEST_OUTPUT: --- +fail_compilation/fail_scope.d(29): Deprecation: scope variable `da` may not be returned +fail_compilation/fail_scope.d(31): Deprecation: scope variable `o` may not be returned +fail_compilation/fail_scope.d(32): Deprecation: scope variable `dg` may not be returned +fail_compilation/fail_scope.d(34): Deprecation: scope variable `da` may not be returned +fail_compilation/fail_scope.d(36): Deprecation: scope variable `o` may not be returned +fail_compilation/fail_scope.d(37): Deprecation: scope variable `dg` may not be returned +fail_compilation/fail_scope.d(39): Deprecation: scope variable `p` may not be returned fail_compilation/fail_scope.d(44): Error: returning `cast(char[])string` escapes a reference to local variable `string` fail_compilation/fail_scope.d(62): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(73): Error: `fail_scope.foo8` called with argument types `(int)` matches both: @@ -15,26 +22,19 @@ fail_compilation/fail_scope.d(107): Deprecation: escaping reference to outer loc fail_compilation/fail_scope.d(126): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(136): Error: returning `foo16226(i)` escapes a reference to local variable `i` --- -//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned -//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned -//fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned -//fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned -//fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned -//fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned -//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned */ alias int delegate() dg_t; -int[] checkEscapeScope1(scope int[] da) { return da; } -int[3] checkEscapeScope2(scope int[3] sa) { return sa; } -Object checkEscapeScope3(scope Object o) { return o; } -dg_t checkEscapeScope4(scope dg_t dg) { return dg; } +int[] checkEscapeScope1(scope int[] da) @safe { return da; } +int[3] checkEscapeScope2(scope int[3] sa) @safe { return sa; } +Object checkEscapeScope3(scope Object o) @safe { return o; } +dg_t checkEscapeScope4(scope dg_t dg) @safe { return dg; } -int[] checkEscapeScope1() { scope int[] da = []; return da; } -int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3]; return sa; } -Object checkEscapeScope3() { scope Object o = new Object; return o; } // same with fail7294.d -dg_t checkEscapeScope4() { scope dg_t dg = () => 1; return dg; } +int[] checkEscapeScope1() @safe { scope int[] da = []; return da; } +int[3] checkEscapeScope2() @safe { scope int[3] sa = [1,2,3]; return sa; } +Object checkEscapeScope3() @safe { scope Object o = new Object; return o; } // same with fail7294.d +dg_t checkEscapeScope4() @safe { scope dg_t dg = () => 1; return dg; } int* test(scope int* p) @safe { return p; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d index 7e68bfc4702..6d5807b641a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d @@ -201,8 +201,8 @@ void hmac(scope ubyte[] secret) /* TEST_OUTPUT: --- -fail_compilation/retscope6.d(12011): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_m_20150 -fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_c_20150 +fail_compilation/retscope6.d(12011): Error: returning `escape_m_20150(& x)` escapes a reference to local variable `x` +fail_compilation/retscope6.d(12022): Error: returning `escape_c_20150(& x)` escapes a reference to local variable `x` --- */ @@ -210,23 +210,23 @@ fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assi // https://issues.dlang.org/show_bug.cgi?id=20150 -int* escape_m_20150(int* r) @safe pure +int* escape_m_20150(int* r) @safe pure nothrow { return r; } -int* f_m_20150() @safe +int* f_m_20150() @safe nothrow { int x = 42; return escape_m_20150(&x); } -const(int)* escape_c_20150(const int* r) @safe pure +const(int)* escape_c_20150(const int* r) @safe pure nothrow { return r; } -const(int)* f_c_20150() @safe +const(int)* f_c_20150() @safe nothrow { int x = 42; return escape_c_20150(&x); @@ -251,3 +251,39 @@ void escape_throw_20150() @safe immutable(char)[4] str; f_throw(str[]); } + +/* TEST_OUTPUT: +--- +fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` calling retscope6.noInfer23021 +fail_compilation/retscope6.d(14022): Error: scope variable `scopePtr` may not be returned +--- +*/ + +#line 14000 +// https://issues.dlang.org/show_bug.cgi?id=23021 + +ref int infer23021(ref int* x) @safe pure nothrow +{ + return *x; +} + +ref int noInfer23021(ref int* x, const(int)** escapeHole = null) @safe pure nothrow +{ + *escapeHole = x; + return *x; +} + +ref int escape23021() @safe +{ + scope int* scopePtr; + int* nonScopePtr = null; + + // don't infer scope + cast(void) noInfer23021(scopePtr); // error + + // ensure we infer return scope + return infer23021(scopePtr); // error + + // ensure we do not infer return ref + return infer23021(nonScopePtr); // no error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22999.d b/gcc/testsuite/gdc.test/fail_compilation/test22999.d new file mode 100644 index 00000000000..99dfe70378b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test22999.d @@ -0,0 +1,27 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/test22999.d(18): Deprecation: switch case fallthrough - use 'goto default;' if intended +fail_compilation/test22999.d(25): Deprecation: switch case fallthrough - use 'goto case;' if intended +--- +*/ + +// no switch fallthrough error with multi-valued case +// https://issues.dlang.org/show_bug.cgi?id=22999 +void main() +{ + int i; + switch (0) + { + case 0, 1: i = 20; + default: assert(0); + } + + switch (0) + { + default: + case 0, 1: i = 20; + case 2, 3: i = 30; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23017.d b/gcc/testsuite/gdc.test/fail_compilation/test23017.d new file mode 100644 index 00000000000..743789a6b52 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23017.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test23017.d(16): Error: class `test23017.CppChildA` with C++ linkage cannot inherit from class `DClass` with D linkage +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23017 +// C++ class may not derive from D class +extern(D) class DClass {} +extern(C++) class CppClass +{ + void foo(); +} + +extern(C++) class CppChildA : DClass {} // error +extern(C++) class CppChildB : CppClass {} + +extern(D) class DChildA : DClass {} +extern(D) class DChildB : CppClass {} // automatically made extern(C++) diff --git a/gcc/testsuite/gdc.test/runnable/testscope.d b/gcc/testsuite/gdc.test/runnable/testscope.d index 32d66b58c76..0ca04df188d 100644 --- a/gcc/testsuite/gdc.test/runnable/testscope.d +++ b/gcc/testsuite/gdc.test/runnable/testscope.d @@ -242,22 +242,6 @@ void test7435() { /********************************************/ -char[] dup12()(char[] a) // although inferred pure, don't infer a is 'return' -{ - char[] res; - foreach (ref e; a) - {} - return res; -} - -char[] foo12() -{ - char[10] buf; - return dup12(buf); -} - -/********************************************/ - void test7049() @safe { int count = 0; diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 5e2566c9ceb..e08d9cdc0fd 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -9ba9a6ae2b8f6811cb85107cb56701df04f36ac6 +27834edb5e1613e3abd43e09880c36d9fc961938 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/exception.d b/libphobos/libdruntime/core/exception.d index a6928660773..81aa43b27d0 100644 --- a/libphobos/libdruntime/core/exception.d +++ b/libphobos/libdruntime/core/exception.d @@ -19,29 +19,6 @@ void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted assert(0, "No appropriate switch clause found"); } -version (D_BetterC) -{ - // When compiling with -betterC we use template functions so if they are - // used the bodies are copied into the user's program so there is no need - // for the D runtime during linking. - - // In the future we might want to convert all functions in this module to - // templates even for ordinary builds instead of providing them as an - // extern(C) library. - - void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted - { - assert(0, "Memory allocation failed"); - } - alias onOutOfMemoryErrorNoGC = onOutOfMemoryError; - - void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted - { - assert(0, "Invalid memory operation"); - } -} -else: - /** * Thrown on a range error. */ @@ -218,17 +195,17 @@ private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure */ class AssertError : Error { - @safe pure nothrow this( string file, size_t line ) + @safe pure nothrow @nogc this( string file, size_t line ) { this(cast(Throwable)null, file, line); } - @safe pure nothrow this( Throwable next, string file = __FILE__, size_t line = __LINE__ ) + @safe pure nothrow @nogc this( Throwable next, string file = __FILE__, size_t line = __LINE__ ) { this( "Assertion failure", file, line, next); } - @safe pure nothrow this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) + @safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) { super( msg, file, line, next ); } @@ -692,26 +669,49 @@ extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FIL throw staticError!FinalizeError(info, e, file, line); } -/** - * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be - * thrown. - * - * Throws: - * $(LREF OutOfMemoryError). - */ -extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ +version (D_BetterC) { - // NOTE: Since an out of memory condition exists, no allocation must occur - // while generating this object. - throw staticError!OutOfMemoryError(); -} + // When compiling with -betterC we use template functions so if they are + // used the bodies are copied into the user's program so there is no need + // for the D runtime during linking. -extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc -{ - // suppress stacktrace until they are @nogc - throw staticError!OutOfMemoryError(false); + // In the future we might want to convert all functions in this module to + // templates even for ordinary builds instead of providing them as an + // extern(C) library. + + void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted + { + assert(0, "Memory allocation failed"); + } + alias onOutOfMemoryErrorNoGC = onOutOfMemoryError; + + void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted + { + assert(0, "Invalid memory operation"); + } } +else +{ + /** + * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be + * thrown. + * + * Throws: + * $(LREF OutOfMemoryError). + */ + extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ + { + // NOTE: Since an out of memory condition exists, no allocation must occur + // while generating this object. + throw staticError!OutOfMemoryError(); + } + extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc + { + // suppress stacktrace until they are @nogc + throw staticError!OutOfMemoryError(false); + } +} /** * A callback for invalid memory operations in D. An diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index a15616c6e0f..e58afa2f985 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -2830,8 +2830,8 @@ extern (C) private struct AA { void* impl; } // size_t _aaLen(in AA aa) pure nothrow @nogc; - private void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow; - private void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow; + private void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow; + private void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow; // inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey); inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t valsz, const TypeInfo tiValueArray) pure nothrow; inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo tiKeyArray) pure nothrow; diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d index 0c38622a879..ab93f191634 100644 --- a/libphobos/libdruntime/rt/aaA.d +++ b/libphobos/libdruntime/rt/aaA.d @@ -504,7 +504,7 @@ extern (C) size_t _aaLen(scope const AA aa) pure nothrow @nogc * If key was not in the aa, a mutable pointer to newly inserted value which * is set to all zeros */ -extern (C) void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, +extern (C) void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, scope const void* pkey) { bool found; @@ -525,7 +525,7 @@ extern (C) void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, * If key was not in the aa, a mutable pointer to newly inserted value which * is set to all zeros */ -extern (C) void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti, +extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, scope const void* pkey, out bool found) { // lazily alloc implementation diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 0feb0b01ef5..3218ace50a0 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -c0cc5e917db105301dd1199b4b3c854626526407 +ac296f80cda437483b743f953dc69cb1271c82df 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/Makefile.am b/libphobos/src/Makefile.am index 75f83974e99..da7a2004ff8 100644 --- a/libphobos/src/Makefile.am +++ b/libphobos/src/Makefile.am @@ -130,7 +130,7 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \ std/experimental/typecons.d std/file.d std/format/internal/floats.d \ std/format/internal/read.d std/format/internal/write.d \ std/format/package.d std/format/read.d std/format/spec.d \ - std/format/write.d std/functional.d std/getopt.d \ + std/format/write.d std/functional.d std/getopt.d std/int128.d \ std/internal/attributes.d std/internal/cstring.d \ std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \ diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in index f2395e2caf7..6f58fee01ac 100644 --- a/libphobos/src/Makefile.in +++ b/libphobos/src/Makefile.in @@ -228,6 +228,7 @@ am__dirstamp = $(am__leading_dot)dirstamp @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/spec.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/functional.lo std/getopt.lo \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/int128.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/attributes.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/cstring.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/biguintcore.lo \ @@ -591,7 +592,7 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/typecons.d std/file.d std/format/internal/floats.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/internal/read.d std/format/internal/write.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/package.d std/format/read.d std/format/spec.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.d std/functional.d std/getopt.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.d std/functional.d std/getopt.d std/int128.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/attributes.d std/internal/cstring.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \ @@ -846,6 +847,7 @@ std/format/spec.lo: std/format/$(am__dirstamp) std/format/write.lo: std/format/$(am__dirstamp) std/functional.lo: std/$(am__dirstamp) std/getopt.lo: std/$(am__dirstamp) +std/int128.lo: std/$(am__dirstamp) std/internal/$(am__dirstamp): @$(MKDIR_P) std/internal @: > std/internal/$(am__dirstamp) diff --git a/libphobos/src/std/base64.d b/libphobos/src/std/base64.d index 866f7005060..d971dba1c71 100644 --- a/libphobos/src/std/base64.d +++ b/libphobos/src/std/base64.d @@ -63,7 +63,7 @@ import std.range.primitives : empty, front, isInputRange, isOutputRange, import std.traits : isArray; // Make sure module header code examples work correctly. -@safe unittest +pure @safe unittest { ubyte[] data = [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]; @@ -82,7 +82,7 @@ import std.traits : isArray; alias Base64 = Base64Impl!('+', '/'); /// -@safe unittest +pure @safe unittest { ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; assert(Base64.encode(data) == "g9cwegE/"); @@ -98,7 +98,7 @@ alias Base64 = Base64Impl!('+', '/'); alias Base64URL = Base64Impl!('-', '_'); /// -@safe unittest +pure @safe unittest { ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; assert(Base64URL.encode(data) == "g9cwegE_"); @@ -114,7 +114,7 @@ alias Base64URL = Base64Impl!('-', '_'); alias Base64URLNoPadding = Base64Impl!('-', '_', Base64.NoPadding); /// -@safe unittest +pure @safe unittest { ubyte[] data = [0x83, 0xd7, 0x30, 0x7b, 0xef]; assert(Base64URLNoPadding.encode(data) == "g9cwe-8"); @@ -180,7 +180,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') * Returns: * The length of a Base64 encoding of an array of the given length. */ - @safe + @safe @nogc pure nothrow size_t encodeLength(in size_t sourceLength) { static if (Padding == NoPadding) @@ -218,8 +218,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') * The slice of $(D_PARAM buffer) that contains the encoded string. */ @trusted - pure char[] encode(R1, R2)(in R1 source, return scope R2 buffer) if (isArray!R1 && is(ElementType!R1 : ubyte) && - is(R2 == char[])) + pure char[] encode(R1, R2)(const scope R1 source, return scope R2 buffer) + if (isArray!R1 && is(ElementType!R1 : ubyte) && is(R2 == char[])) in { assert(buffer.length >= encodeLength(source.length), "Insufficient buffer for encoding"); @@ -277,9 +277,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') } /// - @safe unittest + @nogc nothrow @safe unittest { - ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + ubyte[6] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; char[32] buffer; // much bigger than necessary // Just to be sure... @@ -287,7 +287,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') assert(buffer.length >= encodedLength); // encode() returns a slice to the provided buffer. - auto encoded = Base64.encode(data, buffer[]); + auto encoded = Base64.encode(data[], buffer[]); assert(encoded is buffer[0 .. encodedLength]); assert(encoded == "g9cwegE/"); } diff --git a/libphobos/src/std/int128.d b/libphobos/src/std/int128.d new file mode 100644 index 00000000000..fc992f82422 --- /dev/null +++ b/libphobos/src/std/int128.d @@ -0,0 +1,374 @@ +// Written in the D programming language +/** + * Implements a signed 128 bit integer type. + * + Author: Walter Bright + Copyright: Copyright (c) 2022, D Language Foundation + License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) + Source: $(PHOBOSSRC std/int128.d) + */ +module std.int128; + +private import core.int128; + + +/*********************************** + * 128 bit signed integer type. + */ + +public struct Int128 +{ + @safe pure nothrow @nogc: + + Cent data; /// core.int128.Cent + + /**************** + * Construct an `Int128` from a `long` value. + * The upper 64 bits are formed by sign extension. + * Params: + * lo = signed lower 64 bits + */ + this(long lo) + { + data.lo = lo; + data.hi = lo < 0 ? ~0L : 0; + } + + /**************** + * Construct an `Int128` from a `ulong` value. + * The upper 64 bits are set to zero. + * Params: + * lo = unsigned lower 64 bits + */ + this(ulong lo) + { + data.lo = lo; + data.hi = 0; + } + + /**************** + * Construct an `Int128` from a `long` value. + * Params: + * hi = upper 64 bits + * lo = lower 64 bits + */ + this(long hi, long lo) + { + data.hi = hi; + data.lo = lo; + } + + /******************** + * Construct an `Int128` from a `Cent`. + * Params: + * data = Cent data + */ + this(Cent data) + { + this.data = data; + } + + /******************** + * Returns: hash value for Int128 + */ + size_t toHash() const + { + return cast(size_t)((data.lo & 0xFFFF_FFFF) + (data.hi & 0xFFFF_FFFF) + (data.lo >> 32) + (data.hi >> 32)); + } + + /************************ + * Compare for equality + * Params: lo = signed value to compare with + * Returns: true if Int128 equals value + */ + bool opEquals(long lo) const + { + return data.lo == lo && data.hi == (lo >> 63); + } + + /************************ + * Compare for equality + * Params: lo = unsigned value to compare with + * Returns: true if Int128 equals value + */ + bool opEquals(ulong lo) const + { + return data.hi == 0 && data.lo == lo; + } + + /************************ + * Compare for equality + * Params: op2 = value to compare with + * Returns: true if Int128 equals value + */ + bool opEquals(Int128 op2) const + { + return data.hi == op2.data.hi && data.lo == op2.data.lo; + } + + /** Support unary arithmentic operator + + * Params: op = "+" + * Returns: lvalue of result + */ + Int128 opUnary(string op)() const + if (op == "+") + { + return this; + } + + /** Support unary arithmentic operator - ~ + * Params: op = "-", "~" + * Returns: lvalue of result + */ + Int128 opUnary(string op)() const + if (op == "-" || op == "~") + { + static if (op == "-") + return Int128(neg(this.data)); + else static if (op == "~") + return Int128(com(this.data)); + } + + /** Support unary arithmentic operator ++ -- + * Params: op = "++", "--" + * Returns: lvalue of result + */ + Int128 opUnary(string op)() + if (op == "++" || op == "--") + { + static if (op == "++") + this.data = inc(this.data); + else static if (op == "--") + this.data = dec(this.data); + else + static assert(0, op); + return this; + } + + /** Support casting to a bool + * Params: T = bool + * Returns: boolean result + */ + bool opCast(T : bool)() const + { + return tst(this.data); + } + + /** Support binary arithmetic operators + - * / % & | ^ << >> >>> + * Params: + * op = one of the arithmetic binary operators + * op2 = second operand + * Returns: value after the operation is applied + */ + Int128 opBinary(string op)(Int128 op2) const + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^") + { + static if (op == "+") + return Int128(add(this.data, op2.data)); + else static if (op == "-") + return Int128(sub(this.data, op2.data)); + else static if (op == "*") + return Int128(mul(this.data, op2.data)); + else static if (op == "/") + return Int128(div(this.data, op2.data)); + else static if (op == "%") + { + Cent modulus; + divmod(this.data, op2.data, modulus); + return Int128(modulus); + } + else static if (op == "&") + return Int128(and(this.data, op2.data)); + else static if (op == "|") + return Int128(or(this.data, op2.data)); + else static if (op == "^") + return Int128(xor(this.data, op2.data)); + else + static assert(0, "wrong op value"); + } + + /// ditto + Int128 opBinary(string op)(long op2) const + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^") + { + return mixin("this " ~ op ~ " Int128(0, op2)"); + } + + /// ditto + Int128 opBinaryRight(string op)(long op2) const + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^") + { + mixin("return Int128(0, op2) " ~ op ~ " this;"); + } + + /// ditto + Int128 opBinary(string op)(long op2) const + if (op == "<<") + { + return Int128(shl(this.data, cast(uint) op2)); + } + + /// ditto + Int128 opBinary(string op)(long op2) const + if (op == ">>") + { + return Int128(sar(this.data, cast(uint) op2)); + } + + /// ditto + Int128 opBinary(string op)(long op2) const + if (op == ">>>") + { + return Int128(shr(this.data, cast(uint) op2)); + } + + /** arithmetic assignment operators += -= *= /= %= &= |= ^= <<= >>= >>>= + * Params: op = one of +, -, etc. + * op2 = second operand + * Returns: lvalue of updated left operand + */ + ref Int128 opOpAssign(string op)(Int128 op2) + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^" || + op == "<<" || op == ">>" || op == ">>>") + { + mixin("this = this " ~ op ~ " op2;"); + return this; + } + + /// ditto + ref Int128 opOpAssign(string op)(long op2) + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^" || + op == "<<" || op == ">>" || op == ">>>") + { + mixin("this = this " ~ op ~ " op2;"); + return this; + } + + /** support signed arithmentic comparison operators < <= > >= + * Params: op2 = right hand operand + * Returns: -1 for less than, 0 for equals, 1 for greater than + */ + int opCmp(Int128 op2) const + { + return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1; + } + + /** support signed arithmentic comparison operators < <= > >= + * Params: op2 = right hand operand + * Returns: -1 for less than, 0 for equals, 1 for greater than + */ + int opCmp(long op2) const + { + return opCmp(Int128(0, op2)); + } + + enum min = Int128(long.min, 0); /// minimum value + enum max = Int128(long.max, ulong.max); /// maximum value +} + +/********************************************* Tests ************************************/ + +version (unittest) +{ +import core.stdc.stdio; + +@trusted void print(Int128 c) +{ + printf("%lld, %lld\n", c.data.hi, c.data.lo); +} + +@trusted void printx(Int128 c) +{ + printf("%llx, %llx\n", c.data.hi, c.data.lo); +} +} + +/// Int128 tests +@safe pure nothrow @nogc +unittest +{ + Int128 c = Int128(5, 6); + assert(c == c); + assert(c == +c); + assert(c == - -c); + assert(~c == Int128(~5, ~6)); + ++c; + assert(c == Int128(5, 7)); + assert(--c == Int128(5, 6)); + assert(!!c); + assert(!Int128()); + + assert(c + Int128(10, 20) == Int128(15, 26)); + assert(c - Int128(1, 2) == Int128(4, 4)); + assert(c * Int128(100, 2) == Int128(610, 12)); + assert(c / Int128(3, 2) == Int128(0, 1)); + assert(c % Int128(3, 2) == Int128(2, 4)); + assert((c & Int128(3, 2)) == Int128(1, 2)); + assert((c | Int128(3, 2)) == Int128(7, 6)); + assert((c ^ Int128(3, 2)) == Int128(6, 4)); + + assert(c + 15 == Int128(5, 21)); + assert(c - 15 == Int128(4, -9)); + assert(c * 15 == Int128(75, 90)); + assert(c / 15 == Int128(0, 6148914691236517205)); + assert(c % 15 == Int128(0, 11)); + assert((c & 15) == Int128(0, 6)); + assert((c | 15) == Int128(5, 15)); + assert((c ^ 15) == Int128(5, 9)); + + assert(15 + c == Int128(5, 21)); + assert(15 - c == Int128(-5, 9)); + assert(15 * c == Int128(75, 90)); + assert(15 / c == Int128(0, 0)); + assert(15 % c == Int128(0, 15)); + assert((15 & c) == Int128(0, 6)); + assert((15 | c) == Int128(5, 15)); + assert((15 ^ c) == Int128(5, 9)); + + assert(c << 1 == Int128(10, 12)); + assert(-c >> 1 == Int128(-3, 9223372036854775805)); + assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805)); + + assert((c += 1) == Int128(5, 7)); + assert((c -= 1) == Int128(5, 6)); + assert((c += Int128(0, 1)) == Int128(5, 7)); + assert((c -= Int128(0, 1)) == Int128(5, 6)); + assert((c *= 2) == Int128(10, 12)); + assert((c /= 2) == Int128(5, 6)); + assert((c %= 2) == Int128()); + c += Int128(5, 6); + assert((c *= Int128(10, 20)) == Int128(160, 120)); + assert((c /= Int128(10, 20)) == Int128(0, 15)); + c += Int128(72, 0); + assert((c %= Int128(10, 20)) == Int128(1, -125)); + assert((c &= Int128(3, 20)) == Int128(1, 0)); + assert((c |= Int128(8, 2)) == Int128(9, 2)); + assert((c ^= Int128(8, 2)) == Int128(1, 0)); + c |= Int128(10, 5); + assert((c <<= 1) == Int128(11 * 2, 5 * 2)); + assert((c >>>= 1) == Int128(11, 5)); + c = Int128(long.min, long.min); + assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1)); + + assert(-Int128.min == Int128.min); + assert(Int128.max + 1 == Int128.min); + + c = Int128(5, 6); + assert(c < Int128(6, 5)); + assert(c > 10); + + c = Int128(-1UL); + assert(c == -1UL); + c = Int128(-1L); + assert(c == -1L); +} diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d index 20518b86333..de180fcc548 100644 --- a/libphobos/src/std/path.d +++ b/libphobos/src/std/path.d @@ -1519,7 +1519,7 @@ if (isSomeChar!C) import std.range; // ir() wraps an array in a plain (i.e. non-forward) input range, so that // we can test both code paths - InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p); } + InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p.dup); } version (Posix) { assert(buildPath("foo") == "foo"); diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d index 9ca676d312a..18400e3e859 100644 --- a/libphobos/src/std/traits.d +++ b/libphobos/src/std/traits.d @@ -1422,6 +1422,11 @@ if (isCallable!func) enum val = "val" ~ (name == "val" ? "_" : ""); enum ptr = "ptr" ~ (name == "ptr" ? "_" : ""); mixin(" + enum hasDefaultArg = (PT[i .. i+1] " ~ args ~ ") { return true; }; + "); + static if (is(typeof(hasDefaultArg()))) + { + mixin(" // workaround scope escape check, see // https://issues.dlang.org/show_bug.cgi?id=16582 // should use return scope once available @@ -1432,10 +1437,9 @@ if (isCallable!func) auto " ~ val ~ " = " ~ args ~ "[0]; auto " ~ ptr ~ " = &" ~ val ~ "; return *" ~ ptr ~ "; - }; - "); - static if (is(typeof(get()))) + };"); enum Get = get(); + } else alias Get = void; // If default arg doesn't exist, returns void instead. @@ -1483,6 +1487,17 @@ if (isCallable!func) static foreach (V; Voids) static assert(is(V == void)); } +// https://issues.dlang.org/show_bug.cgi?id=20182 +@safe pure nothrow @nogc unittest +{ + struct S + { + this(ref S) {} + } + + static assert(__traits(compiles, ParameterDefaults!(S.__ctor))); +} + /** * Alternate name for $(LREF ParameterDefaults), kept for legacy compatibility. */