diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-03-12 17:19:49 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-03-15 16:33:00 +0100 |
commit | e8c9f4ab8f0c8ad8da5f7fb0f1a4956507fe64f5 (patch) | |
tree | 46099e73f24300a919394d9f1972fdf5941f672d /gcc | |
parent | 254549d2bb9bb3c2719dec597427919c59514fc3 (diff) | |
download | gcc-e8c9f4ab8f0c8ad8da5f7fb0f1a4956507fe64f5.zip gcc-e8c9f4ab8f0c8ad8da5f7fb0f1a4956507fe64f5.tar.gz gcc-e8c9f4ab8f0c8ad8da5f7fb0f1a4956507fe64f5.tar.bz2 |
d: Merge upstream dmd, druntime b7e3b3b617
D front-end changes:
- `delete' is no longer a keyword.
- Initializing a field with itself has been deprecated.
D runtime changes:
- Add Windows BCrypt bindings under `core.sys.windows.bcrypt'.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream b7e3b3b617.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream b7e3b3b617.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES_WINDOWS): Add
core/sys/windows/bcrypt.d.
* libdruntime/Makefile.in: Regenerate.
* libdruntime/gcc/sections/elf.d (sizeofTLS): Give function the same
mangling as gcc.sections.sizeofTLS.
* libdruntime/gcc/sections/package.d: Import core.internal.traits.
(pinLoadedLibraries): Mangle as function from rt.sections_elf_shared.
(unpinLoadedLibraries): Likewise.
(inheritLoadedLibraries): Likewise.
(cleanupLoadedLibraries): Likewise.
(sizeOfTLS): Add forward declaration.
Diffstat (limited to 'gcc')
49 files changed, 1438 insertions, 2118 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 4172630..a91f40b 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -d1157134103a209d36d6ee9c1df1d61d5929ec6d +b7e3b3b61711bf6c6cad27c7b5b73df0e570c215 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/clone.d b/gcc/d/dmd/clone.d index d7658c6..93b6dc3 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -101,7 +101,7 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure @safe */ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) { - Dsymbol assign = search_function(ad, Id.assign); + Dsymbol assign = search_function(ad, Id.opAssign); if (!assign) return null; @@ -303,7 +303,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) auto fparams = new Parameters(); fparams.push(new Parameter(loc, STC.nodtor, sd.type, Id.p, null, null)); auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_); - auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf); + auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.opAssign, stc, tf); fop.storage_class |= STC.inference; fop.isGenerated = true; Expression e; @@ -482,7 +482,7 @@ bool needOpEquals(StructDeclaration sd) private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) { FuncDeclaration f; - Dsymbol eq = search_function(ad, Id.eq); + Dsymbol eq = search_function(ad, Id.opEquals); if (!eq) return null; @@ -537,7 +537,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) * opEquals is changed to be never implicitly generated. * Now, struct objects comparison s1 == s2 is translated to: * s1.tupleof == s2.tupleof - * to calculate structural equality. See EqualExp.op_overload. + * to calculate structural equality. See `opOverloadEquals`. */ FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc) { @@ -564,7 +564,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) return null; // bitwise comparison would work //printf("StructDeclaration::buildXopEquals() %s\n", sd.toChars()); - if (Dsymbol eq = search_function(sd, Id.eq)) + if (Dsymbol eq = search_function(sd, Id.opEquals)) { if (FuncDeclaration fd = eq.isFuncDeclaration()) { @@ -639,7 +639,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) { //printf("StructDeclaration::buildXopCmp() %s\n", toChars()); - if (Dsymbol cmp = search_function(sd, Id.cmp)) + if (Dsymbol cmp = search_function(sd, Id.opCmp)) { if (FuncDeclaration fd = cmp.isFuncDeclaration()) { @@ -667,7 +667,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) * Consider 'alias this', but except opDispatch. */ Expression e = new DsymbolExp(sd.loc, sd); - e = new DotIdExp(sd.loc, e, Id.cmp); + e = new DotIdExp(sd.loc, e, Id.opCmp); Scope* sc2 = sc.push(); e = e.trySemantic(sc2); sc2.pop(); @@ -688,7 +688,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) default: break; } - if (!s || s.ident != Id.cmp) + if (!s || s.ident != Id.opCmp) e = null; // there's no valid member 'opCmp' } if (!e) @@ -736,7 +736,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) fop.parent = sd; Expression e1 = new IdentifierExp(loc, Id.This); Expression e2 = new IdentifierExp(loc, Id.p); - Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2); + Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.opCmp), e2); fop.fbody = new ReturnStatement(loc, e); const errors = global.startGagging(); // Do not report errors Scope* sc2 = sc.push(); diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index a6cfe6e..6d2a954 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -1529,11 +1529,9 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres : tclass.implicitConvTo(to.mutableOf()); if (match) return paint(); - else - { - emplaceExp!(NullExp)(pue, loc, to); - return pue.exp(); - } + + emplaceExp!(NullExp)(pue, loc, to); + return pue.exp(); } // Allow TypeInfo type painting diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 2f33301..0d95ad4 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -4144,20 +4144,6 @@ Expression typeCombine(BinExp be, Scope* sc) return ErrorExp.get(); } - Type t1 = be.e1.type.toBasetype(); - Type t2 = be.e2.type.toBasetype(); - - if (be.op == EXP.min || be.op == EXP.add) - { - // struct+struct, and class+class are errors - if (t1.ty == Tstruct && t2.ty == Tstruct) - return errorReturn(); - if (t1.ty == Tclass && t2.ty == Tclass) - return errorReturn(); - if (t1.ty == Taarray && t2.ty == Taarray) - return errorReturn(); - } - if (auto result = typeMerge(sc, be.op, be.e1, be.e2)) { if (be.type is null) diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 0d87f6e..c7fb26a 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -3061,7 +3061,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sd.ctor) { - Dsymbol scall = sd.search(Loc.initial, Id.call); + Dsymbol scall = sd.search(Loc.initial, Id.opCall); if (scall) { const xerrors = global.startGagging(); diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 7f7437c..dd9f3da 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -217,17 +217,12 @@ Dsymbol getDsymbol(RootObject oarg) return te.td; if (auto te = ea.isScopeExp()) return te.sds; - else - return null; - } - else - { - // Try to convert Type to symbol - if (auto ta = isType(oarg)) - return ta.toDsymbol(null); - else - return isDsymbol(oarg); // if already a symbol + return null; } + // Try to convert Type to symbol + if (auto ta = isType(oarg)) + return ta.toDsymbol(null); + return isDsymbol(oarg); // if already a symbol } @@ -5752,8 +5747,8 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si if (auto ttp = tp.isTemplateTupleParameter()) return matchArgTuple(ttp); - else - return matchArgParameter(); + + return matchArgParameter(); } MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) @@ -6221,8 +6216,8 @@ void printTemplateStats(bool listInstances, ErrorSink eSink) auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations; if (diff) return diff; - else - return b.ts.numInstantiations - a.ts.numInstantiations; + + return b.ts.numInstantiations - a.ts.numInstantiations; } } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 75d6468..5b8e010 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -535,98 +535,6 @@ extern (C++) abstract class Expression : ASTNode return false; } - extern (D) final bool checkScalar() - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (!type.isScalar()) - { - error(loc, "`%s` is not a scalar, it is a `%s`", toChars(), type.toChars()); - return true; - } - return checkValue(); - } - - extern (D) final bool checkNoBool() - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (type.toBasetype().ty == Tbool) - { - error(loc, "operation not allowed on `bool` `%s`", toChars()); - return true; - } - return false; - } - - extern (D) final bool checkIntegral() - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (!type.isIntegral()) - { - error(loc, "`%s` is not of integral type, it is a `%s`", toChars(), type.toChars()); - return true; - } - return checkValue(); - } - - extern (D) final bool checkArithmetic(EXP op) - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (!type.isIntegral() && !type.isFloating()) - { - // unary aggregate ops error here - const char* msg = type.isAggregate() ? - "operator `%s` is not defined for `%s` of type `%s`" : - "illegal operator `%s` for `%s` of type `%s`"; - error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars()); - return true; - } - return checkValue(); - } - - /******************************* - * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. - * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) - * Returns true if error occurs. - */ - extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null) - { - //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); - if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass()) - return false; - - // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. - switch (rmwOp) - { - case EXP.plusPlus: - case EXP.prePlusPlus: - rmwOp = EXP.addAssign; - break; - case EXP.minusMinus: - case EXP.preMinusMinus: - rmwOp = EXP.minAssign; - break; - default: - break; - } - - error(loc, "read-modify-write operations are not allowed for `shared` variables"); - errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead", - EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1"); - return true; - } - /****************************** * Take address of expression. */ @@ -3039,8 +2947,6 @@ extern (C++) abstract class BinExp : Expression { Expression e1; Expression e2; - Type att1; // Save alias this type to detect recursion - Type att2; // Save alias this type to detect recursion extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe { @@ -3058,20 +2964,6 @@ extern (C++) abstract class BinExp : Expression return e; } - extern (D) final bool checkIntegralBin() - { - bool r1 = e1.checkIntegral(); - bool r2 = e2.checkIntegral(); - return (r1 || r2); - } - - extern (D) final bool checkArithmeticBin() - { - bool r1 = e1.checkArithmetic(this.op); - bool r2 = e2.checkArithmetic(this.op); - return (r1 || r2); - } - /********************* * Mark the operands as will never be dereferenced, * which is useful info for @safe checks. diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index d62aea8..07b163f1 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -679,9 +679,6 @@ public: Expression *e1; Expression *e2; - Type *att1; // Save alias this type to detect recursion - Type *att2; // Save alias this type to detect recursion - BinExp *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index eb4a5f8..fcb47a5 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -663,7 +663,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) assert(!ae.lengthVar); *pe0 = null; AggregateDeclaration ad = isAggregate(ae.e1.type); - Dsymbol slice = search_function(ad, Id.slice); + Dsymbol slice = search_function(ad, Id.opSlice); //printf("slice = %s %s\n", slice.kind(), slice.toChars()); Expression fallback() { @@ -2403,7 +2403,7 @@ private bool checkPostblit(Type t, ref Loc loc, Scope* sc) /*************************************** * Pull out any properties. */ -private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null) +private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, Type[2]* aliasThisStop = null) { //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); Loc loc = e1.loc; @@ -2478,11 +2478,9 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) { e = new AssignExp(loc, e, e2); - if (saveAtts) - { - (cast(BinExp)e).att1 = saveAtts.att1; - (cast(BinExp)e).att2 = saveAtts.att2; - } + if (aliasThisStop) + return e.expressionSemantic(sc, *aliasThisStop); + return e.expressionSemantic(sc); } return e.expressionSemantic(sc); } @@ -2584,11 +2582,8 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) { e = new AssignExp(loc, e, e2); - if (saveAtts) - { - (cast(BinExp)e).att1 = saveAtts.att1; - (cast(BinExp)e).att2 = saveAtts.att2; - } + if (aliasThisStop) + return e.expressionSemantic(sc, *aliasThisStop); } return e.expressionSemantic(sc); } @@ -3816,6 +3811,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Scope* sc; Expression result; + // For binary expressions, stores recursive 'alias this' types of lhs and rhs to prevent endless loops. + // See tryAliasThisSemantic + Type[2] aliasThisStop; + this(Scope* sc) scope @safe { this.sc = sc; @@ -6206,7 +6205,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } // No constructor, look for overload of opCall - if (search_function(sd, Id.call)) + if (search_function(sd, Id.opCall)) goto L1; // overload of opCall, therefore it's a call if (exp.e1.op != EXP.type) @@ -6247,7 +6246,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { L1: // Rewrite as e1.call(arguments) - Expression e = new DotIdExp(exp.loc, exp.e1, Id.call); + Expression e = new DotIdExp(exp.loc, exp.e1, Id.opCall); e = new CallExp(exp.loc, e, exp.arguments, exp.names); e = e.expressionSemantic(sc); result = e; @@ -7536,13 +7535,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(BinAssignExp exp) { - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinaryAssign(sc, aliasThisStop)) { result = e; return; } + Expression e; if (exp.e1.op == EXP.arrayLength) { // arr.length op= e2; @@ -7933,7 +7932,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { const callExpIdent = callExpFunc.ident; isEqualsCallExpression = callExpIdent == Id.__equals || - callExpIdent == Id.eq; + callExpIdent == Id.opEquals; } } if (op == EXP.equal || op == EXP.notEqual || @@ -8777,8 +8776,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("PtrExp::semantic('%s')\n", exp.toChars()); } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadUnary(sc)) { result = e; return; @@ -8835,8 +8833,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("NegExp::semantic('%s')\n", exp.toChars()); } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadUnary(sc)) { result = e; return; @@ -8876,8 +8873,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("UAddExp::semantic('%s')\n", exp.toChars()); } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadUnary(sc)) { result = e; return; @@ -8902,8 +8898,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(ComExp exp) { - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadUnary(sc)) { result = e; return; @@ -8975,17 +8970,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(DeleteExp exp) { - // @@@DEPRECATED_2.109@@@ - // 1. Deprecated since 2.079 - // 2. Error since 2.099 - // 3. Removal of keyword, "delete" can be used for other identities - if (!exp.isRAII) - { - error(exp.loc, "the `delete` keyword is obsolete"); - errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead"); - return setError(); - } - Expression e = exp; if (Expression ex = unaSemantic(exp, sc)) @@ -9176,7 +9160,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0) { - if (Expression e = exp.op_overload(sc)) + if (Expression e = exp.opOverloadCast(sc)) { result = e.implicitCastTo(sc, exp.to); return; @@ -9466,8 +9450,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor error(exp.loc, "upper and lower bounds are needed to slice a pointer"); if (auto ad = isAggregate(tp.next.toBasetype())) { - auto s = search_function(ad, Id.index); - if (!s) s = search_function(ad, Id.slice); + auto s = search_function(ad, Id.opIndex); + if (!s) s = search_function(ad, Id.opSlice); if (s) { auto fd = s.isFuncDeclaration(); @@ -9710,8 +9694,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (result) return; - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadArray(sc)) { result = e; return; @@ -10133,13 +10116,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.e1 = e1x; - Expression e = exp.op_overload(sc); - if (e) - { - result = e; - return; - } - if (exp.e1.checkReadModifyWrite(exp.op)) return setError(); @@ -10182,7 +10158,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Combine de,ea,eb,ec if (de) ea = new CommaExp(exp.loc, de, ea); - e = new CommaExp(exp.loc, ea, eb); + Expression e = new CommaExp(exp.loc, ea, eb); e = new CommaExp(exp.loc, e, ec); e = e.expressionSemantic(sc); result = e; @@ -10192,7 +10168,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.modifiableLvalue(sc); exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); - e = exp; + Expression e = exp; if (exp.e1.checkScalar() || exp.e1.checkSharedAccess(sc)) return setError(); @@ -10209,15 +10185,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(PreExp exp) { - Expression e = exp.op_overload(sc); // printf("PreExp::semantic('%s')\n", toChars()); - if (e) + if (Expression e = exp.opOverloadUnary(sc)) { result = e; return; } // Rewrite as e1+=1 or e1-=1 + Expression e; if (exp.op == EXP.prePlusPlus) e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); else @@ -10328,7 +10304,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor AggregateDeclaration ad = isAggregate(t1b); if (!ad) break; - if (search_function(ad, Id.indexass)) + if (search_function(ad, Id.opIndexAssign)) { // Deal with $ res = resolveOpDollar(sc, ae, &e0); @@ -10347,7 +10323,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ Expressions* a = ae.arguments.copy(); a.insert(0, exp.e2); - res = new DotIdExp(exp.loc, ae.e1, Id.indexass); + res = new DotIdExp(exp.loc, ae.e1, Id.opIndexAssign); res = new CallExp(exp.loc, res, a); if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2) res = res.trySemantic(sc); @@ -10358,7 +10334,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Lfallback: - if (maybeSlice && search_function(ad, Id.sliceass)) + if (maybeSlice && search_function(ad, Id.opSliceAssign)) { // Deal with $ res = resolveOpDollar(sc, ae, ie, &e0); @@ -10381,7 +10357,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor a.push(ie.lwr); a.push(ie.upr); } - res = new DotIdExp(exp.loc, ae.e1, Id.sliceass); + res = new DotIdExp(exp.loc, ae.e1, Id.opSliceAssign); res = new CallExp(exp.loc, res, a); res = res.expressionSemantic(sc); return setResult(Expression.combine(e0, res)); @@ -10471,7 +10447,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * or: * f() = value */ - if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp)) + if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, &aliasThisStop)) return setResult(e); if (e1x.checkRightThis(sc)) @@ -10604,6 +10580,35 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.op == EXP.assign && exp.e1.checkModifiable(sc) == Modifiable.initialization) { + // Check common mistake of misspelled parameters in constructors, + // e.g. `this(int feild) { this.field = field; }` + if (auto dve1 = exp.e1.isDotVarExp) + if (auto dve2 = exp.e2.isDotVarExp) + if (sc.func && sc.func.parameters && dve1.e1.isThisExp && dve2.e1.isThisExp() + && dve1.var.ident.equals(dve2.var.ident)) + { + // @@@DEPRECATED_2.121@@@ + // Deprecated in 2.111, make it an error in 2.121 + deprecation(exp.e1.loc, "cannot initialize field `%s` with itself", dve1.var.toChars()); + auto findParameter(const(char)[] s, ref int cost) + { + foreach (p; *sc.func.parameters) + { + if (p.ident.toString == s) + { + cost = 1; + return p.ident.toString; + } + } + return null; + } + import dmd.root.speller : speller; + if (auto s = speller!findParameter(dve1.var.ident.toString)) + { + deprecationSupplemental(sc.func.loc, "did you mean to use parameter `%.*s`?\n", s.fTuple.expand); + } + } + //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); auto t = exp.type; exp = new ConstructExp(exp.loc, exp.e1, exp.e2); @@ -10826,13 +10831,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!e2x.implicitConvTo(t1)) { AggregateDeclaration ad2 = isAggregate(e2x.type); - if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type)) + if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(aliasThisStop[1], exp.e2.type)) { /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); - result = exp.expressionSemantic(sc); + result = exp.expressionSemantic(sc, aliasThisStop); return; } } @@ -10887,14 +10892,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - if (search_function(sd, Id.call)) + if (search_function(sd, Id.opCall)) { /* Look for static opCall * https://issues.dlang.org/show_bug.cgi?id=2702 * Rewrite as: * e1 = typeof(e1).opCall(arguments) */ - e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call); + e2x = typeDotIdExp(e2x.loc, e1x.type, Id.opCall); e2x = new CallExp(exp.loc, e2x, exp.e2); e2x = e2x.expressionSemantic(sc); @@ -10911,13 +10916,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else // https://issues.dlang.org/show_bug.cgi?id=11355 { AggregateDeclaration ad2 = isAggregate(e2x.type); - if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type)) + if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(aliasThisStop[1], exp.e2.type)) { /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); - result = exp.expressionSemantic(sc); + result = exp.expressionSemantic(sc, aliasThisStop); return; } } @@ -10958,8 +10963,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = ae.e1.optimize(WANTvalue); ae.e2 = ev; - Expression e = ae.op_overload(sc); - if (e) + if (Expression e = ae.opOverloadAssign(sc, aliasThisStop)) { Expression ey = null; if (t2.ty == Tstruct && sd == t2.toDsymbol(sc)) @@ -11009,14 +11013,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } } - else + else if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop)) { - Expression e = exp.op_overload(sc); - if (e) - { - result = e; - return; - } + result = e; + return; } } else @@ -11033,8 +11033,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Disallow assignment operator overloads for same type if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type)) { - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop)) { result = e; return; @@ -11410,7 +11409,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct) { scope sd = (cast(TypeStruct)t1).sym; - Dsymbol opAssign = search_function(sd, Id.assign); + Dsymbol opAssign = search_function(sd, Id.opAssign); // and the struct defines an opAssign if (opAssign) @@ -11705,9 +11704,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(PowAssignExp exp) { - - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinaryAssign(sc, aliasThisStop)) { result = e; return; @@ -11754,7 +11751,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if ((exp.e1.type.isIntegral() || exp.e1.type.isFloating()) && (exp.e2.type.isIntegral() || exp.e2.type.isFloating())) { Expression e0 = null; - e = exp.reorderSettingAAElem(sc); + Expression e = exp.reorderSettingAAElem(sc); e = Expression.extractLast(e, e0); assert(e == exp); @@ -11786,8 +11783,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("CatAssignExp::semantic() %s\n", exp.toChars()); - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinaryAssign(sc, aliasThisStop)) { result = e; return; @@ -11881,49 +11877,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - // Try alias this on first operand - static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc) - { - AggregateDeclaration ad1 = isAggregate(exp.e1.type); - if (!ad1 || !ad1.aliasthis) - return null; - - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - if (isRecursiveAliasThis(exp.att1, exp.e1.type)) - return null; - //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars()); - Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident); - BinExp be = cast(BinExp)exp.copy(); - be.e1 = e1; - return be.trySemantic(sc); - } - - // Try alias this on second operand - static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc) - { - AggregateDeclaration ad2 = isAggregate(exp.e2.type); - if (!ad2 || !ad2.aliasthis) - return null; - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - if (isRecursiveAliasThis(exp.att2, exp.e2.type)) - return null; - //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars()); - Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident); - BinExp be = cast(BinExp)exp.copy(); - be.e2 = e2; - return be.trySemantic(sc); - } - Laliasthis: - result = tryAliasThisForLhs(exp, sc); + result = checkAliasThisForLhs(isAggregate(exp.e1.type), sc, exp, aliasThisStop); if (result) return; - result = tryAliasThisForRhs(exp, sc); + result = checkAliasThisForRhs(isAggregate(exp.e2.type), sc, exp, aliasThisStop); if (result) return; @@ -12076,13 +12035,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("AddExp::semantic('%s')\n", exp.toChars()); } - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; return; @@ -12139,6 +12092,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (exp.checkArithmeticBin()) + return setError(); + tb1 = exp.e1.type.toBasetype(); if (!target.isVectorOpSupported(tb1, exp.op, tb2)) { @@ -12178,13 +12134,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("MinExp::semantic('%s')\n", exp.toChars()); } - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; return; @@ -12217,6 +12167,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (t1.ty == Tpointer) { + Expression e; if (t2.ty == Tpointer) { // https://dlang.org/spec/expression.html#add_expressions @@ -12294,6 +12245,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (exp.checkArithmeticBin()) + return setError(); + t1 = exp.e1.type.toBasetype(); t2 = exp.e2.type.toBasetype(); if (!target.isVectorOpSupported(t1, exp.op, t2)) @@ -12422,14 +12376,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // https://dlang.org/spec/expression.html#cat_expressions //printf("CatExp.semantic() %s\n", toChars()); - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; return; @@ -12581,6 +12528,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); + Expression e; if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { @@ -12598,30 +12546,25 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor trySetCatExpLowering(result); } - override void visit(MulExp exp) + bool commonBinOpSemantic(BinExp exp) { - version (none) - { - printf("MulExp::semantic() %s\n", exp.toChars()); - } - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; - return; + return true; } if (Expression ex = typeCombine(exp, sc)) { result = ex; - return; + return true; } + return false; + } + bool commonArithBinOpSemantic(BinExp exp) + { + if (commonBinOpSemantic(exp)) + return true; Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -12629,15 +12572,28 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); - return; + return true; } result = exp; - return; + return true; } if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) - return setError(); + { + setError(); + return true; + } + return false; + } + override void visit(MulExp exp) + { + version (none) + { + printf("MulExp::semantic() %s\n", exp.toChars()); + } + if (commonArithBinOpSemantic(exp)) + return; if (exp.type.isFloating()) { Type t1 = exp.e1.type; @@ -12676,7 +12632,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // iy * iv = -yv exp.e1.type = exp.type; exp.e2.type = exp.type; - e = new NegExp(exp.loc, exp); + Expression e = new NegExp(exp.loc, exp); e = e.expressionSemantic(sc); result = e; return; @@ -12689,7 +12645,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = t1; // t1 is complex } } - else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) + else if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; @@ -12699,39 +12655,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(DivExp exp) { - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) - { - result = e; - return; - } - - if (Expression ex = typeCombine(exp, sc)) - { - result = ex; - return; - } - - Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - if (!isArrayOpValid(exp)) - { - result = arrayOpInvalidError(exp); - return; - } - result = exp; + if (commonArithBinOpSemantic(exp)) return; - } - - if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) - return setError(); if (exp.type.isFloating()) { @@ -12745,7 +12670,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // x/iv = i(-x/v) exp.e2.type = t1; - e = new NegExp(exp.loc, exp); + Expression e = new NegExp(exp.loc, exp); e = e.expressionSemantic(sc); result = e; return; @@ -12785,7 +12710,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = t1; // t1 is complex } } - else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) + else if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; @@ -12795,45 +12720,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(ModExp exp) { - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) - { - result = e; + if (commonArithBinOpSemantic(exp)) return; - } - if (Expression ex = typeCombine(exp, sc)) - { - result = ex; - return; - } - - Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - if (!isArrayOpValid(exp)) - { - result = arrayOpInvalidError(exp); - return; - } - result = exp; - return; - } - if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) + if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } - if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) - return setError(); - if (exp.type.isFloating()) { exp.type = exp.e1.type; @@ -12848,49 +12743,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(PowExp exp) { - - //printf("PowExp::semantic() %s\n", toChars()); - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) - { - result = e; + if (commonArithBinOpSemantic(exp)) return; - } - - if (Expression ex = typeCombine(exp, sc)) - { - result = ex; - return; - } - - Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - if (!isArrayOpValid(exp)) - { - result = arrayOpInvalidError(exp); - return; - } - result = exp; - return; - } - - if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) - return setError(); - if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) + if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } // First, attempt to fold the expression. - e = exp.optimize(WANTvalue); + Expression e = exp.optimize(WANTvalue); if (e.op != EXP.pow) { e = e.expressionSemantic(sc); @@ -12923,14 +12786,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor private void visitShift(BinExp exp) { - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; return; @@ -12971,14 +12827,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor private void visitBinaryBitOp(BinExp exp) { - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; return; @@ -13136,57 +12985,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - - EXP cmpop = exp.op; - if (auto e = exp.op_overload(sc, &cmpop)) + if (auto e = exp.opOverloadCmp(sc, aliasThisStop)) { - if (!e.type.isScalar() && e.type.equals(exp.e1.type)) - { - error(exp.loc, "recursive `opCmp` expansion"); - return setError(); - } - if (e.op == EXP.call) - { - - if (t1.ty == Tclass && t2.ty == Tclass) - { - // Lower to object.__cmp(e1, e2) - Expression cl = new IdentifierExp(exp.loc, Id.empty); - cl = new DotIdExp(exp.loc, cl, Id.object); - cl = new DotIdExp(exp.loc, cl, Id.__cmp); - cl = cl.expressionSemantic(sc); - - auto arguments = new Expressions(); - // Check if op_overload found a better match by calling e2.opCmp(e1) - // If the operands were swapped, then the result must be reversed - // e1.opCmp(e2) == -e2.opCmp(e1) - // cmpop takes care of this - if (exp.op == cmpop) - { - arguments.push(exp.e1); - arguments.push(exp.e2); - } - else - { - // Use better match found by op_overload - arguments.push(exp.e2); - arguments.push(exp.e1); - } - - cl = new CallExp(exp.loc, cl, arguments); - cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0)); - result = cl.expressionSemantic(sc); - return; - } - - e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0); - e = e.expressionSemantic(sc); - } result = e; return; } - if (Expression ex = typeCombine(exp, sc)) { result = ex; @@ -13284,14 +13088,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(InExp exp) { - - if (Expression ex = binSemanticProp(exp, sc)) - { - result = ex; - return; - } - Expression e = exp.op_overload(sc); - if (e) + if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { result = e; return; @@ -13455,13 +13252,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return false; } - if (auto e = exp.op_overload(sc)) + if (auto e = exp.opOverloadEqual(sc, aliasThisStop)) { result = e; return; } - const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray); const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc); @@ -13931,6 +13727,32 @@ Expression trySemantic(Expression exp, Scope* sc) return e; } +/********************************** + * Try expression semantic on `exp`, gagging semantic errors, + * but don't resolve alias this on a BinExp when the lhs or rhs + * has the corresponding type in `aliasThisStop` (See `isRecursiveAliasThis`). + * + * Params: + * exp = expression to try semantic on + * sc = scope + * aliasThisStop = pair of recursive alias this types to stop endless recursion + * Returns: + * exp after expression semantic, or `null` on error + */ +Expression trySemanticAliasThis(Expression exp, Scope* sc, Type[2] aliasThisStop) +{ + if (exp.expressionSemanticDone) + return exp; + + const errors = global.startGagging(); + Expression e = expressionSemantic(exp, sc, aliasThisStop); + + if (global.endGagging(errors)) + return null; + + return e; +} + /************************** * Helper function for easy error propagation. * If error occurs, returns ErrorExp. Otherwise returns NULL. @@ -14015,6 +13837,18 @@ Expression expressionSemantic(Expression e, Scope* sc) return v.result; } +// ditto, but passes alias this stop types, see trySemanticAliasThis +private Expression expressionSemantic(Expression e, Scope* sc, Type[2] aliasThisStop) +{ + if (e.expressionSemanticDone) + return e; + + scope v = new ExpressionSemanticVisitor(sc); + v.aliasThisStop = aliasThisStop; + e.accept(v); + return v.result; +} + private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) { //printf("dotIdSemanticPropX() %s\n", toChars(exp)); @@ -14849,6 +14683,105 @@ MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink return m; } +private bool checkScalar(Expression e) +{ + if (e.op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (!e.type.isScalar()) + { + error(e.loc, "`%s` is not a scalar, it is a `%s`", e.toChars(), e.type.toChars()); + return true; + } + return e.checkValue(); +} + +private bool checkNoBool(Expression e) +{ + if (e.op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (e.type.toBasetype().ty == Tbool) + { + error(e.loc, "operation not allowed on `bool` `%s`", e.toChars()); + return true; + } + return false; +} + +private bool checkIntegral(Expression e) +{ + if (e.op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (!e.type.isIntegral()) + { + error(e.loc, "`%s` is not of integral type, it is a `%s`", e.toChars(), e.type.toChars()); + return true; + } + return e.checkValue(); +} + +private bool checkArithmetic(Expression e, EXP op) +{ + if (op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (!e.type.isIntegral() && !e.type.isFloating()) + { + // unary aggregate ops error here + const char* msg = e.type.isAggregate() ? + "operator `%s` is not defined for `%s` of type `%s`" : + "illegal operator `%s` for `%s` of type `%s`"; + error(e.loc, msg, EXPtoString(op).ptr, e.toChars(), e.type.toChars()); + return true; + } + + // FIXME: Existing code relies on adding / subtracting types in typeof() expressions: + // alias I = ulong; alias U = typeof(I + 1u); + // https://github.com/dlang/dmd/issues/20763 + if (op == EXP.add || op == EXP.min) + return false; + + return e.checkValue(); +} + +/******************************* + * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. + * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) + * Returns true if error occurs. + */ +private bool checkReadModifyWrite(Expression e, EXP rmwOp, Expression ex = null) +{ + //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); + if (!e.type || !e.type.isShared() || e.type.isTypeStruct() || e.type.isTypeClass()) + return false; + + // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. + switch (rmwOp) + { + case EXP.plusPlus: + case EXP.prePlusPlus: + rmwOp = EXP.addAssign; + break; + case EXP.minusMinus: + case EXP.preMinusMinus: + rmwOp = EXP.minAssign; + break; + default: + break; + } + + error(e.loc, "read-modify-write operations are not allowed for `shared` variables"); + errorSupplemental(e.loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead", + EXPtoString(rmwOp).ptr, e.toChars(), ex ? ex.toChars() : "1"); + return true; +} + private bool checkSharedAccessBin(BinExp binExp, Scope* sc) { const r1 = binExp.e1.checkSharedAccess(sc); @@ -14856,6 +14789,18 @@ private bool checkSharedAccessBin(BinExp binExp, Scope* sc) return (r1 || r2); } +private bool checkIntegralBin(BinExp e) +{ + bool r1 = e.e1.checkIntegral(); + bool r2 = e.e2.checkIntegral(); + return (r1 || r2); +} + +private bool checkArithmeticBin(BinExp e) +{ + return (e.e1.checkArithmetic(e.op) || e.e2.checkArithmetic(e.op)); +} + /*************************************** * If expression is shared, check that we can access it. * Give error message if not. @@ -16451,7 +16396,7 @@ Expression toBoolean(Expression exp, Scope* sc) /* Don't really need to check for opCast first, but by doing so we * get better error messages if it isn't there. */ - if (Dsymbol fd = search_function(ad, Id._cast)) + if (Dsymbol fd = search_function(ad, Id.opCast)) { e = new CastExp(exp.loc, e, Type.tbool); e = e.expressionSemantic(sc); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 993bce8..70f4c83 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -581,8 +581,7 @@ extern (C++) class FuncDeclaration : Declaration { if (isMain()) return "D main"; - else - return Dsymbol.toPrettyChars(QualifyTypes); + return Dsymbol.toPrettyChars(QualifyTypes); } /** for diagnostics, e.g. 'int foo(int x, int y) pure' */ diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index d391bdb..961a0d2 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -2435,7 +2435,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt void visitSymOff(SymOffExp e) { if (e.offset) - buf.printf("(& %s%+lld)", e.var.toChars(), e.offset); + buf.printf("(& %s + %llu)", e.var.toChars(), e.offset); else if (e.var.isTypeInfoDeclaration()) buf.writestring(e.var.toChars()); else diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index ee4214a..9833e198 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -223,60 +223,15 @@ immutable Msgtable[] msgtable = { "__LOCAL_SIZE" }, // For operator overloads - { "uadd", "opPos" }, - { "neg", "opNeg" }, - { "com", "opCom" }, - { "add", "opAdd" }, - { "add_r", "opAdd_r" }, - { "sub", "opSub" }, - { "sub_r", "opSub_r" }, - { "mul", "opMul" }, - { "mul_r", "opMul_r" }, - { "div", "opDiv" }, - { "div_r", "opDiv_r" }, - { "mod", "opMod" }, - { "mod_r", "opMod_r" }, - { "eq", "opEquals" }, - { "cmp", "opCmp" }, - { "iand", "opAnd" }, - { "iand_r", "opAnd_r" }, - { "ior", "opOr" }, - { "ior_r", "opOr_r" }, - { "ixor", "opXor" }, - { "ixor_r", "opXor_r" }, - { "shl", "opShl" }, - { "shl_r", "opShl_r" }, - { "shr", "opShr" }, - { "shr_r", "opShr_r" }, - { "ushr", "opUShr" }, - { "ushr_r", "opUShr_r" }, - { "cat", "opCat" }, - { "cat_r", "opCat_r" }, - { "assign", "opAssign" }, - { "addass", "opAddAssign" }, - { "subass", "opSubAssign" }, - { "mulass", "opMulAssign" }, - { "divass", "opDivAssign" }, - { "modass", "opModAssign" }, - { "andass", "opAndAssign" }, - { "orass", "opOrAssign" }, - { "xorass", "opXorAssign" }, - { "shlass", "opShlAssign" }, - { "shrass", "opShrAssign" }, - { "ushrass", "opUShrAssign" }, - { "catass", "opCatAssign" }, - { "postinc", "opPostInc" }, - { "postdec", "opPostDec" }, - { "index", "opIndex" }, - { "indexass", "opIndexAssign" }, - { "slice", "opSlice" }, - { "sliceass", "opSliceAssign" }, - { "call", "opCall" }, - { "_cast", "opCast" }, - { "opIn" }, - { "opIn_r" }, - { "opStar" }, - { "opDot" }, + { "opEquals" }, + { "opCmp" }, + { "opAssign" }, + { "opIndex" }, + { "opIndexAssign" }, + { "opSlice" }, + { "opSliceAssign" }, + { "opCall" }, + { "opCast" }, { "opDispatch" }, { "opDollar" }, { "opUnary" }, @@ -287,9 +242,6 @@ immutable Msgtable[] msgtable = { "opOpAssign" }, { "opIndexOpAssign" }, { "opSliceOpAssign" }, - { "pow", "opPow" }, - { "pow_r", "opPow_r" }, - { "powass", "opPowAssign" }, { "classNew", "new" }, { "classDelete", "delete" }, diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index aec6807..c181d53 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -489,7 +489,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn else i.exp = e.optimize(WANTvalue); } - else if (search_function(sd, Id.call)) + else if (search_function(sd, Id.opCall)) { /* https://issues.dlang.org/show_bug.cgi?id=1547 * @@ -499,7 +499,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn * i.exp = typeof(sd).opCall(arguments) */ - Expression e = typeDotIdExp(i.loc, sd.type, Id.call); + Expression e = typeDotIdExp(i.loc, sd.type, Id.opCall); e = new CallExp(i.loc, e, i.exp); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); diff --git a/gcc/d/dmd/mangle/cpp.d b/gcc/d/dmd/mangle/cpp.d index 67c9b53..4932b01 100644 --- a/gcc/d/dmd/mangle/cpp.d +++ b/gcc/d/dmd/mangle/cpp.d @@ -60,11 +60,11 @@ package CppOperator isCppOperator(const scope Identifier id) { with (Id) with (CppOperator) { - return (id == _cast) ? Cast : - (id == assign) ? Assign : - (id == eq) ? Eq : - (id == index) ? Index : - (id == call) ? Call : + return (id == opCast) ? Cast : + (id == opAssign) ? Assign : + (id == opEquals) ? Eq : + (id == opIndex) ? Index : + (id == opCall) ? Call : (id == opUnary) ? Unary : (id == opBinary) ? Binary : (id == opOpAssign) ? OpAssign : @@ -435,10 +435,10 @@ private final class CppMangleVisitor : Visitor // 4. null pointer: std::nullptr_t (since C++11) if (t.ty == Tvoid || t.ty == Tbool) return true; - else if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11) + if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11) return true; - else - return t.isTypeBasic() && (t.isIntegral() || t.isReal()); + + return t.isTypeBasic() && (t.isIntegral() || t.isReal()); } /****************************** @@ -1102,13 +1102,13 @@ private final class CppMangleVisitor : Visitor buf.writestring(ctor.isCpCtor ? "C2" : "C1"); else if (d.isAggregateDtor()) buf.writestring("D1"); - else if (d.ident && d.ident == Id.assign) + else if (d.ident && d.ident == Id.opAssign) buf.writestring("aS"); - else if (d.ident && d.ident == Id.eq) + else if (d.ident && d.ident == Id.opEquals) buf.writestring("eq"); - else if (d.ident && d.ident == Id.index) + else if (d.ident && d.ident == Id.opIndex) buf.writestring("ix"); - else if (d.ident && d.ident == Id.call) + else if (d.ident && d.ident == Id.opCall) buf.writestring("cl"); else source_name(d, true); @@ -1939,21 +1939,21 @@ extern(C++): //printf("enum id = '%s'\n", id.toChars()); if (id == Id.__c_long) return writeBasicType(t, 0, 'l'); - else if (id == Id.__c_ulong) + if (id == Id.__c_ulong) return writeBasicType(t, 0, 'm'); - else if (id == Id.__c_char) + if (id == Id.__c_char) return writeBasicType(t, 0, 'c'); - else if (id == Id.__c_wchar_t) + if (id == Id.__c_wchar_t) return writeBasicType(t, 0, 'w'); - else if (id == Id.__c_longlong) + if (id == Id.__c_longlong) return writeBasicType(t, 0, 'x'); - else if (id == Id.__c_ulonglong) + if (id == Id.__c_ulonglong) return writeBasicType(t, 0, 'y'); - else if (id == Id.__c_complex_float) + if (id == Id.__c_complex_float) return Type.tcomplex32.accept(this); - else if (id == Id.__c_complex_double) + if (id == Id.__c_complex_double) return Type.tcomplex64.accept(this); - else if (id == Id.__c_complex_real) + if (id == Id.__c_complex_real) return Type.tcomplex80.accept(this); doSymbol(t); @@ -2362,8 +2362,7 @@ private bool isNamespaceEqual (CPPNamespaceDeclaration a, Nspace b, size_t idx = // We need to see if there's more ident enclosing if (auto pb = b.toParent().isNspace()) return isNamespaceEqual(a.cppnamespace, pb); - else - return a.cppnamespace is null; + return a.cppnamespace is null; } /// Returns: diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index f91687b..b270943 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -1295,17 +1295,15 @@ extern (C++) abstract class Type : ASTNode { if (t.isWildConst()) return MODFlags.wild; - else - return MODFlags.wildconst; + return MODFlags.wildconst; } - else if (isWild()) + if (isWild()) return MODFlags.wild; - else if (isConst()) + if (isConst()) return MODFlags.const_; - else if (isMutable()) + if (isMutable()) return MODFlags.mutable; - else - assert(0); + assert(0); } return 0; } diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index fc7618b..4fc117e 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -111,26 +111,13 @@ private bool isAssignmentOpId(Identifier id) { import dmd.id : Id; - return id == Id.assign - || id == Id.addass - || id == Id.subass - || id == Id.mulass - || id == Id.divass - || id == Id.modass - || id == Id.andass - || id == Id.orass - || id == Id.xorass - || id == Id.shlass - || id == Id.shrass - || id == Id.ushrass - || id == Id.catass - || id == Id.indexass - || id == Id.slice - || id == Id.sliceass + return id == Id.opAssign + || id == Id.opIndexAssign + || id == Id.opSlice + || id == Id.opSliceAssign || id == Id.opOpAssign || id == Id.opIndexOpAssign - || id == Id.opSliceOpAssign - || id == Id.powass; + || id == Id.opSliceOpAssign; } /** diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index c5ee77a..b671986 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -714,8 +714,8 @@ extern(C++) private final class Supported : Objc { if (cd.classKind == ClassKind.objc && fd.isStatic && !cd.objc.isMeta) return cd.objc.metaclass; - else - return cd; + + return cd; } override void addToClassMethodList(FuncDeclaration fd, ClassDeclaration cd) const @@ -805,11 +805,10 @@ extern(C++) private final class Supported : Objc { if (classDeclaration.baseClass) return getRuntimeMetaclass(classDeclaration.baseClass); - else - return classDeclaration; + + return classDeclaration; } - else - return classDeclaration.objc.metaclass; + return classDeclaration.objc.metaclass; } override void addSymbols(AttribDeclaration attribDeclaration, diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 56b3601..92f3bb2 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -71,84 +71,6 @@ bool isCommutative(EXP op) @safe return false; } -/*********************************** - * Get Identifier for operator overload. - */ -private Identifier opId(Expression e) -{ - switch (e.op) - { - case EXP.uadd: return Id.uadd; - case EXP.negate: return Id.neg; - case EXP.tilde: return Id.com; - case EXP.cast_: return Id._cast; - case EXP.in_: return Id.opIn; - case EXP.plusPlus: return Id.postinc; - case EXP.minusMinus: return Id.postdec; - case EXP.add: return Id.add; - case EXP.min: return Id.sub; - case EXP.mul: return Id.mul; - case EXP.div: return Id.div; - case EXP.mod: return Id.mod; - case EXP.pow: return Id.pow; - case EXP.leftShift: return Id.shl; - case EXP.rightShift: return Id.shr; - case EXP.unsignedRightShift: return Id.ushr; - case EXP.and: return Id.iand; - case EXP.or: return Id.ior; - case EXP.xor: return Id.ixor; - case EXP.concatenate: return Id.cat; - case EXP.assign: return Id.assign; - case EXP.addAssign: return Id.addass; - case EXP.minAssign: return Id.subass; - case EXP.mulAssign: return Id.mulass; - case EXP.divAssign: return Id.divass; - case EXP.modAssign: return Id.modass; - case EXP.powAssign: return Id.powass; - case EXP.leftShiftAssign: return Id.shlass; - case EXP.rightShiftAssign: return Id.shrass; - case EXP.unsignedRightShiftAssign: return Id.ushrass; - case EXP.andAssign: return Id.andass; - case EXP.orAssign: return Id.orass; - case EXP.xorAssign: return Id.xorass; - case EXP.concatenateAssign: return Id.catass; - case EXP.equal: return Id.eq; - case EXP.lessThan: - case EXP.lessOrEqual: - case EXP.greaterThan: - case EXP.greaterOrEqual: return Id.cmp; - case EXP.array: return Id.index; - case EXP.star: return Id.opStar; - default: assert(0); - } -} - -/*********************************** - * Get Identifier for reverse operator overload, - * `null` if not supported for this operator. - */ -private Identifier opId_r(Expression e) -{ - switch (e.op) - { - case EXP.in_: return Id.opIn_r; - case EXP.add: return Id.add_r; - case EXP.min: return Id.sub_r; - case EXP.mul: return Id.mul_r; - case EXP.div: return Id.div_r; - case EXP.mod: return Id.mod_r; - case EXP.pow: return Id.pow_r; - case EXP.leftShift: return Id.shl_r; - case EXP.rightShift: return Id.shr_r; - case EXP.unsignedRightShift:return Id.ushr_r; - case EXP.and: return Id.iand_r; - case EXP.or: return Id.ior_r; - case EXP.xor: return Id.ixor_r; - case EXP.concatenate: return Id.cat_r; - default: return null; - } -} - /******************************************* * Helper function to turn operator into template argument list */ @@ -208,7 +130,7 @@ Objects* opToArg(Scope* sc, EXP op) } // Try alias this on first operand -private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e) +Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e, Type[2] aliasThisStop) { if (!ad || !ad.aliasthis) return null; @@ -216,7 +138,7 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - if (isRecursiveAliasThis(e.att1, e.e1.type)) + if (isRecursiveAliasThis(aliasThisStop[0], e.e1.type)) return null; //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars()); BinExp be = cast(BinExp)e.copy(); @@ -227,24 +149,18 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE if (!be.e1) return null; - Expression result; - if (be.op == EXP.concatenateAssign) - result = be.op_overload(sc); - else - result = be.trySemantic(sc); - - return result; + return be.trySemanticAliasThis(sc, aliasThisStop); } // Try alias this on second operand -private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e) +Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e, Type[2] aliasThisStop) { if (!ad || !ad.aliasthis) return null; /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - if (isRecursiveAliasThis(e.att2, e.e2.type)) + if (isRecursiveAliasThis(aliasThisStop[1], e.e2.type)) return null; //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars()); BinExp be = cast(BinExp)e.copy(); @@ -252,189 +168,14 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE if (!be.e2) return null; - Expression result; - if (be.op == EXP.concatenateAssign) - result = be.op_overload(sc); - else - result = be.trySemantic(sc); - - return result; + return be.trySemanticAliasThis(sc, aliasThisStop); } -/************************************ - * Operator overload. - * Check for operator overload, if so, replace - * with function call. - * Params: - * e = expression with operator - * sc = context - * pop = if not null, is set to the operator that was actually overloaded, - * which may not be `e.op`. Happens when operands are reversed to - * match an overload - * Returns: - * `null` if not an operator overload, - * otherwise the lowered expression - */ -Expression op_overload(Expression e, Scope* sc, EXP* pop = null) +Expression opOverloadUnary(UnaExp e, Scope* sc) { - Expression visit(Expression e) - { - assert(0); - } - - Expression visitUna(UnaExp e) - { - //printf("UnaExp::op_overload() (%s)\n", e.toChars()); - Expression result; - if (auto ae = e.e1.isArrayExp()) - { - ae.e1 = ae.e1.expressionSemantic(sc); - ae.e1 = resolveProperties(sc, ae.e1); - Expression ae1old = ae.e1; - const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); - IntervalExp ie = null; - if (maybeSlice && ae.arguments.length) - { - ie = (*ae.arguments)[0].isIntervalExp(); - } - Type att = null; // first cyclic `alias this` type - while (true) - { - if (ae.e1.op == EXP.error) - { - return ae.e1; - } - Expression e0 = null; - Expression ae1save = ae.e1; - ae.lengthVar = null; - Type t1b = ae.e1.type.toBasetype(); - AggregateDeclaration ad = isAggregate(t1b); - if (!ad) - break; - if (search_function(ad, Id.opIndexUnary)) - { - // Deal with $ - result = resolveOpDollar(sc, ae, &e0); - if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) - goto Lfallback; - if (result.op == EXP.error) - return result; - /* Rewrite op(a[arguments]) as: - * a.opIndexUnary!(op)(arguments) - */ - Expressions* a = ae.arguments.copy(); - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexUnary, tiargs); - result = new CallExp(e.loc, result, a); - if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)() - result = result.trySemantic(sc); - else - result = result.expressionSemantic(sc); - if (result) - { - return Expression.combine(e0, result); - } - } - Lfallback: - if (maybeSlice && search_function(ad, Id.opSliceUnary)) - { - // Deal with $ - result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == EXP.error) - return result; - /* Rewrite op(a[i..j]) as: - * a.opSliceUnary!(op)(i, j) - */ - auto a = new Expressions(); - if (ie) - { - a.push(ie.lwr); - a.push(ie.upr); - } - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceUnary, tiargs); - result = new CallExp(e.loc, result, a); - result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); - return result; - } - // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) - { - /* Rewrite op(a[arguments]) as: - * op(a.aliasthis[arguments]) - */ - ae.e1 = resolveAliasThis(sc, ae1save, true); - if (ae.e1) - continue; - } - break; - } - ae.e1 = ae1old; // recovery - ae.lengthVar = null; - } - e.e1 = e.e1.expressionSemantic(sc); - e.e1 = resolveProperties(sc, e.e1); - Type att = null; // first cyclic `alias this` type - while (1) - { - if (e.e1.op == EXP.error) - { - return e.e1; - } - - AggregateDeclaration ad = isAggregate(e.e1.type); - if (!ad) - break; - - Dsymbol fd = null; - /* Rewrite as: - * e1.opUnary!(op)() - */ - fd = search_function(ad, Id.opUnary); - if (fd) - { - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); - result = new CallExp(e.loc, result); - result = result.expressionSemantic(sc); - return result; - } - // D1-style operator overloads, deprecated - if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus) - { - auto id = opId(e); - fd = search_function(ad, id); - if (fd) - { - // @@@DEPRECATED_2.110@@@. - // Deprecated in 2.088, made an error in 2.100 - error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); - return ErrorExp.get(); - } - } - // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars()); - if (auto e1 = resolveAliasThis(sc, e.e1, true)) - { - e.e1 = e1; - continue; - } - break; - } - break; - } - return result; - } - - Expression visitArray(ArrayExp ae) + Expression result; + if (auto ae = e.e1.isArrayExp()) { - //printf("ArrayExp::op_overload() (%s)\n", ae.toChars()); ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; @@ -444,7 +185,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { ie = (*ae.arguments)[0].isIntervalExp(); } - Expression result; Type att = null; // first cyclic `alias this` type while (true) { @@ -458,43 +198,23 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) Type t1b = ae.e1.type.toBasetype(); AggregateDeclaration ad = isAggregate(t1b); if (!ad) - { - // If the non-aggregate expression ae.e1 is indexable or sliceable, - // convert it to the corresponding concrete expression. - if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type) - { - // Convert to SliceExp - if (maybeSlice) - { - result = new SliceExp(ae.loc, ae.e1, ie); - result = result.expressionSemantic(sc); - return result; - } - // Convert to IndexExp - if (ae.arguments.length == 1) - { - result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]); - result = result.expressionSemantic(sc); - return result; - } - } break; - } - if (search_function(ad, Id.index)) + if (search_function(ad, Id.opIndexUnary)) { // Deal with $ result = resolveOpDollar(sc, ae, &e0); - if (!result) // a[i..j] might be: a.opSlice(i, j) + if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) goto Lfallback; if (result.op == EXP.error) return result; - /* Rewrite e1[arguments] as: - * e1.opIndex(arguments) - */ + /* Rewrite op(a[arguments]) as: + * a.opIndexUnary!(op)(arguments) + */ Expressions* a = ae.arguments.copy(); - result = new DotIdExp(ae.loc, ae.e1, Id.index); - result = new CallExp(ae.loc, result, a); - if (maybeSlice) // a[] might be: a.opSlice() + Objects* tiargs = opToArg(sc, e.op); + result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexUnary, tiargs); + result = new CallExp(e.loc, result, a); + if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)() result = result.trySemantic(sc); else result = result.expressionSemantic(sc); @@ -504,36 +224,24 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } } Lfallback: - if (maybeSlice && ae.e1.op == EXP.type) - { - result = new SliceExp(ae.loc, ae.e1, ie); - result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); - return result; - } - if (maybeSlice && search_function(ad, Id.slice)) + if (maybeSlice && search_function(ad, Id.opSliceUnary)) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == EXP.error) - { - if (!e0 && !search_function(ad, Id.dollar)) { - ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars()); - } return result; - } - /* Rewrite a[i..j] as: - * a.opSlice(i, j) - */ + /* Rewrite op(a[i..j]) as: + * a.opSliceUnary!(op)(i, j) + */ auto a = new Expressions(); if (ie) { a.push(ie.lwr); a.push(ie.upr); } - result = new DotIdExp(ae.loc, ae.e1, Id.slice); - result = new CallExp(ae.loc, result, a); + Objects* tiargs = opToArg(sc, e.op); + result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceUnary, tiargs); + result = new CallExp(e.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); return result; @@ -541,10 +249,9 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { - //printf("att arr e1 = %s\n", this.e1.type.toChars()); /* Rewrite op(a[arguments]) as: - * op(a.aliasthis[arguments]) - */ + * op(a.aliasthis[arguments]) + */ ae.e1 = resolveAliasThis(sc, ae1save, true); if (ae.e1) continue; @@ -553,846 +260,810 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } ae.e1 = ae1old; // recovery ae.lengthVar = null; - return result; } - - /*********************************************** - * This is mostly the same as UnaryExp::op_overload(), but has - * a different rewrite. - */ - Expression visitCast(CastExp e, Type att = null) + e.e1 = e.e1.expressionSemantic(sc); + e.e1 = resolveProperties(sc, e.e1); + Type att = null; // first cyclic `alias this` type + while (1) { - //printf("CastExp::op_overload() (%s)\n", e.toChars()); - Expression result; - if (AggregateDeclaration ad = isAggregate(e.e1.type)) + if (e.e1.op == EXP.error) { - Dsymbol fd = null; - /* Rewrite as: - * e1.opCast!(T)() + return e.e1; + } + + AggregateDeclaration ad = isAggregate(e.e1.type); + if (!ad) + break; + + Dsymbol fd = null; + /* Rewrite as: + * e1.opUnary!(op)() + */ + fd = search_function(ad, Id.opUnary); + if (fd) + { + Objects* tiargs = opToArg(sc, e.op); + result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); + result = new CallExp(e.loc, result); + result = result.expressionSemantic(sc); + return result; + } + + // Didn't find it. Forward to aliasthis + if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) + { + /* Rewrite op(e1) as: + * op(e1.aliasthis) */ - fd = search_function(ad, Id._cast); - if (fd) - { - version (all) - { - // Backwards compatibility with D1 if opCast is a function, not a template - if (fd.isFuncDeclaration()) - { - // Rewrite as: e1.opCast() - return build_overload(e.loc, sc, e.e1, null, fd); - } - } - auto tiargs = new Objects(); - tiargs.push(e.to); - result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); - result = new CallExp(e.loc, result); - result = result.expressionSemantic(sc); - return result; - } - // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) + //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars()); + if (auto e1 = resolveAliasThis(sc, e.e1, true)) { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - if (auto e1 = resolveAliasThis(sc, e.e1, true)) - { - result = e.copy(); - (cast(UnaExp)result).e1 = e1; - result = visitCast(result.isCastExp(), att); - return result; - } + e.e1 = e1; + continue; } + break; } - return result; + break; } + return result; +} - Expression visitBin(BinExp e) +Expression opOverloadArray(ArrayExp ae, Scope* sc) +{ + ae.e1 = ae.e1.expressionSemantic(sc); + ae.e1 = resolveProperties(sc, ae.e1); + Expression ae1old = ae.e1; + const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); + IntervalExp ie = null; + if (maybeSlice && ae.arguments.length) { - //printf("BinExp::op_overload() (%s)\n", e.toChars()); - Identifier id = opId(e); - Identifier id_r = opId_r(e); - int argsset = 0; - AggregateDeclaration ad1 = isAggregate(e.e1.type); - AggregateDeclaration ad2 = isAggregate(e.e2.type); - if (e.op == EXP.assign && ad1 == ad2) - { - StructDeclaration sd = ad1.isStructDeclaration(); - if (sd && - (!sd.hasIdentityAssign || - /* Do a blit if we can and the rvalue is something like .init, - * where a postblit is not necessary. - */ - (sd.hasBlitAssign && !e.e2.isLvalue()))) - { - /* This is bitwise struct assignment. */ - return null; - } - } - Dsymbol s = null; - Dsymbol s_r = null; - Objects* tiargs = null; - if (e.op == EXP.plusPlus || e.op == EXP.minusMinus) + ie = (*ae.arguments)[0].isIntervalExp(); + } + Expression result; + Type att = null; // first cyclic `alias this` type + while (true) + { + if (ae.e1.op == EXP.error) { - // Bug4099 fix - if (ad1 && search_function(ad1, Id.opUnary)) - return null; + return ae.e1; } - if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus) + Expression e0 = null; + Expression ae1save = ae.e1; + ae.lengthVar = null; + Type t1b = ae.e1.type.toBasetype(); + AggregateDeclaration ad = isAggregate(t1b); + if (!ad) { - /* Try opBinary and opBinaryRight - */ - if (ad1) + // If the non-aggregate expression ae.e1 is indexable or sliceable, + // convert it to the corresponding concrete expression. + if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type) { - s = search_function(ad1, Id.opBinary); - if (s && !s.isTemplateDeclaration()) + // Convert to SliceExp + if (maybeSlice) { - error(e.e1.loc, "`%s.opBinary` isn't a template", e.e1.toChars()); - return ErrorExp.get(); + result = new SliceExp(ae.loc, ae.e1, ie); + result = result.expressionSemantic(sc); + return result; } - } - if (ad2) - { - s_r = search_function(ad2, Id.opBinaryRight); - if (s_r && !s_r.isTemplateDeclaration()) + // Convert to IndexExp + if (ae.arguments.length == 1) { - error(e.e2.loc, "`%s.opBinaryRight` isn't a template", e.e2.toChars()); - return ErrorExp.get(); + result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]); + result = result.expressionSemantic(sc); + return result; } - if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778 - s_r = null; } - // Set tiargs, the template argument list, which will be the operator string - if (s || s_r) + break; + } + if (search_function(ad, Id.opIndex)) + { + // Deal with $ + result = resolveOpDollar(sc, ae, &e0); + if (!result) // a[i..j] might be: a.opSlice(i, j) + goto Lfallback; + if (result.op == EXP.error) + return result; + /* Rewrite e1[arguments] as: + * e1.opIndex(arguments) + */ + Expressions* a = ae.arguments.copy(); + result = new DotIdExp(ae.loc, ae.e1, Id.opIndex); + result = new CallExp(ae.loc, result, a); + if (maybeSlice) // a[] might be: a.opSlice() + result = result.trySemantic(sc); + else + result = result.expressionSemantic(sc); + if (result) { - id = Id.opBinary; - id_r = Id.opBinaryRight; - tiargs = opToArg(sc, e.op); + return Expression.combine(e0, result); } } - if (!s && !s_r) + Lfallback: + if (maybeSlice && ae.e1.op == EXP.type) + { + result = new SliceExp(ae.loc, ae.e1, ie); + result = result.expressionSemantic(sc); + result = Expression.combine(e0, result); + return result; + } + if (maybeSlice && search_function(ad, Id.opSlice)) { - // Try the D1-style operators, deprecated - if (ad1 && id) + // Deal with $ + result = resolveOpDollar(sc, ae, ie, &e0); + + if (result.op == EXP.error) { - s = search_function(ad1, id); - if (s && id != Id.assign) - { - // @@@DEPRECATED_2.110@@@. - // Deprecated in 2.088, made an error in 2.100 - if (id == Id.postinc || id == Id.postdec) - error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); - else - error(e.loc, "`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); - return ErrorExp.get(); + if (!e0 && !search_function(ad, Id.dollar)) { + ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars()); } + return result; } - if (ad2 && id_r) + /* Rewrite a[i..j] as: + * a.opSlice(i, j) + */ + auto a = new Expressions(); + if (ie) { - s_r = search_function(ad2, id_r); - // https://issues.dlang.org/show_bug.cgi?id=12778 - // If both x.opBinary(y) and y.opBinaryRight(x) found, - // and they are exactly same symbol, x.opBinary(y) should be preferred. - if (s_r && s_r == s) - s_r = null; - if (s_r) - { - // @@@DEPRECATED_2.110@@@. - // Deprecated in 2.088, made an error in 2.100 - error(e.loc, "`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); - return ErrorExp.get(); - } + a.push(ie.lwr); + a.push(ie.upr); } + result = new DotIdExp(ae.loc, ae.e1, Id.opSlice); + result = new CallExp(ae.loc, result, a); + result = result.expressionSemantic(sc); + result = Expression.combine(e0, result); + return result; } - Expressions* args1 = new Expressions(); - Expressions* args2 = new Expressions(); - if (s || s_r) + // Didn't find it. Forward to aliasthis + if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { - /* Try: - * a.opfunc(b) - * b.opfunc_r(a) - * and see which is better. + //printf("att arr e1 = %s\n", this.e1.type.toChars()); + /* Rewrite op(a[arguments]) as: + * op(a.aliasthis[arguments]) */ - args1.setDim(1); - (*args1)[0] = e.e1; - expandTuples(args1); - args2.setDim(1); - (*args2)[0] = e.e2; - expandTuples(args2); - argsset = 1; - MatchAccumulator m; - if (s) - { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - { - return ErrorExp.get(); - } - } - FuncDeclaration lastf = m.lastf; - if (s_r) + ae.e1 = resolveAliasThis(sc, ae1save, true); + if (ae.e1) + continue; + } + break; + } + ae.e1 = ae1old; // recovery + ae.lengthVar = null; + return result; +} + +/*********************************************** + * This is mostly the same as opOverloadUnary but has + * a different rewrite. + */ +Expression opOverloadCast(CastExp e, Scope* sc, Type att = null) +{ + Expression result; + if (AggregateDeclaration ad = isAggregate(e.e1.type)) + { + Dsymbol fd = null; + /* Rewrite as: + * e1.opCast!(T)() + */ + fd = search_function(ad, Id.opCast); + if (fd) + { + version (all) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) + // Backwards compatibility with D1 if opCast is a function, not a template + if (fd.isFuncDeclaration()) { - return ErrorExp.get(); + // Rewrite as: e1.opCast() + return build_overload(e.loc, sc, e.e1, null, fd); } } - if (m.count > 1) - { - // Error, ambiguous - error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); - } - else if (m.last == MATCH.nomatch) - { - if (tiargs) - goto L1; - m.lastf = null; - } - if (e.op == EXP.plusPlus || e.op == EXP.minusMinus) - { - // Kludge because operator overloading regards e++ and e-- - // as unary, but it's implemented as a binary. - // Rewrite (e1 ++ e2) as e1.postinc() - // Rewrite (e1 -- e2) as e1.postdec() - return build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s); - } - else if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch) - { - // Rewrite (e1 op e2) as e1.opfunc(e2) - return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); - } - else - { - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); - } + auto tiargs = new Objects(); + tiargs.push(e.to); + result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); + result = new CallExp(e.loc, result); + result = result.expressionSemantic(sc); + return result; } - L1: - version (all) + // Didn't find it. Forward to aliasthis + if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) { - // Retained for D1 compatibility - if (isCommutative(e.op) && !tiargs) + /* Rewrite op(e1) as: + * op(e1.aliasthis) + */ + if (auto e1 = resolveAliasThis(sc, e.e1, true)) { - s = null; - s_r = null; - if (ad1 && id_r) - { - s_r = search_function(ad1, id_r); - } - if (ad2 && id) - { - s = search_function(ad2, id); - if (s && s == s_r) // https://issues.dlang.org/show_bug.cgi?id=12778 - s = null; - } - if (s || s_r) - { - /* Try: - * a.opfunc_r(b) - * b.opfunc(a) - * and see which is better. - */ - if (!argsset) - { - args1.setDim(1); - (*args1)[0] = e.e1; - expandTuples(args1); - args2.setDim(1); - (*args2)[0] = e.e2; - expandTuples(args2); - } - MatchAccumulator m; - if (s_r) - { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - { - return ErrorExp.get(); - } - } - FuncDeclaration lastf = m.lastf; - if (s) - { - functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - { - return ErrorExp.get(); - } - } - if (m.count > 1) - { - // Error, ambiguous - error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); - } - else if (m.last == MATCH.nomatch) - { - m.lastf = null; - } - - if (lastf && m.lastf == lastf || !s && m.last == MATCH.nomatch) - { - // Rewrite (e1 op e2) as e1.opfunc_r(e2) - return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r); - } - else - { - // Rewrite (e1 op e2) as e2.opfunc(e1) - Expression result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s); - // When reversing operands of comparison operators, - // need to reverse the sense of the op - if (pop) - *pop = reverseRelation(e.op); - return result; - } - } + result = e.copy(); + (cast(UnaExp)result).e1 = e1; + result = opOverloadCast(result.isCastExp(), sc, att); + return result; } } + } + return result; +} - Expression rewrittenLhs; - if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 +// When no operator overload functions are found for `e`, recursively try with `alias this` +// Returns: `null` when still no overload found, otherwise resolved lowering +Expression binAliasThis(BinExp e, Scope* sc, Type[2] aliasThisStop) +{ + AggregateDeclaration ad1 = isAggregate(e.e1.type); + AggregateDeclaration ad2 = isAggregate(e.e2.type); + Expression rewrittenLhs; + if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 + { + if (Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop)) { - if (Expression result = checkAliasThisForLhs(ad1, sc, e)) - { - /* https://issues.dlang.org/show_bug.cgi?id=19441 - * - * alias this may not be used for partial assignment. - * If a struct has a single member which is aliased this - * directly or aliased to a ref getter function that returns - * the mentioned member, then alias this may be - * used since the object will be fully initialised. - * If the struct is nested, the context pointer is considered - * one of the members, hence the `ad1.fields.length == 2 && ad1.vthis` - * condition. - */ - if (result.op != EXP.assign) - return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)` + /* https://issues.dlang.org/show_bug.cgi?id=19441 + * + * alias this may not be used for partial assignment. + * If a struct has a single member which is aliased this + * directly or aliased to a ref getter function that returns + * the mentioned member, then alias this may be + * used since the object will be fully initialised. + * If the struct is nested, the context pointer is considered + * one of the members, hence the `ad1.fields.length == 2 && ad1.vthis` + * condition. + */ + if (result.op != EXP.assign) + return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)` - auto ae = result.isAssignExp(); - if (ae.e1.op != EXP.dotVariable) - return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2` + auto ae = result.isAssignExp(); + if (ae.e1.op != EXP.dotVariable) + return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2` - auto dve = ae.e1.isDotVarExp(); - if (auto ad = dve.var.isMember2()) + auto dve = ae.e1.isDotVarExp(); + if (auto ad = dve.var.isMember2()) + { + // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2` + // Ensure that `var` is the only field member in `ad` + if (ad.fields.length == 1 || (ad.fields.length == 2 && ad.vthis)) { - // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2` - // Ensure that `var` is the only field member in `ad` - if (ad.fields.length == 1 || (ad.fields.length == 2 && ad.vthis)) - { - if (dve.var == ad.aliasthis.sym) - return result; - } + if (dve.var == ad.aliasthis.sym) + return result; } - rewrittenLhs = ae.e1; } + rewrittenLhs = ae.e1; } - if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 - { - if (Expression result = checkAliasThisForRhs(ad2, sc, e)) - return result; - } - if (rewrittenLhs) - { - error(e.loc, "cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", - e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars()); - return ErrorExp.get(); - } - return null; } - - Expression visitEqual(EqualExp e) + if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { - //printf("EqualExp::op_overload() (%s)\n", e.toChars()); - Type t1 = e.e1.type.toBasetype(); - Type t2 = e.e2.type.toBasetype(); + if (Expression result = checkAliasThisForRhs(ad2, sc, e, aliasThisStop)) + return result; + } + if (rewrittenLhs) + { + error(e.loc, "cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", + e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars()); + return ErrorExp.get(); + } + return null; +} - /* Array equality is handled by expressionSemantic() potentially - * lowering to object.__equals(), which takes care of overloaded - * operators for the element types. - */ - if ((t1.ty == Tarray || t1.ty == Tsarray) && - (t2.ty == Tarray || t2.ty == Tsarray)) +Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) +{ + AggregateDeclaration ad1 = isAggregate(e.e1.type); + AggregateDeclaration ad2 = isAggregate(e.e2.type); + if (ad1 == ad2) + { + StructDeclaration sd = ad1.isStructDeclaration(); + if (sd && + (!sd.hasIdentityAssign || + /* Do a blit if we can and the rvalue is something like .init, + * where a postblit is not necessary. + */ + (sd.hasBlitAssign && !e.e2.isLvalue()))) { + /* This is bitwise struct assignment. */ return null; } + } + Dsymbol s = search_function(ad1, Id.opAssign); - /* Check for class equality with null literal or typeof(null). - */ - if (t1.ty == Tclass && e.e2.op == EXP.null_ || - t2.ty == Tclass && e.e1.op == EXP.null_) - { - error(e.loc, "use `%s` instead of `%s` when comparing with `null`", - EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, - EXPtoString(e.op).ptr); - return ErrorExp.get(); - } - if (t1.ty == Tclass && t2.ty == Tnull || - t1.ty == Tnull && t2.ty == Tclass) - { - // Comparing a class with typeof(null) should not call opEquals - return null; - } + bool choseReverse; + if (auto result = pickBestBinaryOverload(sc, null, s, null, e, choseReverse)) + return result; - /* Check for class equality. - */ - if (t1.ty == Tclass && t2.ty == Tclass) - { - ClassDeclaration cd1 = t1.isClassHandle(); - ClassDeclaration cd2 = t2.isClassHandle(); - if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp)) - { - /* Rewrite as: - * .object.opEquals(e1, e2) - */ - if (!ClassDeclaration.object) - { - error(e.loc, "cannot compare classes for equality because `object.Object` was not declared"); - return null; - } + return binAliasThis(e, sc, aliasThisStop); +} - Expression e1x = e.e1; - Expression e2x = e.e2; +Expression opOverloadBinary(BinExp e, Scope* sc, Type[2] aliasThisStop) +{ + if (Expression err = binSemanticProp(e, sc)) + return err; - /* The explicit cast is necessary for interfaces - * https://issues.dlang.org/show_bug.cgi?id=4088 - */ - Type to = ClassDeclaration.object.getType(); - if (cd1.isInterfaceDeclaration()) - e1x = new CastExp(e.loc, e.e1, t1.isMutable() ? to : to.constOf()); - if (cd2.isInterfaceDeclaration()) - e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf()); - - Expression result = new IdentifierExp(e.loc, Id.empty); - result = new DotIdExp(e.loc, result, Id.object); - result = new DotIdExp(e.loc, result, Id.eq); - result = new CallExp(e.loc, result, e1x, e2x); - if (e.op == EXP.notEqual) - result = new NotExp(e.loc, result); - result = result.expressionSemantic(sc); - return result; - } - } + AggregateDeclaration ad1 = isAggregate(e.e1.type); + AggregateDeclaration ad2 = isAggregate(e.e2.type); + + // Try opBinary and opBinaryRight + Dsymbol s = search_function(ad1, Id.opBinary); + if (s && !s.isTemplateDeclaration()) + { + error(e.e1.loc, "`%s.opBinary` isn't a template", e.e1.toChars()); + return ErrorExp.get(); + } + + Dsymbol s_r = search_function(ad2, Id.opBinaryRight); + if (s_r && !s_r.isTemplateDeclaration()) + { + error(e.e2.loc, "`%s.opBinaryRight` isn't a template", e.e2.toChars()); + return ErrorExp.get(); + } + if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778 + s_r = null; + + bool choseReverse; + if (auto res = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, s_r, e, choseReverse)) + return res; + + return binAliasThis(e, sc, aliasThisStop); +} + +Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) +{ + Type t1 = e.e1.type.toBasetype(); + Type t2 = e.e2.type.toBasetype(); + + /* Array equality is handled by expressionSemantic() potentially + * lowering to object.__equals(), which takes care of overloaded + * operators for the element types. + */ + if ((t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) + { + return null; + } + + /* Check for class equality with null literal or typeof(null). + */ + if (t1.ty == Tclass && e.e2.op == EXP.null_ || + t2.ty == Tclass && e.e1.op == EXP.null_) + { + error(e.loc, "use `%s` instead of `%s` when comparing with `null`", + EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, + EXPtoString(e.op).ptr); + return ErrorExp.get(); + } + if (t1.ty == Tclass && t2.ty == Tnull || + t1.ty == Tnull && t2.ty == Tclass) + { + // Comparing a class with typeof(null) should not call opEquals + return null; + } - if (Expression result = compare_overload(e, sc, Id.eq, null)) + /* Check for class equality. + */ + if (t1.ty == Tclass && t2.ty == Tclass) + { + ClassDeclaration cd1 = t1.isClassHandle(); + ClassDeclaration cd2 = t2.isClassHandle(); + if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp)) { - if (lastComma(result).op == EXP.call && e.op == EXP.notEqual) + /* Rewrite as: + * .object.opEquals(e1, e2) + */ + if (!ClassDeclaration.object) { - result = new NotExp(result.loc, result); - result = result.expressionSemantic(sc); + error(e.loc, "cannot compare classes for equality because `object.Object` was not declared"); + return null; } + + Expression e1x = e.e1; + Expression e2x = e.e2; + + /* The explicit cast is necessary for interfaces + * https://issues.dlang.org/show_bug.cgi?id=4088 + */ + Type to = ClassDeclaration.object.getType(); + if (cd1.isInterfaceDeclaration()) + e1x = new CastExp(e.loc, e.e1, t1.isMutable() ? to : to.constOf()); + if (cd2.isInterfaceDeclaration()) + e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf()); + + Expression result = new IdentifierExp(e.loc, Id.empty); + result = new DotIdExp(e.loc, result, Id.object); + result = new DotIdExp(e.loc, result, Id.opEquals); + result = new CallExp(e.loc, result, e1x, e2x); + if (e.op == EXP.notEqual) + result = new NotExp(e.loc, result); + result = result.expressionSemantic(sc); return result; } + } + + EXP cmpOp; + if (Expression result = compare_overload(e, sc, Id.opEquals, cmpOp, aliasThisStop)) + { + if (lastComma(result).op == EXP.call && e.op == EXP.notEqual) + { + result = new NotExp(result.loc, result); + result = result.expressionSemantic(sc); + } + return result; + } - /* Check for pointer equality. + /* Check for pointer equality. + */ + if (t1.ty == Tpointer || t2.ty == Tpointer) + { + /* Rewrite: + * ptr1 == ptr2 + * as: + * ptr1 is ptr2 + * + * This is just a rewriting for deterministic AST representation + * as the backend input. */ - if (t1.ty == Tpointer || t2.ty == Tpointer) + auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity; + Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2); + return r.expressionSemantic(sc); + } + + /* Check for struct equality without opEquals. + */ + if (t1.ty == Tstruct && t2.ty == Tstruct) + { + auto sd = t1.isTypeStruct().sym; + if (sd != t2.isTypeStruct().sym) + return null; + + import dmd.clone : needOpEquals; + if (!sc.previews.fieldwise && !needOpEquals(sd)) { - /* Rewrite: - * ptr1 == ptr2 - * as: - * ptr1 is ptr2 - * - * This is just a rewriting for deterministic AST representation - * as the backend input. - */ + // Use bitwise equality. auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity; Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2); return r.expressionSemantic(sc); } - /* Check for struct equality without opEquals. + /* Do memberwise equality. + * https://dlang.org/spec/expression.html#equality_expressions + * Rewrite: + * e1 == e2 + * as: + * e1.tupleof == e2.tupleof + * + * If sd is a nested struct, and if it's nested in a class, it will + * also compare the parent class's equality. Otherwise, compares + * the identity of parent context through void*. */ - if (t1.ty == Tstruct && t2.ty == Tstruct) - { - auto sd = t1.isTypeStruct().sym; - if (sd != t2.isTypeStruct().sym) - return null; - - import dmd.clone : needOpEquals; - if (!sc.previews.fieldwise && !needOpEquals(sd)) - { - // Use bitwise equality. - auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity; - Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2); - return r.expressionSemantic(sc); - } + e = e.copy().isEqualExp(); + e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof); + e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof); + + auto sc2 = sc.push(); + sc2.noAccessCheck = true; + Expression r = e.expressionSemantic(sc2); + sc2.pop(); + return r; + } - /* Do memberwise equality. - * https://dlang.org/spec/expression.html#equality_expressions - * Rewrite: - * e1 == e2 - * as: - * e1.tupleof == e2.tupleof - * - * If sd is a nested struct, and if it's nested in a class, it will - * also compare the parent class's equality. Otherwise, compares - * the identity of parent context through void*. - */ - e = e.copy().isEqualExp(); - e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof); - e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof); - - auto sc2 = sc.push(); - sc2.noAccessCheck = true; - Expression r = e.expressionSemantic(sc2); - sc2.pop(); - return r; + /* Check for tuple equality. + */ + if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple) + { + auto tup1 = e.e1.isTupleExp(); + auto tup2 = e.e2.isTupleExp(); + size_t dim = tup1.exps.length; + if (dim != tup2.exps.length) + { + error(e.loc, "mismatched sequence lengths, `%d` and `%d`", + cast(int)dim, cast(int)tup2.exps.length); + return ErrorExp.get(); } - /* Check for tuple equality. - */ - if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple) + Expression result; + if (dim == 0) + { + // zero-length tuple comparison should always return true or false. + result = IntegerExp.createBool(e.op == EXP.equal); + } + else { - auto tup1 = e.e1.isTupleExp(); - auto tup2 = e.e2.isTupleExp(); - size_t dim = tup1.exps.length; - if (dim != tup2.exps.length) + for (size_t i = 0; i < dim; i++) { - error(e.loc, "mismatched sequence lengths, `%d` and `%d`", - cast(int)dim, cast(int)tup2.exps.length); - return ErrorExp.get(); + auto ex1 = (*tup1.exps)[i]; + auto ex2 = (*tup2.exps)[i]; + auto eeq = new EqualExp(e.op, e.loc, ex1, ex2); + + if (!result) + result = eeq; + else if (e.op == EXP.equal) + result = new LogicalExp(e.loc, EXP.andAnd, result, eeq); + else + result = new LogicalExp(e.loc, EXP.orOr, result, eeq); } + assert(result); + } + result = Expression.combine(tup1.e0, tup2.e0, result); + result = result.expressionSemantic(sc); - Expression result; - if (dim == 0) - { - // zero-length tuple comparison should always return true or false. - result = IntegerExp.createBool(e.op == EXP.equal); - } - else - { - for (size_t i = 0; i < dim; i++) - { - auto ex1 = (*tup1.exps)[i]; - auto ex2 = (*tup2.exps)[i]; - auto eeq = new EqualExp(e.op, e.loc, ex1, ex2); - - if (!result) - result = eeq; - else if (e.op == EXP.equal) - result = new LogicalExp(e.loc, EXP.andAnd, result, eeq); - else - result = new LogicalExp(e.loc, EXP.orOr, result, eeq); - } - assert(result); - } - result = Expression.combine(tup1.e0, tup2.e0, result); - result = result.expressionSemantic(sc); + return result; + } + return null; +} - return result; - } +Expression opOverloadCmp(CmpExp exp, Scope* sc, Type[2] aliasThisStop) +{ + //printf("CmpExp:: () (%s)\n", e.toChars()); + EXP cmpOp = exp.op; + auto e = compare_overload(exp, sc, Id.opCmp, cmpOp, aliasThisStop); + if (!e) return null; + + if (!e.type.isScalar() && e.type.equals(exp.e1.type)) + { + error(e.loc, "recursive `opCmp` expansion"); + return ErrorExp.get(); } + if (e.op != EXP.call) + return e; - Expression visitCmp(CmpExp e) + Type t1 = exp.e1.type.toBasetype(); + Type t2 = exp.e2.type.toBasetype(); + if (t1.ty != Tclass || t2.ty != Tclass) { - //printf("CmpExp:: () (%s)\n", e.toChars()); - return compare_overload(e, sc, Id.cmp, pop); + return new CmpExp(cmpOp, exp.loc, e, IntegerExp.literal!0).expressionSemantic(sc); } - /********************************* - * Operator overloading for op= - */ - Expression visitBinAssign(BinAssignExp e) + // Lower to object.__cmp(e1, e2) + Expression cl = new IdentifierExp(exp.loc, Id.empty); + cl = new DotIdExp(exp.loc, cl, Id.object); + cl = new DotIdExp(exp.loc, cl, Id.__cmp); + cl = cl.expressionSemantic(sc); + + auto arguments = new Expressions(); + // Check if op_overload found a better match by calling e2.opCmp(e1) + // If the operands were swapped, then the result must be reversed + // e1.opCmp(e2) == -e2.opCmp(e1) + // cmpop takes care of this + if (exp.op == cmpOp) + { + arguments.push(exp.e1); + arguments.push(exp.e2); + } + else + { + // Use better match found by op_overload + arguments.push(exp.e2); + arguments.push(exp.e1); + } + + cl = new CallExp(e.loc, cl, arguments); + cl = new CmpExp(cmpOp, exp.loc, cl, new IntegerExp(0)); + return cl.expressionSemantic(sc); +} + +/********************************* + * Operator overloading for op= + */ +Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisStop) +{ + if (auto ae = e.e1.isArrayExp()) { - //printf("BinAssignExp::op_overload() (%s)\n", e.toChars()); - if (auto ae = e.e1.isArrayExp()) + ae.e1 = ae.e1.expressionSemantic(sc); + ae.e1 = resolveProperties(sc, ae.e1); + Expression ae1old = ae.e1; + const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); + IntervalExp ie = null; + if (maybeSlice && ae.arguments.length) { - ae.e1 = ae.e1.expressionSemantic(sc); - ae.e1 = resolveProperties(sc, ae.e1); - Expression ae1old = ae.e1; - const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); - IntervalExp ie = null; - if (maybeSlice && ae.arguments.length) + ie = (*ae.arguments)[0].isIntervalExp(); + } + Type att = null; // first cyclic `alias this` type + while (true) + { + if (ae.e1.op == EXP.error) { - ie = (*ae.arguments)[0].isIntervalExp(); + return ae.e1; } - Type att = null; // first cyclic `alias this` type - while (true) + Expression e0 = null; + Expression ae1save = ae.e1; + ae.lengthVar = null; + Type t1b = ae.e1.type.toBasetype(); + AggregateDeclaration ad = isAggregate(t1b); + if (!ad) + break; + if (search_function(ad, Id.opIndexOpAssign)) { - if (ae.e1.op == EXP.error) - { - return ae.e1; - } - Expression e0 = null; - Expression ae1save = ae.e1; - ae.lengthVar = null; - Type t1b = ae.e1.type.toBasetype(); - AggregateDeclaration ad = isAggregate(t1b); - if (!ad) - break; - if (search_function(ad, Id.opIndexOpAssign)) - { - // Deal with $ - Expression result = resolveOpDollar(sc, ae, &e0); - if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j) - goto Lfallback; - if (result.op == EXP.error) - return result; - result = e.e2.expressionSemantic(sc); - if (result.op == EXP.error) - return result; - e.e2 = result; - /* Rewrite a[arguments] op= e2 as: - * a.opIndexOpAssign!(op)(e2, arguments) - */ - Expressions* a = ae.arguments.copy(); - a.insert(0, e.e2); - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexOpAssign, tiargs); - result = new CallExp(e.loc, result, a); - if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2) - result = result.trySemantic(sc); - else - result = result.expressionSemantic(sc); - if (result) - { - return Expression.combine(e0, result); - } - } - Lfallback: - if (maybeSlice && search_function(ad, Id.opSliceOpAssign)) - { - // Deal with $ - Expression result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == EXP.error) - return result; - result = e.e2.expressionSemantic(sc); - if (result.op == EXP.error) - return result; - e.e2 = result; - /* Rewrite (a[i..j] op= e2) as: - * a.opSliceOpAssign!(op)(e2, i, j) - */ - auto a = new Expressions(); - a.push(e.e2); - if (ie) - { - a.push(ie.lwr); - a.push(ie.upr); - } - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceOpAssign, tiargs); - result = new CallExp(e.loc, result, a); - result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); + // Deal with $ + Expression result = resolveOpDollar(sc, ae, &e0); + if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j) + goto Lfallback; + if (result.op == EXP.error) return result; - } - // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) + result = e.e2.expressionSemantic(sc); + if (result.op == EXP.error) + return result; + e.e2 = result; + /* Rewrite a[arguments] op= e2 as: + * a.opIndexOpAssign!(op)(e2, arguments) + */ + Expressions* a = ae.arguments.copy(); + a.insert(0, e.e2); + Objects* tiargs = opToArg(sc, e.op); + result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexOpAssign, tiargs); + result = new CallExp(e.loc, result, a); + if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2) + result = result.trySemantic(sc); + else + result = result.expressionSemantic(sc); + if (result) { - /* Rewrite (a[arguments] op= e2) as: - * a.aliasthis[arguments] op= e2 - */ - ae.e1 = resolveAliasThis(sc, ae1save, true); - if (ae.e1) - continue; + return Expression.combine(e0, result); } - break; } - ae.e1 = ae1old; // recovery - ae.lengthVar = null; - } - Expression result = e.binSemanticProp(sc); - if (result) - return result; - // Don't attempt 'alias this' if an error occurred - if (e.e1.type.ty == Terror || e.e2.type.ty == Terror) - { - return ErrorExp.get(); - } - Identifier id = opId(e); - Expressions* args2 = new Expressions(); - AggregateDeclaration ad1 = isAggregate(e.e1.type); - Dsymbol s = null; - Objects* tiargs = null; - /* Try opOpAssign - */ - if (ad1) - { - s = search_function(ad1, Id.opOpAssign); - if (s && !s.isTemplateDeclaration()) + Lfallback: + if (maybeSlice && search_function(ad, Id.opSliceOpAssign)) { - error(e.loc, "`%s.opOpAssign` isn't a template", e.e1.toChars()); - return ErrorExp.get(); + // Deal with $ + Expression result = resolveOpDollar(sc, ae, ie, &e0); + if (result.op == EXP.error) + return result; + result = e.e2.expressionSemantic(sc); + if (result.op == EXP.error) + return result; + e.e2 = result; + /* Rewrite (a[i..j] op= e2) as: + * a.opSliceOpAssign!(op)(e2, i, j) + */ + auto a = new Expressions(); + a.push(e.e2); + if (ie) + { + a.push(ie.lwr); + a.push(ie.upr); + } + Objects* tiargs = opToArg(sc, e.op); + result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceOpAssign, tiargs); + result = new CallExp(e.loc, result, a); + result = result.expressionSemantic(sc); + result = Expression.combine(e0, result); + return result; } - } - // Set tiargs, the template argument list, which will be the operator string - if (s) - { - id = Id.opOpAssign; - tiargs = opToArg(sc, e.op); - } - - // Try D1-style operator overload, deprecated - if (!s && ad1 && id) - { - s = search_function(ad1, id); - if (s) + // Didn't find it. Forward to aliasthis + if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { - // @@@DEPRECATED_2.110@@@. - // Deprecated in 2.088, made an error in 2.100 - scope char[] op = EXPtoString(e.op).dup; - op[$-1] = '\0'; // remove trailing `=` - error(e.loc, "`%s` is obsolete. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr); - return ErrorExp.get(); + /* Rewrite (a[arguments] op= e2) as: + * a.aliasthis[arguments] op= e2 + */ + ae.e1 = resolveAliasThis(sc, ae1save, true); + if (ae.e1) + continue; } + break; } + ae.e1 = ae1old; // recovery + ae.lengthVar = null; + } + Expression result = e.binSemanticProp(sc); + if (result) + return result; + // Don't attempt 'alias this' if an error occurred + if (e.e1.type.ty == Terror || e.e2.type.ty == Terror) + { + return ErrorExp.get(); + } + AggregateDeclaration ad1 = isAggregate(e.e1.type); + Dsymbol s = search_function(ad1, Id.opOpAssign); + if (s && !s.isTemplateDeclaration()) + { + error(e.loc, "`%s.opOpAssign` isn't a template", e.e1.toChars()); + return ErrorExp.get(); + } - if (s) - { - /* Try: - * a.opOpAssign(b) - */ - args2.setDim(1); - (*args2)[0] = e.e2; - expandTuples(args2); - MatchAccumulator m; - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - { - return ErrorExp.get(); - } - if (m.count > 1) - { - // Error, ambiguous - error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); - } - else if (m.last == MATCH.nomatch) - { - if (tiargs) - goto L1; - m.lastf = null; - } - // Rewrite (e1 op e2) as e1.opOpAssign(e2) - return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); - } - L1: - result = checkAliasThisForLhs(ad1, sc, e); - if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs - return result; + bool choseReverse; + if (auto res = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, null, e, choseReverse)) + return res; - return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); - } + result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop); + if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs + return result; - if (pop) - *pop = e.op; + return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop); +} - switch (e.op) - { - case EXP.cast_ : return visitCast(e.isCastExp()); - case EXP.array : return visitArray(e.isArrayExp()); +/** +Given symbols `s` and `s_r`, try to instantiate `e.e1.s!tiargs(e.e2)` and `e.e2.s_r!tiargs(e.e1)`, +and return the one with the best match level. + +Params: + sc = scope + tiargs = (optional) template arguments to instantiate symbols with + s = (optional) symbol of straightforward template (e.g. opBinary) + s_r = (optional) symbol of reversed template (e.g. opBinaryRight) + e = binary expression being overloaded, supplying arguments to the function calls + choseReverse = set to true when `s_r` was chosen instead of `s` +Returns: + Resulting operator overload function call, or `null` if neither symbol worked +*/ +private Expression pickBestBinaryOverload(Scope* sc, Objects* tiargs, Dsymbol s, Dsymbol s_r, BinExp e, out bool choseReverse) +{ + if (!s && !s_r) + return null; - case EXP.notEqual : - case EXP.equal : return visitEqual(e.isEqualExp()); + Expressions* args1 = new Expressions(1); + (*args1)[0] = e.e1; + expandTuples(args1); + Expressions* args2 = new Expressions(1); + (*args2)[0] = e.e2; + expandTuples(args2); + MatchAccumulator m; - case EXP.lessOrEqual : - case EXP.greaterThan : - case EXP.greaterOrEqual: - case EXP.lessThan : return visitCmp(cast(CmpExp)e); + if (s) + { + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) + return ErrorExp.get(); + } + FuncDeclaration lastf = m.lastf; + int count = m.count; + if (s_r) + { + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) + return ErrorExp.get(); + } + if (m.count > 1) + { + /* The following if says "not ambiguous" if there's one match + * from s and one from s_r, in which case we pick s. + * This doesn't follow the spec, but is a workaround for the case + * where opEquals was generated from templates and we cannot figure + * out if both s and s_r came from the same declaration or not. + * The test case is: + * import std.typecons; + * void main() { + * assert(tuple("has a", 2u) == tuple("has a", 1)); + * } + */ + if (!(m.lastf == lastf && m.count == 2 && count == 1)) + { + // Error, ambiguous + error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); + } + } + else if (m.last == MATCH.nomatch) + { + if (tiargs) + return null; + m.lastf = null; + } - default: - if (auto ex = e.isBinAssignExp()) return visitBinAssign(ex); - if (auto ex = e.isBinExp()) return visitBin(ex); - if (auto ex = e.isUnaExp()) return visitUna(ex); - return visit(e); + if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch) + { + choseReverse = false; + // Rewrite (e1 op e2) as e1.opfunc(e2) + return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); + } + else + { + choseReverse = true; + // Rewrite (e1 op e2) as e2.opfunc_r(e1) + return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); } } /****************************************** * Common code for overloading of EqualExp and CmpExp */ -private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop) +private Expression compare_overload(BinExp e, Scope* sc, Identifier id, ref EXP cmpOp, Type[2] aliasThisStop) { //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars()); AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); - Dsymbol s = null; - Dsymbol s_r = null; - if (ad1) - { - s = search_function(ad1, id); - } - if (ad2) + Dsymbol s = search_function(ad1, id); + Dsymbol s_r = search_function(ad2, id); + + if (s == s_r) + s_r = null; + + bool choseReverse; + if (auto res = pickBestBinaryOverload(sc, null, s, s_r, e, choseReverse)) { - s_r = search_function(ad2, id); - if (s == s_r) - s_r = null; - } - Objects* tiargs = null; - if (s || s_r) - { - /* Try: - * a.opEquals(b) - * b.opEquals(a) - * and see which is better. - */ - Expressions* args1 = new Expressions(1); - (*args1)[0] = e.e1; - expandTuples(args1); - Expressions* args2 = new Expressions(1); - (*args2)[0] = e.e2; - expandTuples(args2); - MatchAccumulator m; - if (0 && s && s_r) - { - printf("s : %s\n", s.toPrettyChars()); - printf("s_r: %s\n", s_r.toPrettyChars()); - } - if (s) - { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - return ErrorExp.get(); - } - FuncDeclaration lastf = m.lastf; - int count = m.count; - if (s_r) - { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - return ErrorExp.get(); - } - if (m.count > 1) - { - /* The following if says "not ambiguous" if there's one match - * from s and one from s_r, in which case we pick s. - * This doesn't follow the spec, but is a workaround for the case - * where opEquals was generated from templates and we cannot figure - * out if both s and s_r came from the same declaration or not. - * The test case is: - * import std.typecons; - * void main() { - * assert(tuple("has a", 2u) == tuple("has a", 1)); - * } - */ - if (!(m.lastf == lastf && m.count == 2 && count == 1)) - { - // Error, ambiguous - error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); - } - } - else if (m.last == MATCH.nomatch) - { - m.lastf = null; - } - Expression result; - if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch) - { - // Rewrite (e1 op e2) as e1.opfunc(e2) - result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); - } - else - { - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); - // When reversing operands of comparison operators, - // need to reverse the sense of the op - if (pop) - *pop = reverseRelation(e.op); - } - return result; + if (choseReverse) + cmpOp = reverseRelation(e.op); + return res; } + /* * https://issues.dlang.org/show_bug.cgi?id=16657 * at this point, no matching opEquals was found for structs, @@ -1400,8 +1071,8 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop */ if ((e.op == EXP.equal || e.op == EXP.notEqual) && ad1 == ad2) return null; - Expression result = checkAliasThisForLhs(ad1, sc, e); - return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); + Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop); + return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop); } /*********************************** @@ -1425,6 +1096,8 @@ Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expres */ Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) { + if (!ad) + return null; if (Dsymbol s = ad.search(Loc.initial, funcid)) { //printf("search_function: s = '%s'\n", s.kind()); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index b851b9a..2e29762 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2759,35 +2759,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer error("`new` allocator must be annotated with `@disabled`"); } nextToken(); - - /* @@@DEPRECATED_2.108@@@ - * After deprecation period (2.108), remove all code in the version(all) block. - */ - version (all) - { - auto parameterList = parseParameterList(null); // parameterList ignored - if (parameterList.parameters.length > 0 || parameterList.varargs != VarArg.none) - deprecation("`new` allocator with non-empty parameter list is deprecated"); - auto f = new AST.NewDeclaration(loc, stc); - if (token.value != TOK.semicolon) - { - deprecation("`new` allocator with function definition is deprecated"); - parseContracts(f); // body ignored - f.fbody = null; - f.fensures = null; - f.frequires = null; - } - else - nextToken(); - return f; - } - else - { - check(TOK.leftParenthesis); - check(TOK.rightParenthesis); - check(TOK.semicolon); - return new AST.NewDeclaration(loc, stc); - } + check(TOK.leftParenthesis); + check(TOK.rightParenthesis); + check(TOK.semicolon); + return new AST.NewDeclaration(loc, stc); } /********************************************** @@ -5844,7 +5819,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.plusPlus: case TOK.minusMinus: case TOK.new_: - case TOK.delete_: case TOK.delegate_: case TOK.function_: case TOK.typeid_: @@ -8713,15 +8687,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer e = new AST.ComExp(loc, e); break; - case TOK.delete_: - // @@@DEPRECATED_2.109@@@ - // Use of `delete` keyword has been an error since 2.099. - // Remove from the parser after 2.109. - nextToken(); - e = parseUnaryExp(); - e = new AST.DeleteExp(loc, e, false); - break; - case TOK.cast_: // cast(type) expression { nextToken(); @@ -8839,7 +8804,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.dot: case TOK.plusPlus: case TOK.minusMinus: - case TOK.delete_: case TOK.new_: case TOK.leftParenthesis: case TOK.identifier: diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index def7d46..89f612c 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -270,7 +270,7 @@ private extern(C++) final class Semantic3Visitor : Visitor //{ static int x; if (++x == 2) *(char*)0=0; } //printf("\tlinkage = %d\n", sc.linkage); - if (funcdecl.ident == Id.assign && !funcdecl.inuse) + if (funcdecl.ident == Id.opAssign && !funcdecl.inuse) { if (funcdecl.storage_class & STC.inference) { diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index b499c00..e82a582 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -48,7 +48,6 @@ enum TOK : ubyte false_, throw_, new_, - delete_, variable, slice, version_, @@ -459,7 +458,6 @@ private immutable TOK[] keywords = TOK.false_, TOK.cast_, TOK.new_, - TOK.delete_, TOK.throw_, TOK.module_, TOK.pragma_, @@ -680,7 +678,6 @@ extern (C++) struct Token TOK.false_: "false", TOK.cast_: "cast", TOK.new_: "new", - TOK.delete_: "delete", TOK.throw_: "throw", TOK.module_: "module", TOK.pragma_: "pragma", diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 2a984b4..c12a00b 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -54,7 +54,6 @@ enum class TOK : unsigned char false_, throw_, new_, - delete_, variable, slice, version_, diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index ca10db1..65d267f 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -2025,7 +2025,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } else if (sd.xeq == sd.xerreq) { - if (search_function(sd, Id.eq)) + if (search_function(sd, Id.opEquals)) { .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars()); } @@ -2037,7 +2037,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } else if (!sd.xhash) { - if (search_function(sd, Id.eq)) + if (search_function(sd, Id.opEquals)) { .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars()); } @@ -2075,9 +2075,9 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) __gshared FuncDeclaration fcmp = null; __gshared FuncDeclaration fhash = null; if (!feq) - feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration(); + feq = search_function(ClassDeclaration.object, Id.opEquals).isFuncDeclaration(); if (!fcmp) - fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration(); + fcmp = search_function(ClassDeclaration.object, Id.opCmp).isFuncDeclaration(); if (!fhash) fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration(); assert(fcmp && feq && fhash); @@ -3417,7 +3417,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden if (s) error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars()); - else if (ident == Id.call && mt.ty == Tclass) + else if (ident == Id.opCall && mt.ty == Tclass) error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars()); else if (const n = importHint(ident.toString())) @@ -4883,7 +4883,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag /*************************************** * `ident` was not found as a member of `mt`. - * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`. + * Attempt to use overloaded opDispatch() or `alias this`. * If that fails, forward to visitType(). * Params: * mt = class or struct @@ -4939,21 +4939,6 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag ident != Id.postblit && ident != Id.__xpostblit) { - /* Look for overloaded opDot() to see if we should forward request - * to it. - */ - if (auto fd = search_function(sym, Id.opDot)) - { - /* Rewrite e.ident as: - * e.opDot().ident - */ - e = build_overload(e.loc, sc, e, null, fd); - // @@@DEPRECATED_2.110@@@. - // Deprecated in 2.082, made an error in 2.100. - error(e.loc, "`opDot` is obsolete. Use `alias this`"); - return ErrorExp.get(); - } - /* Look for overloaded opDispatch to see if we should forward request * to it. */ diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d index aa88458..f62147a 100644 --- a/gcc/testsuite/gdc.test/compilable/interpret3.d +++ b/gcc/testsuite/gdc.test/compilable/interpret3.d @@ -6240,9 +6240,9 @@ struct Coord13831 struct Chunk13831 { - this(Coord13831) + this(Coord13831 coord) { - coord = coord; + this.coord = coord; } Coord13831 coord; diff --git a/gcc/testsuite/gdc.test/compilable/nogc.d b/gcc/testsuite/gdc.test/compilable/nogc.d index 959adc4..5f14339 100644 --- a/gcc/testsuite/gdc.test/compilable/nogc.d +++ b/gcc/testsuite/gdc.test/compilable/nogc.d @@ -36,9 +36,6 @@ void foo_compiles() {} static assert(!__traits(compiles, new Struct())); static assert(!__traits(compiles, new Object())); - int* p; - static assert(!__traits(compiles, delete p)); - int[int] aa; static assert( __traits(compiles, aa[0])); static assert(!__traits(compiles, (aa[0] = 10))); diff --git a/gcc/testsuite/gdc.test/compilable/test22510.d b/gcc/testsuite/gdc.test/compilable/test22510.d index af5d0a4..1207bf0 100644 --- a/gcc/testsuite/gdc.test/compilable/test22510.d +++ b/gcc/testsuite/gdc.test/compilable/test22510.d @@ -7,7 +7,7 @@ struct S @disable this(this); this (scope ref inout S) inout { - this.b = b; + this.b = 0; } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctor_self_assignment.d b/gcc/testsuite/gdc.test/fail_compilation/ctor_self_assignment.d new file mode 100644 index 0000000..9d424b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctor_self_assignment.d @@ -0,0 +1,23 @@ +/** +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/ctor_self_assignment.d(17): Deprecation: cannot initialize field `location` with itself +fail_compilation/ctor_self_assignment.d(15): did you mean to use parameter `locaction`? +--- +*/ +// https://forum.dlang.org/post/teghfhpmvkdcfwfeovua@forum.dlang.org + +alias Location = int; + +struct Node +{ + this(Location locaction, uint f) + { + this.location = location; + this.f = f; + } + + Location location; + uint f; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d index 19c6475..f8ebc37 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d @@ -1,52 +1,93 @@ /* -REQUIRED_ARGS: -de +REQUIRED_ARGS: TEST_OUTPUT: --- -fail_compilation/dep_d1_ops.d(105): Error: `opAdd` is obsolete. Use `opBinary(string op)(...) if (op == "+")` instead. -fail_compilation/dep_d1_ops.d(106): Error: `opAdd_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "+")` instead. -fail_compilation/dep_d1_ops.d(107): Error: `opSub` is obsolete. Use `opBinary(string op)(...) if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(108): Error: `opSub_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(109): Error: `opMul` is obsolete. Use `opBinary(string op)(...) if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(110): Error: `opMul_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(111): Error: `opDiv` is obsolete. Use `opBinary(string op)(...) if (op == "/")` instead. -fail_compilation/dep_d1_ops.d(112): Error: `opDiv_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "/")` instead. -fail_compilation/dep_d1_ops.d(113): Error: `opMod` is obsolete. Use `opBinary(string op)(...) if (op == "%")` instead. -fail_compilation/dep_d1_ops.d(114): Error: `opMod_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "%")` instead. -fail_compilation/dep_d1_ops.d(116): Error: `opAnd` is obsolete. Use `opBinary(string op)(...) if (op == "&")` instead. -fail_compilation/dep_d1_ops.d(117): Error: `opOr` is obsolete. Use `opBinary(string op)(...) if (op == "|")` instead. -fail_compilation/dep_d1_ops.d(118): Error: `opXor` is obsolete. Use `opBinary(string op)(...) if (op == "^")` instead. -fail_compilation/dep_d1_ops.d(120): Error: `opShl` is obsolete. Use `opBinary(string op)(...) if (op == "<<")` instead. -fail_compilation/dep_d1_ops.d(121): Error: `opShl_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "<<")` instead. -fail_compilation/dep_d1_ops.d(122): Error: `opShr` is obsolete. Use `opBinary(string op)(...) if (op == ">>")` instead. -fail_compilation/dep_d1_ops.d(123): Error: `opShr_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == ">>")` instead. -fail_compilation/dep_d1_ops.d(124): Error: `opUShr` is obsolete. Use `opBinary(string op)(...) if (op == ">>>")` instead. -fail_compilation/dep_d1_ops.d(125): Error: `opUShr_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == ">>>")` instead. -fail_compilation/dep_d1_ops.d(127): Error: `opCat` is obsolete. Use `opBinary(string op)(...) if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(128): Error: `opCat_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(130): Error: `opNeg` is obsolete. Use `opUnary(string op)() if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(131): Error: `opCom` is obsolete. Use `opUnary(string op)() if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(132): Error: `opPostInc` is obsolete. Use `opUnary(string op)() if (op == "++")` instead. -fail_compilation/dep_d1_ops.d(133): Error: `opPostDec` is obsolete. Use `opUnary(string op)() if (op == "--")` instead. -fail_compilation/dep_d1_ops.d(134): Error: `opStar` is obsolete. Use `opUnary(string op)() if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(136): Error: `opIn` is obsolete. Use `opBinary(string op)(...) if (op == "in")` instead. -fail_compilation/dep_d1_ops.d(137): Error: `opIn_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "in")` instead. -fail_compilation/dep_d1_ops.d(139): Error: `opAddAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "+")` instead. -fail_compilation/dep_d1_ops.d(140): Error: `opSubAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "-")` instead. -fail_compilation/dep_d1_ops.d(141): Error: `opMulAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "*")` instead. -fail_compilation/dep_d1_ops.d(142): Error: `opDivAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "/")` instead. -fail_compilation/dep_d1_ops.d(143): Error: `opModAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "%")` instead. -fail_compilation/dep_d1_ops.d(144): Error: `opAndAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "&")` instead. -fail_compilation/dep_d1_ops.d(145): Error: `opOrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "|")` instead. -fail_compilation/dep_d1_ops.d(146): Error: `opXorAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "^")` instead. -fail_compilation/dep_d1_ops.d(147): Error: `opShlAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "<<")` instead. -fail_compilation/dep_d1_ops.d(148): Error: `opShrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == ">>")` instead. -fail_compilation/dep_d1_ops.d(149): Error: `opUShrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == ">>>")` instead. -fail_compilation/dep_d1_ops.d(150): Error: `opCatAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "~")` instead. -fail_compilation/dep_d1_ops.d(158): Error: `opCom` is obsolete. Use `opUnary(string op)() if (op == "~")` instead. +fail_compilation/dep_d1_ops.d(198): Error: incompatible types for `(s) + (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(199): Error: incompatible types for `(1) + (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(200): Error: incompatible types for `(s) - (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(201): Error: incompatible types for `(1) - (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(202): Error: incompatible types for `(s) * (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(203): Error: incompatible types for `(1) * (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(204): Error: incompatible types for `(s) / (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(205): Error: incompatible types for `(1) / (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(206): Error: incompatible types for `(s) % (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(207): Error: incompatible types for `(1) % (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(209): Error: incompatible types for `(s) & (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(210): Error: incompatible types for `(s) | (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(211): Error: incompatible types for `(s) ^ (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(213): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(214): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(215): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(216): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(217): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(218): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(220): Error: incompatible types for `(s) ~ (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(221): Error: incompatible types for `(1) ~ (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(223): Error: operator `+` is not defined for `s` of type `S` +fail_compilation/dep_d1_ops.d(224): Error: operator `-` is not defined for `s` of type `S` +fail_compilation/dep_d1_ops.d(225): Error: `s` is not of integral type, it is a `S` +fail_compilation/dep_d1_ops.d(226): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(227): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(228): Error: can only `*` a pointer, not a `S` +fail_compilation/dep_d1_ops.d(230): Error: incompatible types for `(s) in (1)`: `S` and `int` +fail_compilation/dep_d1_ops.d(231): Error: incompatible types for `(1) in (s)`: `int` and `S` +fail_compilation/dep_d1_ops.d(233): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(234): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(235): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(236): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(237): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(238): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(239): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(240): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(241): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(242): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(243): Error: `s` is not a scalar, it is a `S` +fail_compilation/dep_d1_ops.d(244): Error: cannot append type `int` to type `S` +fail_compilation/dep_d1_ops.d(248): Error: incompatible types for `(c) + (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(249): Error: incompatible types for `(1) + (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(250): Error: incompatible types for `(c) - (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(251): Error: incompatible types for `(1) - (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(252): Error: incompatible types for `(c) * (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(253): Error: incompatible types for `(1) * (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(254): Error: incompatible types for `(c) / (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(255): Error: incompatible types for `(1) / (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(256): Error: incompatible types for `(c) % (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(257): Error: incompatible types for `(1) % (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(259): Error: incompatible types for `(c) & (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(260): Error: incompatible types for `(c) | (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(261): Error: incompatible types for `(c) ^ (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(263): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(264): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(265): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(266): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(267): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(268): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(270): Error: incompatible types for `(c) ~ (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(271): Error: incompatible types for `(1) ~ (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(273): Error: operator `+` is not defined for `c` of type `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(274): Error: operator `-` is not defined for `c` of type `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(275): Error: `c` is not of integral type, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(276): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(277): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(278): Error: can only `*` a pointer, not a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(280): Error: incompatible types for `(c) in (1)`: `dep_d1_ops.C` and `int` +fail_compilation/dep_d1_ops.d(281): Error: incompatible types for `(1) in (c)`: `int` and `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(283): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(284): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(285): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(286): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(287): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(288): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(289): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(290): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(291): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(292): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(293): Error: `c` is not a scalar, it is a `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(294): Error: cannot append type `int` to type `dep_d1_ops.C` +fail_compilation/dep_d1_ops.d(303): Error: `nd` is not of integral type, it is a `dep_d1_ops.NoDeprecation` --- */ -#line 50 struct S { int opAdd(int i) { return 0; } @@ -74,6 +115,58 @@ struct S int opCat(int i) { return 0; } int opCat_r(int i) { return 0; } + int opPos() { return 0; } + int opNeg() { return 0; } + int opCom() { return 0; } + int opPostInc() { return 0; } + int opPostDec() { return 0; } + int opStar() { return 0; } + + int opIn(int i) { return 0; } + int opIn_r(int i) { return 0; } + + int opAddAssign(int i) { return 0; } + int opSubAssign(int i) { return 0; } + int opMulAssign(int i) { return 0; } + int opDivAssign(int i) { return 0; } + int opModAssign(int i) { return 0; } + int opAndAssign(int i) { return 0; } + int opOrAssign(int i) { return 0; } + int opXorAssign(int i) { return 0; } + int opShlAssign(int i) { return 0; } + int opShrAssign(int i) { return 0; } + int opUShrAssign(int i) { return 0; } + int opCatAssign(int i) { return 0; } +} + +class C +{ + int opAdd(int i) { return 0; } + int opAdd_r(int i) { return 0; } + int opSub(int i) { return 0; } + int opSub_r(int i) { return 0; } + int opMul(int i) { return 0; } + int opMul_r(int i) { return 0; } + int opDiv(int i) { return 0; } + int opDiv_r(int i) { return 0; } + int opMod(int i) { return 0; } + int opMod_r(int i) { return 0; } + + int opAnd(int i) { return 0; } + int opOr(int i) { return 0; } + int opXor(int i) { return 0; } + + int opShl(int i) { return 0; } + int opShl_r(int i) { return 0; } + int opShr(int i) { return 0; } + int opShr_r(int i) { return 0; } + int opUShr(int i) { return 0; } + int opUShr_r(int i) { return 0; } + + int opCat(int i) { return 0; } + int opCat_r(int i) { return 0; } + + int opPos() { return 0; } int opNeg() { return 0; } int opCom() { return 0; } int opPostInc() { return 0; } @@ -99,55 +192,107 @@ struct S void main() { - S s; int i; + { + S s; + i = s + 1; + i = 1 + s; + i = s - 1; + i = 1 - s; + i = s * 1; + i = 1 * s; + i = s / 1; + i = 1 / s; + i = s % 1; + i = 1 % s; + + i = s & 1; + i = s | 1; + i = s ^ 1; + + i = s << 1; + i = 1 << s; + i = s >> 1; + i = 1 >> s; + i = s >>> 1; + i = 1 >>> s; + + i = s ~ 1; + i = 1 ~ s; + + i = +s; + i = -s; + i = ~s; + s++; + s--; + i = *s; + + i = s in 1; + i = 1 in s; + + s += 1; + s -= 1; + s *= 1; + s /= 1; + s %= 1; + s &= 1; + s |= 1; + s ^= 1; + s <<= 1; + s >>= 1; + s >>>= 1; + s ~= 1; + } + { + C c; + i = c + 1; + i = 1 + c; + i = c - 1; + i = 1 - c; + i = c * 1; + i = 1 * c; + i = c / 1; + i = 1 / c; + i = c % 1; + i = 1 % c; + + i = c & 1; + i = c | 1; + i = c ^ 1; + + i = c << 1; + i = 1 << c; + i = c >> 1; + i = 1 >> c; + i = c >>> 1; + i = 1 >>> c; - i = s + 1; - i = 1 + s; - i = s - 1; - i = 1 - s; - i = s * 1; - i = 1 * s; - i = s / 1; - i = 1 / s; - i = s % 1; - i = 1 % s; - - i = s & 1; - i = s | 1; - i = s ^ 1; - - i = s << 1; - i = 1 << s; - i = s >> 1; - i = 1 >> s; - i = s >>> 1; - i = 1 >>> s; - - i = s ~ 1; - i = 1 ~ s; - - i = -s; - i = ~s; - s++; - s--; - i = *s; - - i = s in 1; - i = 1 in s; - - s += 1; - s -= 1; - s *= 1; - s /= 1; - s %= 1; - s &= 1; - s |= 1; - s ^= 1; - s <<= 1; - s >>= 1; - s >>>= 1; - s ~= 1; + i = c ~ 1; + i = 1 ~ c; + + i = +c; + i = -c; + i = ~c; + c++; + c--; + i = *c; + + i = c in 1; + i = 1 in c; + + c += 1; + c -= 1; + c *= 1; + c /= 1; + c %= 1; + c &= 1; + c |= 1; + c ^= 1; + c <<= 1; + c >>= 1; + c >>>= 1; + c ~= 1; + } scope nd = new NoDeprecation; assert((42 in nd) == 0); diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d deleted file mode 100644 index 46c9493..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d +++ /dev/null @@ -1,30 +0,0 @@ -/* -REQUIRED_ARGS: -de -TEST_OUTPUT: ---- -fail_compilation/deprecateopdot.d(27): Error: `opDot` is obsolete. Use `alias this` -fail_compilation/deprecateopdot.d(28): Error: `opDot` is obsolete. Use `alias this` -fail_compilation/deprecateopdot.d(29): Error: `opDot` is obsolete. Use `alias this` ---- -*/ -struct S6 -{ - int a, b; -} -struct T6 -{ - S6 s; - - S6* opDot() return - { - return &s; - } -} - -void test6() -{ - T6 t; - t.a = 4; - assert(t.a == 4); - t.b = 5; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d b/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d deleted file mode 100644 index 326d82e..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d +++ /dev/null @@ -1,19 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/diag_class_alloc.d(15): Error: `new` allocator must be annotated with `@disabled` -fail_compilation/diag_class_alloc.d(16): Deprecation: `new` allocator with non-empty parameter list is deprecated -fail_compilation/diag_class_alloc.d(16): Deprecation: `new` allocator with function definition is deprecated ---- -*/ - -// This test exists to ensure class allocators and deallocators emit an appropriate error message. -// This test can be deleted when class allocators and deallocators are removed from the language. - -class C -{ - new(size_t size) // error message - { - return malloc(size); - } -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10534.d b/gcc/testsuite/gdc.test/fail_compilation/fail10534.d index b5bb67c..f0e0b85 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10534.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10534.d @@ -1,22 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10534.d(28): Error: illegal operator `+` for `a` of type `int delegate()` -fail_compilation/fail10534.d(28): Error: illegal operator `+` for `b` of type `int delegate()` -fail_compilation/fail10534.d(29): Error: illegal operator `-` for `a` of type `int delegate()` -fail_compilation/fail10534.d(29): Error: illegal operator `-` for `b` of type `int delegate()` -fail_compilation/fail10534.d(30): Error: illegal operator `/` for `a` of type `int delegate()` -fail_compilation/fail10534.d(30): Error: illegal operator `/` for `b` of type `int delegate()` -fail_compilation/fail10534.d(31): Error: illegal operator `*` for `a` of type `int delegate()` -fail_compilation/fail10534.d(31): Error: illegal operator `*` for `b` of type `int delegate()` -fail_compilation/fail10534.d(36): Error: illegal operator `+` for `a` of type `int function()` -fail_compilation/fail10534.d(36): Error: illegal operator `+` for `b` of type `int function()` -fail_compilation/fail10534.d(37): Error: illegal operator `-` for `a` of type `int function()` -fail_compilation/fail10534.d(37): Error: illegal operator `-` for `b` of type `int function()` -fail_compilation/fail10534.d(38): Error: illegal operator `/` for `a` of type `int function()` -fail_compilation/fail10534.d(38): Error: illegal operator `/` for `b` of type `int function()` -fail_compilation/fail10534.d(39): Error: illegal operator `*` for `a` of type `int function()` -fail_compilation/fail10534.d(39): Error: illegal operator `*` for `b` of type `int function()` +fail_compilation/fail10534.d(24): Error: illegal operator `+` for `a` of type `int delegate()` +fail_compilation/fail10534.d(24): Error: illegal operator `+` for `b` of type `int delegate()` +fail_compilation/fail10534.d(25): Error: illegal operator `-` for `a` of type `int delegate()` +fail_compilation/fail10534.d(25): Error: illegal operator `-` for `b` of type `int delegate()` +fail_compilation/fail10534.d(26): Error: illegal operator `/` for `a` of type `int delegate()` +fail_compilation/fail10534.d(27): Error: illegal operator `*` for `a` of type `int delegate()` +fail_compilation/fail10534.d(32): Error: illegal operator `+` for `a` of type `int function()` +fail_compilation/fail10534.d(32): Error: illegal operator `+` for `b` of type `int function()` +fail_compilation/fail10534.d(33): Error: illegal operator `-` for `a` of type `int function()` +fail_compilation/fail10534.d(33): Error: illegal operator `-` for `b` of type `int function()` +fail_compilation/fail10534.d(34): Error: illegal operator `/` for `a` of type `int function()` +fail_compilation/fail10534.d(35): Error: illegal operator `*` for `a` of type `int function()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11445.d b/gcc/testsuite/gdc.test/fail_compilation/fail11445.d index 3295b24..e4105b8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail11445.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11445.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail11445.d(11): Error: incompatible types for `(a) + (b)`: both operands are of type `double[string]` +fail_compilation/fail11445.d(11): Error: illegal operator `+` for `a` of type `double[string]` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d index 9c82b2c..a1c1bab 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d @@ -14,7 +14,7 @@ fail_compilation/fail13902.d(33): Error: returning `&s1.v` escapes a reference t fail_compilation/fail13902.d(38): Error: returning `& sa1` escapes a reference to local variable `sa1` fail_compilation/fail13902.d(39): Error: returning `& sa2` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(40): Error: returning `& x` escapes a reference to local variable `x` -fail_compilation/fail13902.d(41): Error: returning `(& x+4)` escapes a reference to local variable `x` +fail_compilation/fail13902.d(41): Error: returning `(& x + 4)` escapes a reference to local variable `x` fail_compilation/fail13902.d(42): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x` fail_compilation/fail13902.d(45): Error: returning `& y` escapes a reference to local variable `y` --- @@ -59,7 +59,7 @@ fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference t fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1` fail_compilation/fail13902.d(82): Error: returning `& sa2` escapes a reference to parameter `sa2` fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x` -fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x` +fail_compilation/fail13902.d(84): Error: returning `(& x + 4)` escapes a reference to parameter `x` fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x` fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to parameter `y` --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14343.d b/gcc/testsuite/gdc.test/fail_compilation/fail14343.d new file mode 100644 index 0000000..d644ec9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14343.d @@ -0,0 +1,25 @@ +// https://issues.dlang.org/show_bug.cgi?id=14343 +/* TEST_OUTPUT: +--- +fail_compilation/fail14343.d(21): Error: cannot modify struct instance `s` of type `S14343b` because it contains `const` or `immutable` members +fail_compilation/fail14343.d(23): Error: cannot modify struct instance `s` of type `S14343b` because it contains `const` or `immutable` members +--- +*/ + +struct S14343b +{ + int i; + immutable(Object) o; + + void opAddAssign(int j) { i += j; } + void opAssign(S14343b other) {} +} + +void test14343() +{ + S14343b s; + ++s; + assert(s.i == 1); + s++; + assert(s.i == 2); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d deleted file mode 100644 index 3531245..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d +++ /dev/null @@ -1,79 +0,0 @@ -// REQUIRED_ARGS: -o- - -/* -TEST_OUTPUT: ---- -fail_compilation/fail14486.d(47): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(47): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(48): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(48): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(53): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(53): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(54): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(54): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(59): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(59): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(60): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(60): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(65): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(65): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(66): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(66): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(71): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(71): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(72): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(72): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(77): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(77): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/fail14486.d(78): Error: the `delete` keyword is obsolete -fail_compilation/fail14486.d(78): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ---- -*/ - -class C0a { } -class C1a { ~this() {} } - -class C0b { } -class C1b { ~this() {} } - -struct S0a { } -struct S1a { ~this() {} } - -struct S0b { } -struct S1b { ~this() {} } - -void test1a() @nogc pure @safe -{ - C0a c0; delete c0; // error - C1a c1; delete c1; // error -} - -void test1b() nothrow -{ - C0b c0; delete c0; // no error - C1b c1; delete c1; // error -} - -void test2a() @nogc pure @safe -{ - S0a* s0; delete s0; // error - S1a* s1; delete s1; // error -} - -void test2b() nothrow -{ - S0b* s0; delete s0; // no error - S1b* s1; delete s1; // error -} - -void test3a() @nogc pure @safe -{ - S0a[] a0; delete a0; // error - S1a[] a1; delete a1; // error -} - -void test3b() nothrow -{ - S0b[] a0; delete a0; // no error - S1b[] a1; delete a1; // error -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17906.d b/gcc/testsuite/gdc.test/fail_compilation/fail17906.d deleted file mode 100644 index 41f7465..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17906.d +++ /dev/null @@ -1,13 +0,0 @@ -// REQUIRED_ARGS: -de -/* TEST_OUTPUT: ---- -fail_compilation/fail17906.d(12): Error: the `delete` keyword is obsolete -fail_compilation/fail17906.d(12): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ---- -*/ -// https://issues.dlang.org/show_bug.cgi?id=18647 -deprecated void main () -{ - Object o = new Object; - delete o; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d deleted file mode 100644 index ffc12f1..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d +++ /dev/null @@ -1,15 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail2361.d(14): Error: the `delete` keyword is obsolete -fail_compilation/fail2361.d(14): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ---- -*/ - -class C {} - -void main() -{ - immutable c = new immutable(C); - delete c; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail297.d b/gcc/testsuite/gdc.test/fail_compilation/fail297.d index 5fc3bbf..3bb25dd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail297.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail297.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail297.d(30): Error: incompatible types for `(Bar()) + (baz())`: `Bar` and `const(Bar)` +fail_compilation/fail297.d(30): Error: operator `+` is not defined for `Bar()` of type `Bar` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3.d b/gcc/testsuite/gdc.test/fail_compilation/fail3.d index 5c1ea91..1c40c4f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail3.d(41): Error: incompatible types for `(a) + (b)`: both operands are of type `vec2` +fail_compilation/fail3.d(41): Error: operator `+` is not defined for `a` of type `vec2` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d index 0db6a45..a8b53f1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d @@ -209,8 +209,6 @@ fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(275): Error: cannot take address of expression `([1] * 6)[0..2]` because it is not an lvalue fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]` -fail_compilation/fail_arrayop2.d(281): Error: the `delete` keyword is obsolete -fail_compilation/fail_arrayop2.d(281): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(290): Error: cannot modify expression `[1] * 6` because it is not an lvalue @@ -235,6 +233,8 @@ fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed --- */ + + // Test all expressions, which can take arrays as their operands but cannot be a part of array operation. void test15407exp() { @@ -277,8 +277,8 @@ void test15407exp() // PtrExp, *([1] * 6).ptr is also invalid -> show better diagnostic { auto r = *([1] * 6); } - // DeleteExp - e1 - delete ([1] * 6); + + // TypeDArray.dotExp, cannot check in ArrayLengthExp.semantic() { auto r = (6 * da[]).length; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d deleted file mode 100644 index ed640fb..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d +++ /dev/null @@ -1,13 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/faildeleteaa.d(12): Error: the `delete` keyword is obsolete -fail_compilation/faildeleteaa.d(12): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ---- -*/ - -void main() -{ - int[int] aa = [1 : 2]; - delete aa[1]; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d index edbb4e6..2c6191e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d +++ b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d @@ -1,21 +1,24 @@ /** TEST_OUTPUT: --- -fail_compilation/hexstring.d(29): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` -fail_compilation/hexstring.d(33): Error: hex string length 1 must be a multiple of 2 to cast to `immutable(ushort[])` -fail_compilation/hexstring.d(34): Error: hex string length 3 must be a multiple of 4 to cast to `immutable(uint[])` -fail_compilation/hexstring.d(35): Error: hex string length 5 must be a multiple of 8 to cast to `immutable(ulong[])` -fail_compilation/hexstring.d(36): Error: array cast from `wstring` to `immutable(ulong[])` is not supported at compile time -fail_compilation/hexstring.d(36): perhaps remove postfix `w` from hex string -fail_compilation/hexstring.d(37): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time -fail_compilation/hexstring.d(38): Error: array cast from `string` to `immutable(ushort[])` is not supported at compile time -fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time -fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string -fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5 -fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"11223344"d` of type `dstring` to `immutable(float[])` -fail_compilation/hexstring.d(42): Error: cannot implicitly convert expression `x"1122"w` of type `wstring` to `immutable(ubyte[])` -fail_compilation/hexstring.d(50): Error: array cast from `string` to `S[]` is not supported at compile time -fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` +fail_compilation/hexstring.d(30): Error: array cast from `string` to `ubyte[3][1]` is not supported at compile time +fail_compilation/hexstring.d(33): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(37): Error: hex string length 1 must be a multiple of 2 to cast to `immutable(ushort[])` +fail_compilation/hexstring.d(38): Error: hex string length 3 must be a multiple of 4 to cast to `immutable(uint[])` +fail_compilation/hexstring.d(39): Error: hex string length 5 must be a multiple of 8 to cast to `immutable(ulong[])` +fail_compilation/hexstring.d(40): Error: array cast from `wstring` to `immutable(ulong[])` is not supported at compile time +fail_compilation/hexstring.d(40): perhaps remove postfix `w` from hex string +fail_compilation/hexstring.d(41): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(42): Error: array cast from `string` to `immutable(ushort[])` is not supported at compile time +fail_compilation/hexstring.d(43): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(43): perhaps remove postfix `c` from hex string +fail_compilation/hexstring.d(44): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5 +fail_compilation/hexstring.d(45): Error: cannot implicitly convert expression `x"11223344"d` of type `dstring` to `immutable(float[])` +fail_compilation/hexstring.d(46): Error: cannot implicitly convert expression `x"1122"w` of type `wstring` to `immutable(ubyte[])` +fail_compilation/hexstring.d(47): Error: array cast from `string` to `ubyte[3][1]` is not supported at compile time +fail_compilation/hexstring.d(48): Error: array cast from `string` to `ubyte[3][1][1]` is not supported at compile time +fail_compilation/hexstring.d(56): Error: array cast from `string` to `S[]` is not supported at compile time +fail_compilation/hexstring.d(32): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` --- */ immutable ubyte[] s0 = x"123F"; @@ -24,6 +27,7 @@ static assert(s0[1] == 0x3F); immutable byte[] s1 = x"123F"; enum E(X) = cast(X[]) x"AABBCCDD"; static assert(E!int[0] == 0xAABBCCDD); +immutable ubyte[3] s2 = cast(ubyte[3][1])x"FFAAFF"; ubyte[] f1 = x"123F"; immutable ubyte[] f2 = "123F"; @@ -40,6 +44,8 @@ immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c; immutable uint[] f12 = x"1122334455"d; immutable float[] f13 = x"11223344"d; immutable ubyte[] f14 = x"1122"w; +immutable ubyte[3][1] f16 = cast(ubyte[3][1])x"FFBBFF"; +immutable ubyte[3][1][1] f17 = cast(ubyte[3][1][1])x"FFCCFF"; // https://issues.dlang.org/show_bug.cgi?id=24832 struct S diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11968.d b/gcc/testsuite/gdc.test/fail_compilation/ice11968.d deleted file mode 100644 index 1d50b66..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11968.d +++ /dev/null @@ -1,9 +0,0 @@ -/* -TEST_OUTPUT: ----- -fail_compilation/ice11968.d(9): Error: the `delete` keyword is obsolete -fail_compilation/ice11968.d(9): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ----- -*/ - -void main() { delete __FILE__ ; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d index b2bea5b..ba6956e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d @@ -57,23 +57,3 @@ fail_compilation/nogc1.d(55): Error: allocating with `new` causes a GC allocatio scope Object o1 = new Object(); // no error scope o2 = new Object(); // no error } - -/***************** DeleteExp *******************/ - -/* -TEST_OUTPUT: ---- -fail_compilation/nogc1.d(76): Error: the `delete` keyword is obsolete -fail_compilation/nogc1.d(76): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/nogc1.d(77): Error: the `delete` keyword is obsolete -fail_compilation/nogc1.d(77): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead -fail_compilation/nogc1.d(78): Error: the `delete` keyword is obsolete -fail_compilation/nogc1.d(78): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ---- -*/ -@nogc void testDelete(int* p, Object o, S1* s) -{ - delete p; - delete o; - delete s; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16195.d b/gcc/testsuite/gdc.test/fail_compilation/test16195.d deleted file mode 100644 index 018ab0d..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/test16195.d +++ /dev/null @@ -1,15 +0,0 @@ -/* - * TEST_OUTPUT: ---- -fail_compilation/test16195.d(14): Error: the `delete` keyword is obsolete -fail_compilation/test16195.d(14): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead ---- - */ - - -// https://issues.dlang.org/show_bug.cgi?id=16195 - -@safe pure nothrow @nogc void test(int* p) -{ - delete p; -} diff --git a/gcc/testsuite/gdc.test/runnable/funclit.d b/gcc/testsuite/gdc.test/runnable/funclit.d index 253df8f..bce4e9a 100644 --- a/gcc/testsuite/gdc.test/runnable/funclit.d +++ b/gcc/testsuite/gdc.test/runnable/funclit.d @@ -384,16 +384,6 @@ void test6714() } /***************************************************/ -// https://issues.dlang.org/show_bug.cgi?id=7193 - -void test7193() -{ - static assert(!__traits(compiles, { - delete a => a; - })); -} - -/***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7207 // on CastExp @@ -1331,7 +1321,6 @@ int main() test11(); test3235(); test6714(); - test7193(); test7202(); test7288(); test7499(); diff --git a/gcc/testsuite/gdc.test/runnable/newdel.d b/gcc/testsuite/gdc.test/runnable/newdel.d index 8ba7a0c..8888c75 100644 --- a/gcc/testsuite/gdc.test/runnable/newdel.d +++ b/gcc/testsuite/gdc.test/runnable/newdel.d @@ -42,10 +42,29 @@ void test1() } /*********************************************/ +// delete is no longer a keyword and can be used as an identifier + +enum E +{ + add, delete +} + +E delete() +{ + return E.delete; +} + +void test2() +{ + assert(delete() == E.delete); +} + +/*********************************************/ int main() { test1(); + test2(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/opover.d b/gcc/testsuite/gdc.test/runnable/opover.d index 253a7a5..4e34e52 100644 --- a/gcc/testsuite/gdc.test/runnable/opover.d +++ b/gcc/testsuite/gdc.test/runnable/opover.d @@ -2,29 +2,13 @@ RUN_OUTPUT: --- i = 1 -Writer.opShl(char[]) -BinaryWriter.opShl(int) -a + 1 = 2 -1 + a = 2 -a + b = 3 -b + a = 3 i = 64 12 534 -A::opShl(int 4) -4A::opShl(char[]) - A::opShl(int 12) -12A::opShl(char[]) - -B::opShl_r(A) Success --- */ -// Test operator overloading -// Ignore deprecation warnings for D1 style operator overloading -// TRANSFORM_OUTPUT: remove_lines("Deprecation: `op") - import core.stdc.stdio; /**************************************/ @@ -996,20 +980,11 @@ struct S14343b void test14343() { - { - S14343a s, t; + S14343a s, t; - t = s; // OK - ++s; // OK - s++; // OK <- Error: cannot modify struct s S with immutable members - } - { - S14343b s; - ++s; - assert(s.i == 1); - s++; - assert(s.i == 2); - } + t = s; // OK + ++s; // OK + s++; // OK <- Error: cannot modify struct s S with immutable members } /**************************************/ @@ -1081,20 +1056,13 @@ void test20475() /**************************************/ int main() { - test1(); - test2(); - test3(); test4(); test5(); test6(); test7(); - test8(); test9(); - test10(); test11(); test12(); - test13(); - test14(); test15(); test1547(); test4953a(); diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index cbcbd1a..5893560 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -4091,30 +4091,30 @@ void test4258() { struct Foo4258 { // binary ++/-- - int opPostInc()() if (false) { return 0; } + int opUnary(string op)() if (false) { return 0; } // binary 1st - int opAdd(R)(R rhs) if (false) { return 0; } - int opAdd_r(R)(R rhs) if (false) { return 0; } + int opBinary(string op, R)(R rhs) if (false) { return 0; } + int opBinaryRight(string op, R)(R rhs) if (false) { return 0; } // compare - int opCmp(R)(R rhs) if (false) { return 0; } + int opCmp(R)(const(R) rhs) const if (false) { return 0; } // binary-op assign - int opAddAssign(R)(R rhs) if (false) { return 0; } + int opOpAssign(string op, R)(R rhs) if (false) { return 0; } } struct Bar4258 { // binary commutive 1 - int opAdd_r(R)(R rhs) if (false) { return 0; } + int opBinary(string op, R)(R rhs) if (false) { return 0; } // binary-op assign int opOpAssign(string op, R)(R rhs) if (false) { return 0; } } struct Baz4258 { // binary commutive 2 - int opAdd(R)(R rhs) if (false) { return 0; } + int opBinaryRight(string op, R)(R rhs) if (false) { return 0; } } -static assert(!is(typeof(Foo4258.init++))); +static assert(!is(typeof(++Foo4258.init))); static assert(!is(typeof(Foo4258.init + 1))); static assert(!is(typeof(1 + Foo4258.init))); static assert(!is(typeof(Foo4258.init < Foo4258.init))); |