From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1873) id 633CE3858C60; Mon, 20 Dec 2021 18:33:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 633CE3858C60 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="utf-8" From: Iain Buclaw To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-6079] d: Merge upstream dmd ad8412530, druntime fd9a4544, phobos 495e835c2. X-Act-Checkin: gcc X-Git-Author: Iain Buclaw X-Git-Refname: refs/heads/master X-Git-Oldrev: 7d5d5032c7200714388db63c7a5676b6ab3e040e X-Git-Newrev: b3f58f87d78b958e35e4a44f5fdb4b7721cb2837 Message-Id: <20211220183342.633CE3858C60@sourceware.org> Date: Mon, 20 Dec 2021 18:33:42 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Dec 2021 18:33:42 -0000 https://gcc.gnu.org/g:b3f58f87d78b958e35e4a44f5fdb4b7721cb2837 commit r12-6079-gb3f58f87d78b958e35e4a44f5fdb4b7721cb2837 Author: Iain Buclaw Date: Mon Dec 20 19:25:32 2021 +0100 d: Merge upstream dmd ad8412530, druntime fd9a4544, phobos 495e835c2. D front-end changes: - Import dmd v2.098.1 - Remove calling of _d_delstruct from code generator. Druntime changes: - Import druntime v2.098.1 Phobos changes: - Import phobos v2.098.1 gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd ad8412530. * expr.cc (ExprVisitor::visit (DeleteExp *)): Remove code generation of _d_delstruct. * runtime.def (DELSTRUCT): Remove. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime fd9a4544. * src/MERGE: Merge upstream phobos 495e835c2. Diff: --- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/canthrow.d | 16 ++ gcc/d/dmd/dcast.d | 73 ++++----- gcc/d/dmd/dinterpret.d | 41 +++++ gcc/d/dmd/dsymbol.d | 16 +- gcc/d/dmd/dsymbolsem.d | 24 ++- gcc/d/dmd/expressionsem.d | 26 ++- gcc/d/dmd/id.d | 3 + gcc/d/dmd/initsem.d | 106 ++++++------ gcc/d/dmd/nogc.d | 14 ++ gcc/d/dmd/semantic3.d | 3 +- gcc/d/dmd/tokens.d | 26 +-- gcc/d/dmd/tokens.h | 11 +- gcc/d/dmd/typesem.d | 178 ++++++++++----------- gcc/d/expr.cc | 12 +- gcc/d/runtime.def | 2 - gcc/testsuite/gdc.test/compilable/test22593.d | 13 ++ gcc/testsuite/gdc.test/fail_compilation/ice17074.d | 12 +- .../gdc.test/fail_compilation/test22593.d | 23 +++ libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/builtins.d | 48 +++++- libphobos/libdruntime/core/lifetime.d | 20 +-- libphobos/libdruntime/core/sys/linux/sched.d | 3 + libphobos/libdruntime/object.d | 30 +++- libphobos/src/MERGE | 2 +- libphobos/src/std/format/write.d | 23 +++ libphobos/src/std/range/interfaces.d | 9 ++ libphobos/src/std/typecons.d | 2 +- 28 files changed, 468 insertions(+), 272 deletions(-) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index d7eff4ffd2f..b42576c2ce6 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -93108bb9ea6216d67fa97bb4842fb59f26f6bfc7 +ad8412530e607ffebec36f2dbdff1a6f2798faf7 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 b67a9d14dd4..b1877151c88 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -82,6 +82,22 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow if (global.errors && !ce.e1.type) return; // error recovery + + import dmd.id : Id; + + if (ce.f && ce.f.ident == Id._d_delstruct) + { + // Only check if the dtor throws. + Type tb = (*ce.arguments)[0].type.toBasetype(); + auto ts = tb.nextOf().baseElemOf().isTypeStruct(); + if (ts) + { + auto sd = ts.sym; + if (sd.dtor) + checkFuncThrows(ce, sd.dtor); + } + } + /* If calling a function or delegate that is typed as nothrow, * then this expression cannot throw. * Note that pure functions can throw. diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 2e5a79d0feb..a572a1ff6e0 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1565,9 +1565,9 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) result = e; return; } - if (e.op == EXP.variable) + if (auto ve = e.isVarExp()) { - VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); + VarDeclaration v = ve.var.isVarDeclaration(); if (v && v.storage_class & STC.manifest) { result = e.ctfeInterpret(); @@ -1852,8 +1852,8 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) override void visit(StructLiteralExp e) { visit(cast(Expression)e); - if (result.op == EXP.structLiteral) - (cast(StructLiteralExp)result).stype = t; // commit type + if (auto sle = result.isStructLiteralExp()) + sle.stype = t; // commit type } override void visit(StringExp e) @@ -1866,7 +1866,8 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed); - if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) + if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid && + (!sc || !(sc.flags & SCOPE.Cfile))) { e.error("cannot convert string literal to `void*`"); result = ErrorExp.get(); @@ -1883,7 +1884,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (!e.committed) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); se.committed = 1; copied = 1; } @@ -1908,7 +1909,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { if (!copied) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); copied = 1; } se.type = t; @@ -1924,7 +1925,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) */ if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); d_uns64 szx = tb.nextOf().size(); assert(szx <= 255); se.sz = cast(ubyte)szx; @@ -1952,7 +1953,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { if (!copied) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); copied = 1; } return lcast(); @@ -1961,7 +1962,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { if (!copied) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); copied = 1; } return lcast(); @@ -1977,7 +1978,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { if (!copied) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); copied = 1; } if (tb.ty == Tsarray) @@ -2088,7 +2089,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) L1: if (!copied) { - se = cast(StringExp)e.copy(); + se = e.copy().isStringExp(); copied = 1; } @@ -2154,10 +2155,10 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } // Look for pointers to functions where the functions are overloaded. - if (e.e1.op == EXP.overloadSet && + if (e.e1.isOverExp() && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { - OverExp eo = cast(OverExp)e.e1; + OverExp eo = e.e1.isOverExp(); FuncDeclaration f = null; for (size_t i = 0; i < eo.vars.a.dim; i++) { @@ -2188,11 +2189,11 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } } - if (e.e1.op == EXP.variable && + if (e.e1.isVarExp() && typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && tb.ty == Tpointer && tb.nextOf().ty == Tfunction) { - auto ve = cast(VarExp)e.e1; + auto ve = e.e1.isVarExp(); auto f = ve.var.isFuncDeclaration(); if (f) { @@ -2303,7 +2304,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) goto L1; } - ae = cast(ArrayLiteralExp)e.copy(); + ae = e.copy().isArrayLiteralExp(); if (e.basis) ae.basis = e.basis.castTo(sc, tb.nextOf()); ae.elements = e.elements.copy(); @@ -2325,7 +2326,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) Type tp = typeb.nextOf().pointerTo(); if (!tp.equals(ae.type)) { - ae = cast(ArrayLiteralExp)e.copy(); + ae = e.copy().isArrayLiteralExp(); ae.type = tp; } } @@ -2382,7 +2383,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (tb.ty == Taarray && typeb.ty == Taarray && tb.nextOf().toBasetype().ty != Tvoid) { - AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e.copy(); + AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp(); ae.keys = e.keys.copy(); ae.values = e.values.copy(); assert(e.keys.dim == e.values.dim); @@ -2422,7 +2423,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { result = e.copy(); result.type = t; - (cast(SymOffExp)result).hasOverloads = false; + result.isSymOffExp().hasOverloads = false; return; } @@ -2641,7 +2642,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { Expression e1x = e.e1.implicitCastTo(sc, t1b); assert(e1x.op != EXP.error); - e = cast(SliceExp)e.copy(); + e = e.copy().isSliceExp(); e.e1 = e1x; e.type = t; result = e; @@ -2751,10 +2752,10 @@ Expression inferType(Expression e, Type t, int flag = 0) if (t) switch (e.op) { - case EXP.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e); - case EXP.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e); - case EXP.function_: return visitFun(cast(FuncExp) e); - case EXP.question: return visitTer(cast(CondExp) e); + case EXP.arrayLiteral: return visitAle(e.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAar(e.isAssocArrayLiteralExp()); + case EXP.function_: return visitFun(e.isFuncExp()); + case EXP.question: return visitTer(e.isCondExp()); default: } return e; @@ -2830,9 +2831,9 @@ Expression scaleFactor(BinExp be, Scope* sc) */ private bool isVoidArrayLiteral(Expression e, Type other) { - while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1)) + while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && (e.isArrayLiteralExp().elements.dim == 1)) { - auto ale = cast(ArrayLiteralExp)e; + auto ale = e.isArrayLiteralExp(); e = ale[0]; if (other.ty == Tsarray || other.ty == Tarray) other = other.nextOf(); @@ -2842,7 +2843,7 @@ private bool isVoidArrayLiteral(Expression e, Type other) if (other.ty != Tsarray && other.ty != Tarray) return false; Type t = e.type; - return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0); + return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && e.isArrayLiteralExp().elements.dim == 0); } /** @@ -3463,20 +3464,20 @@ LmodCompare: Expression rhs = e2; // T[x .. y] op ? - if (e1.isSliceExp()) - lhs = new IndexExp(Loc.initial, (cast(UnaExp)e1).e1, IntegerExp.literal!0); + if (auto se1 = e1.isSliceExp()) + lhs = new IndexExp(Loc.initial, se1.e1, IntegerExp.literal!0); // [t1, t2, .. t3] op ? - if (e1.isArrayLiteralExp()) - lhs = (cast(ArrayLiteralExp)e1).opIndex(0); + if (auto ale1 = e1.isArrayLiteralExp()) + lhs = ale1.opIndex(0); // ? op U[z .. t] - if (e2.isSliceExp()) - rhs = new IndexExp(Loc.initial, (cast(UnaExp)e2).e1, IntegerExp.literal!0); + if (auto se2 = e2.isSliceExp()) + rhs = new IndexExp(Loc.initial, se2.e1, IntegerExp.literal!0); // ? op [u1, u2, .. u3] - if (e2.isArrayLiteralExp()) - rhs = (cast(ArrayLiteralExp)e2).opIndex(0); + if (auto ale2 = e2.isArrayLiteralExp()) + rhs = ale2.opIndex(0); // create a new binary expression with the new lhs and rhs (at this stage, at least // one of lhs/rhs has been replaced with the 0'th element of the array it was before) diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 8f20c38f6f1..fc5b9a8843b 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -4837,6 +4837,47 @@ public: result = interpret(ce, istate); return; } + else if (fd.ident == Id._d_delstruct) + { + // Only interpret the dtor and the argument. + assert(e.arguments.dim == 1); + + Type tb = (*e.arguments)[0].type.toBasetype(); + auto ts = tb.nextOf().baseElemOf().isTypeStruct(); + if (ts) + { + result = interpretRegion((*e.arguments)[0], istate); + if (exceptionOrCant(result)) + return; + + if (result.op == EXP.null_) + { + result = CTFEExp.voidexp; + return; + } + + if (result.op != EXP.address || + (cast(AddrExp)result).e1.op != EXP.structLiteral) + { + e.error("`delete` on invalid struct pointer `%s`", result.toChars()); + result = CTFEExp.cantexp; + return; + } + + auto sd = ts.sym; + if (sd.dtor) + { + auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1; + result = interpretFunction(pue, sd.dtor, istate, null, sle); + if (exceptionOrCant(result)) + return; + + result = CTFEExp.voidexp; + } + } + + return; + } } else if (auto soe = ecall.isSymOffExp()) { diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 0f75157f874..e34a94ad44b 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -2453,10 +2453,10 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (i1 && i2) return collision(); // can't both have initializers - if (i1) + if (i1) // vd is the definition { - vd2._init = vd._init; - vd._init = null; + sds.symtab.update(vd); // replace vd2 with the definition + return vd; } /* BUG: the types should match, which needs semantic() to be run on it @@ -2497,14 +2497,10 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (fd.fbody && fd2.fbody) return collision(); // can't both have bodies - if (fd.fbody) + if (fd.fbody) // fd is the definition { - fd2.fbody = fd.fbody; // transfer body to existing declaration - fd.fbody = null; - - auto tf = fd.type.toTypeFunction(); - auto tf2 = fd2.type.toTypeFunction(); - tf2.parameterList = tf.parameterList; // transfer parameter list. + sds.symtab.update(fd); // replace fd2 in symbol table with fd + return fd; } /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it. diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 3a9abd2d87e..118b861d059 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -3981,15 +3981,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; TypeFunction tf = ctd.type.toTypeFunction(); + immutable dim = tf.parameterList.length; + auto sd = ad.isStructDeclaration(); /* See if it's the default constructor * But, template constructor should not become a default constructor. */ if (ad && (!ctd.parent.isTemplateInstance() || ctd.parent.isTemplateMixin())) { - immutable dim = tf.parameterList.length; - - if (auto sd = ad.isStructDeclaration()) + if (sd) { if (dim == 0 && tf.parameterList.varargs == VarArg.none) // empty default ctor w/o any varargs { @@ -4034,6 +4034,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ad.defaultCtor = ctd; } } + // https://issues.dlang.org/show_bug.cgi?id=22593 + else if (auto ti = ctd.parent.isTemplateInstance()) + { + if (sd && sd.hasCopyCtor && (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) + { + auto param = tf.parameterList[0]; + + // if the template instance introduces an rvalue constructor + // between the members of a struct declaration, we should check if a + // copy constructor exists and issue an error in that case. + if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) + { + .error(ctd.loc, "Cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars); + .errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`", + ti.toChars(), sd.toChars()); + } + } + } } override void visit(PostBlitDeclaration pbd) diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 48e47cef250..2f1cd4767c5 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -7316,6 +7316,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead."); } + Expression e = exp; + if (Expression ex = unaSemantic(exp, sc)) { result = ex; @@ -7352,7 +7354,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (tb.ty == Tstruct) { ad = (cast(TypeStruct)tb).sym; - semanticTypeInfo(sc, tb); + + Identifier hook = global.params.tracegc ? Id._d_delstructTrace : Id._d_delstruct; + if (!verifyHookExist(exp.loc, *sc, Id._d_delstructImpl, "deleting struct with dtor", Id.object)) + return setError(); + + // Lower to .object._d_delstruct{,Trace}(exp.e1) + Expression id = new IdentifierExp(exp.loc, Id.empty); + id = new DotIdExp(exp.loc, id, Id.object); + + auto tiargs = new Objects(); + tiargs.push(exp.e1.type); + id = new DotTemplateInstanceExp(exp.loc, id, Id._d_delstructImpl, tiargs); + id = new DotIdExp(exp.loc, id, hook); + + e = new CallExp(exp.loc, id, exp.e1); + /* Gag errors generated by calls to `_d_delstruct`, because they display + * internal compiler information, which is unnecessary to the user. + */ + uint errors = global.startGagging(); + e = e.expressionSemantic(sc); + global.endGagging(errors); } break; @@ -7397,7 +7419,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (err) return setError(); - result = exp; + result = e; } override void visit(CastExp exp) diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 83c89c05fda..d33b676a032 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -311,6 +311,9 @@ immutable Msgtable[] msgtable = { "__ArrayPostblit" }, { "__ArrayDtor" }, { "_d_delThrowable" }, + { "_d_delstructImpl" }, + { "_d_delstruct" }, + { "_d_delstructTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 51ee27d00fe..826b0adebed 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -284,7 +284,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ case Tarray: break; case Tvector: - t = (cast(TypeVector)t).basetype; + t = t.isTypeVector().basetype; break; case Taarray: case Tstruct: // consider implicit constructor call @@ -346,7 +346,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ // found a tuple, expand it if (ei && ei.exp.op == EXP.tuple) { - TupleExp te = cast(TupleExp)ei.exp; + TupleExp te = ei.exp.isTupleExp(); i.index.remove(j); i.value.remove(j); for (size_t k = 0; k < te.exps.dim; ++k) @@ -462,7 +462,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { return i; // Failed, suppress duplicate error messages } - if (i.exp.type.ty == Ttuple && (cast(TypeTuple)i.exp.type).arguments.dim == 0) + if (i.exp.type.isTypeTuple() && i.exp.type.isTypeTuple().arguments.dim == 0) { Type et = i.exp.type; i.exp = new TupleExp(i.exp.loc, new Expressions()); @@ -492,12 +492,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ */ if (i.exp.op == EXP.string_ && tb.ty == Tsarray) { - StringExp se = cast(StringExp)i.exp; + StringExp se = i.exp.isStringExp(); Type typeb = se.type.toBasetype(); TY tynto = tb.nextOf().ty; if (!se.committed && (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && - se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) + se.numberOfCodeUnits(tynto) < tb.isTypeSArray().dim.toInteger()) { i.exp = se.castTo(sc, t); goto L1; @@ -520,7 +520,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ // Look for implicit constructor call if (tb.ty == Tstruct && !(ti.ty == Tstruct && tb.toDsymbol(sc) == ti.toDsymbol(sc)) && !i.exp.implicitConvTo(t)) { - StructDeclaration sd = (cast(TypeStruct)tb).sym; + StructDeclaration sd = tb.isTypeStruct().sym; if (sd.ctor) { // Rewrite as S().ctor(exp) @@ -573,18 +573,16 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ // better diagnostic message, as same as AssignExp::semantic. if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch) { - uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger(); + uinteger_t dim1 = tb.isTypeSArray().dim.toInteger(); uinteger_t dim2 = dim1; - if (i.exp.op == EXP.arrayLiteral) + if (auto ale = i.exp.isArrayLiteralExp()) { - ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp; dim2 = ale.elements ? ale.elements.dim : 0; } - else if (i.exp.op == EXP.slice) + else if (auto se = i.exp.isSliceExp()) { - Type tx = toStaticArrayType(cast(SliceExp)i.exp); - if (tx) - dim2 = (cast(TypeSArray)tx).dim.toInteger(); + if (Type tx = toStaticArrayType(se)) + dim2 = tx.isTypeSArray().dim.toInteger(); } if (dim1 != dim2) { @@ -746,10 +744,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ * Params: * t = element type * dim = max number of elements + * simple = true if array of simple elements * Returns: * # of elements in array */ - size_t array(Type t, size_t dim) + size_t array(Type t, size_t dim, ref bool simple) { //printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length); auto tn = t.nextOf().toBasetype(); @@ -791,14 +790,30 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (tnsa && di.initializer.isExpInitializer()) { // no braces enclosing array initializer, so recurse - array(tnsa, nelems); + array(tnsa, nelems, simple); } else if (auto tns = tn.isTypeStruct()) { - if (di.initializer.isExpInitializer()) + if (auto ei = di.initializer.isExpInitializer()) { // no braces enclosing struct initializer - dil[n].initializer = structs(tns); + + /* Disambiguate between an exp representing the entire + * struct, and an exp representing the first field of the struct + */ + if (needInterpret) + sc = sc.startCTFE(); + ei.exp = ei.exp.expressionSemantic(sc); + ei.exp = resolveProperties(sc, ei.exp); + if (needInterpret) + sc = sc.endCTFE(); + if (ei.exp.implicitConvTo(tn)) + di.initializer = elem(di.initializer); // the whole struct + else + { + simple = false; + dil[n].initializer = structs(tns); // the first field + } } else dil[n].initializer = elem(di.initializer); @@ -816,7 +831,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } size_t dim = tsa.isIncomplete() ? dil.length : cast(size_t)tsa.dim.toInteger(); - auto newdim = array(t, dim); + bool simple = true; + auto newdim = array(t, dim, simple); if (errors) return err(); @@ -849,7 +865,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ /* If an array of simple elements, replace with an ArrayInitializer */ auto tnb = tn.toBasetype(); - if (!(tnb.isTypeSArray() || tnb.isTypeStruct())) + if (!tnb.isTypeSArray() && (!tnb.isTypeStruct() || simple)) { auto ai = new ArrayInitializer(ci.loc); ai.dim = cast(uint) dil.length; @@ -884,12 +900,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ final switch (init.kind) { - case InitKind.void_: return visitVoid (cast( VoidInitializer)init); - case InitKind.error: return visitError (cast( ErrorInitializer)init); - case InitKind.struct_: return visitStruct(cast(StructInitializer)init); - case InitKind.array: return visitArray (cast( ArrayInitializer)init); - case InitKind.exp: return visitExp (cast( ExpInitializer)init); - case InitKind.C_: return visitC (cast( CInitializer)init); + case InitKind.void_: return visitVoid (init.isVoidInitializer()); + case InitKind.error: return visitError (init.isErrorInitializer()); + case InitKind.struct_: return visitStruct(init.isStructInitializer()); + case InitKind.array: return visitArray (init.isArrayInitializer()); + case InitKind.exp: return visitExp (init.isExpInitializer()); + case InitKind.C_: return visitC (init.isCInitializer()); } } @@ -943,8 +959,7 @@ Initializer inferType(Initializer init, Scope* sc) { return iz; } - assert(iz.isExpInitializer()); - (*values)[i] = (cast(ExpInitializer)iz).exp; + (*values)[i] = iz.isExpInitializer().exp; assert(!(*values)[i].isErrorExp()); } Expression e = new AssocArrayLiteralExp(init.loc, keys, values); @@ -966,8 +981,7 @@ Initializer inferType(Initializer init, Scope* sc) { return iz; } - assert(iz.isExpInitializer()); - (*elements)[i] = (cast(ExpInitializer)iz).exp; + (*elements)[i] = iz.isExpInitializer().exp; assert(!(*elements)[i].isErrorExp()); } Expression e = new ArrayLiteralExp(init.loc, null, elements); @@ -996,9 +1010,8 @@ Initializer inferType(Initializer init, Scope* sc) init.exp = resolveAliasThis(sc, init.exp); init.exp = resolveProperties(sc, init.exp); - if (init.exp.op == EXP.scope_) + if (auto se = init.exp.isScopeExp()) { - ScopeExp se = cast(ScopeExp)init.exp; TemplateInstance ti = se.sds.isTemplateInstance(); if (ti && ti.semanticRun == PASS.semantic && !ti.aliasdecl) se.error("cannot infer type from %s `%s`, possible circular dependency", se.sds.kind(), se.toChars()); @@ -1021,16 +1034,15 @@ Initializer inferType(Initializer init, Scope* sc) return new ErrorInitializer(); } } - if (init.exp.op == EXP.address) + if (auto ae = init.exp.isAddrExp()) { - AddrExp ae = cast(AddrExp)init.exp; if (ae.e1.op == EXP.overloadSet) { init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars()); return new ErrorInitializer(); } } - if (init.exp.op == EXP.error) + if (init.exp.isErrorExp()) { return new ErrorInitializer(); } @@ -1050,12 +1062,12 @@ Initializer inferType(Initializer init, Scope* sc) final switch (init.kind) { - case InitKind.void_: return visitVoid (cast( VoidInitializer)init); - case InitKind.error: return visitError (cast( ErrorInitializer)init); - case InitKind.struct_: return visitStruct(cast(StructInitializer)init); - case InitKind.array: return visitArray (cast( ArrayInitializer)init); - case InitKind.exp: return visitExp (cast( ExpInitializer)init); - case InitKind.C_: return visitC (cast( CInitializer)init); + case InitKind.void_: return visitVoid (init.isVoidInitializer()); + case InitKind.error: return visitError (init.isErrorInitializer()); + case InitKind.struct_: return visitStruct(init.isStructInitializer()); + case InitKind.array: return visitArray (init.isArrayInitializer()); + case InitKind.exp: return visitExp (init.isExpInitializer()); + case InitKind.C_: return visitC (init.isCInitializer()); } } @@ -1260,12 +1272,12 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n final switch (init.kind) { - case InitKind.void_: return visitVoid (cast( VoidInitializer)init); - case InitKind.error: return visitError (cast( ErrorInitializer)init); - case InitKind.struct_: return visitStruct(cast(StructInitializer)init); - case InitKind.array: return visitArray (cast( ArrayInitializer)init); - case InitKind.exp: return visitExp (cast( ExpInitializer)init); - case InitKind.C_: return visitC (cast( CInitializer)init); + case InitKind.void_: return visitVoid (init.isVoidInitializer()); + case InitKind.error: return visitError (init.isErrorInitializer()); + case InitKind.struct_: return visitStruct(init.isStructInitializer()); + case InitKind.array: return visitArray (init.isArrayInitializer()); + case InitKind.exp: return visitExp (init.isExpInitializer()); + case InitKind.C_: return visitC (init.isCInitializer()); } } @@ -1308,7 +1320,7 @@ private bool hasNonConstPointers(Expression e) { if (ae.type.nextOf().hasPointers() && checkArray(ae.values)) return true; - if ((cast(TypeAArray)ae.type).index.hasPointers()) + if (ae.type.isTypeAArray().index.hasPointers()) return checkArray(ae.keys); return false; } diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 31a25a71417..8bdddb8f9ea 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -83,6 +83,20 @@ public: } f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } + else if (fd.ident == Id._d_delstruct) + { + // In expressionsem.d, `delete s` was lowererd to `_d_delstruct(s)`. + // The following code handles the call like the original expression, + // so the error is menaningful to the user. + if (f.setGC()) + { + e.error("cannot use `delete` in `@nogc` %s `%s`", f.kind(), + f.toPrettyChars()); + err = true; + return; + } + f.printGCUsage(e.loc, "`delete` requires the GC"); + } } override void visit(ArrayLiteralExp e) diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index da328fdcaf9..49b87d6bf47 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -419,8 +419,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.insert(_arguments); _arguments.parent = funcdecl; } - if ((f.linkage == LINK.d || f.parameterList.length) && - !(sc.flags & SCOPE.Cfile)) // don't want to require importing stdarg for C files + if (f.linkage == LINK.d || f.parameterList.length) { // Declare _argptr Type t = target.va_listType(funcdecl.loc, sc); diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 2d98d5eeed8..e5b05d38a45 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -23,7 +23,7 @@ import dmd.common.outbuffer; import dmd.root.rmem; import dmd.utf; -enum TOK : ushort +enum TOK : ubyte { reserved, @@ -84,10 +84,7 @@ enum TOK : ushort rightShiftAssign, unsignedRightShift, unsignedRightShiftAssign, - concatenate, concatenateAssign, // ~= - concatenateElemAssign, - concatenateDcharAssign, add, min, addAssign, @@ -109,15 +106,11 @@ enum TOK : ushort tilde, plusPlus, minusMinus, - construct, - blit, dot, comma, question, andAnd, orOr, - prePlusPlus, - preMinusMinus, // Numeric literals int32Literal, @@ -144,7 +137,6 @@ enum TOK : ushort hexadecimalString, this_, super_, - tuple, error, // Basic types @@ -244,7 +236,6 @@ enum TOK : ushort parameters, traits, - overloadSet, pure_, nothrow_, gshared, @@ -564,7 +555,6 @@ private immutable TOK[] keywords = TOK.gshared, TOK.traits, TOK.vector, - TOK.overloadSet, TOK.file, TOK.fileFullPath, TOK.line, @@ -769,7 +759,6 @@ extern (C++) struct Token TOK.gshared: "__gshared", TOK.traits: "__traits", TOK.vector: "__vector", - TOK.overloadSet: "__overloadset", TOK.file: "__FILE__", TOK.fileFullPath: "__FILE_FULL_PATH__", TOK.line: "__LINE__", @@ -793,8 +782,6 @@ extern (C++) struct Token TOK.xor: "^", TOK.xorAssign: "^=", TOK.assign: "=", - TOK.construct: "=", - TOK.blit: "=", TOK.lessThan: "<", TOK.greaterThan: ">", TOK.lessOrEqual: "<=", @@ -824,8 +811,6 @@ extern (C++) struct Token TOK.dollar: "$", TOK.plusPlus: "++", TOK.minusMinus: "--", - TOK.prePlusPlus: "++", - TOK.preMinusMinus: "--", TOK.type: "type", TOK.question: "?", TOK.negate: "-", @@ -842,9 +827,6 @@ extern (C++) struct Token TOK.andAssign: "&=", TOK.orAssign: "|=", TOK.concatenateAssign: "~=", - TOK.concatenateElemAssign: "~=", - TOK.concatenateDcharAssign: "~=", - TOK.concatenate: "~", TOK.call: "call", TOK.identity: "is", TOK.notIdentity: "!is", @@ -860,7 +842,6 @@ extern (C++) struct Token // For debugging TOK.error: "error", TOK.string_: "string", - TOK.tuple: "tuple", TOK.declaration: "declaration", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", @@ -1113,11 +1094,6 @@ nothrow: return toString(value).ptr; } - static const(char)* toChars(ushort value) - { - return toString(cast(TOK)value).ptr; - } - extern (D) static string toString(TOK value) pure nothrow @nogc @safe { return tochars[value]; diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 2e1d1f44492..e095aa6b91a 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -32,7 +32,7 @@ class Identifier; ? && || */ -enum class TOK : unsigned short +enum class TOK : unsigned char { reserved, @@ -93,10 +93,7 @@ enum class TOK : unsigned short rightShiftAssign, unsignedRightShift, unsignedRightShiftAssign, - concatenate, concatenateAssign, // ~= - concatenateElemAssign, - concatenateDcharAssign, add, min, addAssign, @@ -118,15 +115,11 @@ enum class TOK : unsigned short tilde, plusPlus, minusMinus, - construct, - blit, dot, comma, question, andAnd, orOr, - prePlusPlus, - preMinusMinus, // Numeric literals int32Literal, // 104, @@ -153,7 +146,6 @@ enum class TOK : unsigned short hexadecimalString, this_, super_, - tuple, error, // Basic types @@ -253,7 +245,6 @@ enum class TOK : unsigned short parameters, // 210 traits, - overloadSet, pure_, nothrow_, gshared, diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 2a864161ff6..b8c43174f4a 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -271,7 +271,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb sm = null; } // Same check as in Expression.semanticY(DotIdExp) - else if (sm.isPackage() && checkAccess(sc, cast(Package)sm)) + else if (sm.isPackage() && checkAccess(sc, sm.isPackage())) { // @@@DEPRECATED_2.096@@@ // Should be an error in 2.106. Just remove the deprecation call @@ -509,7 +509,7 @@ private Type stripDefaultArgs(Type t) Parameters* params = stripParams(tf.parameterList.parameters); if (tret == tf.next && params == tf.parameterList.parameters) return t; - TypeFunction tr = cast(TypeFunction)tf.copy(); + TypeFunction tr = tf.copy().isTypeFunction(); tr.parameterList.parameters = params; tr.next = tret; //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars()); @@ -520,7 +520,7 @@ private Type stripDefaultArgs(Type t) Parameters* args = stripParams(tt.arguments); if (args == tt.arguments) return t; - TypeTuple tr = cast(TypeTuple)t.copy(); + TypeTuple tr = t.copy().isTypeTuple(); tr.arguments = args; return tr; } @@ -588,11 +588,11 @@ Expression typeToExpression(Type t) return null; switch (t.ty) { - case Tsarray: return visitSArray(cast(TypeSArray) t); - case Taarray: return visitAArray(cast(TypeAArray) t); - case Tident: return visitIdentifier(cast(TypeIdentifier) t); - case Tinstance: return visitInstance(cast(TypeInstance) t); - case Tmixin: return visitMixin(cast(TypeMixin) t); + case Tsarray: return visitSArray(t.isTypeSArray()); + case Taarray: return visitAArray(t.isTypeAArray()); + case Tident: return visitIdentifier(t.isTypeIdentifier()); + case Tinstance: return visitInstance(t.isTypeInstance()); + case Tmixin: return visitMixin(t.isTypeMixin()); default: return null; } } @@ -684,7 +684,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars()); return error(); } - TypeSArray t = cast(TypeSArray)mtype.basetype; + TypeSArray t = mtype.basetype.isTypeSArray(); const sz = cast(int)t.size(loc); final switch (target.isVectorTypeSupported(sz, t.nextOf())) { @@ -790,8 +790,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) return overflowError(); Type tbx = tbn.baseElemOf(); - if (tbx.ty == Tstruct && !(cast(TypeStruct)tbx).sym.members || - tbx.ty == Tenum && !(cast(TypeEnum)tbx).sym.members) + if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members || + tbx.ty == Tenum && !tbx.isTypeEnum().sym.members) { /* To avoid meaningless error message, skip the total size limit check * when the bottom of element type is opaque. @@ -802,7 +802,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) tbn.ty == Tarray || tbn.ty == Tsarray || tbn.ty == Taarray || - (tbn.ty == Tstruct && ((cast(TypeStruct)tbn).sym.sizeok == Sizeok.done)) || + (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) || tbn.ty == Tclass) { /* Only do this for types that don't need to have semantic() @@ -819,7 +819,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { // Index the tuple to get the type assert(mtype.dim); - TypeTuple tt = cast(TypeTuple)tbn; + TypeTuple tt = tbn.isTypeTuple(); uinteger_t d = mtype.dim.toUInteger(); if (d >= tt.arguments.dim) { @@ -1026,9 +1026,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) */ } } - else if (tbase.ty == Tclass && !(cast(TypeClass)tbase).sym.isInterfaceDeclaration()) + else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration()) { - ClassDeclaration cd = (cast(TypeClass)tbase).sym; + ClassDeclaration cd = tbase.isTypeClass().sym; if (cd.semanticRun < PASS.semanticdone) cd.dsymbolSemantic(null); @@ -1275,7 +1275,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { - FuncExp fe = cast(FuncExp)e; + FuncExp fe = e.isFuncExp(); // Replace function literal with a function symbol, // since default arg expression must be copied when used // and copying the literal itself is wrong. @@ -1402,8 +1402,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum)) { Type tb2 = t.baseElemOf(); - if (tb2.ty == Tstruct && !(cast(TypeStruct)tb2).sym.members || - tb2.ty == Tenum && !(cast(TypeEnum)tb2).sym.memtype) + if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members || + tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype) { if (global.params.previewIn && (fparam.storageClass & STC.in_)) { @@ -1467,7 +1467,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { Type tv = t.baseElemOf(); - if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.noDefaultCtor) + if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor) { .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars()); errors = true; @@ -1824,26 +1824,26 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (e.op) { case EXP.dotVariable: - mtype.sym = (cast(DotVarExp)e).var; + mtype.sym = e.isDotVarExp().var; break; case EXP.variable: - mtype.sym = (cast(VarExp)e).var; + mtype.sym = e.isVarExp().var; break; case EXP.function_: - auto fe = cast(FuncExp)e; + auto fe = e.isFuncExp(); mtype.sym = fe.td ? fe.td : fe.fd; break; case EXP.dotTemplateDeclaration: - mtype.sym = (cast(DotTemplateExp)e).td; + mtype.sym = e.isDotTemplateExp().td; break; case EXP.dSymbol: - mtype.sym = (cast(DsymbolExp)e).s; + mtype.sym = e.isDsymbolExp().s; break; case EXP.template_: - mtype.sym = (cast(TemplateExp)e).td; + mtype.sym = e.isTemplateExp().td; break; case EXP.scope_: - mtype.sym = (cast(ScopeExp)e).sds; + mtype.sym = e.isScopeExp().sds; break; case EXP.tuple: TupleExp te = e.toTupleExp(); @@ -1854,13 +1854,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (src.op) { case EXP.type: - (*elems)[i] = (cast(TypeExp)src).type; + (*elems)[i] = src.isTypeExp().type; break; case EXP.dotType: - (*elems)[i] = (cast(DotTypeExp)src).sym.isType(); + (*elems)[i] = src.isDotTypeExp().sym.isType(); break; case EXP.overloadSet: - (*elems)[i] = (cast(OverExp)src).type; + (*elems)[i] = src.isOverExp().type; break; default: if (auto sym = isDsymbol(src)) @@ -1873,13 +1873,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) mtype.sym = td; break; case EXP.dotType: - result = (cast(DotTypeExp)e).sym.isType(); + result = e.isDotTypeExp().sym.isType(); break; case EXP.type: - result = (cast(TypeExp)e).type; + result = e.isTypeExp().type; break; case EXP.overloadSet: - result = (cast(OverExp)e).type; + result = e.isOverExp().type; break; default: break; @@ -2211,26 +2211,26 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (type.ty) { default: return visitType(type); - case Tvector: return visitVector(cast(TypeVector)type); - case Tsarray: return visitSArray(cast(TypeSArray)type); - case Tarray: return visitDArray(cast(TypeDArray)type); - case Taarray: return visitAArray(cast(TypeAArray)type); - case Tpointer: return visitPointer(cast(TypePointer)type); - case Treference: return visitReference(cast(TypeReference)type); - case Tfunction: return visitFunction(cast(TypeFunction)type); - case Tdelegate: return visitDelegate(cast(TypeDelegate)type); - case Tident: return visitIdentifier(cast(TypeIdentifier)type); - case Tinstance: return visitInstance(cast(TypeInstance)type); - case Ttypeof: return visitTypeof(cast(TypeTypeof)type); - case Ttraits: return visitTraits(cast(TypeTraits)type); - case Treturn: return visitReturn(cast(TypeReturn)type); - case Tstruct: return visitStruct(cast(TypeStruct)type); - case Tenum: return visitEnum(cast(TypeEnum)type); - case Tclass: return visitClass(cast(TypeClass)type); - case Ttuple: return visitTuple (cast(TypeTuple)type); - case Tslice: return visitSlice(cast(TypeSlice)type); - case Tmixin: return visitMixin(cast(TypeMixin)type); - case Ttag: return visitTag(cast(TypeTag)type); + case Tvector: return visitVector(type.isTypeVector()); + case Tsarray: return visitSArray(type.isTypeSArray()); + case Tarray: return visitDArray(type.isTypeDArray()); + case Taarray: return visitAArray(type.isTypeAArray()); + case Tpointer: return visitPointer(type.isTypePointer()); + case Treference: return visitReference(type.isTypeReference()); + case Tfunction: return visitFunction(type.isTypeFunction()); + case Tdelegate: return visitDelegate(type.isTypeDelegate()); + case Tident: return visitIdentifier(type.isTypeIdentifier()); + case Tinstance: return visitInstance(type.isTypeInstance()); + case Ttypeof: return visitTypeof(type.isTypeTypeof()); + case Ttraits: return visitTraits(type.isTypeTraits()); + case Treturn: return visitReturn(type.isTypeReturn()); + case Tstruct: return visitStruct(type.isTypeStruct()); + case Tenum: return visitEnum(type.isTypeEnum()); + case Tclass: return visitClass(type.isTypeClass()); + case Ttuple: return visitTuple(type.isTypeTuple()); + case Tslice: return visitSlice(type.isTypeSlice()); + case Tmixin: return visitMixin(type.isTypeMixin()); + case Ttag: return visitTag(type.isTypeTag()); } } @@ -2300,7 +2300,7 @@ extern (C++) Type merge(Type type) case Tsarray: // prevents generating the mangle if the array dim is not yet known - if (!(cast(TypeSArray) type).dim.isIntegerExp()) + if (!type.isTypeSArray().dim.isIntegerExp()) return type; goto default; @@ -2308,7 +2308,7 @@ extern (C++) Type merge(Type type) break; case Taarray: - if (!(cast(TypeAArray)type).index.merge().deco) + if (!type.isTypeAArray().index.merge().deco) return type; goto default; @@ -2761,10 +2761,10 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden visitBasic(cast(TypeBasic)t) : visitType(t); - case Terror: return visitError (cast(TypeError)t); - case Tvector: return visitVector(cast(TypeVector)t); - case Tenum: return visitEnum (cast(TypeEnum)t); - case Ttuple: return visitTuple (cast(TypeTuple)t); + case Terror: return visitError (t.isTypeError()); + case Tvector: return visitVector(t.isTypeVector()); + case Tenum: return visitEnum (t.isTypeEnum()); + case Ttuple: return visitTuple (t.isTypeTuple()); } } @@ -2889,7 +2889,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type { Expression e = cast(Expression)o; if (e.op == EXP.dSymbol) - return returnSymbol((cast(DsymbolExp)e).s); + return returnSymbol(e.isDsymbolExp().s); else return returnExp(e); } @@ -3154,8 +3154,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type * template functions. */ } - if (auto f = mt.exp.op == EXP.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration() - : mt.exp.op == EXP.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null) + if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration() + : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null) { // f might be a unittest declaration which is incomplete when compiled // without -unittest. That causes a segfault in checkForwardRef, see @@ -3350,17 +3350,17 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type switch (mt.ty) { - default: visitType (mt); break; - case Tsarray: visitSArray (cast(TypeSArray)mt); break; - case Tarray: visitDArray (cast(TypeDArray)mt); break; - case Taarray: visitAArray (cast(TypeAArray)mt); break; - case Tident: visitIdentifier(cast(TypeIdentifier)mt); break; - case Tinstance: visitInstance (cast(TypeInstance)mt); break; - case Ttypeof: visitTypeof (cast(TypeTypeof)mt); break; - case Treturn: visitReturn (cast(TypeReturn)mt); break; - case Tslice: visitSlice (cast(TypeSlice)mt); break; - case Tmixin: visitMixin (cast(TypeMixin)mt); break; - case Ttraits: visitTraits (cast(TypeTraits)mt); break; + default: visitType (mt); break; + case Tsarray: visitSArray (mt.isTypeSArray()); break; + case Tarray: visitDArray (mt.isTypeDArray()); break; + case Taarray: visitAArray (mt.isTypeAArray()); break; + case Tident: visitIdentifier(mt.isTypeIdentifier()); break; + case Tinstance: visitInstance (mt.isTypeInstance()); break; + case Ttypeof: visitTypeof (mt.isTypeTypeof()); break; + case Treturn: visitReturn (mt.isTypeReturn()); break; + case Tslice: visitSlice (mt.isTypeSlice()); break; + case Tmixin: visitMixin (mt.isTypeMixin()); break; + case Ttraits: visitTraits (mt.isTypeTraits()); break; } } @@ -4616,16 +4616,16 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) switch (mt.ty) { - case Tvector: return visitVector (cast(TypeVector)mt); - case Tsarray: return visitSArray (cast(TypeSArray)mt); - case Tstruct: return visitStruct (cast(TypeStruct)mt); - case Tenum: return visitEnum (cast(TypeEnum)mt); - case Terror: return visitError (cast(TypeError)mt); - case Tarray: return visitDArray (cast(TypeDArray)mt); - case Taarray: return visitAArray (cast(TypeAArray)mt); - case Treference: return visitReference(cast(TypeReference)mt); - case Tdelegate: return visitDelegate (cast(TypeDelegate)mt); - case Tclass: return visitClass (cast(TypeClass)mt); + case Tvector: return visitVector (mt.isTypeVector()); + case Tsarray: return visitSArray (mt.isTypeSArray()); + case Tstruct: return visitStruct (mt.isTypeStruct()); + case Tenum: return visitEnum (mt.isTypeEnum()); + case Terror: return visitError (mt.isTypeError()); + case Tarray: return visitDArray (mt.isTypeDArray()); + case Taarray: return visitAArray (mt.isTypeAArray()); + case Treference: return visitReference(mt.isTypeReference()); + case Tdelegate: return visitDelegate (mt.isTypeDelegate()); + case Tclass: return visitClass (mt.isTypeClass()); default: return mt.isTypeBasic() ? visitBasic(cast(TypeBasic)mt) @@ -4786,12 +4786,12 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi switch (mt.ty) { - case Tvector: return visitVector (cast(TypeVector)mt); - case Tsarray: return visitSArray (cast(TypeSArray)mt); - case Tfunction: return visitFunction(cast(TypeFunction)mt); - case Tstruct: return visitStruct (cast(TypeStruct)mt); - case Tenum: return visitEnum (cast(TypeEnum)mt); - case Ttuple: return visitTuple (cast(TypeTuple)mt); + case Tvector: return visitVector (mt.isTypeVector()); + case Tsarray: return visitSArray (mt.isTypeSArray()); + case Tfunction: return visitFunction(mt.isTypeFunction()); + case Tstruct: return visitStruct (mt.isTypeStruct()); + case Tenum: return visitEnum (mt.isTypeEnum()); + case Ttuple: return visitTuple (mt.isTypeTuple()); case Tnull: return new NullExp(Loc.initial, Type.tnull); @@ -4803,7 +4803,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi case Treference: case Tdelegate: case Tclass: return new NullExp(loc, mt); - case Tnoreturn: return visitNoreturn(cast(TypeNoreturn) mt); + case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn()); default: return mt.isTypeBasic() ? visitBasic(cast(TypeBasic)mt) : diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index f1c014dbc16..665d12205b3 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1477,16 +1477,10 @@ public: t1 = build_address (t1); Type *tnext = tb1->isTypePointer ()->next->toBasetype (); + /* This case should have been rewritten to `_d_delstruct` in the + semantic phase. */ if (TypeStruct *ts = tnext->isTypeStruct ()) - { - if (ts->sym->dtor) - { - tree ti = build_typeinfo (e->loc, tnext); - this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid, - 2, t1, ti); - return; - } - } + gcc_assert (!ts->sym->dtor); /* Otherwise, the garbage collector is called to immediately free the memory allocated for the pointer. */ diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index 3961a1d9bed..ef54a37d9bc 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -85,8 +85,6 @@ DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0) /* Used when calling delete on a pointer. */ DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0) -DEF_D_RUNTIME (DELSTRUCT, "_d_delstruct", RT(VOID), - P2(POINTER_VOIDPTR, TYPEINFO), 0) /* Used when calling new on an array. The `i' variant is for when the initializer is nonzero, and the `m' variant is when initializing a diff --git a/gcc/testsuite/gdc.test/compilable/test22593.d b/gcc/testsuite/gdc.test/compilable/test22593.d new file mode 100644 index 00000000000..20912941620 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22593.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=22593 + +struct Foo(T){ + this(Rhs, this This)(scope Rhs rhs){ + } + + this(ref scope typeof(this) rhs){ + } +} + +struct Bar{ + Foo!int foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17074.d b/gcc/testsuite/gdc.test/fail_compilation/ice17074.d index 53e75e40934..84c4d8533e2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice17074.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice17074.d @@ -1,19 +1,13 @@ /* -TEST_OUTPUT: ---- -fail_compilation/ice17074.d(9): Error: identifier expected for C++ namespace -fail_compilation/ice17074.d(9): Error: found `__overloadset` when expecting `)` -fail_compilation/ice17074.d(9): Error: declaration expected, not `)` ---- */ extern(C++, std.__overloadset) void ice_std_keyword(); /* TEST_OUTPUT: --- -fail_compilation/ice17074.d(19): Error: identifier expected for C++ namespace -fail_compilation/ice17074.d(19): Error: found `*` when expecting `)` -fail_compilation/ice17074.d(19): Error: declaration expected, not `)` +fail_compilation/ice17074.d(13): Error: identifier expected for C++ namespace +fail_compilation/ice17074.d(13): Error: found `*` when expecting `)` +fail_compilation/ice17074.d(13): Error: declaration expected, not `)` --- */ extern(C++, std.*) void ice_std_token(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22593.d b/gcc/testsuite/gdc.test/fail_compilation/test22593.d new file mode 100644 index 00000000000..f90287e9e06 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test22593.d @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=22593 + +/* +TEST_OUTPUT: +--- +fail_compilation/test22593.d(14): Error: Cannot define both an rvalue constructor and a copy constructor for `struct Foo` +fail_compilation/test22593.d(22): Template instance `__ctor!(immutable(Foo!int), immutable(Foo!int))` creates a rvalue constructor for `struct Foo` +fail_compilation/test22593.d(22): Error: template instance `test22593.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` error instantiating +--- +*/ + +struct Foo(T) +{ + this(Rhs, this This)(scope Rhs rhs){} + + this(ref scope typeof(this) rhs){} +} + +void main() +{ + immutable Foo!int a; + a.__ctor(a); +} diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index b3da9063ce3..70f7ff596a8 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -6364e010bc87f3621028c8ac648133535c126fb3 +fd9a45448244fb9dd4326520ad8526c540895eb0 The first line of this file holds the git revision number of the last merge done from the dlang/druntime repository. diff --git a/libphobos/libdruntime/core/builtins.d b/libphobos/libdruntime/core/builtins.d index f2ca5038c59..1ed80f7d94a 100644 --- a/libphobos/libdruntime/core/builtins.d +++ b/libphobos/libdruntime/core/builtins.d @@ -1,11 +1,45 @@ /********************************************** - * This module implements common builtins for the D frontend. - * - * Copyright: Copyright © 2019, The D Language Foundation - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Authors: Walter Bright - * Source: $(DRUNTIMESRC core/builtins.d) - */ +To provide access to features that would be otherwise counterproductive or +difficult to implement, compilers provide an interface consisting of a set +of builtins (also called intrinsics) which can be called like normal functions. + +This module exposes builtins both common to all D compilers +(those provided by the frontend) and specific to the host compiler i.e. those +specific to either LLVM or GCC (`ldc.intrinsics` and `gcc.builtins` are publicly imported, respectively). +Host-specific intrinsics cannot be reliably listed here, however listings can be found +at the documentation for the relevant backends, i.e. +$(LINK2 https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html, GCC) and +$(LINK2 https://llvm.org/docs/LangRef.html, LLVM). It should be noted that not all +builtins listed are necessarily supported by the host compiler, please file a bug +if this is the case for your workload. + +Use of this module reduces the amount of conditional compilation needed +to use a given builtin. For example, to write a target independent function +that uses prefetching we can write the following: +--- +float usePrefetch(float[] x) +{ + // There is only one import statement required rather than two (versioned) imports + import core.builtins; + version (GNU) + __builtin_prefetch(x.ptr); + version (LDC) + /+ + For the curious: 0, 3, 1 mean `x` will only be read-from (0), it will be used + very often (3), and it should be fetched to the data-cache (1). + +/ + llvm_prefetch(x.ptr, 0, 3, 1); + const doMath = blahBlahBlah; + return doMath; +} +--- + + +Copyright: Copyright © 2021, The D Language Foundation +License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) +Authors: Walter Bright +Source: $(DRUNTIMESRC core/builtins.d) +*/ module core.builtins; diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index 8fb61a547d5..9a99f2da02a 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -1545,9 +1545,8 @@ template forward(args...) { import core.internal.traits : AliasSeq; - static if (args.length) + template fwd(alias arg) { - alias arg = args[0]; // by ref || lazy || const/immutable static if (__traits(isRef, arg) || __traits(isOut, arg) || @@ -1556,15 +1555,16 @@ template forward(args...) alias fwd = arg; // (r)value else - @property auto fwd(){ return move(arg); } - - static if (args.length == 1) - alias forward = fwd; - else - alias forward = AliasSeq!(fwd, forward!(args[1..$])); + @property auto fwd(){ pragma(inline, true); return move(arg); } } + + alias Result = AliasSeq!(); + static foreach (arg; args) + Result = AliasSeq!(Result, fwd!arg); + static if (Result.length == 1) + alias forward = Result[0]; else - alias forward = AliasSeq!(); + alias forward = Result; } /// @@ -2316,7 +2316,7 @@ template _d_delstructImpl(T) @system pure nothrow unittest { int dtors = 0; - struct S { ~this() { ++dtors; } } + struct S { ~this() nothrow { ++dtors; } } S *s = new S(); _d_delstructImpl!(typeof(s))._d_delstruct(s); diff --git a/libphobos/libdruntime/core/sys/linux/sched.d b/libphobos/libdruntime/core/sys/linux/sched.d index dc815a0fc3c..e828b7447d1 100644 --- a/libphobos/libdruntime/core/sys/linux/sched.d +++ b/libphobos/libdruntime/core/sys/linux/sched.d @@ -153,6 +153,9 @@ version (CRuntime_Glibc) int sched_getcpu(); } +/* Reassociate the calling thread with namespace referred to by fd */ +int setns(int fd, int nstype); + enum CLONE_FILES = 0x400; enum CLONE_FS = 0x200; enum CLONE_NEWCGROUP = 0x2000000; diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 29b5d58de5b..c989caa64bf 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -4667,17 +4667,33 @@ public import core.internal.switch_: __switch_error; public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable); // Compare class and interface objects for ordering. -private int __cmp(Obj)(Obj lhs, Obj rhs) -if (is(Obj : Object)) +int __cmp(C1, C2)(C1 lhs, C2 rhs) +if ((is(C1 : const(Object)) || (is(C1 == interface) && (__traits(getLinkage, C1) == "D"))) && + (is(C2 : const(Object)) || (is(C2 == interface) && (__traits(getLinkage, C2) == "D")))) { - if (lhs is rhs) + static if (is(C1 == typeof(null)) && is(C2 == typeof(null))) + { return 0; - // Regard null references as always being "less than" - if (!lhs) + } + else static if (is(C1 == typeof(null))) + { + // Regard null references as always being "less than" return -1; - if (!rhs) + } + else static if (is(C2 == typeof(null))) + { return 1; - return lhs.opCmp(rhs); + } + else + { + if (lhs is rhs) + return 0; + if (lhs is null) + return -1; + if (rhs is null) + return 1; + return lhs.opCmp(rhs); + } } // objects diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index c9d166b03a7..b517749b542 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -575b67a9b4f78415f96ca77ad50b2de4c667cc74 +495e835c2da47606142ff24c85de707e3b955a9a 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/format/write.d b/libphobos/src/std/format/write.d index c7587688fc0..e67d95ccc23 100644 --- a/libphobos/src/std/format/write.d +++ b/libphobos/src/std/format/write.d @@ -1287,3 +1287,26 @@ void formatValue(Writer, T, Char)(auto ref Writer w, auto ref T val, scope const assertThrown!FormatException(formattedWrite(w, "%(%0*d%)", new int[1])); } + +// https://issues.dlang.org/show_bug.cgi?id=22609 +@safe pure unittest +{ + static enum State: ubyte { INACTIVE } + static struct S { + State state = State.INACTIVE; + int generation = 1; + alias state this; + // DMDBUG: https://issues.dlang.org/show_bug.cgi?id=16657 + auto opEquals(S other) const { return state == other.state && generation == other.generation; } + auto opEquals(State other) const { return state == other; } + } + + import std.array : appender; + import std.format.spec : singleSpec; + + auto writer = appender!string(); + const spec = singleSpec("%s"); + S a; + writer.formatValue(a, spec); + assert(writer.data == "0"); +} diff --git a/libphobos/src/std/range/interfaces.d b/libphobos/src/std/range/interfaces.d index 475f35b51da..6d55d4149c7 100644 --- a/libphobos/src/std/range/interfaces.d +++ b/libphobos/src/std/range/interfaces.d @@ -201,6 +201,9 @@ interface RandomAccessFinite(E) : BidirectionalRange!(E) { /**Interface for an infinite random access range of type `E`.*/ interface RandomAccessInfinite(E) : ForwardRange!E { + /// + enum bool empty = false; + /**Calls $(REF moveAt, std, range, primitives) on the wrapped range, if * possible. Otherwise, throws an $(LREF UnsupportedRangeMethod) exception. */ @@ -213,6 +216,12 @@ interface RandomAccessInfinite(E) : ForwardRange!E { E opIndex(size_t); } +// https://issues.dlang.org/show_bug.cgi?id=22608 +@safe unittest +{ + static assert(isRandomAccessRange!(RandomAccessInfinite!int)); +} + /**Adds assignable elements to InputRange.*/ interface InputAssignable(E) : InputRange!E { /// diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index 6dee863521d..cde2b9da055 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -6971,7 +6971,7 @@ mixin template Proxy(alias a) static if (is(typeof(a.opCmp(b)))) return a.opCmp(b); else static if (is(typeof(b.opCmp(a)))) - return -b.opCmp(b); + return -b.opCmp(a); else return a < b ? -1 : a > b ? +1 : 0; }