314 changes: 128 additions & 186 deletions src/expression.c

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions src/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ bool arrayExpressionSemantic(Expressions *exps, Scope *sc);
TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s);
Expression *valueNoDtor(Expression *e);
int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1);
Expression *resolveAliasThis(Scope *sc, Expression *e);
Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag = false);
Expression *callCpCtor(Scope *sc, Expression *e);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
Expression *resolveOpDollar(Scope *sc, SliceExp *se, Expression **pe0);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0);
Expression *integralPromotions(Expression *e, Scope *sc);
void discardValue(Expression *e);
bool isTrivialExp(Expression *e);
Expand Down Expand Up @@ -1019,6 +1019,7 @@ class SliceExp : public UnaExp
bool upperIsInBounds; // true if upr <= e1.length
bool lowerIsLessThanUpper; // true if lwr <= upr

SliceExp(Loc loc, Expression *e1, IntervalExp *ie);
SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr);
Expression *syntaxCopy();
Expression *semantic(Scope *sc);
Expand Down Expand Up @@ -1082,7 +1083,8 @@ class ArrayExp : public UnaExp
size_t currentDimension; // for opDollar
VarDeclaration *lengthVar;

ArrayExp(Loc loc, Expression *e1, Expressions *arguments);
ArrayExp(Loc loc, Expression *e1, Expression *index = NULL);
ArrayExp(Loc loc, Expression *e1, Expressions *args);
Expression *syntaxCopy();
Expression *semantic(Scope *sc);
bool isLvalue();
Expand Down
3 changes: 2 additions & 1 deletion src/magicport.json
Original file line number Diff line number Diff line change
Expand Up @@ -2736,7 +2736,7 @@
"function needDirectEq",
"function extractOpDollarSideEffect",
"function resolveOpDollarScope*ArrayExp*Expression**",
"function resolveOpDollarScope*SliceExp*Expression**",
"function resolveOpDollarScope*ArrayExp*IntervalExp*Expression**",
"enum CtfeGoal",
"enum OwnedBy",
"variable WANTvalue",
Expand Down Expand Up @@ -2889,6 +2889,7 @@
"imports" :
[
"aggregate",
"aliasthis",
"arraytypes",
"core.stdc.stdio",
"core.stdc.string",
Expand Down
20 changes: 5 additions & 15 deletions src/mtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -3905,12 +3905,9 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol
if (*pe)
{
// It's really an index expression
Expressions *exps = new Expressions();
exps->setDim(1);
(*exps)[0] = dim;
if (Dsymbol *s = getDsymbol(*pe))
*pe = new DsymbolExp(loc, s, 1);
*pe = new ArrayExp(loc, *pe, exps);
*pe = new ArrayExp(loc, *pe, dim);
}
else if (*ps)
{
Expand Down Expand Up @@ -4283,10 +4280,7 @@ Expression *TypeSArray::toExpression()
{
Expression *e = next->toExpression();
if (e)
{ Expressions *arguments = new Expressions();
arguments->push(dim);
e = new ArrayExp(dim->loc, e, arguments);
}
e = new ArrayExp(dim->loc, e, dim);
return e;
}

Expand Down Expand Up @@ -4383,7 +4377,7 @@ void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol
// It's really a slice expression
if (Dsymbol *s = getDsymbol(*pe))
*pe = new DsymbolExp(loc, s, 1);
*pe = new SliceExp(loc, *pe, NULL, NULL);
*pe = new ArrayExp(loc, *pe);
}
else if (*ps)
{
Expand Down Expand Up @@ -4826,11 +4820,7 @@ Expression *TypeAArray::toExpression()
{
Expression *ei = index->toExpression();
if (ei)
{
Expressions *arguments = new Expressions();
arguments->push(ei);
return new ArrayExp(loc, e, arguments);
}
return new ArrayExp(loc, e, ei);
}
return NULL;
}
Expand Down Expand Up @@ -8934,7 +8924,7 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol
// It's really a slice expression
if (Dsymbol *s = getDsymbol(*pe))
*pe = new DsymbolExp(loc, s, 1);
*pe = new SliceExp(loc, *pe, lwr, upr);
*pe = new ArrayExp(loc, *pe, new IntervalExp(loc, lwr, upr));
}
else if (*ps)
{
Expand Down
509 changes: 240 additions & 269 deletions src/opover.c

Large diffs are not rendered by default.

17 changes: 0 additions & 17 deletions test/fail_compilation/fail1.d

This file was deleted.

17 changes: 0 additions & 17 deletions test/fail_compilation/fail2.d

This file was deleted.

58 changes: 58 additions & 0 deletions test/fail_compilation/fail_opover.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// REQUIRED_ARGS: -o-

/*
TEST_OUTPUT:
---
fail_compilation/fail_opover.d(13): Error: no [] operator overload for type object.Object
fail_compilation/fail_opover.d(17): Error: no [] operator overload for type TestS
---
*/
void test1()
{
Object m;
m[] = error;

struct TestS {}
TestS s;
s[] = error;
}

/*
TEST_OUTPUT:
---
fail_compilation/fail_opover.d(46): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(47): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(48): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(49): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(50): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(51): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(52): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(53): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(54): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(55): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(56): Error: no [] operator overload for type S
fail_compilation/fail_opover.d(57): Error: no [] operator overload for type S
---
*/
void test2()
{
struct S
{
void func(int) {}
alias func this;
}
S s;
// The errors failing aliasthis access need to be gagged for better error messages.
s[]; // in ArrayExp::op_overload()
s[1]; // ditto
s[1..2]; // ditto
+s[]; // in UnaExp::op_overload()
+s[1]; // ditto
+s[1..2]; // ditto
s[] = 3; // in AssignExp::semantic()
s[1] = 3; // ditto
s[1..2] = 3; // ditto
s[] += 3; // in BinAssignExp::op_overload()
s[1] += 3; // ditto
s[1..2] += 3; // ditto
}
30 changes: 30 additions & 0 deletions test/fail_compilation/ice14621.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice14621.d(22): Error: static assert (false) is false
fail_compilation/ice14621.d(28): instantiated from here: erroneousTemplateInstantiation!()
---
*/

void main()
{
S s;
s.foo();
}

struct S
{
float[] array;
alias array this;

template erroneousTemplateInstantiation()
{
static assert(false);
}

void foo()
{
S ret;
ret[] = erroneousTemplateInstantiation!();
}
}
191 changes: 190 additions & 1 deletion test/runnable/opover2.d
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ bool thrown(E, T)(lazy T val)
catch (E e) { return true; }
}

