From patchwork Mon Mar 21 19:57:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1607882 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=fuBz/aWj; 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 (ip-8-43-85-97.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 4KMlmz4Pt2z9s0r for ; Tue, 22 Mar 2022 06:58:57 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0F900386481F for ; Mon, 21 Mar 2022 19:58:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0F900386481F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1647892734; bh=0v6veIpJBzuD5LGU/GyAk3nwEmOJ/uGogLE6W/lCXJ0=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=fuBz/aWjtT0zAzFZ0qXFOCNqHSqUQqg7+9h4D5tFb41de4zuHYdefpdDryFoJQLfb TxFh7ymr14uKjP76ctvlJmZ93al6Ab05bx4y/NrMUFF+fUC2Erktc6BkcMfYJPAxuf fYYHzQYVLao/oc+h31xxK132mHTBJRXfoK1PjCGM= 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 548DB386481F for ; Mon, 21 Mar 2022 19:57:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 548DB386481F Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2: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 4KMllN2W4Zz9sW4; Mon, 21 Mar 2022 20:57:36 +0100 (CET) To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd 2503f17e5, phobos a74fa63e6. Date: Mon, 21 Mar 2022 20:57:21 +0100 Message-Id: <20220321195721.1638883-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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 2503f17e5, and the standard library with phobos a74fa63e6. D front-end changes: - Import dmd mainline development. - Removed internal d_intN and d_unsN aliases to stdint types, which caused a regression on Solaris where int8_t is a char (PR104911). Phobos changes: - Import phobos mainline development. Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and committed to mainline. Regards, Iain. --- PR d/104911 gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 2503f17e5. * d-convert.cc (convert_expr): Replace d_uns64 with dinteger_t. * d-lang.cc: Remove dmd/root/file.h include. (d_handle_option): Update for new front-end interface. (d_parse_file): Likewise. libphobos/ChangeLog: * src/MERGE: Merge upstream phobos a74fa63e6. --- gcc/d/d-codegen.cc | 2 +- gcc/d/d-convert.cc | 4 +- gcc/d/d-lang.cc | 20 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/aggregate.d | 2 +- gcc/d/dmd/aggregate.h | 2 +- gcc/d/dmd/astenums.d | 9 + gcc/d/dmd/attrib.d | 8 +- gcc/d/dmd/blockexit.d | 2 +- gcc/d/dmd/canthrow.d | 2 +- gcc/d/dmd/constfold.d | 50 ++--- gcc/d/dmd/cparse.d | 175 +++++++++++++++--- gcc/d/dmd/cppmangle.d | 2 + gcc/d/dmd/ctfeexpr.d | 65 +++---- gcc/d/dmd/dcast.d | 8 +- gcc/d/dmd/declaration.d | 8 +- gcc/d/dmd/declaration.h | 3 +- gcc/d/dmd/dinterpret.d | 84 +++------ gcc/d/dmd/dmacro.d | 29 +-- gcc/d/dmd/dmodule.d | 78 +++----- gcc/d/dmd/doc.d | 4 +- gcc/d/dmd/dscope.d | 2 +- gcc/d/dmd/dsymbol.d | 7 +- gcc/d/dmd/dsymbol.h | 2 +- gcc/d/dmd/dsymbolsem.d | 134 +++++++++++--- gcc/d/dmd/dtemplate.d | 4 +- gcc/d/dmd/dtoh.d | 25 ++- gcc/d/dmd/escape.d | 120 ++++++++---- gcc/d/dmd/expression.d | 22 +-- gcc/d/dmd/expressionsem.d | 18 +- gcc/d/dmd/file_manager.d | 133 +++++++------ gcc/d/dmd/file_manager.h | 19 -- gcc/d/dmd/globals.d | 19 +- gcc/d/dmd/globals.h | 19 +- gcc/d/dmd/hdrgen.d | 1 - gcc/d/dmd/id.d | 3 + gcc/d/dmd/importc.d | 22 ++- gcc/d/dmd/lexer.d | 14 +- gcc/d/dmd/module.h | 6 +- gcc/d/dmd/mtype.d | 52 +++--- gcc/d/dmd/mtype.h | 40 ++-- gcc/d/dmd/optimize.d | 8 +- gcc/d/dmd/parse.d | 6 +- gcc/d/dmd/root/file.h | 41 ---- gcc/d/dmd/root/filename.d | 7 +- gcc/d/dmd/root/string.d | 6 +- gcc/d/dmd/semantic2.d | 11 +- gcc/d/dmd/semantic3.d | 16 +- gcc/d/dmd/statementsem.d | 33 ++-- gcc/d/dmd/target.d | 37 ++-- gcc/d/dmd/target.h | 14 +- gcc/d/dmd/template.h | 1 + gcc/d/dmd/tokens.d | 6 +- gcc/d/dmd/traits.d | 48 ++--- gcc/d/dmd/typesem.d | 25 +-- gcc/testsuite/gdc.dg/pr105004.d | 14 ++ .../compilable/dtoh_AliasDeclaration.d | 1 - .../compilable/dtoh_StructDeclaration.d | 47 ++++- .../compilable/dtoh_TemplateDeclaration.d | 18 -- .../gdc.test/compilable/dtoh_forwarding.d | 3 - .../gdc.test/compilable/dtoh_ignored.d | 2 - .../compilable/dtoh_invalid_identifiers.d | 2 - .../gdc.test/compilable/dtoh_names.d | 12 -- .../compilable/dtoh_required_symbols.d | 4 +- gcc/testsuite/gdc.test/compilable/scope.d | 2 +- .../gdc.test/fail_compilation/fail19948.d | 18 ++ .../gdc.test/fail_compilation/fail22881.d | 60 ++++++ .../gdc.test/fail_compilation/pull12941.d | 4 +- .../gdc.test/fail_compilation/retscope2.d | 2 +- .../gdc.test/fail_compilation/test15191.d | 2 +- .../gdc.test/fail_compilation/test17422.d | 2 +- .../gdc.test/fail_compilation/test20881.d | 30 +++ .../gdc.test/fail_compilation/test21912.d | 4 +- .../runnable_cxx/extra-files/test22898.cpp | 7 + .../gdc.test/runnable_cxx/test22898.d | 28 +++ libphobos/src/MERGE | 2 +- libphobos/src/std/conv.d | 35 ++-- libphobos/src/std/sumtype.d | 35 +++- libphobos/src/std/traits.d | 40 ++++ libphobos/src/std/uni/package.d | 4 +- 80 files changed, 1113 insertions(+), 745 deletions(-) delete mode 100644 gcc/d/dmd/file_manager.h delete mode 100644 gcc/d/dmd/root/file.h create mode 100644 gcc/testsuite/gdc.dg/pr105004.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail19948.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22881.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test20881.d create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22898.cpp create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/test22898.d diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 3e54d3bffd0..3206edd17e8 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -1161,7 +1161,7 @@ build_struct_literal (tree type, vec *init) if (COMPLEX_FLOAT_TYPE_P (type)) { gcc_assert (vec_safe_length (init) == 2); - return build_complex (type, (*init)[0].value, (*init)[1].value); + return complex_expr (type, (*init)[0].value, (*init)[1].value); } vec *ve = NULL; diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc index 5a7a64fdac1..3a6a32ab024 100644 --- a/gcc/d/d-convert.cc +++ b/gcc/d/d-convert.cc @@ -518,8 +518,8 @@ convert_expr (tree exp, Type *etype, Type *totype) else if (tbtype->ty == TY::Tarray) { /* Assume tvoid->size() == 1. */ - d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size (); - d_uns64 tsize = tbtype->nextOf ()->toBasetype ()->size (); + dinteger_t fsize = ebtype->nextOf ()->toBasetype ()->size (); + dinteger_t tsize = tbtype->nextOf ()->toBasetype ()->size (); if (fsize != tsize) { diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index f887840f4bf..4a7aa8983b7 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "dmd/mangle.h" #include "dmd/module.h" #include "dmd/mtype.h" -#include "dmd/root/file.h" #include "dmd/target.h" #include "opts.h" @@ -579,7 +578,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.fix16997 = value; global.params.markdown = value; global.params.noSharedAccess = value; - global.params.rvalueRefParam = value; + global.params.rvalueRefParam = FeatureState::enabled; global.params.inclusiveInContracts = value; global.params.shortenedMethods = value; break; @@ -625,7 +624,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fpreview_rvaluerefparam: - global.params.rvalueRefParam = value; + global.params.rvalueRefParam = FeatureState::enabled; break; case OPT_fpreview_shortenedmethods: @@ -1069,9 +1068,8 @@ d_parse_file (void) /* Overwrite the source file for the module, the one created by Module::create would have a forced a `.d' suffix. */ - m->srcBuffer = FileBuffer::create (); - m->srcBuffer->data.length = len; - m->srcBuffer->data.ptr = buffer; + m->src.length = len; + m->src.ptr = buffer; } else { @@ -1108,7 +1106,7 @@ d_parse_file (void) m->importedFrom = m; m->parse (); - if (m->isDocFile) + if (m->filetype == FileType::ddoc) { gendocfile (m); /* Remove M from list of modules. */ @@ -1146,7 +1144,8 @@ d_parse_file (void) for (size_t i = 0; i < modules.length; i++) { Module *m = modules[i]; - if (m->isHdrFile || (d_option.fonly && m != Module::rootModule)) + if (m->filetype == FileType::dhdr + || (d_option.fonly && m != Module::rootModule)) continue; if (global.params.verbose) @@ -1374,7 +1373,7 @@ d_parse_file (void) /* Skip generating code for header files, or when the module wasn't specified by `-fonly=`. */ - if ((m->isHdrFile && m != main_module) + if ((m->filetype == FileType::dhdr && m != main_module) || (d_option.fonly && m != Module::rootModule)) continue; @@ -1421,7 +1420,8 @@ d_parse_file (void) for (size_t i = 0; i < modules.length; i++) { Module *m = modules[i]; - if (m->isHdrFile || (d_option.fonly && m != Module::rootModule)) + if (m->filetype == FileType::dhdr + || (d_option.fonly && m != Module::rootModule)) continue; remove (m->hdrfile.toChars ()); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 220088969c5..3e3e1134452 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -cbba5f41a32cfed7f22a213d537f8e2dee0b92f7 +2503f17e5767bc4fcd0cf3889c90fa0415b0edaa The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 1add36a0299..f790730fce9 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -234,7 +234,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol abstract void finalizeSize(); - override final d_uns64 size(const ref Loc loc) + override final uinteger_t size(const ref Loc loc) { //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); bool ok = determineSize(loc); diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 796144ac810..bdeb38e8b45 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -124,7 +124,7 @@ public: size_t nonHiddenFields(); bool determineSize(const Loc &loc); virtual void finalizeSize() = 0; - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); bool fill(const Loc &loc, Expressions *elements, bool ctorinit); Type *getType(); bool isDeprecated() const; // is aggregate deprecated? diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index ea10c4e9c40..1a2cf8b0641 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -430,3 +430,12 @@ enum PINLINE : ubyte never, /// never inline always, /// always inline } + +/// Source file type +enum FileType : ubyte +{ + d, /// normal D source file + dhdr, /// D header file (.di) + ddoc, /// Ddoc documentation file (.dd) + c, /// C source file +} diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index cf9e9ce5a22..9c2bbd672a7 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -247,12 +247,12 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration */ if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest)) scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest); - if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared)) - scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared); + if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared)) + scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared); if (stc & (STC.const_ | STC.immutable_ | STC.manifest)) scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest); - if (stc & (STC.gshared | STC.shared_ | STC.tls)) - scstc &= ~(STC.gshared | STC.shared_ | STC.tls); + if (stc & (STC.gshared | STC.shared_)) + scstc &= ~(STC.gshared | STC.shared_); if (stc & (STC.safe | STC.trusted | STC.system)) scstc &= ~(STC.safe | STC.trusted | STC.system); scstc |= stc; diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 5132a2dc46a..5c012049342 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -146,7 +146,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement())) { } - else if (!func.getModule().isCFile) + 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); diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 745e552a8e2..a38cbb1610b 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -246,7 +246,7 @@ private CT Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow) if (vd.storage_class & STC.manifest) { } - else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared)) + else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.gshared)) { } else diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 96ca5207511..9941c167b06 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -619,31 +619,31 @@ UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2) switch (e1.type.toBasetype().ty) { case Tint8: - value = cast(d_int8)value >> count; + value = cast(byte)value >> count; break; case Tuns8: case Tchar: - value = cast(d_uns8)value >> count; + value = cast(ubyte)value >> count; break; case Tint16: - value = cast(d_int16)value >> count; + value = cast(short)value >> count; break; case Tuns16: case Twchar: - value = cast(d_uns16)value >> count; + value = cast(ushort)value >> count; break; case Tint32: - value = cast(d_int32)value >> count; + value = cast(int)value >> count; break; case Tuns32: case Tdchar: - value = cast(d_uns32)value >> count; + value = cast(uint)value >> count; break; case Tint64: - value = cast(d_int64)value >> count; + value = cast(long)value >> count; break; case Tuns64: - value = cast(d_uns64)value >> count; + value = cast(ulong)value >> count; break; case Terror: emplaceExp!(ErrorExp)(&ue); @@ -1106,31 +1106,31 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) switch (typeb.ty) { case Tint8: - result = cast(d_int8)cast(sinteger_t)r; + result = cast(byte)cast(sinteger_t)r; break; case Tchar: case Tuns8: - result = cast(d_uns8)cast(dinteger_t)r; + result = cast(ubyte)cast(dinteger_t)r; break; case Tint16: - result = cast(d_int16)cast(sinteger_t)r; + result = cast(short)cast(sinteger_t)r; break; case Twchar: case Tuns16: - result = cast(d_uns16)cast(dinteger_t)r; + result = cast(ushort)cast(dinteger_t)r; break; case Tint32: - result = cast(d_int32)r; + result = cast(int)r; break; case Tdchar: case Tuns32: - result = cast(d_uns32)r; + result = cast(uint)r; break; case Tint64: - result = cast(d_int64)r; + result = cast(long)r; break; case Tuns64: - result = cast(d_uns64)r; + result = cast(ulong)r; break; default: assert(0); @@ -1348,14 +1348,6 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) } } - static bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure - { - assert(lwr <= upr); - return !(newlwr <= newupr && - lwr <= newlwr && - newupr <= upr); - } - if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64) { StringExp es1 = cast(StringExp)e1; @@ -1395,6 +1387,16 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) return ue; } +/* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]` + */ +bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure +{ + assert(lwr <= upr); + return !(newlwr <= newupr && + lwr <= newlwr && + newupr <= upr); +} + /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'. * existingAE[firstIndex..firstIndex+newval.length] = newval. */ diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 2edab14c2a4..fb52b63fe29 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -48,14 +48,16 @@ final class CParser(AST) : Parser!AST 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. + /* C cannot be parsed without determining if an identifier is a type or a variable. + * For expressions like `(T)-3`, is it a cast or a minus expression? + * It also occurs with `typedef int (F)(); F fun;` + * but to build the AST we need to distinguish `fun` being a function as opposed to a variable. + * To fix, build a symbol table for the typedefs. + * Symbol table of typedefs indexed by Identifier cast to void*. + * 1. if an identifier is a typedef, then it will return a non-null Type + * 2. if an identifier is not a typedef, then it will return null */ - AST.Identifiers funcTypeIds; /// Identifiers in this are typedefs of function types + Array!(void*) typedefTab; /// Array of AST.Type[Identifier], typedef's indexed by Identifier extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, const ref TARGET target) @@ -97,6 +99,7 @@ final class CParser(AST) : Parser!AST { //printf("cparseTranslationUnit()\n"); symbols = new AST.Dsymbols(); + typedefTab.push(null); // C11 6.2.1-3 symbol table for "file scope" while (1) { if (token.value == TOK.endOfFile) @@ -115,6 +118,10 @@ final class CParser(AST) : Parser!AST wrap.push(s); } + // end of file scope + typedefTab.pop(); + assert(typedefTab.length == 0); + return wrap; } @@ -150,10 +157,17 @@ final class CParser(AST) : Parser!AST //printf("cparseStatement()\n"); - const funcTypeIdsLengthSave = funcTypeIds.length; + const typedefTabLengthSave = typedefTab.length; auto symbolsSave = symbols; + if (flags & ParseStatementFlags.scope_) + { + typedefTab.push(null); // introduce new block scope + } + if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))) + { symbols = new AST.Dsymbols(); + } switch (token.value) { @@ -593,7 +607,7 @@ final class CParser(AST) : Parser!AST if (pEndloc) *pEndloc = prevloc; symbols = symbolsSave; - funcTypeIds.setDim(funcTypeIdsLengthSave); + typedefTab.setDim(typedefTabLengthSave); return s; } @@ -1002,8 +1016,18 @@ final class CParser(AST) : Parser!AST { if (token.value == TOK.leftParenthesis) { + auto tk = peek(&token); + if (tk.value == TOK.identifier && + !isTypedef(tk.ident) && + peek(tk).value == TOK.rightParenthesis) + { + // ( identifier ) is an expression + return cparseUnaryExp(); + } + // If ( type-name ) auto pt = &token; + if (isCastExpression(pt)) { // Expression may be either a cast or a compound literal, which @@ -1573,7 +1597,7 @@ final class CParser(AST) : Parser!AST return; } - const funcTypeIdsLengthSave = funcTypeIds.length; + const typedefTabLengthSave = typedefTab.length; auto symbolsSave = symbols; Specifier specifier; specifier.packalign = this.packalign; @@ -1683,13 +1707,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); + typedefTab.setDim(typedefTabLengthSave); symbols = symbolsSave; symbols.push(s); return; } AST.Dsymbol s = null; - funcTypeIds.setDim(funcTypeIdsLengthSave); + typedefTab.setDim(typedefTabLengthSave); symbols = symbolsSave; if (!symbols) symbols = new AST.Dsymbols; // lazilly create it @@ -1747,12 +1771,9 @@ 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); + insertTypedefToTypedefTab(id, dt); // remember typedefs } else if (id) { @@ -1791,6 +1812,8 @@ final class CParser(AST) : Parser!AST initializer = new AST.VoidInitializer(token.loc); s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier)); } + if (level != LVL.global) + insertIdToTypedefTab(id); // non-typedef declarations can hide typedefs in outer scopes } if (s !is null) { @@ -1868,6 +1891,10 @@ final class CParser(AST) : Parser!AST */ AST.Dsymbol cparseFunctionDefinition(Identifier id, AST.TypeFunction ft, ref Specifier specifier) { + /* Start function scope + */ + typedefTab.push(null); + if (token.value != TOK.leftCurly) // if not start of a compound-statement { // Do declaration-list @@ -1930,6 +1957,8 @@ final class CParser(AST) : Parser!AST const locFunc = token.loc; auto body = cparseStatement(ParseStatementFlags.curly); // don't start a new scope; continue with parameter scope + typedefTab.pop(); // end of function scope + auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn); if (addFuncName) @@ -2737,6 +2766,16 @@ final class CParser(AST) : Parser!AST return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc); } + /* Create function prototype scope + */ + typedefTab.push(null); + + AST.ParameterList finish() + { + typedefTab.pop(); + return AST.ParameterList(parameters, varargs, varargsStc); + } + /* The check for identifier-list comes later, * when doing the trailing declaration-list (opt) */ @@ -2752,7 +2791,7 @@ final class CParser(AST) : Parser!AST varargs = AST.VarArg.variadic; // C-style variadics nextToken(); check(TOK.rightParenthesis); - return AST.ParameterList(parameters, varargs, varargsStc); + return finish(); } Specifier specifier; @@ -2777,7 +2816,7 @@ final class CParser(AST) : Parser!AST check(TOK.comma); } nextToken(); - return AST.ParameterList(parameters, varargs, varargsStc); + return finish(); } /*********************************** @@ -4121,12 +4160,14 @@ final class CParser(AST) : Parser!AST * ( expression ) * Params: * pt = starting token, updated to one past end of constant-expression if true - * afterParenType = true if already seen ( type-name ) + * afterParenType = true if already seen `( type-name )` * Returns: * true if matches ( type-name ) ... */ private bool isCastExpression(ref Token* pt, bool afterParenType = false) { + enum log = false; + if (log) printf("isCastExpression(tk: `%s`, afterParenType: %d)\n", token.toChars(pt.value), afterParenType); auto t = pt; switch (t.value) { @@ -4144,19 +4185,23 @@ final class CParser(AST) : Parser!AST { // ( type-name ) { initializer-list } if (!isInitializer(tk)) + { return false; + } t = tk; break; } if (tk.value == TOK.leftParenthesis && peek(tk).value == TOK.rightParenthesis) + { return false; // (type-name)() is not a cast (it might be a function call) + } if (!isCastExpression(tk, true)) { if (afterParenType) // could be ( type-name ) ( unary-expression ) goto default; // where unary-expression also matched type-name - return false; + return true; } // ( type-name ) cast-expression t = tk; @@ -4164,11 +4209,14 @@ final class CParser(AST) : Parser!AST default: if (!afterParenType || !isUnaryExpression(t, afterParenType)) + { return false; + } // if we've already seen ( type-name ), then this is a cast break; } pt = t; + if (log) printf("isCastExpression true\n"); return true; } @@ -4576,9 +4624,14 @@ final class CParser(AST) : Parser!AST return s; } + //} + + /******************************************************************************/ + /************************** typedefTab symbol table ***************************/ + //{ + /******************************** * Determines if type t is a function type. - * Make this work without needing semantic analysis. * Params: * t = type to test * Returns: @@ -4591,20 +4644,84 @@ final class CParser(AST) : Parser!AST return true; if (auto tid = t.isTypeIdentifier()) { - /* Scan array of typedef identifiers that are an alias for - * a function type - */ - foreach (ftid; funcTypeIds[]) + auto pt = lookupTypedef(tid.ident); + if (pt && *pt) { - if (tid.ident == ftid) - { - return true; - } + return (*pt).isTypeFunction() !is null; } } return false; } + /******************************** + * Determine if `id` is a symbol for a Typedef. + * Params: + * id = possible typedef + * Returns: + * true if id is a Type + */ + bool isTypedef(Identifier id) + { + auto pt = lookupTypedef(id); + return (pt && *pt); + } + + /******************************* + * Add `id` to typedefTab[], but only if it will mask an existing typedef. + * Params: id = identifier for non-typedef symbol + */ + void insertIdToTypedefTab(Identifier id) + { + //printf("insertIdToTypedefTab(id: %s) level %d\n", id.toChars(), cast(int)typedefTab.length - 1); + if (isTypedef(id)) // if existing typedef + { + /* Add id as null, so we can later distinguish it from a non-null typedef + */ + auto tab = cast(void*[void*])(typedefTab[$ - 1]); + tab[cast(void*)id] = cast(void*)null; + } + } + + /******************************* + * Add `id` to typedefTab[] + * Params: + * id = identifier for typedef symbol + * t = type of the typedef symbol + */ + void insertTypedefToTypedefTab(Identifier id, AST.Type t) + { + //printf("insertTypedefToTypedefTab(id: %s, t: %s) level %d\n", id.toChars(), t ? t.toChars() : "null".ptr, cast(int)typedefTab.length - 1); + if (auto tid = t.isTypeIdentifier()) + { + // Try to resolve the TypeIdentifier to its type + auto pt = lookupTypedef(tid.ident); + if (pt && *pt) + t = *pt; + } + auto tab = cast(void*[void*])(typedefTab[$ - 1]); + tab[cast(void*)id] = cast(void*)t; + typedefTab[$ - 1] = cast(void*)tab; + } + + /********************************* + * Lookup id in typedefTab[]. + * Returns: + * if not found, then null. + * if found, then Type*. Deferencing it will yield null if it is not + * a typedef, and a type if it is a typedef. + */ + AST.Type* lookupTypedef(Identifier id) + { + foreach_reverse (tab; typedefTab[]) + { + if (auto pt = cast(void*)id in cast(void*[void*])tab) + { + return cast(AST.Type*)pt; + } + } + return null; // not found + } + //} /******************************************************************************/ diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 9564b03f753..13ef34c052b 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -1908,6 +1908,8 @@ extern(C++): return writeBasicType(t, 0, 'l'); else if (id == Id.__c_ulong) return writeBasicType(t, 0, 'm'); + else if (id == Id.__c_char) + return writeBasicType(t, 0, 'c'); else if (id == Id.__c_wchar_t) return writeBasicType(t, 0, 'w'); else if (id == Id.__c_longlong) diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 9bc453de189..9078f90dc30 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -343,10 +343,9 @@ UnionExp copyLiteral(Expression e) { auto tsa = v.type.isTypeSArray(); auto len = cast(size_t)tsa.dim.toInteger(); - UnionExp uex = void; - m = createBlockDuplicatedArrayLiteral(&uex, e.loc, v.type, m, len); - if (m == uex.exp()) - m = uex.copy(); + m = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, m, len); + if (m == ue.exp()) + m = ue.copy(); } } el = m; @@ -583,10 +582,9 @@ ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc l // If it is a multidimensional array literal, do it recursively auto tsa = type.nextOf().isTypeSArray(); const len = cast(size_t)tsa.dim.toInteger(); - UnionExp ue = void; - elem = createBlockDuplicatedArrayLiteral(&ue, loc, type.nextOf(), elem, len); - if (elem == ue.exp()) - elem = ue.copy(); + elem = createBlockDuplicatedArrayLiteral(pue, loc, type.nextOf(), elem, len); + if (elem == pue.exp()) + elem = pue.copy(); } // Buzilla 15681 @@ -791,9 +789,8 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2) } // return e1 - e2 as an integer, or error if not possible -UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expression e2) +Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expression e1, Expression e2) { - UnionExp ue = void; dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(e1, &ofs1); Expression agg2 = getAggregateFromPointer(e2, &ofs2); @@ -801,39 +798,38 @@ UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expressi { Type pointee = (cast(TypePointer)agg1.type).next; const sz = pointee.size(); - emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); + emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ && (cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr) { Type pointee = (cast(TypePointer)agg1.type).next; const sz = pointee.size(); - emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); + emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) { - emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type); + emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type); } else { error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars()); - emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); + emplaceExp!(CTFEExp)(pue, EXP.cantExpression); } - return ue; + return pue.exp(); } // Return eptr op e2, where eptr is a pointer, e2 is an integer, // and op is EXP.add or EXP.min -UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2) +Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2) { - UnionExp ue; if (eptr.type.nextOf().ty == Tvoid) { error(loc, "cannot perform arithmetic on `void*` pointers at compile time"); Lcant: - emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); - return ue; + emplaceExp!(CTFEExp)(pue, EXP.cantExpression); + return pue.exp(); } if (eptr.op == EXP.address) eptr = (cast(AddrExp)eptr).e1; @@ -885,10 +881,10 @@ UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr } if (agg1.op == EXP.symbolOffset) { - emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz); - SymOffExp se = cast(SymOffExp)ue.exp(); + emplaceExp!(SymOffExp)(pue, loc, (cast(SymOffExp)agg1).var, indx * sz); + SymOffExp se = cast(SymOffExp)pue.exp(); se.type = type; - return ue; + return pue.exp(); } if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_) { @@ -903,17 +899,17 @@ UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t), ctfeEmplaceExp!IntegerExp(loc, indx + dim, Type.tsize_t)); se.type = type.toBasetype().nextOf(); - emplaceExp!(AddrExp)(&ue, loc, se); - ue.exp().type = type; - return ue; + emplaceExp!(AddrExp)(pue, loc, se); + pue.exp().type = type; + return pue.exp(); } // Create a CTFE pointer &agg1[indx] auto ofs = ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t); Expression ie = ctfeEmplaceExp!IndexExp(loc, agg1, ofs); ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992 - emplaceExp!(AddrExp)(&ue, loc, ie); - ue.exp().type = type; - return ue; + emplaceExp!(AddrExp)(pue, loc, ie); + pue.exp().type = type; + return pue.exp(); } // Return 1 if true, 0 if false @@ -1755,9 +1751,8 @@ Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length /// oldlen, change its length to newlen. If the newlen is longer than oldlen, /// all new elements will be set to the default initializer for the element type. -UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen) +Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen) { - UnionExp ue; Type elemType = arrayType.next; assert(elemType); Expression defaultElem = elemType.defaultInitLiteral(loc); @@ -1794,8 +1789,8 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres assert(0); } } - emplaceExp!(StringExp)(&ue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz); - StringExp se = cast(StringExp)ue.exp(); + emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz); + StringExp se = cast(StringExp)pue.exp(); se.type = arrayType; se.sz = oldse.sz; se.committed = oldse.committed; @@ -1823,11 +1818,11 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres foreach (size_t i; copylen .. newlen) (*elements)[i] = defaultElem; } - emplaceExp!(ArrayLiteralExp)(&ue, loc, arrayType, elements); - ArrayLiteralExp aae = cast(ArrayLiteralExp)ue.exp(); + emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements); + ArrayLiteralExp aae = cast(ArrayLiteralExp)pue.exp(); aae.ownedByCtfe = OwnedBy.ctfe; } - return ue; + return pue.exp(); } /*************************** CTFE Sanity Checks ***************************/ diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 69036ada483..887bb898383 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1894,7 +1894,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) { se = e.copy().isStringExp(); - d_uns64 szx = tb.nextOf().size(); + uinteger_t szx = tb.nextOf().size(); assert(szx <= 255); se.sz = cast(ubyte)szx; se.len = cast(size_t)tb.isTypeSArray().dim.toInteger(); @@ -2059,7 +2059,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } { - d_uns64 szx = tb.nextOf().size(); + uinteger_t szx = tb.nextOf().size(); assert(szx <= 255); se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx); } @@ -2742,7 +2742,7 @@ Expression scaleFactor(BinExp be, Scope* sc) // Replace (ptr + int) with (ptr + (int * stride)) Type t = Type.tptrdiff_t; - d_uns64 stride = t1b.nextOf().size(be.loc); + uinteger_t stride = t1b.nextOf().size(be.loc); if (!t.equals(t2b)) be.e2 = be.e2.castTo(sc, t); eoff = be.e2; @@ -2757,7 +2757,7 @@ Expression scaleFactor(BinExp be, Scope* sc) Type t = Type.tptrdiff_t; Expression e; - d_uns64 stride = t2b.nextOf().size(be.loc); + uinteger_t stride = t2b.nextOf().size(be.loc); if (!t.equals(t1b)) e = be.e1.castTo(sc, t); else diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 585ac2f0b60..82a5f3b72f9 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -250,7 +250,7 @@ extern (C++) abstract class Declaration : Dsymbol return "declaration"; } - override final d_uns64 size(const ref Loc loc) + override final uinteger_t size(const ref Loc loc) { assert(type); const sz = type.size(); @@ -1141,7 +1141,7 @@ extern (C++) class VarDeclaration : Declaration if (!isField()) return; - assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter | STC.tls))); + assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter))); //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); @@ -1217,7 +1217,7 @@ extern (C++) class VarDeclaration : Declaration override final inout(AggregateDeclaration) isThis() inout { - if (!(storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe))) + if (!(storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.gshared | STC.ctfe))) { /* The casting is necessary because `s = s.parent` is otherwise rejected */ @@ -1285,7 +1285,7 @@ extern (C++) class VarDeclaration : Declaration error("forward referenced"); type = Type.terror; } - else if (storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared) || + else if (storage_class & (STC.static_ | STC.extern_ | STC.gshared) || parent.isModule() || parent.isTemplateInstance() || parent.isNspace()) { assert(!isParameter() && !isResult()); diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 93e3a5a0b5d..9986ea3ea36 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -71,7 +71,6 @@ struct IntRange; #define STCnodtor 0x10000000ULL /// do not run destructor #define STCnothrow 0x20000000ULL /// `nothrow` meaning never throws exceptions #define STCpure 0x40000000ULL /// `pure` function - #define STCtls 0x80000000ULL /// thread local #define STCalias 0x100000000ULL /// `alias` parameter #define STCshared 0x200000000ULL /// accessible from multiple threads @@ -123,7 +122,7 @@ public: DString mangleOverride; // overridden symbol with pragma(mangle, "...") const char *kind() const; - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 6c3454daf10..30a8a444155 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -1886,7 +1886,7 @@ public: { // Check for unsupported type painting operations Type elemtype = (cast(TypeArray)val.type).next; - d_uns64 elemsize = elemtype.size(); + const elemsize = elemtype.size(); // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*. if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size()) @@ -2981,8 +2981,7 @@ public: Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; - *pue = pointerDifference(e.loc, e.type, e1, e2); - result = (*pue).exp(); + result = pointerDifference(pue, e.loc, e.type, e1, e2); return; } if (e.e1.type.ty == Tpointer && e.e2.type.isintegral()) @@ -2995,8 +2994,7 @@ public: Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; - *pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2); - result = (*pue).exp(); + result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2); return; } if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add) @@ -3009,8 +3007,7 @@ public: Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; - *pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1); - result = (*pue).exp(); + result = pointerArithmetic(pue, e.loc, e.op, e.type, e2, e1); return; } if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer) @@ -3041,7 +3038,7 @@ public: if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift) { const sinteger_t i2 = e2.toInteger(); - const d_uns64 sz = e1.type.size() * 8; + const uinteger_t sz = e1.type.size() * 8; if (i2 < 0 || i2 >= sz) { e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1); @@ -3602,7 +3599,9 @@ public: e.op == EXP.plusPlus || e.op == EXP.minusMinus)) { - newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy(); + newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy(); + if (newval == pue.exp()) + newval = pue.copy(); } else { @@ -3675,7 +3674,9 @@ public: UnionExp utmp = void; oldval = resolveSlice(oldval, &utmp); - newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy(); + newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen); + if (newval == pue.exp()) + newval = pue.copy(); e1 = assignToLvalue(e, e1, newval); if (exceptionOrCant(e1)) @@ -3994,61 +3995,18 @@ public: // aggregate[] = newval // aggregate[low..upp] = newval // ------------------------------ - version (all) // should be move in interpretAssignCommon as the evaluation of e1 - { - Expression oldval = interpretRegion(se.e1, istate); - - // Set the $ variable - uinteger_t dollar = resolveArrayLength(oldval); - if (se.lengthVar) - { - Expression dollarExp = ctfeEmplaceExp!IntegerExp(e1.loc, dollar, Type.tsize_t); - ctfeGlobals.stack.push(se.lengthVar); - setValue(se.lengthVar, dollarExp); - } - Expression lwr = interpretRegion(se.lwr, istate); - if (exceptionOrCantInterpret(lwr)) - { - if (se.lengthVar) - ctfeGlobals.stack.pop(se.lengthVar); - return lwr; - } - Expression upr = interpretRegion(se.upr, istate); - if (exceptionOrCantInterpret(upr)) - { - if (se.lengthVar) - ctfeGlobals.stack.pop(se.lengthVar); - return upr; - } - if (se.lengthVar) - ctfeGlobals.stack.pop(se.lengthVar); // $ is defined only in [L..U] - - const dim = dollar; - lowerbound = lwr ? lwr.toInteger() : 0; - upperbound = upr ? upr.toInteger() : dim; - - if (lowerbound < 0 || dim < upperbound) - { - e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`", - ulong(dim), ulong(lowerbound), ulong(upperbound)); - return CTFEExp.cantexp; - } - } - aggregate = oldval; - firstIndex = lowerbound; + aggregate = interpretRegion(se.e1, istate); + lowerbound = se.lwr ? se.lwr.toInteger() : 0; + upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate); + // Slice of a slice --> change the bounds if (auto oldse = aggregate.isSliceExp()) { - // Slice of a slice --> change the bounds - if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger()) - { - e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", - ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger()); - return CTFEExp.cantexp; - } aggregate = oldse.e1; firstIndex = lowerbound + oldse.lwr.toInteger(); } + else + firstIndex = lowerbound; } else { @@ -5520,7 +5478,7 @@ public: assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_); dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger(); //Type *pointee = ((TypePointer *)agg.type)->next; - if (iupr > (len + 1) || iupr < ilwr) + if (sliceBoundsCheck(0, len, ilwr, iupr)) { e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len); result = CTFEExp.cantexp; @@ -5624,9 +5582,9 @@ public: // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr'] uinteger_t lo1 = se.lwr.toInteger(); uinteger_t up1 = se.upr.toInteger(); - if (ilwr > iupr || iupr > up1 - lo1) + if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr)) { - e.error("slice `[%llu..%llu]` exceeds array bounds `[%llu..%llu]`", ilwr, iupr, lo1, up1); + e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1); result = CTFEExp.cantexp; return; } @@ -5641,7 +5599,7 @@ public: } if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_) { - if (iupr < ilwr || dollar < iupr) + if (sliceBoundsCheck(0, dollar, ilwr, iupr)) { e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar); result = CTFEExp.cantexp; diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d index 0e891fb3b79..9beac6b5dcd 100644 --- a/gcc/d/dmd/dmacro.d +++ b/gcc/d/dmd/dmacro.d @@ -31,18 +31,12 @@ extern (C++) struct MacroTable extern (D) void define(const(char)[] name, const(char)[] text) { //printf("MacroTable::define('%.*s' = '%.*s')\n", cast(int)name.length, name.ptr, text.length, text.ptr); - Macro* table; - for (table = mactab; table; table = table.next) + if (auto table = name in mactab) { - if (table.name == name) - { - table.text = text; - return; - } + (*table).text = text; + return; } - table = new Macro(name, text); - table.next = mactab; - mactab = table; + mactab[name] = new Macro(name, text); } /***************************************************** @@ -266,20 +260,16 @@ extern (C++) struct MacroTable extern (D) Macro* search(const(char)[] name) { - Macro* table; //printf("Macro::search(%.*s)\n", cast(int)name.length, name.ptr); - for (table = mactab; table; table = table.next) + if (auto table = name in mactab) { - if (table.name == name) - { - //printf("\tfound %d\n", table.textlen); - break; - } + //printf("\tfound %d\n", table.textlen); + return *table; } - return table; + return null; } - Macro* mactab; + private Macro*[const(char)[]] mactab; } /* ************************************************************************ */ @@ -288,7 +278,6 @@ private: struct Macro { - Macro* next; // next in list const(char)[] name; // macro name const(char)[] text; // macro replacement text int inuse; // macro is in use (don't expand) diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 00fa031397c..35d2aba70d9 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -75,7 +75,7 @@ void removeHdrFilesAndFail(ref Param params, ref Modules modules) { foreach (m; modules) { - if (m.isHdrFile) + if (m.filetype == FileType.dhdr) continue; File.remove(m.hdrfile.toChars()); } @@ -351,12 +351,10 @@ extern (C++) final class Module : Package const FileName objfile; // output .obj file const FileName hdrfile; // 'header' file FileName docfile; // output documentation file - FileBuffer* srcBuffer; // set during load(), free'd in parse() + const(ubyte)[] src; /// Raw content of the file uint errors; // if any errors in file uint numlines; // number of lines in source file - bool isHdrFile; // if it is a header (.di) file - bool isCFile; // if it is a C (.c) file - bool isDocFile; // if it is a documentation input file, not D source + FileType filetype; // source file type bool hasAlwaysInlines; // contains references to functions that must be inlined bool isPackageFile; // if it is a package.d Package pkg; // if isPackageFile is true, the Package that contains this package.d @@ -590,24 +588,17 @@ extern (C++) final class Module : Package } /** - * Loads the source buffer from the given read result into `this.srcBuffer`. + * Trigger the relevant semantic error when a file cannot be read * - * Will take ownership of the buffer located inside `readResult`. + * We special case `object.d` as a failure is likely to be a rare + * but difficult to diagnose case for the user. Packages also require + * special handling to avoid exposing the compiler's internals. * * Params: - * loc = the location - * readResult = the result of reading a file containing the source code - * - * Returns: `true` if successful + * loc = The location at which the file read originated (e.g. import) */ - bool loadSourceBuffer(const ref Loc loc, ref File.ReadResult readResult) + private void onFileReadError(const ref Loc loc) { - //printf("Module::loadSourceBuffer('%s') file '%s'\n", toChars(), srcfile.toChars()); - // take ownership of buffer - srcBuffer = new FileBuffer(readResult.extractSlice()); - if (readResult.success) - return true; - if (FileName.equals(srcfile.toString(), "object.d")) { .error(loc, "cannot find source code for runtime library file 'object.d'"); @@ -621,7 +612,6 @@ extern (C++) final class Module : Package // have a valid location come from the command-line. // Error that their file cannot be found and return early. .error(loc, "cannot find input file `%s`", srcfile.toChars()); - return false; } else { @@ -653,7 +643,6 @@ extern (C++) final class Module : Package removeHdrFilesAndFail(global.params, Module.amodules); } - return false; } /** @@ -666,37 +655,23 @@ extern (C++) final class Module : Package * loc = the location * * Returns: `true` if successful - * See_Also: loadSourceBuffer */ bool read(const ref Loc loc) { - if (srcBuffer) + if (this.src) return true; // already read //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); - - - - bool success; - if (auto readResult = FileManager.fileManager.lookup(srcfile)) + if (auto result = FileManager.fileManager.lookup(srcfile)) { - srcBuffer = readResult; - success = true; - } - else - { - auto readResult = File.read(srcfile.toChars()); - if (loadSourceBuffer(loc, readResult)) - { - FileManager.fileManager.add(srcfile, srcBuffer); - success = true; - } - } - if (success && global.params.emitMakeDeps) - { - global.params.makeDeps.push(srcfile.toChars()); + this.src = result.data; + if (global.params.emitMakeDeps) + global.params.makeDeps.push(srcfile.toChars()); + return true; } - return success; + + this.onFileReadError(loc); + return false; } /// syntactic parse @@ -830,7 +805,7 @@ extern (C++) final class Module : Package //printf("Module::parse(srcname = '%s')\n", srcname); isPackageFile = (strcmp(srcfile.name(), package_d) == 0 || strcmp(srcfile.name(), package_di) == 0); - const(char)[] buf = cast(const(char)[]) srcBuffer.data; + const(char)[] buf = cast(const(char)[]) this.src; bool needsReencoding = true; bool hasBOM = true; //assume there's a BOM @@ -942,7 +917,7 @@ extern (C++) final class Module : Package if (buf.length>= 4 && buf[0..4] == "Ddoc") { comment = buf.ptr + 4; - isDocFile = true; + filetype = FileType.ddoc; if (!docfile) setDocfile(); return this; @@ -955,7 +930,7 @@ extern (C++) final class Module : Package if (FileName.equalsExt(arg, dd_ext)) { comment = buf.ptr; // the optional Ddoc, if present, is handled above. - isDocFile = true; + filetype = FileType.ddoc; if (!docfile) setDocfile(); return this; @@ -963,9 +938,7 @@ extern (C++) final class Module : Package /* If it has the extension ".di", it is a "header" file. */ if (FileName.equalsExt(arg, hdr_ext)) - { - isHdrFile = true; - } + filetype = FileType.dhdr; /// Promote `this` to a root module if requested via `-i` void checkCompiledImport() @@ -982,7 +955,7 @@ extern (C++) final class Module : Package */ if (FileName.equalsExt(arg, c_ext) || FileName.equalsExt(arg, i_ext)) { - isCFile = true; + filetype = FileType.c; scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c); p.nextToken(); @@ -1014,8 +987,7 @@ extern (C++) final class Module : Package members = p.parseModuleContent(); numlines = p.scanloc.linnum; } - srcBuffer.destroy(); - srcBuffer = null; + /* The symbol table into which the module is to be inserted. */ @@ -1141,7 +1113,7 @@ extern (C++) final class Module : Package //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); if (_scope) return; // already done - if (isDocFile) + if (filetype == FileType.ddoc) { error("is a Ddoc file, cannot import it"); return; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index d03b5bb6398..d05060df045 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -425,7 +425,7 @@ extern(C++) void gendocfile(Module m) dc.copyright.nooutput = 1; m.macrotable.define("COPYRIGHT", dc.copyright.body_); } - if (m.isDocFile) + if (m.filetype == FileType.ddoc) { const ploc = m.md ? &m.md.loc : &m.loc; const loc = Loc(ploc.filename ? ploc.filename : srcfilename.ptr, @@ -4991,7 +4991,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s default: leadingBlank = false; - if (sc._module.isDocFile || inCode) + if (sc._module.filetype == FileType.ddoc || inCode) break; const start = cast(char*)buf[].ptr + i; if (isIdStart(start)) diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 936d19af623..aa30b5d7414 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -174,7 +174,7 @@ struct Scope m = m.parent; m.addMember(null, sc.scopesym); m.parent = null; // got changed by addMember() - if (_module.isCFile) + if (_module.filetype == FileType.c) sc.flags |= SCOPE.Cfile; // Create the module scope underneath the global scope sc = sc.push(_module); diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index f8ada2b1ea1..9e50bd56d43 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -465,10 +465,7 @@ extern (C++) class Dsymbol : ASTNode final bool isCsymbol() { if (Module m = getModule()) - { - if (m.isCFile) - return true; - } + return m.filetype == FileType.c; return false; } @@ -975,7 +972,7 @@ extern (C++) class Dsymbol : ASTNode * Returns: * SIZE_INVALID when the size cannot be determined */ - d_uns64 size(const ref Loc loc) + uinteger_t size(const ref Loc loc) { error("Dsymbol `%s` has no size", toChars()); return SIZE_INVALID; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index c5af06eb4cd..aad0f2da2b4 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -223,7 +223,7 @@ public: virtual void importAll(Scope *sc); virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone); virtual bool overloadInsert(Dsymbol *s); - virtual d_uns64 size(const Loc &loc); + virtual uinteger_t size(const Loc &loc); virtual bool isforwardRef(); virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member virtual bool isExport() const; // is Dsymbol exported? diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index b68d840c396..b31dc9d0eb9 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -716,7 +716,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (dsym.storage_class & STC.scope_) { - StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.tls | STC.gshared); + StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.gshared); if (stc) { OutBuffer buf; @@ -733,7 +733,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } - if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe)) + if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.gshared | STC.ctfe)) { } else @@ -794,7 +794,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (dsym.type.hasWild()) { - if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg()) + if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg()) { dsym.error("only parameters or stack based variables can be `inout`"); } @@ -841,7 +841,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor FuncDeclaration fd = parent.isFuncDeclaration(); if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor)) { - if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.tls | STC.gshared) || !fd) + if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.gshared) || !fd) { dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`"); } @@ -871,7 +871,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } else if (!dsym._init && - !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field | STC.parameter)) && + !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) && dsym.type.hasVoidInitPointers()) { if (sc.func.setUnsafe()) @@ -891,7 +891,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym.error("manifest constants must have initializers"); bool isBlit = false; - d_uns64 sz; + uinteger_t sz; if (sc.flags & SCOPE.Cfile && !dsym._init) { addDefaultCInitializer(dsym); @@ -977,7 +977,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // If local variable, use AssignExp to handle all the various // possibilities. - if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.tls | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer()) + if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer()) { //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); if (!ei) @@ -1476,7 +1476,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (scd.decl) { sc = sc.push(); - sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.gshared); + sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared); sc.inunion = scd.isunion ? scd : null; sc.flags = 0; for (size_t i = 0; i < scd.decl.dim; i++) @@ -4233,21 +4233,41 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ if (scd.isInstantiated() && scd.semanticRun < PASS.semantic) { - /* Add this prefix to the function: - * static int gate; - * if (++gate != 1) return; - * Note that this is not thread safe; should not have threads - * during static construction. + /* Add this prefix to the constructor: + * ``` + * static int gate; + * if (++gate != 1) return; + * ``` + * or, for shared constructor: + * ``` + * shared int gate; + * if (core.atomic.atomicOp!"+="(gate, 1) != 1) return; + * ``` */ + const bool isShared = !!scd.isSharedStaticCtorDeclaration(); auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null); - v.storage_class = STC.temp | (scd.isSharedStaticCtorDeclaration() ? STC.static_ : STC.tls); + v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0); auto sa = new Statements(); Statement s = new ExpStatement(Loc.initial, v); sa.push(s); - Expression e = new IdentifierExp(Loc.initial, v.ident); - e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!1); + Expression e; + if (isShared) + { + e = doAtomicOp("+=", v.ident, IntegerExp.literal!(1)); + if (e is null) + { + scd.error("shared static constructor within a template require `core.atomic : atomicOp` to be present"); + return; + } + } + else + { + e = new AddAssignExp( + Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!1); + } + e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!1); s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial); @@ -4309,22 +4329,41 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ if (sdd.isInstantiated() && sdd.semanticRun < PASS.semantic) { - /* Add this prefix to the function: - * static int gate; - * if (--gate != 0) return; - * Increment gate during constructor execution. - * Note that this is not thread safe; should not have threads - * during static destruction. + /* Add this prefix to the constructor: + * ``` + * static int gate; + * if (--gate != 0) return; + * ``` + * or, for shared constructor: + * ``` + * shared int gate; + * if (core.atomic.atomicOp!"-="(gate, 1) != 0) return; + * ``` */ + const bool isShared = !!sdd.isSharedStaticDtorDeclaration(); auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null); - v.storage_class = STC.temp | (sdd.isSharedStaticDtorDeclaration() ? STC.static_ : STC.tls); + v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0); auto sa = new Statements(); Statement s = new ExpStatement(Loc.initial, v); sa.push(s); - Expression e = new IdentifierExp(Loc.initial, v.ident); - e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!(-1)); + Expression e; + if (isShared) + { + e = doAtomicOp("-=", v.ident, IntegerExp.literal!(1)); + if (e is null) + { + sdd.error("shared static destructo within a template require `core.atomic : atomicOp` to be present"); + return; + } + } + else + { + e = new AddAssignExp( + Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!(-1)); + } + e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!0); s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial); @@ -6833,3 +6872,48 @@ bool determineFields(AggregateDeclaration ad) return true; } + +/// Do an atomic operation (currently tailored to [shared] static ctors|dtors) needs +private CallExp doAtomicOp (string op, Identifier var, Expression arg) +{ + __gshared Import imp = null; + __gshared Identifier[1] id; + + assert(op == "-=" || op == "+="); + + const loc = Loc.initial; + + // Below code is similar to `loadStdMath` (used for `^^` operator) + if (!imp) + { + id[0] = Id.core; + auto s = new Import(Loc.initial, id[], Id.atomic, null, true); + // Module.load will call fatal() if there's no std.math available. + // Gag the error here, pushing the error handling to the caller. + uint errors = global.startGagging(); + s.load(null); + if (s.mod) + { + s.mod.importAll(null); + s.mod.dsymbolSemantic(null); + } + global.endGagging(errors); + imp = s; + } + // Module couldn't be loaded + if (imp.mod is null) + return null; + + Objects* tiargs = new Objects(1); + (*tiargs)[0] = new StringExp(loc, op); + + Expressions* args = new Expressions(2); + (*args)[0] = new IdentifierExp(loc, var); + (*args)[1] = arg; + + auto sc = new ScopeExp(loc, imp.mod); + auto dti = new DotTemplateInstanceExp( + loc, sc, Id.atomicOp, tiargs); + + return CallExp.create(loc, dti, args); +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index adb91edec78..366ed60bf33 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -1943,7 +1943,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] } - else if (global.params.rvalueRefParam) + else if (global.params.rvalueRefParam == FeatureState.enabled) { // Allow implicit conversion to ref } @@ -8346,7 +8346,7 @@ struct TemplateStats } } -void printTemplateStats() +extern (C++) void printTemplateStats() { static struct TemplateDeclarationStats { diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 285b834f468..46982e391c0 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -860,7 +860,7 @@ public: origType = vd.originalType; scope(exit) origType = null; - if (!vd.alignment.isDefault()) + if (!vd.alignment.isDefault() && !vd.alignment.isUnknown()) { buf.printf("// Ignoring var %s alignment %d", vd.toChars(), vd.alignment.get()); buf.writenl(); @@ -940,7 +940,7 @@ public: return; } - if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) || + if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.gshared) || vd.parent && vd.parent.isModule()) { if (vd.linkage != LINK.c && vd.linkage != LINK.cpp && !(tdparent && (this.linkage == LINK.c || this.linkage == LINK.cpp))) @@ -948,11 +948,6 @@ public: ignored("variable %s because of linkage", vd.toPrettyChars()); return; } - if (vd.storage_class & AST.STC.tls) - { - ignored("variable %s because of thread-local storage", vd.toPrettyChars()); - return; - } if (!isSupportedType(type)) { ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars()); @@ -1934,6 +1929,8 @@ public: buf.writestring("unsigned long long"); else if (ed.ident == DMDType.c_long_double) buf.writestring("long double"); + else if (ed.ident == DMDType.c_char) + buf.writestring("char"); else if (ed.ident == DMDType.c_wchar_t) buf.writestring("wchar_t"); else if (ed.ident == DMDType.c_complex_float) @@ -2681,6 +2678,18 @@ public: { if (vd._init && !vd._init.isVoidInitializer()) return AST.initializerToExpression(vd._init); + else if (auto ts = vd.type.isTypeStruct()) + { + if (!ts.sym.noDefaultCtor && !ts.sym.isUnionDeclaration()) + { + // Generate a call to the default constructor that we've generated. + auto sle = new AST.StructLiteralExp(Loc.initial, ts.sym, new AST.Expressions(0)); + sle.type = vd.type; + return sle; + } + else + return vd.type.defaultInitLiteral(Loc.initial); + } else return vd.type.defaultInitLiteral(Loc.initial); } @@ -2971,6 +2980,7 @@ struct DMDType __gshared Identifier c_longlong; __gshared Identifier c_ulonglong; __gshared Identifier c_long_double; + __gshared Identifier c_char; __gshared Identifier c_wchar_t; __gshared Identifier c_complex_float; __gshared Identifier c_complex_double; @@ -2984,6 +2994,7 @@ struct DMDType c_ulonglong = Identifier.idPool("__c_ulonglong"); c_long_double = Identifier.idPool("__c_long_double"); c_wchar_t = Identifier.idPool("__c_wchar_t"); + c_char = Identifier.idPool("__c_char"); c_complex_float = Identifier.idPool("__c_complex_float"); c_complex_double = Identifier.idPool("__c_complex_double"); c_complex_real = Identifier.idPool("__c_complex_real"); diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index be11f26b04a..e9dcdc0532c 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -658,7 +658,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) p == fd) { if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars()); - inferReturn(fd, v); // infer addition of 'return' to make `return scope` + inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope` } if (!(va && va.isScope()) || vaIsRef) @@ -1215,7 +1215,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func) { - inferReturn(sc.func, v); // infer addition of 'return' + inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return' continue; } @@ -1355,7 +1355,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func && (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope)) { - inferReturn(sc.func, v); // infer addition of 'return' + inferReturn(sc.func, v, /*returnScope:*/ false); // infer addition of 'return' } else { @@ -1404,23 +1404,25 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) * Params: * fd = function that v is a parameter to * v = parameter that needs to be STC.return_ + * returnScope = infer `return scope` instead of `return ref` */ - -private void inferReturn(FuncDeclaration fd, VarDeclaration v) +private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) { // v is a local in the current function - //printf("for function '%s' inferring 'return' for variable '%s'\n", fd.toChars(), v.toChars()); - v.storage_class |= STC.return_ | STC.returninferred; + //printf("for function '%s' inferring 'return' for variable '%s', returnScope: %d\n", fd.toChars(), v.toChars(), returnScope); + auto newStcs = STC.return_ | STC.returninferred | (returnScope ? STC.returnScope : 0); + v.storage_class |= newStcs; if (v == fd.vthis) { /* v is the 'this' reference, so mark the function */ - fd.storage_class |= STC.return_ | STC.returninferred; + fd.storage_class |= newStcs; if (auto tf = fd.type.isTypeFunction()) { //printf("'this' too %p %s\n", tf, sc.func.toChars()); + tf.isreturnscope = returnScope; tf.isreturn = true; tf.isreturninferred = true; } @@ -1434,7 +1436,7 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v) { if (p.ident == v.ident) { - p.storageClass |= STC.return_ | STC.returninferred; + p.storageClass |= newStcs; break; // there can be only one } } @@ -1732,33 +1734,69 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { DotVarExp dve = e.e1.isDotVarExp(); FuncDeclaration fd = dve.var.isFuncDeclaration(); - AggregateDeclaration ad; - if (global.params.useDIP1000 == FeatureState.enabled && tf.isreturn && fd && (ad = fd.isThis()) !is null) + if (global.params.useDIP1000 == FeatureState.enabled) { - if (ad.isClassDeclaration() || tf.isScopeQual) // this is 'return scope' - dve.e1.accept(this); - else if (ad.isStructDeclaration()) // this is 'return ref' - { - if (tf.isref) + if (fd && fd.isThis()) + { + /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this` + */ + + /***************************** + * Concoct storage class for member function's implicit `this` parameter. + * Params: + * fd = member function + * Returns: + * storage class for fd's `this` + */ + StorageClass getThisStorageClass(FuncDeclaration fd) { - /* Treat calling: - * struct S { ref S foo() return; } - * as: - * this; - */ + StorageClass stc; + auto tf = fd.type.toBasetype().isTypeFunction(); + if (tf.isreturn) + stc |= STC.return_; + if (tf.isreturnscope) + stc |= STC.returnScope; + auto ad = fd.isThis(); + if (ad.isClassDeclaration() || tf.isScopeQual) + stc |= STC.scope_; + if (ad.isStructDeclaration()) + stc |= STC.ref_; // `this` for a struct member function is passed by `ref` + return stc; + } + + const psr = buildScopeRef(getThisStorageClass(fd)); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) dve.e1.accept(this); + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + { + if (tf.isref) + { + /* Treat calling: + * struct S { ref S foo() return; } + * as: + * this; + */ + dve.e1.accept(this); + } + else + escapeByRef(dve.e1, er, live); } - else - escapeByRef(dve.e1, er, live); } } - else if (dve.var.storage_class & STC.return_ || tf.isreturn) + else { - if (dve.var.storage_class & STC.scope_) + // Calling member function before dip1000 + StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); + if (tf.isreturn) + stc |= STC.return_; + + const psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) dve.e1.accept(this); - else if (dve.var.storage_class & STC.ref_) + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) escapeByRef(dve.e1, er, live); } + // If it's also a nested function that is 'return scope' if (fd && fd.isNested()) { @@ -1996,19 +2034,29 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) return; } - if (dve.var.storage_class & STC.return_ || tf.isreturn) - { - if (dve.var.storage_class & STC.ref_ || tf.isref) - dve.e1.accept(this); - else if (dve.var.storage_class & STC.scope_ || tf.isScopeQual) - escapeByValue(dve.e1, er, live); - } + StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); + if (tf.isreturn) + stc |= STC.return_; + if (tf.isref) + stc |= STC.ref_; + if (tf.isScopeQual) + stc |= STC.scope_; + if (tf.isreturnscope) + stc |= STC.returnScope; + + const psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + dve.e1.accept(this); + else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + escapeByValue(dve.e1, er, live); + // If it's also a nested function that is 'return ref' - FuncDeclaration fd = dve.var.isFuncDeclaration(); - if (fd && fd.isNested()) + if (FuncDeclaration fd = dve.var.isFuncDeclaration()) { - if (tf.isreturn) + if (fd.isNested() && tf.isreturn) + { er.byexp.push(e); + } } } // If it's a delegate, check it too diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 45fefc03dea..7abfe7f0878 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -1797,7 +1797,7 @@ extern (C++) final class IntegerExp : Expression { super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp)); this.type = Type.tint32; - this.value = cast(d_int32)value; + this.value = cast(int)value; } static IntegerExp create(const ref Loc loc, dinteger_t value, Type type) @@ -1838,8 +1838,8 @@ extern (C++) final class IntegerExp : Expression const val = normalize(ty, value); value = val; return (ty == Tuns64) - ? real_t(cast(d_uns64)val) - : real_t(cast(d_int64)val); + ? real_t(cast(ulong)val) + : real_t(cast(long)val); } override real_t toImaginary() @@ -1895,38 +1895,38 @@ extern (C++) final class IntegerExp : Expression break; case Tint8: - result = cast(d_int8)value; + result = cast(byte)value; break; case Tchar: case Tuns8: - result = cast(d_uns8)value; + result = cast(ubyte)value; break; case Tint16: - result = cast(d_int16)value; + result = cast(short)value; break; case Twchar: case Tuns16: - result = cast(d_uns16)value; + result = cast(ushort)value; break; case Tint32: - result = cast(d_int32)value; + result = cast(int)value; break; case Tdchar: case Tuns32: - result = cast(d_uns32)value; + result = cast(uint)value; break; case Tint64: - result = cast(d_int64)value; + result = cast(long)value; break; case Tuns64: - result = cast(d_uns64)value; + result = cast(ulong)value; break; case Tpointer: diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index f8e5af4ac95..580281643ca 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -1992,7 +1992,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } else if (p.storageClass & STC.ref_) { - if (global.params.rvalueRefParam && + if (global.params.rvalueRefParam == FeatureState.enabled && !arg.isLvalue() && targ.isCopyable()) { /* allow rvalues to be passed to ref parameters by copying @@ -7118,6 +7118,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + exp.e1 = exp.e1.arrayFuncConv(sc); + Type tb = exp.e1.type.toBasetype(); switch (tb.ty) { @@ -7441,6 +7443,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction()) + exp.e1 = exp.e1.arrayFuncConv(sc); + // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (exp.e1.op == EXP.type) exp.e1 = resolveAliasThis(sc, exp.e1); @@ -10336,7 +10341,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Need to divide the result by the stride // Replace (ptr - ptr) with (ptr - ptr) / stride - d_int64 stride; + long stride; // make sure pointer types are compatible if (Expression ex = typeCombine(exp, sc)) @@ -10351,7 +10356,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t); } - else if (stride == cast(d_int64)SIZE_INVALID) + else if (stride == cast(long)SIZE_INVALID) e = ErrorExp.get(); else { @@ -12575,6 +12580,13 @@ 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()) + { + // Sizeof string literal includes the terminating 0 + auto se = exp.e1.isStringExp(); + Expression e = new IntegerExp(exp.loc, (se.len + 1) * se.sz, Type.tsize_t); + return e; + } else { if (exp.e1.isTypeExp() || exp.e1.isTemplateExp()) diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index 7e0f404dd73..9ba38078c3f 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -20,38 +20,12 @@ import dmd.identifier; enum package_d = "package." ~ mars_ext; enum package_di = "package." ~ hdr_ext; -extern(C++) struct FileManager +struct FileManager { private StringTable!(FileBuffer*) files; private __gshared bool initialized = false; nothrow: - extern(D) private FileBuffer* readToFileBuffer(const(char)[] filename) - { - if (!initialized) - FileManager._init(); - - auto readResult = File.read(filename); - if (readResult.success) - { - FileBuffer* fb; - if (auto val = files.lookup(filename)) - fb = val.value; - - if (!fb) - fb = FileBuffer.create(); - - fb.data = readResult.extractSlice(); - - return files.insert(filename, fb) == null ? null : fb; - } - else - { - return null; - } - - } - /******************************************** * Look for the source file if it's different from filename. * Look for .di, .d, directory, and along global.path. @@ -63,7 +37,7 @@ nothrow: * the found file name or * `null` if it is not different from filename. */ - extern(D) static const(char)[] lookForSourceFile(const char[] filename, const char*[] path) + static const(char)[] lookForSourceFile(const char[] filename, const char*[] path) { //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr); /* Search along path[] for .di file, then .d file, then .i file, then .c file. @@ -74,6 +48,9 @@ nothrow: scope(exit) FileName.free(sdi.ptr); const sd = FileName.forceExt(filename, mars_ext); + // Special file name representing `stdin`, always assume its presence + if (sd == "__stdin.d") + return sd; if (FileName.exists(sd) == 1) return sd; scope(exit) FileName.free(sd.ptr); @@ -164,33 +141,35 @@ nothrow: * Returns: the loaded source file if it was found in memory, * otherwise `null` */ - extern(D) FileBuffer* lookup(FileName filename) + const(FileBuffer)* lookup(FileName filename) { if (!initialized) FileManager._init(); - if (auto val = files.lookup(filename.toString)) + const name = filename.toString; + if (auto val = files.lookup(name)) + return val.value; + + if (name == "__stdin.d") { - // There is a chance that the buffer could've been - // stolen by a reader with extractSlice, so we should - // try and do our reading logic if that happens. - if (val !is null && val.value.data !is null) - { - return val.value; - } + auto buffer = new FileBuffer(readFromStdin().extractSlice()); + if (this.files.insert(name, buffer) is null) + assert(0, "stdin: Insert after lookup failure should never return `null`"); + return buffer; } - const name = filename.toString; - auto res = FileName.exists(name); - if (res == 1) - return readToFileBuffer(name); + if (FileName.exists(name) != 1) + return null; - return null; - } + auto readResult = File.read(name); + if (!readResult.success) + return null; - extern(C++) FileBuffer* lookup(const(char)* filename) - { - return lookup(FileName(filename.toDString)); + FileBuffer* fb = new FileBuffer(readResult.extractSlice()); + if (files.insert(name, fb) is null) + assert(0, "Insert after lookup failure should never return `null`"); + + return fb; } /** @@ -201,15 +180,15 @@ nothrow: * Returns: the loaded source file if it was found in memory, * otherwise `null` */ - extern(D) const(char)[][] getLines(FileName file) + const(char)[][] getLines(FileName file) { if (!initialized) FileManager._init(); const(char)[][] lines; - if (FileBuffer* buffer = lookup(file)) + if (const buffer = lookup(file)) { - ubyte[] slice = buffer.data[0 .. buffer.data.length]; + const slice = buffer.data[0 .. buffer.data.length]; size_t start, end; ubyte c; for (auto i = 0; i < slice.length; i++) @@ -260,7 +239,7 @@ nothrow: * * Returns: The FileBuffer added, or null */ - extern(D) FileBuffer* add(FileName filename, FileBuffer* filebuffer) + FileBuffer* add(FileName filename, FileBuffer* filebuffer) { if (!initialized) FileManager._init(); @@ -269,19 +248,10 @@ nothrow: return val == null ? null : val.value; } - extern(C++) FileBuffer* add(const(char)* filename, FileBuffer* filebuffer) - { - if (!initialized) - FileManager._init(); - - auto val = files.insert(filename.toDString, filebuffer); - return val == null ? null : val.value; - } - __gshared fileManager = FileManager(); // Initialize the global FileManager singleton - extern(C++) static __gshared void _init() + private void _init() { if (!initialized) { @@ -295,3 +265,46 @@ nothrow: files._init(); } } + +private FileBuffer readFromStdin() nothrow +{ + import core.stdc.stdio; + import dmd.errors; + import dmd.root.rmem; + + enum bufIncrement = 128 * 1024; + size_t pos = 0; + size_t sz = bufIncrement; + + ubyte* buffer = null; + for (;;) + { + buffer = cast(ubyte*)mem.xrealloc(buffer, sz + 4); // +2 for sentinel and +2 for lexer + + // Fill up buffer + do + { + assert(sz > pos); + size_t rlen = fread(buffer + pos, 1, sz - pos, stdin); + pos += rlen; + if (ferror(stdin)) + { + import core.stdc.errno; + error(Loc.initial, "cannot read from stdin, errno = %d", errno); + fatal(); + } + if (feof(stdin)) + { + // We're done + assert(pos < sz + 2); + buffer[pos .. pos + 4] = '\0'; + return FileBuffer(buffer[0 .. pos]); + } + } while (pos < sz); + + // Buffer full, expand + sz += bufIncrement; + } + + assert(0); +} diff --git a/gcc/d/dmd/file_manager.h b/gcc/d/dmd/file_manager.h deleted file mode 100644 index 6705f24301f..00000000000 --- a/gcc/d/dmd/file_manager.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved - * written by Walter Bright - * https://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * https://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.h - */ - -#pragma once - -#include "root/file.h" - -struct FileManager -{ - static void _init(); - FileBuffer* lookup(const char* filename); - FileBuffer* add(const char* filename, FileBuffer* filebuffer); -}; diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index eccd1ee183d..6697a05a142 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -161,11 +161,11 @@ extern (C++) struct Param FeatureState dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 bool fieldwise; // do struct equality testing field-wise rather than by memcmp() - bool rvalueRefParam; // allow rvalues to be arguments to ref parameters - // https://dconf.org/2019/talks/alexandrescu.html - // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a - // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html - // Implementation: https://github.com/dlang/dmd/pull/9817 + FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters + // https://dconf.org/2019/talks/alexandrescu.html + // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a + // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html + // Implementation: https://github.com/dlang/dmd/pull/9817 CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support @@ -486,15 +486,6 @@ alias dinteger_t = ulong; alias sinteger_t = long; alias uinteger_t = ulong; -alias d_int8 = int8_t; -alias d_uns8 = uint8_t; -alias d_int16 = int16_t; -alias d_uns16 = uint16_t; -alias d_int32 = int32_t; -alias d_uns32 = uint32_t; -alias d_int64 = int64_t; -alias d_uns64 = uint64_t; - version (DMDLIB) { version = LocOffset; diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 49fa5b98e95..9bbe0c9fe03 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -145,7 +145,7 @@ struct Param FeatureState dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 bool fieldwise; // do struct equality testing field-wise rather than by memcmp() - bool rvalueRefParam; // allow rvalues to be arguments to ref parameters + FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters CppStdRevision cplusplus; // version of C++ name mangling to support bool markdown; // enable Markdown replacements in Ddoc bool vmarkdown; // list instances of Markdown replacements in Ddoc @@ -346,15 +346,6 @@ typedef long long sinteger_t; typedef unsigned long long uinteger_t; #endif -typedef int8_t d_int8; -typedef uint8_t d_uns8; -typedef int16_t d_int16; -typedef uint16_t d_uns16; -typedef int32_t d_int32; -typedef uint32_t d_uns32; -typedef int64_t d_int64; -typedef uint64_t d_uns64; - // file location struct Loc { @@ -415,4 +406,12 @@ enum class PINLINE : uint8_t always // always inline }; +enum class FileType : uint8_t +{ + d, /// normal D source file + dhdr, /// D header file (.di) + ddoc, /// Ddoc documentation file (.dd) + c, /// C source file +}; + typedef uinteger_t StorageClass; diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 6b8ecc5c07f..f2552d4d1cf 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -2843,7 +2843,6 @@ string stcToString(ref StorageClass stc) SCstring(STC.pure_, Token.toString(TOK.pure_)), SCstring(STC.ref_, Token.toString(TOK.ref_)), SCstring(STC.return_, Token.toString(TOK.return_)), - SCstring(STC.tls, "__thread"), SCstring(STC.gshared, Token.toString(TOK.gshared)), SCstring(STC.nogc, "@nogc"), SCstring(STC.live, "@live"), diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 31a44db2542..2ec75ab2516 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -123,6 +123,7 @@ immutable Msgtable[] msgtable = { "__c_longlong" }, { "__c_ulonglong" }, { "__c_long_double" }, + { "__c_char" }, { "__c_wchar_t" }, { "__c_complex_float" }, { "__c_complex_double" }, @@ -359,6 +360,8 @@ immutable Msgtable[] msgtable = { "core" }, { "etc" }, { "attribute" }, + { "atomic" }, + { "atomicOp" }, { "math" }, { "sin" }, { "cos" }, diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 72e0e1a93a5..ec44ee0df5c 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -274,6 +274,7 @@ Expression castCallAmbiguity(Expression e, Scope* sc) bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2) { + //printf("cFuncEquivalence()\n %s\n %s\n", tf1.toChars(), tf2.toChars()); if (tf1.equals(tf2)) return true; @@ -284,22 +285,31 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2) if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0) return true; - if (!tf1.parameterList.hasIdentifierList && - !tf2.parameterList.hasIdentifierList) - return false; // both functions are prototyped - - // Otherwise ignore variadicness, as K+R functions are all variadic - if (!tf1.nextOf().equals(tf2.nextOf())) return false; // function return types don't match if (tf1.parameterList.length != tf2.parameterList.length) return false; + if (!tf1.parameterList.hasIdentifierList && !tf2.parameterList.hasIdentifierList) // if both are prototyped + { + if (tf1.parameterList.varargs != tf2.parameterList.varargs) + return false; + } + foreach (i, fparam ; tf1.parameterList) { Type t1 = fparam.type; Type t2 = tf2.parameterList[i].type; + + /* Strip off head const. + * Not sure if this is C11, but other compilers treat + * `void fn(int)` and `fn(const int x)` + * as equivalent. + */ + t1 = t1.mutableOf(); + t2 = t2.mutableOf(); + if (!t1.equals(t2)) return false; } diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index dbdf6a503d1..3ff2eae2651 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -371,6 +371,12 @@ class Lexer 'd'; return; } + else if (p[1] == '8' && p[2] == '\"') // C UTF-8 string literal + { + p += 2; + escapeStringConstant(t); + return; + } goto case_ident; case 'r': @@ -1979,8 +1985,8 @@ class Lexer if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)) { if (Ccompile && base == 10 && - (p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L')) - goto Lreal; // if `1.f` or `1.L` + (p[1] == 'e' || p[1] == 'E' || p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L')) + goto Lreal; // if `1.e6` or `1.f` or `1.L` goto Ldone; // if ".identifier" or ".unicode" } if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80)) @@ -2495,8 +2501,10 @@ class Lexer } } const isLong = (result == TOK.float80Literal || result == TOK.imaginary80Literal); - if (isOutOfRange && !isLong) + if (isOutOfRange && !isLong && (!Ccompile || hex)) { + /* C11 6.4.4.2 doesn't actually care if it is not representable if it is not hex + */ const char* suffix = (result == TOK.float32Literal || result == TOK.imaginary32Literal) ? "f" : ""; error(scanloc, "number `%s%s` is not representable", sbufptr, suffix); } diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index f020bfdb5a3..048b3a0452c 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -71,12 +71,10 @@ public: FileName objfile; // output .obj file FileName hdrfile; // 'header' file FileName docfile; // output documentation file - FileBuffer *srcBuffer; // set during load(), free'd in parse() + DArray src; // Raw content of the file unsigned errors; // if any errors in file unsigned numlines; // number of lines in source file - bool isHdrFile; // if it is a header (.di) file - bool isCFile; // if it is a C (.c) file - bool isDocFile; // if it is a documentation input file, not D source + FileType filetype; // source file type bool hasAlwaysInlines; // contains references to functions that must be inlined bool isPackageFile; // if it is a package.d Package *pkg; // if isPackageFile is true, the Package that contains this package.d diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 18af7721df1..1494044da59 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -55,7 +55,7 @@ import dmd.visitor; enum LOGDOTEXP = 0; // log ::dotExp() enum LOGDEFAULTINIT = 0; // log ::defaultInit() -enum SIZE_INVALID = (~cast(d_uns64)0); // error return from size() functions +enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions /*************************** @@ -887,12 +887,12 @@ extern (C++) abstract class Type : ASTNode stringtable = stringtable.init; } - final d_uns64 size() + final uinteger_t size() { return size(Loc.initial); } - d_uns64 size(const ref Loc loc) + uinteger_t size(const ref Loc loc) { error(loc, "no size for type `%s`", toChars()); return SIZE_INVALID; @@ -2770,7 +2770,7 @@ extern (C++) final class TypeError : Type return this; } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { return SIZE_INVALID; } @@ -3237,7 +3237,7 @@ extern (C++) final class TypeBasic : Type return this; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { uint size; //printf("TypeBasic::size()\n"); @@ -3411,8 +3411,8 @@ extern (C++) final class TypeBasic : Type // If converting from integral to integral if (tob.flags & TFlags.integral) { - d_uns64 sz = size(Loc.initial); - d_uns64 tosz = tob.size(Loc.initial); + const sz = size(Loc.initial); + const tosz = tob.size(Loc.initial); /* Can't convert to smaller size */ @@ -3512,7 +3512,7 @@ extern (C++) final class TypeVector : Type return new TypeVector(basetype.syntaxCopy()); } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { return basetype.size(); } @@ -3661,7 +3661,7 @@ extern (C++) final class TypeSArray : TypeArray return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0; } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { //printf("TypeSArray::size()\n"); const n = numberOfElems(loc); @@ -3860,7 +3860,7 @@ extern (C++) final class TypeDArray : TypeArray return result; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { //printf("TypeDArray::size()\n"); return target.ptrsize * 2; @@ -3964,7 +3964,7 @@ extern (C++) final class TypeAArray : TypeArray return result; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return target.ptrsize; } @@ -4056,7 +4056,7 @@ extern (C++) final class TypePointer : TypeNext return result; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return target.ptrsize; } @@ -4159,7 +4159,7 @@ extern (C++) final class TypeReference : TypeNext return result; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return target.ptrsize; } @@ -4596,8 +4596,10 @@ extern (C++) final class TypeFunction : TypeNext if (global.gag && !global.params.showGaggedErrors) return null; // show qualification when toChars() is the same but types are different - auto at = arg.type.toChars(); - bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0; + // https://issues.dlang.org/show_bug.cgi?id=19948 + // when comparing the type with strcmp, we need to drop the qualifier + auto at = arg.type.mutableOf().toChars(); + bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.mutableOf().toChars()) == 0; if (qual) at = arg.type.toPrettyChars(true); OutBuffer buf; @@ -4845,7 +4847,7 @@ extern (C++) final class TypeFunction : TypeNext // Need to make this a rvalue through a temporary m = MATCH.convert; } - else if (!global.params.rvalueRefParam || + else if (global.params.rvalueRefParam != FeatureState.enabled || p.storageClass & STC.out_ || !arg.type.isCopyable()) // can't copy to temp for ref parameter { @@ -5328,7 +5330,7 @@ extern (C++) final class TypeDelegate : TypeNext return t; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return target.ptrsize * 2; } @@ -5435,7 +5437,7 @@ extern (C++) final class TypeTraits : Type v.visit(this); } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { return SIZE_INVALID; } @@ -5562,7 +5564,7 @@ extern (C++) abstract class TypeQualified : Type idents.push(e); } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { error(this.loc, "size of type `%s` is not known", toChars()); return SIZE_INVALID; @@ -5717,7 +5719,7 @@ extern (C++) final class TypeTypeof : TypeQualified return s; } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { if (exp.type) return exp.type.size(loc); @@ -5792,7 +5794,7 @@ extern (C++) final class TypeStruct : Type return "struct"; } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { return sym.size(loc); } @@ -6148,7 +6150,7 @@ extern (C++) final class TypeEnum : Type return this; } - override d_uns64 size(const ref Loc loc) + override uinteger_t size(const ref Loc loc) { return sym.getMemtype(loc).size(loc); } @@ -6315,7 +6317,7 @@ extern (C++) final class TypeClass : Type return "class"; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return target.ptrsize; } @@ -6718,7 +6720,7 @@ extern (C++) final class TypeNull : Type return true; } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return tvoidptr.size(loc); } @@ -6777,7 +6779,7 @@ extern (C++) final class TypeNoreturn : Type return true; // bottom type can be implicitly converted to any other type } - override d_uns64 size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) const { return 0; } diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 3f085b06091..07c574d42b7 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -100,7 +100,7 @@ enum class TY : uint8_t TMAX }; -#define SIZE_INVALID (~(d_uns64)0) // error return from size() functions +#define SIZE_INVALID (~(uinteger_t)0) // error return from size() functions /** @@ -230,8 +230,8 @@ public: char *toPrettyChars(bool QualifyTypes = false); static void _init(); - d_uns64 size(); - virtual d_uns64 size(const Loc &loc); + uinteger_t size(); + virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); Type *trySemantic(const Loc &loc, Scope *sc); Type *merge2(); @@ -357,7 +357,7 @@ public: const char *kind(); TypeError *syntaxCopy(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); Expression *defaultInitLiteral(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; @@ -393,7 +393,7 @@ public: const char *kind(); TypeBasic *syntaxCopy(); - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; unsigned alignsize(); bool isintegral(); bool isfloating() /*const*/; @@ -418,7 +418,7 @@ public: static TypeVector *create(Type *basetype); const char *kind(); TypeVector *syntaxCopy(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); unsigned alignsize(); bool isintegral(); bool isfloating(); @@ -448,7 +448,7 @@ public: const char *kind(); TypeSArray *syntaxCopy(); bool isIncomplete(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); unsigned alignsize(); bool isString(); bool isZeroInit(const Loc &loc); @@ -471,7 +471,7 @@ class TypeDArray : public TypeArray public: const char *kind(); TypeDArray *syntaxCopy(); - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; unsigned alignsize() /*const*/; bool isString(); bool isZeroInit(const Loc &loc) /*const*/; @@ -491,7 +491,7 @@ public: static TypeAArray *create(Type *t, Type *index); const char *kind(); TypeAArray *syntaxCopy(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); bool isZeroInit(const Loc &loc) /*const*/; bool isBoolean() /*const*/; bool hasPointers() /*const*/; @@ -507,7 +507,7 @@ public: static TypePointer *create(Type *t); const char *kind(); TypePointer *syntaxCopy(); - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); bool isscalar() /*const*/; @@ -522,7 +522,7 @@ class TypeReference : public TypeNext public: const char *kind(); TypeReference *syntaxCopy(); - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; bool isZeroInit(const Loc &loc) /*const*/; void accept(Visitor *v) { v->visit(this); } }; @@ -655,7 +655,7 @@ public: const char *kind(); TypeDelegate *syntaxCopy(); Type *addStorageClass(StorageClass stc); - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; unsigned alignsize() /*const*/; MATCH implicitConvTo(Type *to); bool isZeroInit(const Loc &loc) /*const*/; @@ -675,7 +675,7 @@ class TypeTraits : public Type const char *kind(); TypeTraits *syntaxCopy(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); Dsymbol *toDsymbol(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; @@ -704,7 +704,7 @@ public: void addIdent(Identifier *ident); void addInst(TemplateInstance *inst); void addIndex(RootObject *expr); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; @@ -744,7 +744,7 @@ public: const char *kind(); TypeTypeof *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; @@ -778,7 +778,7 @@ public: static TypeStruct *create(StructDeclaration *sym); const char *kind(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); unsigned alignsize(); TypeStruct *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); @@ -808,7 +808,7 @@ public: const char *kind(); TypeEnum *syntaxCopy(); - d_uns64 size(const Loc &loc); + uinteger_t size(const Loc &loc); unsigned alignsize(); Type *memType(const Loc &loc = Loc()); Dsymbol *toDsymbol(Scope *sc); @@ -844,7 +844,7 @@ public: CPPMANGLE cppmangle; const char *kind(); - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; TypeClass *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); ClassDeclaration *isClassHandle(); @@ -899,7 +899,7 @@ public: MATCH implicitConvTo(Type *to); bool isBoolean() /*const*/; - d_uns64 size(const Loc &loc) /*const*/; + uinteger_t size(const Loc &loc) /*const*/; void accept(Visitor *v) { v->visit(this); } }; @@ -911,7 +911,7 @@ public: MATCH implicitConvTo(Type* to); MATCH constConv(Type* to); bool isBoolean() /* const */; - d_uns64 size(const Loc& loc) /* const */; + uinteger_t size(const Loc& loc) /* const */; unsigned alignsize(); void accept(Visitor *v) { v->visit(this); } diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index cc02bd9ea7c..5a86931305a 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -221,7 +221,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr) return; if (lengthVar._init && !lengthVar._init.isVoidInitializer()) return; // we have previously calculated the length - d_uns64 len; + dinteger_t len; if (auto se = arr.isStringExp()) len = se.len; else if (auto ale = arr.isArrayLiteralExp()) @@ -253,7 +253,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) auto tsa = type.toBasetype().isTypeSArray(); if (!tsa) return; // we don't know the length yet - d_uns64 len = tsa.dim.toInteger(); + const len = tsa.dim.toInteger(); Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t); lengthVar._init = new ExpInitializer(Loc.initial, dollar); lengthVar.storage_class |= STC.static_ | STC.const_; @@ -809,7 +809,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.e2.isConst() == 1) { sinteger_t i2 = e.e2.toInteger(); - d_uns64 sz = e.e1.type.size(e.e1.loc); + uinteger_t sz = e.e1.type.size(e.e1.loc); assert(sz != SIZE_INVALID); sz *= 8; if (i2 < 0 || i2 >= sz) @@ -895,7 +895,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.e2.isConst() == 1) { sinteger_t i2 = e.e2.toInteger(); - d_uns64 sz = e.e1.type.size(e.e1.loc); + uinteger_t sz = e.e1.type.size(e.e1.loc); assert(sz != SIZE_INVALID); sz *= 8; if (i2 < 0 || i2 >= sz) diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 480a96c25db..f6472bf925d 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -30,7 +30,7 @@ import dmd.tokens; /*********************************************************** */ -class Parser(AST) : Lexer +class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { AST.ModuleDeclaration* md; @@ -1263,7 +1263,7 @@ class Parser(AST) : Lexer } checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest); - checkConflictSTCGroup(STC.gshared | STC.shared_ | STC.tls); + checkConflictSTCGroup(STC.gshared | STC.shared_); checkConflictSTCGroup!true(STC.safeGroup); return orig; @@ -9599,5 +9599,3 @@ private bool writeMixin(const(char)[] s, ref Loc loc) return true; } - - diff --git a/gcc/d/dmd/root/file.h b/gcc/d/dmd/root/file.h deleted file mode 100644 index 44ca024d105..00000000000 --- a/gcc/d/dmd/root/file.h +++ /dev/null @@ -1,41 +0,0 @@ - -/* Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved - * written by Walter Bright - * https://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * https://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/dmd/root/file.h - */ - -#pragma once - -#include "array.h" -#include "filename.h" - -struct FileBuffer -{ - DArray data; - - FileBuffer(const FileBuffer &) /* = delete */; - ~FileBuffer() { mem.xfree(data.ptr); } - - static FileBuffer *create(); -}; - -struct File -{ - struct ReadResult - { - bool success; - FileBuffer buffer; - }; - - // Read the full content of a file. - static ReadResult read(const char *name); - - // Write a file, returning `true` on success. - static bool write(const char *name, const void *data, d_size_t size); - - // Delete a file. - static void remove(const char *name); -}; diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 292fccfb110..3b7b75b0aff 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -36,6 +36,8 @@ version (Windows) import core.sys.windows.windef; import core.sys.windows.winnls; + import dmd.common.string : extendedPathThen; + extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc; extern (Windows) void SetLastError(DWORD) nothrow @nogc; extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow; @@ -855,7 +857,7 @@ nothrow: } else version (Windows) { - return name.toWStringzThen!((wname) + return name.extendedPathThen!((wname) { const dw = GetFileAttributesW(&wname[0]); if (dw == -1) @@ -1005,7 +1007,7 @@ nothrow: // Have canonicalize_file_name, which malloc's memory. // We need a dmd.root.rmem allocation though. auto path = name.toCStringThen!((n) => canonicalize_file_name(n.ptr)); - scope(exit) .free(path.ptr); + scope(exit) .free(path); if (path !is null) return xarraydup(path.toDString); } @@ -1124,7 +1126,6 @@ version(Windows) */ private int _mkdir(const(char)[] path) nothrow { - import dmd.common.string : extendedPathThen; const createRet = path.extendedPathThen!( p => CreateDirectoryW(&p[0], null /*securityAttributes*/)); // different conventions for CreateDirectory and mkdir diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d index ec62292d7df..93c596ff0cd 100644 --- a/gcc/d/dmd/root/string.d +++ b/gcc/d/dmd/root/string.d @@ -201,10 +201,10 @@ int dstrcmp()( scope const char[] s1, scope const char[] s2 ) @trusted unittest { assert(dstrcmp("Fraise", "Fraise") == 0); - assert(dstrcmp("Baguette", "Croissant") == -1); - assert(dstrcmp("Croissant", "Baguette") == 1); + assert(dstrcmp("Baguette", "Croissant") < 0); + assert(dstrcmp("Croissant", "Baguette") > 0); - static assert(dstrcmp("Baguette", "Croissant") == -1); + static assert(dstrcmp("Baguette", "Croissant") < 0); // UTF-8 decoding for the CT variant assert(dstrcmp("안녕하세요!", "안녕하세요!") == 0); diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 85c4d5bf6a5..b9029a16ef8 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -330,11 +330,14 @@ private extern(C++) final class Semantic2Visitor : Visitor // gets imported, it is unaffected by context. Scope* sc = Scope.createGlobal(mod); // create root scope //printf("Module = %p\n", sc.scopesym); - // Pass 2 semantic routines: do initializers and function bodies - for (size_t i = 0; i < mod.members.dim; i++) + if (mod.members) { - Dsymbol s = (*mod.members)[i]; - s.semantic2(sc); + // Pass 2 semantic routines: do initializers and function bodies + for (size_t i = 0; i < mod.members.dim; i++) + { + Dsymbol s = (*mod.members)[i]; + s.semantic2(sc); + } } if (mod.userAttribDecl) { diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index b706777a1ed..d237caf9356 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -187,14 +187,17 @@ private extern(C++) final class Semantic3Visitor : Visitor // gets imported, it is unaffected by context. Scope* sc = Scope.createGlobal(mod); // create root scope //printf("Module = %p\n", sc.scopesym); - // Pass 3 semantic routines: do initializers and function bodies - for (size_t i = 0; i < mod.members.dim; i++) + if (mod.members) { - Dsymbol s = (*mod.members)[i]; - //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars()); - s.semantic3(sc); + // Pass 3 semantic routines: do initializers and function bodies + for (size_t i = 0; i < mod.members.dim; i++) + { + Dsymbol s = (*mod.members)[i]; + //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars()); + s.semantic3(sc); - mod.runDeferredSemantic2(); + mod.runDeferredSemantic2(); + } } if (mod.userAttribDecl) { @@ -1282,6 +1285,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.isreturn = true; + f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope); if (funcdecl.storage_class & STC.returninferred) f.isreturninferred = true; } diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index f229918d899..6ffba68fc49 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -987,18 +987,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor if (dim == 2) { Parameter p = (*fs.parameters)[0]; - auto var = new VarDeclaration(loc, p.type.mutableOf(), Identifier.generateId("__key"), null); - var.storage_class |= STC.temp | STC.foreach_; - if (var.storage_class & (STC.ref_ | STC.out_)) - var.storage_class |= STC.nodtor; + fs.key = new VarDeclaration(loc, p.type.mutableOf(), Identifier.generateId("__key"), null); + fs.key.storage_class |= STC.temp | STC.foreach_; + if (fs.key.isReference()) + fs.key.storage_class |= STC.nodtor; - fs.key = var; if (p.storageClass & STC.ref_) { - if (var.type.constConv(p.type) == MATCH.nomatch) + if (fs.key.type.constConv(p.type) == MATCH.nomatch) { fs.error("key type mismatch, `%s` to `ref %s`", - var.type.toChars(), p.type.toChars()); + fs.key.type.toChars(), p.type.toChars()); return retError(); } } @@ -1008,7 +1007,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor IntRange dimrange = getIntRange(ta.dim); // https://issues.dlang.org/show_bug.cgi?id=12504 dimrange.imax = SignExtendedNumber(dimrange.imax.value-1); - if (!IntRange.fromType(var.type).contains(dimrange)) + if (!IntRange.fromType(fs.key.type).contains(dimrange)) { fs.error("index type `%s` cannot cover index range 0..%llu", p.type.toChars(), ta.dim.toInteger()); @@ -1020,17 +1019,15 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor // Now declare the value { Parameter p = (*fs.parameters)[dim - 1]; - auto var = new VarDeclaration(loc, p.type, p.ident, null); - var.storage_class |= STC.foreach_; - var.storage_class |= p.storageClass & (STC.scope_ | STC.IOR | STC.TYPECTOR); - if (var.isReference()) - var.storage_class |= STC.nodtor; - - fs.value = var; - if (var.storage_class & STC.ref_) + fs.value = new VarDeclaration(loc, p.type, p.ident, null); + fs.value.storage_class |= STC.foreach_; + fs.value.storage_class |= p.storageClass & (STC.scope_ | STC.IOR | STC.TYPECTOR); + if (fs.value.isReference()) { + fs.value.storage_class |= STC.nodtor; + if (fs.aggr.checkModifiable(sc2, ModifyFlags.noError) == Modifiable.initialization) - var.setInCtorOnly = true; + fs.value.setInCtorOnly = true; Type t = tab.nextOf(); if (t.constConv(p.type) == MATCH.nomatch) @@ -1053,7 +1050,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor */ auto id = Identifier.generateId("__r"); auto ie = new ExpInitializer(loc, new SliceExp(loc, fs.aggr, null, null)); - const valueIsRef = cast(bool) ((*fs.parameters)[dim - 1].storageClass & STC.ref_); + const valueIsRef = (*fs.parameters)[$ - 1].isReference(); VarDeclaration tmp; if (fs.aggr.op == EXP.arrayLiteral && !valueIsRef) { diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index 7b9c454b33a..eb85c676a4b 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -61,7 +61,7 @@ extern (C++) struct Target import dmd.dscope : Scope; import dmd.expression : Expression; import dmd.func : FuncDeclaration; - import dmd.globals : Loc, d_int64; + import dmd.globals : Loc; import dmd.astenums : LINK, TY; import dmd.mtype : Type, TypeFunction, TypeTuple; import dmd.root.ctfloat : real_t; @@ -125,18 +125,18 @@ extern (C++) struct Target */ extern (C++) struct FPTypeProperties(T) { - real_t max; /// largest representable value that's not infinity - real_t min_normal; /// smallest representable normalized value that's not 0 - real_t nan; /// NaN value - real_t infinity; /// infinity value - real_t epsilon; /// smallest increment to the value 1 - - d_int64 dig; /// number of decimal digits of precision - d_int64 mant_dig; /// number of bits in mantissa - d_int64 max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable - d_int64 min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value - d_int64 max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable) - d_int64 min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value + real_t max; /// largest representable value that's not infinity + real_t min_normal; /// smallest representable normalized value that's not 0 + real_t nan; /// NaN value + real_t infinity; /// infinity value + real_t epsilon; /// smallest increment to the value 1 + + long dig; /// number of decimal digits of precision + long mant_dig; /// number of bits in mantissa + long max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable + long min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value + long max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable) + long min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value } FPTypeProperties!float FloatProperties; /// @@ -245,17 +245,6 @@ extern (C++) struct Target */ extern (C++) bool isReturnOnStack(TypeFunction tf, bool needsThis); - /*** - * Determine the size a value of type `t` will be when it - * is passed on the function parameter stack. - * Params: - * loc = location to use for error messages - * t = type of parameter - * Returns: - * size used on parameter stack - */ - extern (C++) ulong parameterSize(const ref Loc loc, Type t); - /** * Decides whether an `in` parameter of the specified POD type is to be * passed by reference or by value. To be used with `-preview=in` only! diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index f3d3859e224..096c16fd610 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -175,12 +175,12 @@ struct Target real_t infinity; real_t epsilon; - d_int64 dig; - d_int64 mant_dig; - d_int64 max_exp; - d_int64 min_exp; - d_int64 max_10_exp; - d_int64 min_10_exp; + int64_t dig; + int64_t mant_dig; + int64_t max_exp; + int64_t min_exp; + int64_t max_10_exp; + int64_t min_10_exp; }; FPTypeProperties FloatProperties; @@ -194,7 +194,6 @@ private: public: void _init(const Param& params); // Type sizes and support. - void setTriple(const char* _triple); unsigned alignsize(Type *type); unsigned fieldalign(Type *type); Type *va_listType(const Loc &loc, Scope *sc); // get type of va_list @@ -204,7 +203,6 @@ public: LINK systemLinkage(); TypeTuple *toArgTypes(Type *t); bool isReturnOnStack(TypeFunction *tf, bool needsThis); - d_uns64 parameterSize(const Loc& loc, Type *t); bool preferPassByRef(Type *t); Expression *getTargetInfo(const char* name, const Loc& loc); bool isCalleeDestroyingArgs(TypeFunction* tf); diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 42517f6403c..86863769141 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -314,3 +314,4 @@ Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); TemplateParameter *isTemplateParameter(RootObject *o); bool isError(const RootObject *const o); +void printTemplateStats(); diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 6e56eb25474..1790996619b 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -942,17 +942,17 @@ nothrow: switch (value) { case TOK.int32Literal: - sprintf(&buffer[0], "%d", cast(d_int32)intvalue); + sprintf(&buffer[0], "%d", cast(int)intvalue); break; case TOK.uns32Literal: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.wchar_tLiteral: - sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue); + sprintf(&buffer[0], "%uU", cast(uint)unsvalue); break; case TOK.charLiteral: { - const v = cast(d_int32)intvalue; + const v = cast(int)intvalue; if (v >= ' ' && v <= '~') sprintf(&buffer[0], "'%c'", v); else diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 61602518163..dbdcfd4af85 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -166,28 +166,28 @@ shared static this() /** * get an array of size_t values that indicate possible pointer words in memory * if interpreted as the type given as argument - * Returns: the size of the type in bytes, d_uns64.max on error + * Returns: the size of the type in bytes, ulong.max on error */ -d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) +ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) { - d_uns64 sz; + ulong sz; if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration()) sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc); else sz = t.size(loc); if (sz == SIZE_INVALID) - return d_uns64.max; + return ulong.max; const sz_size_t = Type.tsize_t.size(loc); if (sz > sz.max - sz_size_t) { error(loc, "size overflow for type `%s`", t.toChars()); - return d_uns64.max; + return ulong.max; } - d_uns64 bitsPerWord = sz_size_t * 8; - d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t; - d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; + ulong bitsPerWord = sz_size_t * 8; + ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; + ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; data.setDim(cast(size_t)cntdata); data.zero(); @@ -196,15 +196,15 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) { alias visit = Visitor.visit; public: - extern (D) this(Array!(d_uns64)* _data, d_uns64 _sz_size_t) + extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) { this.data = _data; this.sz_size_t = _sz_size_t; } - void setpointer(d_uns64 off) + void setpointer(ulong off) { - d_uns64 ptroff = off / sz_size_t; + ulong ptroff = off / sz_size_t; (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t)); } @@ -242,12 +242,12 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) override void visit(TypeSArray t) { - d_uns64 arrayoff = offset; - d_uns64 nextsize = t.next.size(); + ulong arrayoff = offset; + ulong nextsize = t.next.size(); if (nextsize == SIZE_INVALID) error = true; - d_uns64 dim = t.dim.toInteger(); - for (d_uns64 i = 0; i < dim; i++) + ulong dim = t.dim.toInteger(); + for (ulong i = 0; i < dim; i++) { offset = arrayoff + i * nextsize; t.next.accept(this); @@ -340,7 +340,7 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) override void visit(TypeStruct t) { - d_uns64 structoff = offset; + ulong structoff = offset; foreach (v; t.sym.fields) { offset = structoff + v.offset; @@ -355,7 +355,7 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references void visitClass(TypeClass t) { - d_uns64 classoff = offset; + ulong classoff = offset; // skip vtable-ptr and monitor if (t.sym.baseClass) visitClass(cast(TypeClass)t.sym.baseClass.type); @@ -367,9 +367,9 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) offset = classoff; } - Array!(d_uns64)* data; - d_uns64 offset; - d_uns64 sz_size_t; + Array!(ulong)* data; + ulong offset; + ulong sz_size_t; bool error; } @@ -378,7 +378,7 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) pbv.visitClass(cast(TypeClass)t); else t.accept(pbv); - return pbv.error ? d_uns64.max : sz; + return pbv.error ? ulong.max : sz; } /** @@ -406,9 +406,9 @@ private Expression pointerBitmap(TraitsExp e) return ErrorExp.get(); } - Array!(d_uns64) data; - d_uns64 sz = getTypePointerBitmap(e.loc, t, &data); - if (sz == d_uns64.max) + Array!(ulong) data; + ulong sz = getTypePointerBitmap(e.loc, t, &data); + if (sz == ulong.max) return ErrorExp.get(); auto exps = new Expressions(data.dim + 1); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 57188af90d6..e5f839bb8a3 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1304,7 +1304,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // default arg must be an lvalue if (isRefOrOut && !isAuto && !(global.params.previewIn && (fparam.storageClass & STC.in_)) && - !(global.params.rvalueRefParam)) + global.params.rvalueRefParam != FeatureState.enabled) e = e.toLvalue(sc, e); fparam.defaultArg = e; @@ -1504,16 +1504,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) /* Scope attribute is not necessary if the parameter type does not have pointers */ - /* Constructors are treated as if they are being returned through the hidden parameter, - * which is by ref, and the ref there is ignored. - */ - const returnByRef = tf.isref && !tf.isctor; - if (!returnByRef && isRefReturnScope(fparam.storageClass)) - { - /* if `ref return scope`, evaluate to `ref` `return scope` - */ - fparam.storageClass |= STC.returnScope; - } const sr = buildScopeRef(fparam.storageClass); switch (sr) { @@ -1534,17 +1524,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) break; } - /* now set STC.returnScope based only on tf.isref. This is inconsistent, as mentioned above, - * but necessary for compatibility for now. - */ - fparam.storageClass &= ~STC.returnScope; - if (!tf.isref && isRefReturnScope(fparam.storageClass)) - { - /* if `ref return scope`, evaluate to `ref` `return scope` - */ - fparam.storageClass |= STC.returnScope; - } - // Remove redundant storage classes for type, they are already applied fparam.storageClass &= ~(STC.TYPECTOR); @@ -2411,7 +2390,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden } if (ident == Id.__sizeof) { - d_uns64 sz = mt.size(loc); + const sz = mt.size(loc); if (sz == SIZE_INVALID) return ErrorExp.get(); e = new IntegerExp(loc, sz, Type.tsize_t); diff --git a/gcc/testsuite/gdc.dg/pr105004.d b/gcc/testsuite/gdc.dg/pr105004.d new file mode 100644 index 00000000000..60b3c3f635e --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr105004.d @@ -0,0 +1,14 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105004 +// { dg-do compile } + +private struct _Complex(T) +{ + T re; + T im; +} +enum __c_complex_float : _Complex!float; + +__c_complex_float pr105004(float re, float im) +{ + return typeof(return)(re, im); +} diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d index e0a96d4dfa3..10f5807f5c3 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d @@ -125,7 +125,6 @@ typedef /* noreturn */ char Impossible[0]; template struct Array final { - // Ignoring var length alignment 0 uint32_t length; Array() { diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d index 1bfc25bd683..2d48999c410 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d @@ -175,7 +175,7 @@ struct A final s() { } - A(int32_t a, S s = S(0, 0, 0LL, {})) : + A(int32_t a, S s = S()) : a(a), s(s) {} @@ -186,6 +186,37 @@ union U int32_t i; char c; }; + +struct Array final +{ + uint32_t length; +private: + _d_dynamicArray< char > data; + char smallarray[1$?:32=u|64=LLU$]; +public: + Array() : + length() + { + } + Array(uint32_t length) : + length(length) + {} +}; + +struct Params final +{ + bool obj; + Array ddocfiles; + Params() : + obj(true), + ddocfiles() + { + } + Params(bool obj, Array ddocfiles = Array()) : + obj(obj), + ddocfiles(ddocfiles) + {} +}; --- */ @@ -284,3 +315,17 @@ extern(C++) union U int i; char c; } + +extern (C++) struct Array +{ + uint length; +private: + char[] data; + char[1] smallarray; +} + +extern (C++) struct Params +{ + bool obj = true; + Array ddocfiles; +} diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d index 5f747fda8c8..e9e57da87f0 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d @@ -73,14 +73,10 @@ struct ActualBuffer final template struct A final { - // Ignoring var x alignment 0 T x; - // Ignoring var Enum alignment 0 enum : int32_t { Enum = 42 }; - // Ignoring var GsharedNum alignment 0 static int32_t GsharedNum; - // Ignoring var MemNum alignment 0 const int32_t MemNum; void foo(); A() @@ -91,8 +87,6 @@ struct A final template struct NotInstantiated final { - // Ignoring var noInit alignment 0 - // Ignoring var missingSem alignment 0 NotInstantiated() { } @@ -113,7 +107,6 @@ struct B final template struct Foo final { - // Ignoring var val alignment 0 T val; Foo() { @@ -123,7 +116,6 @@ struct Foo final template struct Bar final { - // Ignoring var v alignment 0 Foo v; Bar() { @@ -141,9 +133,7 @@ struct Array final void get() const; template bool opCast() const; - // Ignoring var i alignment 0 typename T::Member i; - // Ignoring var j alignment 0 typename Outer::Member::Nested j; void visit(typename T::Member::Nested i); Array() @@ -159,7 +149,6 @@ extern A > aaint; template class Parent { - // Ignoring var parentMember alignment 0 public: T parentMember; void parentFinal(); @@ -169,7 +158,6 @@ public: template class Child final : public Parent { - // Ignoring var childMember alignment 0 public: T childMember; void parentVirtual(); @@ -207,14 +195,10 @@ extern HasMixinsTemplate hmti; template struct NotAA final { - // Ignoring var length alignment 0 enum : int32_t { length = 12 }; - // Ignoring var buffer alignment 0 T buffer[length]; - // Ignoring var otherBuffer alignment 0 T otherBuffer[SomeOtherLength]; - // Ignoring var calcBuffer alignment 0 T calcBuffer[foo(1)]; NotAA() { @@ -224,9 +208,7 @@ struct NotAA final template struct BufferTmpl final { - // Ignoring var buffer alignment 0 Buffer buffer; - // Ignoring var buffer2 alignment 0 Buffer buffer2; BufferTmpl() { diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d index 483e58f6ae5..2f5b7dfe68d 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d @@ -86,7 +86,6 @@ struct ExternDStructRequired final template struct ExternDTemplStruct final { - // Ignoring var member alignment 0 T member; ExternDTemplStruct() { @@ -129,7 +128,6 @@ extern TemplClass* templClass; template class TemplClass { - // Ignoring var member alignment 0 public: T member; }; @@ -139,7 +137,6 @@ extern TemplStruct* templStruct; template class TemplStruct { - // Ignoring var member alignment 0 public: T member; }; diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d index 47c0172009d..1e1b88736d4 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d @@ -62,11 +62,9 @@ private: template struct WithImaginaryTemplate final { - // Ignoring var member alignment 0 float member; // Ignored function onReturn because its return type cannot be mapped to C++ // Ignored function onParam because one of its parameters has type `ifloat` which cannot be mapped to C++ - // Ignoring var onVariable alignment 0 // Ignored variable onVariable because its type cannot be mapped to C++ WithImaginaryTemplate() { diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d index 821c37c6d53..c7d4c14e0c7 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d @@ -58,7 +58,6 @@ namespace const_cast template struct S final { - // Ignoring var x alignment 0 register_ x; S() { @@ -104,7 +103,6 @@ extern void user(Alias* i); template struct InvalidNames final { - // Ignoring var register alignment 0 typename_ register_; void foo(typename_ and_); InvalidNames() diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_names.d b/gcc/testsuite/gdc.test/compilable/dtoh_names.d index 068fc68ef51..8a7eb7ffffb 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_names.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_names.d @@ -63,13 +63,9 @@ struct Outer final template struct InnerTmpl final { - // Ignoring var innerTmplOuterPtr alignment 0 static Outer* innerTmplOuterPtr; - // Ignoring var innerTmplPtr alignment 0 static Middle* innerTmplPtr; - // Ignoring var innerTmplInnerPtr alignment 0 static Inner* innerTmplInnerPtr; - // Ignoring var innerTmplInnerTmplPtr alignment 0 static InnerTmpl* innerTmplInnerTmplPtr; InnerTmpl() { @@ -84,15 +80,11 @@ struct Outer final template struct MiddleTmpl final { - // Ignoring var middleTmplPtr alignment 0 static MiddleTmpl* middleTmplPtr; - // Ignoring var middleTmplInnerTmplPtr alignment 0 static MiddleTmpl* middleTmplInnerTmplPtr; struct Inner final { - // Ignoring var ptr alignment 0 static Inner* ptr; - // Ignoring var ptr2 alignment 0 static MiddleTmpl* ptr2; Inner() { @@ -102,13 +94,9 @@ struct Outer final template struct InnerTmpl final { - // Ignoring var innerTmplPtr alignment 0 static InnerTmpl* innerTmplPtr; - // Ignoring var innerTmplPtrDiff alignment 0 static InnerTmpl* innerTmplPtrDiff; - // Ignoring var middleTmplInnerTmplPtr alignment 0 static MiddleTmpl* middleTmplInnerTmplPtr; - // Ignoring var a alignment 0 static T a; static U bar(); InnerTmpl() diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d b/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d index 6e2d2f1e38c..d41cb1bc213 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d @@ -65,9 +65,7 @@ enum class ExternDEnum template <> struct ExternDStructTemplate final { - // Ignoring var i alignment 0 int32_t i; - // Ignoring var d alignment 0 double d; ExternDStructTemplate() { @@ -131,7 +129,7 @@ struct ExternCppStruct final st() { } - ExternCppStruct(ExternDStruct s, ExternDEnum e = (ExternDEnum)0, ExternDStructTemplate< > st = ExternDStructTemplate< >(0, NAN)) : + ExternCppStruct(ExternDStruct s, ExternDEnum e = (ExternDEnum)0, ExternDStructTemplate< > st = ExternDStructTemplate< >()) : s(s), e(e), st(st) diff --git a/gcc/testsuite/gdc.test/compilable/scope.d b/gcc/testsuite/gdc.test/compilable/scope.d index 7e81028d278..95c784627fa 100644 --- a/gcc/testsuite/gdc.test/compilable/scope.d +++ b/gcc/testsuite/gdc.test/compilable/scope.d @@ -142,7 +142,7 @@ int f1_20682(return scope ref D d) @safe return d.pos; } -ref int f2_20682(return scope ref D d) @safe +ref int f2_20682(return ref scope D d) @safe { return d.pos; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d new file mode 100644 index 00000000000..6122e418339 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d @@ -0,0 +1,18 @@ +// https://issues.dlang.org/show_bug.cgi?id=19948 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail19948.d(15): Error: function `fail19948.func(const(X))` is not callable using argument types `(X)` +fail_compilation/fail19948.d(15): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +--- +*/ + +struct X {} +void main() +{ + struct X {} + func(X()); +} + +void func(const(X)) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22881.d b/gcc/testsuite/gdc.test/fail_compilation/fail22881.d new file mode 100644 index 00000000000..31195f6c7a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22881.d @@ -0,0 +1,60 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail22881.d(101): Error: pointer slice `[0..6]` exceeds allocated memory block `[0..5]` +fail_compilation/fail22881.d(102): Error: pointer slice `[0..6]` exceeds allocated memory block `[0..5]` +fail_compilation/fail22881.d(110): Error: pointer slice `[3..5]` exceeds allocated memory block `[0..4]` +fail_compilation/fail22881.d(113): called from here: `ptr22881()` +fail_compilation/fail22881.d(113): while evaluating: `static assert(ptr22881())` +fail_compilation/fail22881.d(203): Error: slice `[0..2]` is out of bounds +fail_compilation/fail22881.d(207): called from here: `null22881()` +fail_compilation/fail22881.d(207): while evaluating: `static assert(null22881())` +fail_compilation/fail22881.d(305): Error: slice `[2..4]` exceeds array bounds `[0..3]` +fail_compilation/fail22881.d(308): called from here: `slice22881()` +fail_compilation/fail22881.d(308): while evaluating: `static assert(slice22881())` +fail_compilation/fail22881.d(401): Error: slice `[0..1]` exceeds array bounds `[0..0]` +fail_compilation/fail22881.d(403): Error: slice `[0..1]` exceeds array bounds `[0..0]` +--- +*/ +#line 100 +// SliceExp: e1.type.ty == pointer +static pstr22881 = "hello".ptr[0 .. 6]; +static parr22881 = ['h','e','l','l','o'].ptr[0 .. 6]; + +bool ptr22881() +{ + char *p1 = new char[4].ptr; + p1[0 .. 4] = "str\0"; + char *s1 = p1[1 .. 3].ptr; + char *s2 = s1[1 .. 3].ptr; // = p1[2 .. 4] + char *s3 = s2[1 .. 3].ptr; // = p1[3 .. 5] + return true; +} +static assert(ptr22881()); + + +#line 200 +// SliceExp: e1.op == null +bool null22881() +{ + string[][1] nullexp; + nullexp[0][0 .. 2] = "st"; + return true; +} +static assert(null22881()); + +#line 300 +// SliceExp: e1.op == slice +bool slice22881() +{ + char[] str = "abcd".dup; + char[] slice = str[1 .. 4]; + slice[2 .. 4] = "ab"; + return true; +} +static assert(slice22881()); + +#line 400 +// SliceExp: e1.op == arrayLiteral +static arr22881 = [][0 .. 1]; +// SliceExp: e1.op == string_ +static str22881 = ""[0 .. 1]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d index b0208686fe1..fce4ab7345e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d +++ b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument types `(int*)` matches both: -fail_compilation/pull12941.d(101): `pull12941.foo(ref return scope int* p)` +fail_compilation/pull12941.d(101): `pull12941.foo(return ref scope int* p)` and: -fail_compilation/pull12941.d(102): `pull12941.foo(out return scope int* p)` +fail_compilation/pull12941.d(102): `pull12941.foo(return out scope int* p)` fail_compilation/pull12941.d(111): Error: function `pull12941.bar(return scope int* p)` is not callable using argument types `(int)` fail_compilation/pull12941.d(111): cannot pass argument `1` of type `int` to parameter `return scope int* p` fail_compilation/pull12941.d(112): Error: function `pull12941.abc(return ref int* p)` is not callable using argument types `(int)` diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d index 8e6e0a46c5f..68269ae2da3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d @@ -130,7 +130,7 @@ fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a referen struct S700 { - @safe S700* get1() return scope + @safe S700* get1() scope return { return &this; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d index 2ac3b562198..f2a117c0b80 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d @@ -56,7 +56,7 @@ int* addrOfRefGlobal() } // Slice: -ref int*[1] identityArr(ref return scope int*[1] x) +ref int*[1] identityArr(return ref scope int*[1] x) { return x; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17422.d b/gcc/testsuite/gdc.test/fail_compilation/test17422.d index 7bb1315894e..80f8fbe2613 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17422.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test17422.d @@ -7,7 +7,7 @@ fail_compilation/test17422.d(23): Error: scope variable `p` may not be returned */ struct RC { - Object get() return scope @trusted + Object get() return @trusted { return cast(Object) &store[0]; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20881.d b/gcc/testsuite/gdc.test/fail_compilation/test20881.d new file mode 100644 index 00000000000..72826352af2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test20881.d @@ -0,0 +1,30 @@ +/* +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/test20881.d(27): Error: address of variable `s` assigned to `global` with longer lifetime +fail_compilation/test20881.d(28): Error: address of variable `s` assigned to `global` with longer lifetime +fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `global` with longer lifetime +--- +*/ +@safe: + +// https://issues.dlang.org/show_bug.cgi?id=20881 + +struct S +{ + int* ptr; + + auto borrowA() return /*scope inferred*/ { return ptr; } + int* borrowB() return { return ptr; } + int* borrowC() scope return { return ptr; } +} + +void main() +{ + static int* global; + S s; + global = s.borrowA; + global = s.borrowB; + global = s.borrowC; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21912.d b/gcc/testsuite/gdc.test/fail_compilation/test21912.d index 5bb92a352a1..925210bf875 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21912.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21912.d @@ -32,12 +32,12 @@ Dg escapeAssign(int i, return scope Dg dg) return dg; } -ref Dg identityR(ref return scope Dg dg) +ref Dg identityR(return ref scope Dg dg) { return dg; } -ref Dg escapeAssignRef(int i, ref return scope Dg dg) +ref Dg escapeAssignRef(int i, return ref scope Dg dg) { dg = () => i; return dg; diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22898.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22898.cpp new file mode 100644 index 00000000000..28680074896 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22898.cpp @@ -0,0 +1,7 @@ +int testCppCMangle (unsigned long long val, char ch) +{ + int vch = (char)val; + if (vch != ch) + return 0; + return vch; +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test22898.d b/gcc/testsuite/gdc.test/runnable_cxx/test22898.d new file mode 100644 index 00000000000..32506238785 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test22898.d @@ -0,0 +1,28 @@ +// EXTRA_CPP_SOURCES: test22898.cpp + +import core.stdc.config; + +extern(C++): + +version (AArch64) version = UnsignedChar; +version (ARM) version = UnsignedChar; +version (RISCV32) version = UnsignedChar; +version (RISCV64) version = UnsignedChar; +version (PPC) version = UnsignedChar; +version (PPC64) version = UnsignedChar; +version (S390) version = UnsignedChar; +version (SystemZ) version = UnsignedChar; + +version (UnsignedChar) + enum __c_char : ubyte; +else + enum __c_char : byte; + +int testCppCMangle (cpp_ulonglong, __c_char); + +void main() +{ + auto val = cast(cpp_ulonglong)18446744073709551488UL; + auto ch = cast(__c_char)val; + assert(testCppCMangle(val, ch) == cast(int)ch); +} diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 963ffe020de..6eb555ed29b 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -16cb085b584f100fa677e2e64ff6b6dbb4921ad1 +a74fa63e6775d626850d8ebd854d9803c7ffb97d 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/conv.d b/libphobos/src/std/conv.d index 8512a445daf..06b37978ba6 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -1153,7 +1153,7 @@ if (!(isImplicitlyConvertible!(S, T) && } // https://issues.dlang.org/show_bug.cgi?id=16108 -@system unittest +@safe unittest { static struct A { @@ -1341,12 +1341,12 @@ if (is (T == immutable) && isExactSomeString!T && is(S == enum)) assert(to!string(a) == "[1.5, 2.5]"); } -@system unittest +@safe unittest { // Conversion representing class object with string class A { - override string toString() const { return "an A"; } + override string toString() @safe const { return "an A"; } } A a; assert(to!string(a) == "null"); @@ -1354,7 +1354,7 @@ if (is (T == immutable) && isExactSomeString!T && is(S == enum)) assert(to!string(a) == "an A"); // https://issues.dlang.org/show_bug.cgi?id=7660 - class C { override string toString() const { return "C"; } } + class C { override string toString() @safe const { return "C"; } } struct S { C c; alias c this; } S s; s.c = new C(); assert(to!string(s) == "C"); @@ -1739,10 +1739,10 @@ if (!isImplicitlyConvertible!(S, T) && isAssociativeArray!S && foreach (k1, v1; value) { // Cast values temporarily to Unqual!V2 to store them to result variable - result[to!K2(k1)] = cast(Unqual!V2) to!V2(v1); + result[to!K2(k1)] = to!(Unqual!V2)(v1); } // Cast back to original type - return cast(T) result; + return () @trusted { return cast(T) result; }(); } @safe unittest @@ -3105,7 +3105,7 @@ if (isSomeString!Source && !is(Source == enum) && * A $(LREF ConvException) if `source` is empty, if no number could be * parsed, or if an overflow occurred. */ -auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source) +auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source source) if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && isFloatingPoint!Target && !is(Target == enum)) { @@ -3122,6 +3122,13 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum alias p = source; } + void advanceSource() @trusted + { + // p is assigned from source.representation above so the cast is valid + static if (isNarrowString!Source) + source = cast(Source) p; + } + static immutable real[14] negtab = [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; @@ -3138,6 +3145,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum enforce(!p.empty, bailOut()); + size_t count = 0; bool sign = false; switch (p.front) @@ -3168,8 +3176,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum // skip past the last 'f' ++count; p.popFront(); - static if (isNarrowString!Source) - source = cast(Source) p; + advanceSource(); static if (doCount) { return tuple!("data", "count")(sign ? -Target.infinity : Target.infinity, count); @@ -3189,8 +3196,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum p.popFront(); if (p.empty) { - static if (isNarrowString!Source) - source = cast(Source) p; + advanceSource(); static if (doCount) { return tuple!("data", "count")(cast (Target) (sign ? -0.0 : 0.0), count); @@ -3222,8 +3228,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum // skip past the last 'n' ++count; p.popFront(); - static if (isNarrowString!Source) - source = cast(Source) p; + advanceSource(); static if (doCount) { return tuple!("data", "count")(Target.nan, count); @@ -3418,8 +3423,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum // if overflow occurred enforce(ldval != real.infinity, new ConvException("Range error")); - static if (isNarrowString!Source) - source = cast(Source) p; + advanceSource(); static if (doCount) { return tuple!("data", "count")(cast (Target) (sign ? -ldval : ldval), count); @@ -3430,6 +3434,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum } } + /// @safe unittest { diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 8da38bdb4e6..f4f42167044 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -234,7 +234,7 @@ import std.meta : anySatisfy, allSatisfy; import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor; import std.traits : isAssignable, isCopyable, isStaticArray, isRvalueAssignable; import std.traits : ConstOf, ImmutableOf, InoutOf, TemplateArgsOf; -import std.traits : CommonType; +import std.traits : CommonType, DeducedParameterType; import std.typecons : ReplaceTypeUnless; import std.typecons : Flag; @@ -359,6 +359,10 @@ public: /// ditto this(immutable(T) value) immutable; + + /// ditto + this(Value)(Value value) inout + if (is(Value == DeducedParameterType!(inout(T)))); } static foreach (tid, T; Types) @@ -414,6 +418,25 @@ public: { @disable this(immutable(T) value) immutable; } + + static if (isCopyable!(inout(T))) + { + static if (IndexOf!(inout(T), Map!(InoutOf, Types)) == tid) + { + /// ditto + this(Value)(Value value) inout + if (is(Value == DeducedParameterType!(inout(T)))) + { + __traits(getMember, storage, Storage.memberName!T) = value; + tag = tid; + } + } + } + else + { + @disable this(Value)(Value value) inout + if (is(Value == DeducedParameterType!(inout(T)))); + } } static if (anySatisfy!(hasElaborateCopyConstructor, Types)) @@ -1554,6 +1577,16 @@ version (D_BetterC) {} else SumType!Value s; } +// Construction of inout-qualified SumTypes +// https://issues.dlang.org/show_bug.cgi?id=22901 +@safe unittest +{ + static inout(SumType!(int[])) example(inout(int[]) arr) + { + return inout(SumType!(int[]))(arr); + } +} + /// True if `T` is an instance of the `SumType` template, otherwise false. private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...); diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d index 596c11cfb00..9ca676d312a 100644 --- a/libphobos/src/std/traits.d +++ b/libphobos/src/std/traits.d @@ -9080,3 +9080,43 @@ enum isCopyable(S) = __traits(isCopyable, S); static assert(isCopyable!int); static assert(isCopyable!(int[])); } + +/** + * The parameter type deduced by IFTI when an expression of type T is passed as + * an argument to a template function. + * + * For all types other than pointer and slice types, `DeducedParameterType!T` + * is the same as `T`. For pointer and slice types, it is `T` with the + * outer-most layer of qualifiers dropped. + */ +package(std) template DeducedParameterType(T) +{ + static if (is(T == U*, U) || is(T == U[], U)) + alias DeducedParameterType = Unqual!T; + else + alias DeducedParameterType = T; +} + +@safe unittest +{ + static assert(is(DeducedParameterType!(const(int)) == const(int))); + static assert(is(DeducedParameterType!(const(int[2])) == const(int[2]))); + + static assert(is(DeducedParameterType!(const(int*)) == const(int)*)); + static assert(is(DeducedParameterType!(const(int[])) == const(int)[])); +} + +@safe unittest +{ + static struct NoCopy + { + @disable this(this); + } + + static assert(is(DeducedParameterType!NoCopy == NoCopy)); +} + +@safe unittest +{ + static assert(is(DeducedParameterType!(inout(int[])) == inout(int)[])); +} diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 9780b1b318f..eeeda721813 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -9824,7 +9824,7 @@ dchar toLower(dchar c) /++ Creates a new array which is identical to `s` except that all of its - characters are converted to lowercase (by preforming Unicode lowercase mapping). + characters are converted to lowercase (by performing Unicode lowercase mapping). If none of `s` characters were affected, then `s` itself is returned if `s` is a `string`-like type. @@ -10028,7 +10028,7 @@ dchar toUpper(dchar c) /++ Allocates a new array which is identical to `s` except that all of its - characters are converted to uppercase (by preforming Unicode uppercase mapping). + characters are converted to uppercase (by performing Unicode uppercase mapping). If none of `s` characters were affected, then `s` itself is returned if `s` is a `string`-like type.