Bug 3059 – Nonsensical complex op= should be illegal
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D1 (retired)
Platform
All
OS
All
Creation time
2009-06-09T16:33:00Z
Last change time
2014-02-15T13:12:56Z
Keywords
accepts-invalid, patch
Assigned to
bugzilla
Creator
clugdbug
Comments
Comment #0 by clugdbug — 2009-06-09T16:33:48Z
All operations A op= B, where A is real or imaginary and A op B is complex, should be illegal, as they are mathematically nonsensical. Sending these operations to the back-end is responsible for at least two internal compiler errors.
The operations +=, -=, *=, /=, and %= are all affected. Applies to both D1 and D2.
TEST CASE:
void main() {
ireal x = 3.0i;
double y=3;
y /= 2.0 + 6i;
x *= 7.0i;
x *= 3.0i+2;
x %= (2+ 6.0i);
x += 2.0;
x -= 1+4i;
y -= 3.0i;
}
Patch (expression.c):
This patch fixes makes the nonsensical operations illegal.
Where possible, the error message suggests an alternative.
This also fixes two ICE bugs: bug 718 and bug 2839.
=====================
@@ -8313,6 +8340,35 @@
return this;
}
+// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+void checkComplexMulAssign(char *opstr, Loc loc, Expression *e1, Expression *e2) {
+ // Any multiplication by an imaginary or complex number yields a complex result.
+ // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+ if ( e1->type->isreal() && e2->type->iscomplex()) {
+ error(loc, "%s %s= %s is undefined. Did you mean %s %s= %s.re ?",
+ e1->type->toChars(), opstr, e2->type->toChars(),
+ e1->type->toChars(), opstr, e2->type->toChars());
+ } else if (e1->type->isimaginary() && e2->type->iscomplex()) {
+ error(loc, "%s %s= %s is undefined. Did you mean %s %s= %s.im ?",
+ e1->type->toChars(), opstr, e2->type->toChars(),
+ e1->type->toChars(), opstr, e2->type->toChars());
+ } else if ((e1->type->isreal() || e1->type->isimaginary()) && e2->type->isimaginary()) {
+ error(loc, "%s %s= %s is an undefined operation", e1->type->toChars(), opstr, e2->type->toChars());
+ }
+}
+
+// generate an error if this is a nonsensical += or -=, eg real += imaginary
+void checkComplexAddAssign(char *opstr, Loc loc, Expression *e1, Expression *e2) {
+ // Addition or subtraction of a real and an imaginary is a complex result.
+ // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+ if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) ||
+ (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex()))
+ ) {
+ error(loc, "%s %s= %s is undefined (result is complex)", e1->type->toChars(), opstr, e2->type->toChars());
+ }
+}
+
+
AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2)
@@ -8408,6 +8472,7 @@
typeCombine(sc);
e1->checkArithmetic();
e2->checkArithmetic();
+ checkComplexAddAssign("+", loc, e1, e2);
if (type->isreal() || type->isimaginary())
{
assert(global.errors || e2->type->isfloating());
@@ -8455,6 +8520,7 @@
{
e1 = e1->checkArithmetic();
e2 = e2->checkArithmetic();
+ checkComplexAddAssign("-", loc, e1, e2);
type = e1->type;
typeCombine(sc);
if (type->isreal() || type->isimaginary())
@@ -8556,6 +8622,7 @@
typeCombine(sc);
e1->checkArithmetic();
e2->checkArithmetic();
+ checkComplexMulAssign("*", loc, e1, e2);
if (e2->type->isfloating())
{ Type *t1;
Type *t2;
@@ -8619,6 +8686,7 @@
typeCombine(sc);
e1->checkArithmetic();
e2->checkArithmetic();
+ checkComplexMulAssign("/", loc, e1, e2);
if (e2->type->isimaginary())
{ Type *t1;
Type *t2;
@@ -8662,6 +8730,8 @@
Expression *ModAssignExp::semantic(Scope *sc)
{
+ BinExp::semantic(sc);
+ checkComplexMulAssign("%", loc, e1, e2);
return commonSemanticAssign(sc);
}