void stompStack() { int[256] sa = 0xdeadbeef; }

/**************************************/

class A
Expand Down Expand Up @@ -927,7 +929,7 @@ int test6798a()
auto opIndex(A...)(A indices){ return [[indices]]; }
}
S2 s2;
static assert(!__traits(compiles, s2[] ));
assert(s2[] == [[]]);
assert(s2[1] == [[1]]);
assert(s2[1, 2] == [[1, 2]]);
assert(s2[1..2] == [1, 2]);
Expand Down Expand Up @@ -1828,6 +1830,187 @@ void test14057()

/**************************************/

struct Tuple20(T...) { T field; alias field this; }

void test20a()
{
// ae1save in in AssignExp::semantic
int a, b;

struct A1
{
void opIndexAssign(int v, Tuple20!(int, int) ) { a = v; }
Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
}
struct A2
{
A1 a1;
alias a1 this;
ref int opIndexAssign(int) { return b; }
}

stompStack();
A2 foo() { return A2(); }
foo()[1..2] = 1;
// ref A1 __tmp = foo().a1; __tmp.opIndexAssign(1, __tmp.opSlice!0(1, 2));
assert(a == 1); // should work
assert(b == 0);
}

void test20b()
{
// ae1save in UnaExp::op_overload()
int a, b;

struct A1
{
void opIndexUnary(string op)(Tuple20!(int, int) ) { a = 1; }
Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
void dummy() {} // nessary to make A1 nested struct
}
struct A2
{
A1 a1;
alias a1 this;
int opIndexUnary(string op)(int) { return 0; }
}

stompStack();
A2 foo() { return A2(); }
+foo()[1..2];
// ref A1 __tmp = foo().a1; __tmp.opIndexUnary!"+"(__tmp.opSlice!0(1, 2));
assert(a == 1); // should pass
assert(b == 0);
}

