aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2025-03-12 17:19:49 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2025-03-15 16:33:00 +0100
commite8c9f4ab8f0c8ad8da5f7fb0f1a4956507fe64f5 (patch)
tree46099e73f24300a919394d9f1972fdf5941f672d /gcc
parent254549d2bb9bb3c2719dec597427919c59514fc3 (diff)
downloadgcc-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')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/clone.d18
-rw-r--r--gcc/d/dmd/ctfeexpr.d8
-rw-r--r--gcc/d/dmd/dcast.d14
-rw-r--r--gcc/d/dmd/dsymbolsem.d2
-rw-r--r--gcc/d/dmd/dtemplate.d23
-rw-r--r--gcc/d/dmd/expression.d108
-rw-r--r--gcc/d/dmd/expression.h3
-rw-r--r--gcc/d/dmd/expressionsem.d617
-rw-r--r--gcc/d/dmd/func.d3
-rw-r--r--gcc/d/dmd/hdrgen.d2
-rw-r--r--gcc/d/dmd/id.d66
-rw-r--r--gcc/d/dmd/initsem.d4
-rw-r--r--gcc/d/dmd/mangle/cpp.d43
-rw-r--r--gcc/d/dmd/mtype.d12
-rw-r--r--gcc/d/dmd/mustuse.d23
-rw-r--r--gcc/d/dmd/objc.d11
-rw-r--r--gcc/d/dmd/opover.d1757
-rw-r--r--gcc/d/dmd/parse.d44
-rw-r--r--gcc/d/dmd/semantic3.d2
-rw-r--r--gcc/d/dmd/tokens.d3
-rw-r--r--gcc/d/dmd/tokens.h1
-rw-r--r--gcc/d/dmd/typesem.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/interpret3.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/nogc.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22510.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctor_self_assignment.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d325
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10534.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11445.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13902.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14343.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14486.d79
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17906.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2361.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail297.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/hexstring.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11968.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nogc1.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16195.d15
-rw-r--r--gcc/testsuite/gdc.test/runnable/funclit.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/newdel.d19
-rw-r--r--gcc/testsuite/gdc.test/runnable/opover.d40
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtest46.d16
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)));