From patchwork Fri Jun 24 18:56:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1648136 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=UNB/8QP4; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LV5vK3Ly2z9sG2 for ; Sat, 25 Jun 2022 04:56:44 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CCB4E3850220 for ; Fri, 24 Jun 2022 18:56:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CCB4E3850220 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1656097000; bh=lqm8D7MbaHyQBX9nKQ+p/JS3+k2DCVxUjCGXB8njgaI=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=UNB/8QP4Sc0k2y7qDS64MCCJvHBZD34f6GfFs8yfw5hIZpqOHASpolKVbCrhpzDRR F2hMCXczkwARYJydoiRA+0SY+az+hRLNhtigRtAUjbUoUkksnZQ+87PFpbb8PZPshb tT5QTALRcdIxRAYiCliU7/WcdyRbOCWC0WtEgqpU= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [80.241.56.171]) by sourceware.org (Postfix) with ESMTPS id 10CE1385BAED for ; Fri, 24 Jun 2022 18:56:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 10CE1385BAED Received: from smtp1.mailbox.org (smtp1.mailbox.org [10.196.197.1]) (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-201.mailbox.org (Postfix) with ESMTPS id 4LV5tj4dr1z9sRV; Fri, 24 Jun 2022 20:56:13 +0200 (CEST) To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd 529110f66, druntime 148608b7. Date: Fri, 24 Jun 2022 20:56:11 +0200 Message-Id: <20220624185611.3905081-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.0 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.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.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 529110f66. The git revision hash of libdruntime has also been bumped, though the only changes made have been outside what is merged downstream. D front-end changes: - Import latest bug fixes to mainline. Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 529110f66. * decl.cc (DeclVisitor::visit (TupleDeclaration *)): Update for new front-end interface. * types.cc (layout_aggregate_members): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 148608b7. --- gcc/d/decl.cc | 6 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/canthrow.d | 13 +- gcc/d/dmd/cparse.d | 34 ++++- gcc/d/dmd/declaration.d | 63 +++++---- gcc/d/dmd/dinterpret.d | 17 +-- gcc/d/dmd/dmangle.d | 18 ++- gcc/d/dmd/dsymbolsem.d | 33 +++-- gcc/d/dmd/dtoh.d | 128 +++++++++--------- gcc/d/dmd/expression.d | 8 +- gcc/d/dmd/expressionsem.d | 104 ++++++++++---- gcc/d/dmd/foreachvar.d | 14 +- gcc/d/dmd/importc.d | 4 + gcc/d/dmd/ob.d | 22 +-- gcc/d/dmd/parse.d | 11 +- gcc/d/dmd/root/filename.d | 27 ++-- gcc/d/dmd/semantic2.d | 5 + gcc/d/dmd/semantic3.d | 2 +- gcc/d/types.cc | 6 +- .../compilable/dtoh_AnonDeclaration.d | 14 +- .../compilable/dtoh_StructDeclaration.d | 18 ++- .../compilable/dtoh_TemplateDeclaration.d | 6 +- .../gdc.test/compilable/dtoh_mangling.d | 8 +- .../gdc.test/compilable/dtoh_protection.d | 28 +++- gcc/testsuite/gdc.test/compilable/test23168.d | 30 ++++ gcc/testsuite/gdc.test/compilable/test23169.d | 14 ++ gcc/testsuite/gdc.test/compilable/testparse.d | 10 ++ gcc/testsuite/gdc.test/runnable/test23010.d | 43 ++++++ libphobos/libdruntime/MERGE | 2 +- 29 files changed, 464 insertions(+), 226 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/test23168.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23169.d create mode 100644 gcc/testsuite/gdc.test/runnable/test23010.d diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 8676a1b588b..b82e2d55c13 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -225,9 +225,9 @@ public: RootObject *o = (*d->objects)[i]; if (o->dyncast () == DYNCAST_EXPRESSION) { - DsymbolExp *de = ((Expression *) o)->isDsymbolExp (); - if (de != NULL && de->s->isDeclaration ()) - this->build_dsymbol (de->s); + VarExp *ve = ((Expression *) o)->isVarExp (); + if (ve) + this->build_dsymbol (ve->var); } } } diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index d1e3dc16312..f5c42f0ff00 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -6203135dcf0112d3211add0cbfb22fecc5df1af4 +529110f66d7d301d62d943a4e4482edaddeb46ea 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/canthrow.d b/gcc/d/dmd/canthrow.d index a38cbb1610b..fe6e1e344b9 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -270,18 +270,7 @@ private CT Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow) } else if (auto td = s.isTupleDeclaration()) { - for (size_t i = 0; i < td.objects.dim; i++) - { - RootObject o = (*td.objects)[i]; - if (o.dyncast() == DYNCAST.expression) - { - Expression eo = cast(Expression)o; - if (auto se = eo.isDsymbolExp()) - { - result |= Dsymbol_canThrow(se.s, func, mustNotThrow); - } - } - } + td.foreachVar(&symbolDg); } return result; } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 62ba889cc13..dff76345fa5 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -2413,11 +2413,19 @@ final class CParser(AST) : Parser!AST if (scw & scwx) error("duplicate storage class"); scw |= scwx; + // C11 6.7.1-2 At most one storage-class may be given, except that + // _Thread_local may appear with static or extern. const scw2 = scw & (SCW.xstatic | SCW.xextern | SCW.xauto | SCW.xregister | SCW.xtypedef); if (scw2 & (scw2 - 1) || - scw & (SCW.xauto | SCW.xregister) && scw & (SCW.xinline | SCW.x_Noreturn)) + scw & (SCW.x_Thread_local) && scw & (SCW.xauto | SCW.xregister | SCW.xtypedef)) { - error("conflicting storage class"); + error("multiple storage classes in declaration specifiers"); + scw &= ~scwx; + } + if (level == LVL.local && + scw & (SCW.x_Thread_local) && scw & (SCW.xinline | SCW.x_Noreturn)) + { + error("`inline` and `_Noreturn` function specifiers not allowed for `_Thread_local`"); scw &= ~scwx; } if (level & (LVL.parameter | LVL.prototype) && @@ -2964,7 +2972,8 @@ final class CParser(AST) : Parser!AST cparseGnuAttributes(specifier); if (specifier.mod & MOD.xconst) t = toConst(t); - auto param = new AST.Parameter(STC.parameter, t, id, null, null); + auto param = new AST.Parameter(specifiersToSTC(LVL.parameter, specifier), + t, id, null, null); parameters.push(param); if (token.value == TOK.rightParenthesis) break; @@ -4630,6 +4639,15 @@ final class CParser(AST) : Parser!AST stc = AST.STC.extern_ | AST.STC.gshared; else if (specifier.scw & SCW.xstatic) stc = AST.STC.gshared; + else if (specifier.scw & SCW.xregister) + stc = AST.STC.register; + } + else if (level == LVL.parameter) + { + if (specifier.scw & SCW.xregister) + stc = AST.STC.register | AST.STC.parameter; + else + stc = AST.STC.parameter; } else if (level == LVL.member) { @@ -5138,6 +5156,7 @@ final class CParser(AST) : Parser!AST if (!defines || defines.length < 10) // minimum length of a #define line return; const length = defines.length; + defines.writeByte(0); auto slice = defines.peekChars()[0 .. length]; resetDefineLines(slice); // reset lexer @@ -5234,12 +5253,15 @@ final class CParser(AST) : Parser!AST } skipToNextLine(); } - else if (n.value != TOK.endOfLine) + else { - skipToNextLine(); + scan(&n); + if (n.value != TOK.endOfLine) + { + skipToNextLine(); + } } nextDefineLine(); - assert(p - slice.ptr <= length); } } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index bb0feb642bd..ffb33d379db 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -656,23 +656,46 @@ extern (C++) final class TupleDeclaration : Declaration override bool needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects.dim; i++) + return isexp ? foreachVar((s) { return s.needThis(); }) != 0 : false; + } + + /*********************************************************** + * Calls dg(Dsymbol) for each Dsymbol, which should be a VarDeclaration + * inside VarExp (isexp == true). + * Params: + * dg = delegate to call for each Dsymbol + */ + extern (D) void foreachVar(scope void delegate(Dsymbol) dg) + { + assert(isexp); + foreach (o; *objects) { - RootObject o = (*objects)[i]; - if (o.dyncast() == DYNCAST.expression) - { - Expression e = cast(Expression)o; - if (DsymbolExp ve = e.isDsymbolExp()) - { - Declaration d = ve.s.isDeclaration(); - if (d && d.needThis()) - { - return true; - } - } - } + if (auto e = o.isExpression()) + if (auto ve = e.isVarExp()) + dg(ve.var); } - return false; + } + + /*********************************************************** + * Calls dg(Dsymbol) for each Dsymbol, which should be a VarDeclaration + * inside VarExp (isexp == true). + * If dg returns !=0, stops and returns that value else returns 0. + * Params: + * dg = delegate to call for each Dsymbol + * Returns: + * last value returned by dg() + */ + extern (D) int foreachVar(scope int delegate(Dsymbol) dg) + { + assert(isexp); + foreach (o; *objects) + { + if (auto e = o.isExpression()) + if (auto ve = e.isVarExp()) + if(auto ret = dg(ve.var)) + return ret; + } + return 0; } override inout(TupleDeclaration) isTupleDeclaration() inout @@ -1142,15 +1165,7 @@ extern (C++) class VarDeclaration : Declaration // If this variable was really a tuple, set the offsets for the tuple fields TupleDeclaration v2 = aliassym.isTupleDeclaration(); assert(v2); - for (size_t i = 0; i < v2.objects.dim; i++) - { - RootObject o = (*v2.objects)[i]; - assert(o.dyncast() == DYNCAST.expression); - Expression e = cast(Expression)o; - assert(e.op == EXP.dSymbol); - DsymbolExp se = e.isDsymbolExp(); - se.s.setFieldOffset(ad, fieldState, isunion); - } + v2.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); return; } diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index bb25210019f..5841a252454 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -2306,16 +2306,12 @@ public: result = null; // Reserve stack space for all tuple members - if (!td.objects) - return; - foreach (o; *td.objects) + td.foreachVar((s) { - Expression ex = isExpression(o); - DsymbolExp ds = ex ? ex.isDsymbolExp() : null; - VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null; + VarDeclaration v2 = s.isVarDeclaration(); assert(v2); if (v2.isDataseg() && !v2.isCTFE()) - continue; + return 0; ctfeGlobals.stack.push(v2); if (v2._init) @@ -2325,7 +2321,7 @@ public: { einit = interpretRegion(ie.exp, istate, goal); if (exceptionOrCant(einit)) - return; + return 1; } else if (v2._init.isVoidInitializer()) { @@ -2335,11 +2331,12 @@ public: { e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); result = CTFEExp.cantexp; - return; + return 1; } setValue(v2, einit); } - } + return 0; + }); return; } if (v.isStatic()) diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 76042969b9b..25794e2c21d 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -371,10 +371,20 @@ public: if (ta.isnogc) buf.writestring("Ni"); - if (ta.isreturn && !ta.isreturninferred) - buf.writestring("Nj"); - else if (ta.isScopeQual && !ta.isscopeinferred) - buf.writestring("Nl"); + // `return scope` must be in that order + if (ta.isreturnscope && !ta.isreturninferred) + { + buf.writestring("NjNl"); + } + else + { + // when return ref, the order is `scope return` + if (ta.isScopeQual && !ta.isscopeinferred) + buf.writestring("Nl"); + + if (ta.isreturn && !ta.isreturninferred) + buf.writestring("Nj"); + } if (ta.islive) buf.writestring("Nm"); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 7fd47818759..11a51f10e99 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -647,7 +647,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else ti = dsym._init ? dsym._init.syntaxCopy() : null; - StorageClass storage_class = STC.temp | STC.local | dsym.storage_class; + StorageClass storage_class = STC.temp | dsym.storage_class; if ((dsym.storage_class & STC.parameter) && (arg.storageClass & STC.parameter)) storage_class |= arg.storageClass; auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class); @@ -656,15 +656,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor v.dsymbolSemantic(sc); - if (sc.scopesym) - { - //printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars()); - if (sc.scopesym.members) - // Note this prevents using foreach() over members, because the limits can change - sc.scopesym.members.push(v); - } - - Expression e = new DsymbolExp(dsym.loc, v); + Expression e = new VarExp(dsym.loc, v); (*exps)[i] = e; } auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps); @@ -728,6 +720,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else if (!dsym.type.hasPointers()) { dsym.storage_class &= ~STC.scope_; // silently ignore; may occur in generic code + // https://issues.dlang.org/show_bug.cgi?id=23168 + if (dsym.storage_class & STC.returnScope) + { + dsym.storage_class &= ~(STC.return_ | STC.returnScope); + } } } @@ -3208,10 +3205,19 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc |= STC.scope_; // If 'this' has no pointers, remove 'scope' as it has no meaning + // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`, + // but existing code relies on `hasPointers()` being called here to resolve forward references: + // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) { sc.stc &= ~STC.scope_; tf.isScopeQual = false; + if (tf.isreturnscope) + { + sc.stc &= ~(STC.return_ | STC.returnScope); + tf.isreturn = false; + tf.isreturnscope = false; + } } sc.linkage = funcdecl._linkage; @@ -6840,7 +6846,12 @@ bool determineFields(AggregateDeclaration ad) return 1; if (v.aliassym) - return 0; // If this variable was really a tuple, skip it. + { + // If this variable was really a tuple, process each element. + if (auto tup = v.aliassym.isTupleDeclaration()) + return tup.foreachVar(tv => tv.apply(&func, ad)); + return 0; + } if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter)) return 0; diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 9afcc7fe687..c570068f7d6 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -873,7 +873,11 @@ public: // Tuple field are expanded into multiple VarDeclarations // (we'll visit them later) if (vd.type && vd.type.isTypeTuple()) + { + assert(vd.aliassym); + vd.toAlias().accept(this); return; + } if (vd.originalType && vd.type == AST.Type.tsize_t) origType = vd.originalType; @@ -1263,41 +1267,38 @@ public: size_t varCount; bool first = true; buf.level++; - foreach (m; *sd.members) + foreach (vd; sd.fields) { - if (auto vd = m.isVarDeclaration()) - { - if (!memberField(vd)) - continue; - varCount++; + if (!memberField(vd) || vd.overlapped) + continue; + varCount++; - if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && - !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) - { - continue; - } - if (vd._init && vd._init.isVoidInitializer()) - continue; + if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && + !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) + { + continue; + } + if (vd._init && vd._init.isVoidInitializer()) + continue; - if (first) - { - buf.writestringln(" :"); - first = false; - } - else - { - buf.writestringln(","); - } - writeIdentifier(vd, true); - buf.writeByte('('); + if (first) + { + buf.writestringln(" :"); + first = false; + } + else + { + buf.writestringln(","); + } + writeIdentifier(vd, true); + buf.writeByte('('); - if (vd._init) - { - auto e = AST.initializerToExpression(vd._init); - printExpressionFor(vd.type, e, true); - } - buf.printf(")"); + if (vd._init) + { + auto e = AST.initializerToExpression(vd._init); + printExpressionFor(vd.type, e, true); } + buf.printf(")"); } buf.level--; buf.writenl(); @@ -1308,49 +1309,43 @@ public: { buf.printf("%s(", sd.ident.toChars()); first = true; - foreach (m; *sd.members) + foreach (vd; sd.fields) { - if (auto vd = m.isVarDeclaration()) + if (!memberField(vd) || vd.overlapped) + continue; + if (!first) + buf.writestring(", "); + assert(vd.type); + assert(vd.ident); + typeToBuffer(vd.type, vd, true); + // Don't print default value for first parameter to not clash + // with the default ctor defined above + if (!first) { - if (!memberField(vd)) - continue; - if (!first) - buf.writestring(", "); - assert(vd.type); - assert(vd.ident); - typeToBuffer(vd.type, vd, true); - // Don't print default value for first parameter to not clash - // with the default ctor defined above - if (!first) - { - buf.writestring(" = "); - printExpressionFor(vd.type, findDefaultInitializer(vd)); - } - first = false; + buf.writestring(" = "); + printExpressionFor(vd.type, findDefaultInitializer(vd)); } + first = false; } buf.writestring(") :"); buf.level++; buf.writenl(); first = true; - foreach (m; *sd.members) + foreach (vd; sd.fields) { - if (auto vd = m.isVarDeclaration()) - { - if (!memberField(vd)) - continue; - - if (first) - first = false; - else - buf.writestringln(","); - - writeIdentifier(vd, true); - buf.writeByte('('); - writeIdentifier(vd, true); - buf.writeByte(')'); - } + if (!memberField(vd) || vd.overlapped) + continue; + + if (first) + first = false; + else + buf.writestringln(","); + + writeIdentifier(vd, true); + buf.writeByte('('); + writeIdentifier(vd, true); + buf.writeByte(')'); } buf.writenl(); buf.writestringln("{}"); @@ -1663,6 +1658,13 @@ public: assert(false, "This node type should be handled in the EnumDeclaration"); } + override void visit(AST.TupleDeclaration tup) + { + debug (Debug_DtoH) mixin(traceVisit!tup); + + tup.foreachVar((s) { s.accept(this); }); + } + /** * Prints a member/parameter/variable declaration into `buf`. * diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index ceecf4b5e74..397a41b33b7 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -348,14 +348,16 @@ int expandAliasThisTuples(Expressions* exps, size_t starti = 0) if (TupleDeclaration td = exp.isAliasThisTuple) { exps.remove(u); - foreach (i, o; *td.objects) + size_t i; + td.foreachVar((s) { - auto d = o.isExpression().isDsymbolExp().s.isDeclaration(); + auto d = s.isDeclaration(); auto e = new DotVarExp(exp.loc, exp, d); assert(d.type); e.type = d.type; exps.insert(u + i, e); - } + ++i; + }); version (none) { printf("expansion ->\n"); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index dcc5b5095ed..99e003b1856 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -6004,10 +6004,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); se = se.toUTF8(sc); - auto namez = se.toStringz().ptr; + auto namez = se.toStringz(); if (!global.filePath) { - e.error("need `-J` switch to import text file `%s`", namez); + e.error("need `-J` switch to import text file `%s`", namez.ptr); return setError(); } @@ -6036,8 +6036,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - auto name = FileName.searchPath(global.filePath, namez, false); - if (!name) + auto resolvedNamez = FileName.searchPath(global.filePath, namez, false); + if (!resolvedNamez) { e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); e.errorSupplemental("Path(s) searched (as provided by `-J`):"); @@ -6051,11 +6051,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - sc._module.contentImportedFiles.push(name); + sc._module.contentImportedFiles.push(resolvedNamez.ptr); if (global.params.verbose) { const slice = se.peekString(); - message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, name); + message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr); } if (global.params.moduleDeps.buffer !is null) { @@ -6072,27 +6072,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ob.writestring("string : "); ob.write(se.peekString()); ob.writestring(" ("); - escapePath(ob, name); + escapePath(ob, resolvedNamez.ptr); ob.writestring(")"); ob.writenl(); } if (global.params.makeDeps.doOutput) { - global.params.makeDeps.files.push(name); + global.params.makeDeps.files.push(resolvedNamez.ptr); } { - auto fileName = FileName(name.toDString); + auto fileName = FileName(resolvedNamez); if (auto fmResult = global.fileManager.lookup(fileName)) { se = new StringExp(e.loc, fmResult); } else { - auto readResult = File.read(name.toDString); + auto readResult = File.read(resolvedNamez); if (!readResult.success) { - e.error("cannot read file `%s`", name); + e.error("cannot read file `%s`", resolvedNamez.ptr); return setError(); } else @@ -6963,18 +6963,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.error("cannot take address of `%s`", exp.e1.toChars()); return setError(); } - if (auto dve = exp.e1.isDotVarExp()) - { - /* https://issues.dlang.org/show_bug.cgi?id=22749 - * Error about taking address of any bit-field, regardless of - * whether SCOPE.Cfile is set. - */ - if (auto bf = dve.var.isBitFieldDeclaration()) - { - exp.error("cannot take address of bit-field `%s`", bf.toChars()); - return setError(); - } - } + if (!checkAddressable(exp, sc)) + return setError(); bool hasOverloads; if (auto f = isFuncAddress(exp, &hasOverloads)) @@ -8323,6 +8313,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor t1b = t1b.castMod(tv1.mod); exp.e1.type = t1b; } + if (t1b.ty == Tsarray || t1b.ty == Tarray) + { + if (!checkAddressable(exp, sc)) + return setError(); + } /* Run semantic on e2 */ @@ -13152,6 +13147,69 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) return true; } +/************************************** + * This check ensures that the object in `exp` can have its address taken, or + * issue a diagnostic error. + * Params: + * e = expression to check + * sc = context + * Returns: + * true if the expression is addressable + */ +bool checkAddressable(Expression e, Scope* sc) +{ + Expression ex = e; + while (true) + { + switch (ex.op) + { + case EXP.dotVariable: + // https://issues.dlang.org/show_bug.cgi?id=22749 + // Error about taking address of any bit-field, regardless of + // whether SCOPE.Cfile is set. + if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration()) + { + e.error("cannot take address of bit-field `%s`", bf.toChars()); + return false; + } + goto case EXP.cast_; + + case EXP.index: + ex = ex.isBinExp().e1; + continue; + + case EXP.address: + case EXP.array: + case EXP.cast_: + ex = ex.isUnaExp().e1; + continue; + + case EXP.variable: + if (sc.flags & SCOPE.Cfile) + { + // C11 6.5.3.2: A variable that has its address taken cannot be + // stored in a register. + // C11 6.3.2.1: An array that has its address computed with `[]` + // or cast to an lvalue pointer cannot be stored in a register. + if (ex.isVarExp().var.storage_class & STC.register) + { + if (e.isIndexExp()) + e.error("cannot index through register variable `%s`", ex.toChars()); + else + e.error("cannot take address of register variable `%s`", ex.toChars()); + return false; + } + } + break; + + default: + break; + } + break; + } + return true; +} + /******************************* * Checks the attributes of a function. diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index 53ed62efd70..63281b5760c 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -75,19 +75,7 @@ void foreachVar(Expression e, void delegate(VarDeclaration) dgVar) if (!v) return; if (TupleDeclaration td = v.toAlias().isTupleDeclaration()) - { - if (!td.objects) - return; - foreach (o; *td.objects) - { - Expression ex = isExpression(o); - DsymbolExp s = ex ? ex.isDsymbolExp() : null; - assert(s); - VarDeclaration v2 = s.s.isVarDeclaration(); - assert(v2); - dgVar(v2); - } - } + td.foreachVar((s) { dgVar(s.isVarDeclaration()); }); else dgVar(v); Dsymbol s = v.toAlias(); diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index bcfbd9a122c..afec5ef1ead 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -81,10 +81,14 @@ Expression arrayFuncConv(Expression e, Scope* sc) auto t = e.type.toBasetype(); if (auto ta = t.isTypeDArray()) { + if (!checkAddressable(e, sc)) + return ErrorExp.get(); e = e.castTo(sc, ta.next.pointerTo()); } else if (auto ts = t.isTypeSArray()) { + if (!checkAddressable(e, sc)) + return ErrorExp.get(); e = e.castTo(sc, ts.next.pointerTo()); } else if (t.isTypeFunction()) diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 121a266b428..5ff73c983f0 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -1407,16 +1407,7 @@ void genKill(ref ObState obstate, ObNode* ob) } else if (auto td = s.isTupleDeclaration()) { - foreach (o; *td.objects) - { - if (auto eo = o.isExpression()) - { - if (auto se = eo.isDsymbolExp()) - { - Dsymbol_visit(se.s); - } - } - } + td.foreachVar(&Dsymbol_visit); } } @@ -2107,16 +2098,7 @@ void checkObErrors(ref ObState obstate) } else if (auto td = s.isTupleDeclaration()) { - foreach (o; *td.objects) - { - if (auto eo = o.isExpression()) - { - if (auto se = eo.isDsymbolExp()) - { - Dsymbol_visit(se.s); - } - } - } + td.foreachVar(&Dsymbol_visit); } } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index eb5e6942948..4e3fd533c18 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -5877,7 +5877,8 @@ LagainStc: { if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null)) goto Ldeclaration; - if (peekNext() == TOK.leftParenthesis) + const tv = peekNext(); + if (tv == TOK.leftParenthesis) { // mixin(string) AST.Expression e = parseAssignExp(); @@ -5893,6 +5894,14 @@ LagainStc: } break; } + else if (tv == TOK.template_) + { + // mixin template + nextToken(); + AST.Dsymbol d = parseTemplateDeclaration(true); + s = new AST.ExpStatement(loc, d); + break; + } AST.Dsymbol d = parseMixin(); s = new AST.ExpStatement(loc, d); if (flags & ParseStatementFlags.scope_) diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 3b7b75b0aff..226141d4608 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -734,16 +734,15 @@ nothrow: * Returns: * index of the first reserved character in path if found, size_t.max otherwise */ - extern (D) static size_t findReservedChar(const(char)* name) pure @nogc + extern (D) static size_t findReservedChar(const(char)[] name) pure @nogc @safe { version (Windows) { - size_t idx = 0; // According to https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions // the following characters are not allowed in path: < > : " | ? * - for (const(char)* p = name; *p; p++, idx++) + foreach (idx; 0 .. name.length) { - char c = *p; + char c = name[idx]; if (c == '<' || c == '>' || c == ':' || c == '"' || c == '|' || c == '?' || c == '*') { return idx; @@ -784,21 +783,21 @@ nothrow: * Returns: * true if path contains '..' reference to parent directory */ - extern (D) static bool refersToParentDir(const(char)* name) pure @nogc + extern (D) static bool refersToParentDir(const(char)[] name) pure @nogc @safe { - if (name[0] == '.' && name[1] == '.' && (!name[2] || isDirSeparator(name[2]))) + size_t s = 0; + foreach (i; 0 .. name.length) { - return true; - } - - for (const(char)* p = name; *p; p++) - { - char c = *p; - if (isDirSeparator(c) && p[1] == '.' && p[2] == '.' && (!p[3] || isDirSeparator(p[3]))) + if (isDirSeparator(name[i])) { - return true; + if (name[s..i] == "..") + return true; + s = i + 1; } } + if (name[s..$] == "..") + return true; + return false; } unittest diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 73dcaa6c960..bf18a2140fb 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -677,6 +677,11 @@ private extern(C++) final class Semantic2Visitor : Visitor { visit(cast(AggregateDeclaration) cd); } + + override void visit(TupleDeclaration td) + { + td.foreachVar((s) { s.accept(this); }); + } } /** diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index a056c99b11e..c5d7667fefc 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -483,7 +483,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_)) stc |= STC.maybescope; - stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope); + stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope | STC.register); v.storage_class = stc; v.dsymbolSemantic(sc2); if (!sc2.insert(v)) diff --git a/gcc/d/types.cc b/gcc/d/types.cc index b706c91560e..38cc7f5111c 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -392,10 +392,10 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) RootObject *ro = (*td->objects)[j]; gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION); Expression *e = (Expression *) ro; - gcc_assert (e->op == EXP::dSymbol); - DsymbolExp *se = e->isDsymbolExp (); + gcc_assert (e->op == EXP::variable); + VarExp *ve = e->isVarExp (); - tmembers.push (se->s); + tmembers.push (ve->var); } fields += layout_aggregate_members (&tmembers, context, diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d index 20134f5b449..a4c6ce4ce2c 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d @@ -61,9 +61,21 @@ struct S final int32_t innerPrivate; int32_t innerBar; }; - S() + S() : + y(), + z(), + outerPrivate(), + innerPrivate(), + innerBar() { } + S(int32_t y, double z = NAN, int32_t outerPrivate = 0, int32_t innerPrivate = 0, int32_t innerBar = 0) : + y(y), + z(z), + outerPrivate(outerPrivate), + innerPrivate(innerPrivate), + innerBar(innerBar) + {} }; extern void foo(); diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d index 8c7ba9be672..2e36c7d02be 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d @@ -173,12 +173,16 @@ struct A final A() : a(), - s() + s(), + x(), + y() { } - A(int32_t a, S s = S()) : + A(int32_t a, S s = S(), int32_t x = 0, int32_t y = 0) : a(a), - s(s) + s(s), + x(x), + y(y) {} }; @@ -196,11 +200,13 @@ private: char smallarray[1$?:32=u|64=LLU$]; public: Array() : - length() + length(), + data() { } - Array(uint32_t length) : - length(length) + Array(uint32_t length, _d_dynamicArray< char > data = {}) : + length(length), + data(data) {} }; diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d index 1e2be909e75..1ed63180dda 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d @@ -219,9 +219,13 @@ struct ImportedBuffer final { typedef ActualBuffer Buffer; ActualBuffer buffer2; - ImportedBuffer() + ImportedBuffer() : + buffer2() { } + ImportedBuffer(ActualBuffer buffer2) : + buffer2(buffer2) + {} }; --- */ diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d index 10967c83137..fda9efa5d34 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d @@ -64,9 +64,15 @@ struct HasMangleMember final int32_t someAttrC; int32_t someAttrCpp; void hasDefaultVar(int32_t i = someAttrC); - HasMangleMember() + HasMangleMember() : + someAttrC(), + someAttrCpp() { } + HasMangleMember(int32_t someAttrC, int32_t someAttrCpp = 0) : + someAttrC(someAttrC), + someAttrCpp(someAttrCpp) + {} }; extern "C" void hasDefaultVar(int32_t i = someVarC); diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d index 3fd54c7de74..dc07c7b8f8b 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d @@ -50,9 +50,21 @@ protected: private: int32_t e; public: - S1() + S1() : + a(), + b(), + c(), + d(), + e() { } + S1(int32_t a, int32_t b = 0, int32_t c = 0, int32_t d = 0, int32_t e = 0) : + a(a), + b(b), + c(c), + d(d), + e(e) + {} }; class S2 final @@ -102,10 +114,12 @@ public: public: int32_t publicInner; PublicInnerStruct() : + privateInner(), publicInner() { } - PublicInnerStruct(int32_t publicInner) : + PublicInnerStruct(int32_t privateInner, int32_t publicInner = 0) : + privateInner(privateInner), publicInner(publicInner) {} }; @@ -118,10 +132,12 @@ private: public: int32_t publicInner; PrivateInnerClass() : + privateInner(), publicInner() { } - PrivateInnerClass(int32_t publicInner) : + PrivateInnerClass(int32_t privateInner, int32_t publicInner = 0) : + privateInner(privateInner), publicInner(publicInner) {} }; @@ -142,9 +158,13 @@ private: public: typedef PrivateInnerEnum PublicAlias; - Outer() + Outer() : + privateOuter() { } + Outer(int32_t privateOuter) : + privateOuter(privateOuter) + {} }; --- */ diff --git a/gcc/testsuite/gdc.test/compilable/test23168.d b/gcc/testsuite/gdc.test/compilable/test23168.d new file mode 100644 index 00000000000..61a4ff3b6dc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23168.d @@ -0,0 +1,30 @@ +// https://issues.dlang.org/show_bug.cgi?id=23168 +// Issue 23168 - [DIP1000] return scope wrongly rewritten for structs with no indirections + +@safe: +struct Ptr +{ + int* fun() return scope { return null; } +} + +int* funf(ref return scope Ptr p) { return null; } + +int* use() +{ + Ptr ptr; + return ptr.fun; + return funf(ptr); +} + +// Prevent forward reference 'regression' +// See https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 +struct S +{ + void f() scope {} + alias x = _get_value; + + static if (true) + int _get_value() {return 3;} + else + int _get_value() {return 4;} +} diff --git a/gcc/testsuite/gdc.test/compilable/test23169.d b/gcc/testsuite/gdc.test/compilable/test23169.d new file mode 100644 index 00000000000..6237661a923 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23169.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=23169 +// Issue 23169 - [DIP1000] Mangling does not distinguish return and return scope + +struct Ptr +{ + int* impl; + void* fun0() return scope {return impl;} + void* fun1() scope return {return impl;} + void* fun2() return {return &this;} +} + +static assert(Ptr.fun0.mangleof == "_D9test231693Ptr4fun0MFNjNlZPv"); +static assert(Ptr.fun1.mangleof == "_D9test231693Ptr4fun1MFNlNjZPv"); +static assert(Ptr.fun2.mangleof == "_D9test231693Ptr4fun2MFNjZPv"); diff --git a/gcc/testsuite/gdc.test/compilable/testparse.d b/gcc/testsuite/gdc.test/compilable/testparse.d index 99378a9df53..cef1575e901 100644 --- a/gcc/testsuite/gdc.test/compilable/testparse.d +++ b/gcc/testsuite/gdc.test/compilable/testparse.d @@ -191,3 +191,13 @@ void test22019() break; } } + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=23205 + +void test23205() +{ + mixin template tpl() { int x; } + mixin tpl!(); + x = 123; +} diff --git a/gcc/testsuite/gdc.test/runnable/test23010.d b/gcc/testsuite/gdc.test/runnable/test23010.d new file mode 100644 index 00000000000..1cbacfc9279 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23010.d @@ -0,0 +1,43 @@ +// https://issues.dlang.org/show_bug.cgi?id=23010 + +alias AliasSeq(T...) = T; + +mixin template faz() { + alias T = AliasSeq!(int); + T bar = 12345; + + void write1() { + assert(bar[0] == 12345); + } + + AliasSeq!(string, float) foo = AliasSeq!("qwerty", 1.25f); + + void write2() { + assert(foo == AliasSeq!("qwerty", 1.25f)); + foo = AliasSeq!("asdfg", 2.5f); // this even crashed before + assert(foo == AliasSeq!("asdfg", 2.5f)); + } +} + +void main() { + mixin faz!(); + write1; + write2; + fun; +} + +// Testing static symbol generation ('toobj.d' changes) + +static AliasSeq!(int, string) tup; + +void fun() +{ + auto v = tup; + + struct S(T...) { + static T b; + } + + alias T = S!(int, float); + auto p = T.b; +} diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 3f4a0ec63e3..2fc1bc1cf6a 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -e150cca179515ce5113e828aac94c20c0b983b7c +148608b7935c3f9a4ea3a26f74cb90cd07efc91c The first line of this file holds the git revision number of the last merge done from the dlang/druntime repository.