void test20c()
{
// ae1save in ArrayExp::op_overload()
int a, b;

struct A1
{
void opIndex(Tuple20!(int, int) ) { a = 1; }
Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
}
struct A2
{
A1 a1;
alias a1 this;
int opIndex(int) { return 0; }
}

stompStack();
A2 foo() { return A2(); }
foo()[1..2];
// ref A1 __tmp = foo().a1; __tmp.opIndex(__tmp.opSlice!0(1, 2));
assert(a == 1); // should pass
assert(b == 0);
}

void test20d()
{
// ae1save in BinAssignExp::op_overload()
int a, b;

struct A1
{
void opIndexOpAssign(string op)(int v, Tuple20!(int, int) ) { a = v; }
Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
void dummy() {} // nessary to make A1 nested struct
}
struct A2
{
A1 a1;
alias a1 this;
ref int opIndexOpAssign(alias op)(int) { return b; }
}

stompStack();
A2 foo() { return A2(); }
foo()[1..2] += 1;
// ref A1 __tmp = foo().a1; __tmp.opIndexOpAssign!"+"(1, __tmp.opSlice!0(1, 2));
assert(a == 1); // should pass
assert(b == 0);
}

/**************************************/
// 14624

void test14624()
{
struct A1
{
int x;
ref int opIndex() { return x; }
ref int opSlice() { assert(0); }
}
{
A1 a = A1(1);
auto x = a[]; // a.opIndex()
assert(x == a.x);
auto y = -a[]; // -a.opIndex() <-- not found: a.opIndexUnary!"-"
assert(y == -a.x);
a[] = 1; // a.opIndex() = 1; <-- not found: a.opIndexAssign(int)
assert(a.x == 1);
a[] += 1; // a.opIndex() += 1; <-- not found: a.opIndexOpAssign!"+"(int)
assert(a.x == 2);
}

struct A2
{
int x;
ref int opIndex() { x = 10; return x; }
ref int opSlice() { assert(0); }
ref int opSliceUnary(alias op)() { x = 11; return x; }
ref int opSliceAssign(int) { x = 12; return x; }
ref int opSliceOpAssign(alias op)(int) { x = 13; return x; }
}
{
A2 a = A2(1);
auto x = a[]; // a.opIndex()
assert(a.x == 10);
auto y = -a[]; // a.opSliceUnary!"-"() is preferred than: -a.opIndex()
assert(a.x == 11);
a[] = 1; // a.opSliceAssign(1) is preferred than: a.opIndex() = 1;
assert(a.x == 12);
a[] += 1; // a.opSliceOpAssign!"+"(1) is preferred than: a.opIndex() += 1;
assert(a.x == 13);
}
}

/**************************************/
// 14625

void test14625()
{
struct R
{
@property bool empty() { return true; }
@property int front() { return 0; }
void popFront() {}
}

struct C1
{
R opIndex() { return R(); }
R opSlice() { assert(0); }
}
C1 c1;
foreach (e; c1) {} // OK <- asserts in opSlice()
foreach (e; c1[]) {} // OK, opIndex()

struct C2
{
R opIndex() { return R(); }
}
C2 c2;
foreach (e; c2) {} // OK <- rejected
foreach (e; c2[]) {} // OK, opIndex()
}

/**************************************/

int main()
{
test1();
Expand Down Expand Up @@ -1867,6 +2050,12 @@ int main()
test11062();
test11311();
test14057();
test20a();
test20b();
test20c();
test20d();
test14624();
test14625();

printf("Success\n");
return 0;
Expand Down