From c3097afd5c6d023df955b8de866b6bef298a88d8 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 4 Aug 2025 15:10:13 +0100 Subject: [PATCH 1/9] Disallow assigning to struct rvalue Fixes #21507. --- compiler/src/dmd/expressionsem.d | 6 ++++ compiler/src/dmd/opover.d | 5 ++++ compiler/test/fail_compilation/fail17491.d | 4 +-- compiler/test/fail_compilation/fail9936.d | 8 ++--- .../fail_compilation/struct_rvalue_assign.d | 30 +++++++++++++++++++ 5 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 compiler/test/fail_compilation/struct_rvalue_assign.d diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 6767054b40ec..faafe8169b23 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -12380,6 +12380,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (exp.op == EXP.assign) { + if (!exp.e1.isLvalue()) + { + error(exp.e1.loc, "cannot assign to struct rvalue `%s`", + exp.e1.toChars()); + return setError(); + } if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop)) { result = e; diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index 0fd85726a384..372c4b7f8886 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -1004,6 +1004,11 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt if (e.e1.type.isTypeError() || e.e2.type.isTypeError()) return ErrorExp.get(); + if (e.e1.type.ty == Tstruct && !e.e1.isLvalue()) + { + error(e.e1.loc, "cannot assign to struct rvalue `%s`", e.e1.toChars()); + return ErrorExp.get(); + } AggregateDeclaration ad1 = isAggregate(e.e1.type); Dsymbol s = search_function(ad1, Id.opOpAssign); if (s && !(s.isTemplateDeclaration() || s.isOverloadSet())) diff --git a/compiler/test/fail_compilation/fail17491.d b/compiler/test/fail_compilation/fail17491.d index 718948c2832b..33a49d95ea91 100644 --- a/compiler/test/fail_compilation/fail17491.d +++ b/compiler/test/fail_compilation/fail17491.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/fail17491.d(22): Error: cannot modify expression `(S17491).init` because it is not an lvalue +fail_compilation/fail17491.d(22): Error: cannot assign to struct rvalue `S17491(0)` fail_compilation/fail17491.d(23): Error: cannot take address of expression `S17491(0)` because it is not an lvalue fail_compilation/fail17491.d(25): Error: cannot modify expression `S17491(0).field` because it is not an lvalue fail_compilation/fail17491.d(26): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue -fail_compilation/fail17491.d(31): Error: cannot modify expression `S17491(0)` because it is not an lvalue +fail_compilation/fail17491.d(31): Error: cannot assign to struct rvalue `S17491(0)` fail_compilation/fail17491.d(32): Error: cannot take address of expression `S17491(0)` because it is not an lvalue fail_compilation/fail17491.d(34): Error: cannot modify expression `S17491(0).field` because it is not an lvalue fail_compilation/fail17491.d(35): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue diff --git a/compiler/test/fail_compilation/fail9936.d b/compiler/test/fail_compilation/fail9936.d index 0d7d44ae439b..345461efb593 100644 --- a/compiler/test/fail_compilation/fail9936.d +++ b/compiler/test/fail_compilation/fail9936.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/fail9936.d(25): Error: `S().opBinary` isn't a template fail_compilation/fail9936.d(26): Error: `S().opBinaryRight` isn't a template -fail_compilation/fail9936.d(27): Error: `S().opOpAssign` isn't a template +fail_compilation/fail9936.d(27): Error: `s.opOpAssign` isn't a template fail_compilation/fail9936.d(29): Error: `S().opIndexUnary` isn't a template fail_compilation/fail9936.d(30): Error: `S().opUnary` isn't a template --- @@ -17,14 +17,14 @@ struct S auto opIndexUnary(S s) { return 1; } auto opUnary(S s) { return 1; } } -void main() +void f(S s) { static assert(!is(typeof( S() + S() ))); static assert(!is(typeof( 100 + S() ))); - static assert(!is(typeof( S() += S() ))); + static assert(!is(typeof( s += S() ))); S() + S(); 100 + S(); - S() += S(); + s += S(); +S()[0]; +S(); diff --git a/compiler/test/fail_compilation/struct_rvalue_assign.d b/compiler/test/fail_compilation/struct_rvalue_assign.d new file mode 100644 index 000000000000..36ae37203174 --- /dev/null +++ b/compiler/test/fail_compilation/struct_rvalue_assign.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/struct_rvalue_assign.d(11): Error: cannot assign to struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(12): Error: cannot assign to struct rvalue `foo()` +--- +*/ + +void main () +{ + foo() = S.init; + foo() += 5; +} + +S foo() +{ + return S.init; +} + +struct S +{ + int i; + + void opAssign(S s) + { + this.i = s.i; + } + + void opOpAssign(string op : "+")(int) {} +} From 35b7eaacf187d676b01fedf92304a4d7cdf5cd7f Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 13 Aug 2025 16:39:36 +0100 Subject: [PATCH 2/9] Allow rvalue inside typeof --- compiler/src/dmd/expressionsem.d | 2 +- compiler/src/dmd/opover.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index faafe8169b23..b5e3f7753c09 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -12380,7 +12380,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (exp.op == EXP.assign) { - if (!exp.e1.isLvalue()) + if (!sc.intypeof && !exp.e1.isLvalue()) { error(exp.e1.loc, "cannot assign to struct rvalue `%s`", exp.e1.toChars()); diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index 372c4b7f8886..eec905c58ed0 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -1004,7 +1004,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt if (e.e1.type.isTypeError() || e.e2.type.isTypeError()) return ErrorExp.get(); - if (e.e1.type.ty == Tstruct && !e.e1.isLvalue()) + if (!sc.intypeof && e.e1.type.ty == Tstruct && !e.e1.isLvalue()) { error(e.e1.loc, "cannot assign to struct rvalue `%s`", e.e1.toChars()); return ErrorExp.get(); From fcce07aeabaa4949363bd10ba3a2cc82e9034a50 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 13 Aug 2025 15:38:11 +0100 Subject: [PATCH 3/9] Also error for inc/dec --- compiler/src/dmd/expressionsem.d | 6 ++++++ compiler/test/fail_compilation/struct_rvalue_assign.d | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index b5e3f7753c09..4d9fcb6cbed8 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -11642,6 +11642,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // printf("PreExp::semantic('%s')\n", toChars()); if (Expression e = exp.opOverloadUnary(sc)) { + if (!sc.intypeof && exp.e1.type.ty == Tstruct && !exp.e1.isLvalue()) + { + error(exp.e1.loc, "cannot modify struct rvalue `%s`", + exp.e1.toChars()); + e = ErrorExp.get(); + } result = e; return; } diff --git a/compiler/test/fail_compilation/struct_rvalue_assign.d b/compiler/test/fail_compilation/struct_rvalue_assign.d index 36ae37203174..2b2bca856af2 100644 --- a/compiler/test/fail_compilation/struct_rvalue_assign.d +++ b/compiler/test/fail_compilation/struct_rvalue_assign.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/struct_rvalue_assign.d(11): Error: cannot assign to struct rvalue `foo()` fail_compilation/struct_rvalue_assign.d(12): Error: cannot assign to struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(13): Error: cannot assign to struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(14): Error: cannot modify struct rvalue `foo()` --- */ @@ -10,6 +11,7 @@ void main () { foo() = S.init; foo() += 5; + ++foo(); } S foo() @@ -27,4 +29,5 @@ struct S } void opOpAssign(string op : "+")(int) {} + void opUnary(string op : "++")() {} } From a8ab43eb15ba390804843830a69dd67fe5d1abe6 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 13 Aug 2025 17:05:17 +0100 Subject: [PATCH 4/9] Don't error for alias this assign --- compiler/src/dmd/expressionsem.d | 6 ------ compiler/src/dmd/opover.d | 9 ++++++++- compiler/test/fail_compilation/fail17491.d | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 4d9fcb6cbed8..8b76f2a53f03 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -12386,12 +12386,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (exp.op == EXP.assign) { - if (!sc.intypeof && !exp.e1.isLvalue()) - { - error(exp.e1.loc, "cannot assign to struct rvalue `%s`", - exp.e1.toChars()); - return setError(); - } if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop)) { result = e; diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index eec905c58ed0..d786500ab2d4 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -537,8 +537,15 @@ Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) bool choseReverse; if (auto result = pickBestBinaryOverload(sc, null, s, null, e, choseReverse)) + { + if (!sc.intypeof && e.e1.type.ty == Tstruct && !e.e1.isLvalue()) + { + error(e.e1.loc, "cannot assign to struct rvalue `%s`", + e.e1.toChars()); + return ErrorExp.get(); + } return result; - + } return binAliasThis(e, sc, aliasThisStop); } diff --git a/compiler/test/fail_compilation/fail17491.d b/compiler/test/fail_compilation/fail17491.d index 33a49d95ea91..718948c2832b 100644 --- a/compiler/test/fail_compilation/fail17491.d +++ b/compiler/test/fail_compilation/fail17491.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/fail17491.d(22): Error: cannot assign to struct rvalue `S17491(0)` +fail_compilation/fail17491.d(22): Error: cannot modify expression `(S17491).init` because it is not an lvalue fail_compilation/fail17491.d(23): Error: cannot take address of expression `S17491(0)` because it is not an lvalue fail_compilation/fail17491.d(25): Error: cannot modify expression `S17491(0).field` because it is not an lvalue fail_compilation/fail17491.d(26): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue -fail_compilation/fail17491.d(31): Error: cannot assign to struct rvalue `S17491(0)` +fail_compilation/fail17491.d(31): Error: cannot modify expression `S17491(0)` because it is not an lvalue fail_compilation/fail17491.d(32): Error: cannot take address of expression `S17491(0)` because it is not an lvalue fail_compilation/fail17491.d(34): Error: cannot modify expression `S17491(0).field` because it is not an lvalue fail_compilation/fail17491.d(35): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue From 535791ea481b008f3fa4d6129f4711453d413476 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 15 Aug 2025 15:49:43 +0100 Subject: [PATCH 5/9] Fix phobos segfault --- compiler/src/dmd/expressionsem.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 8b76f2a53f03..fd887e7ed3c3 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -11642,7 +11642,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // printf("PreExp::semantic('%s')\n", toChars()); if (Expression e = exp.opOverloadUnary(sc)) { - if (!sc.intypeof && exp.e1.type.ty == Tstruct && !exp.e1.isLvalue()) + if (!sc.intypeof && exp.e1.type && exp.e1.type.ty == Tstruct && + !exp.e1.isLvalue()) { error(exp.e1.loc, "cannot modify struct rvalue `%s`", exp.e1.toChars()); From ef2fac64393c75f1b1a737d81e779a07dc5178f7 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 12 Dec 2025 10:38:06 +0000 Subject: [PATCH 6/9] Refactor with `checkRvalueAssign`, allow nested struct assign Nested struct may assign context pointer's data, so not a no-op: https://github.com/CyberShadow/ae/blob/v0.0.3672/utils/array.d#LR1072-L1093 --- compiler/src/dmd/expressionsem.d | 5 +---- compiler/src/dmd/opover.d | 22 ++++++++++++++----- .../fail_compilation/struct_rvalue_assign.d | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index fd887e7ed3c3..5cb2a0a2163a 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -11642,11 +11642,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // printf("PreExp::semantic('%s')\n", toChars()); if (Expression e = exp.opOverloadUnary(sc)) { - if (!sc.intypeof && exp.e1.type && exp.e1.type.ty == Tstruct && - !exp.e1.isLvalue()) + if (checkRvalueAssign(sc, exp.e1, "modify")) { - error(exp.e1.loc, "cannot modify struct rvalue `%s`", - exp.e1.toChars()); e = ErrorExp.get(); } result = e; diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index d786500ab2d4..296f26908b4d 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -538,10 +538,8 @@ Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) bool choseReverse; if (auto result = pickBestBinaryOverload(sc, null, s, null, e, choseReverse)) { - if (!sc.intypeof && e.e1.type.ty == Tstruct && !e.e1.isLvalue()) + if (checkRvalueAssign(sc, e.e1, "assign to")) { - error(e.e1.loc, "cannot assign to struct rvalue `%s`", - e.e1.toChars()); return ErrorExp.get(); } return result; @@ -549,6 +547,21 @@ Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) return binAliasThis(e, sc, aliasThisStop); } +bool checkRvalueAssign(Scope *sc, Expression e, const char *op) +{ + if (!sc.intypeof && e.type && e.type.ty == Tstruct && !e.isLvalue()) + { + TypeStruct ts = cast(TypeStruct)e.type; + // nested struct may assign data outside of the struct, e.g. ae.utils.array.list(args) + if (!ts.sym.isNested()) + { + error(e.loc, "cannot %s struct rvalue `%s`", op, e.toChars()); + return true; + } + } + return false; +} + Expression opOverloadBinary(BinExp e, Scope* sc, Type[2] aliasThisStop) { if (Expression err = binSemanticProp(e, sc)) @@ -1011,9 +1024,8 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt if (e.e1.type.isTypeError() || e.e2.type.isTypeError()) return ErrorExp.get(); - if (!sc.intypeof && e.e1.type.ty == Tstruct && !e.e1.isLvalue()) + if (checkRvalueAssign(sc, e.e1, "modify")) { - error(e.e1.loc, "cannot assign to struct rvalue `%s`", e.e1.toChars()); return ErrorExp.get(); } AggregateDeclaration ad1 = isAggregate(e.e1.type); diff --git a/compiler/test/fail_compilation/struct_rvalue_assign.d b/compiler/test/fail_compilation/struct_rvalue_assign.d index 2b2bca856af2..baf2e80183dd 100644 --- a/compiler/test/fail_compilation/struct_rvalue_assign.d +++ b/compiler/test/fail_compilation/struct_rvalue_assign.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/struct_rvalue_assign.d(12): Error: cannot assign to struct rvalue `foo()` -fail_compilation/struct_rvalue_assign.d(13): Error: cannot assign to struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(13): Error: cannot modify struct rvalue `foo()` fail_compilation/struct_rvalue_assign.d(14): Error: cannot modify struct rvalue `foo()` --- */ From 70f2bdb04be9dbdd68ee979050571dc389074e86 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 12 Dec 2025 10:39:14 +0000 Subject: [PATCH 7/9] Test other rvalue unary ops still work --- .../test/fail_compilation/struct_rvalue_assign.d | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/test/fail_compilation/struct_rvalue_assign.d b/compiler/test/fail_compilation/struct_rvalue_assign.d index baf2e80183dd..a725223b5d2b 100644 --- a/compiler/test/fail_compilation/struct_rvalue_assign.d +++ b/compiler/test/fail_compilation/struct_rvalue_assign.d @@ -12,22 +12,16 @@ void main () foo() = S.init; foo() += 5; ++foo(); + cast(void) ~foo(); // other unary ops are OK } -S foo() -{ - return S.init; -} +S foo() => S.init; struct S { int i; - void opAssign(S s) - { - this.i = s.i; - } - + void opAssign(S s) {} void opOpAssign(string op : "+")(int) {} - void opUnary(string op : "++")() {} + void opUnary(string op)() {} } From bb582faf0eeafd85aecce703b4cf845c6e052a6d Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 13 Dec 2025 12:45:31 +0000 Subject: [PATCH 8/9] Suggest calling operator overload directly for side-effects --- compiler/src/dmd/expressionsem.d | 2 +- compiler/src/dmd/opover.d | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 5cb2a0a2163a..85037980f271 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -11642,7 +11642,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // printf("PreExp::semantic('%s')\n", toChars()); if (Expression e = exp.opOverloadUnary(sc)) { - if (checkRvalueAssign(sc, exp.e1, "modify")) + if (checkRvalueAssign(sc, exp.e1, Id.opUnary)) { e = ErrorExp.get(); } diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index 296f26908b4d..d01fde1be8e4 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -538,7 +538,7 @@ Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) bool choseReverse; if (auto result = pickBestBinaryOverload(sc, null, s, null, e, choseReverse)) { - if (checkRvalueAssign(sc, e.e1, "assign to")) + if (checkRvalueAssign(sc, e.e1, Id.opAssign)) { return ErrorExp.get(); } @@ -547,7 +547,7 @@ Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) return binAliasThis(e, sc, aliasThisStop); } -bool checkRvalueAssign(Scope *sc, Expression e, const char *op) +bool checkRvalueAssign(Scope *sc, Expression e, Identifier op) { if (!sc.intypeof && e.type && e.type.ty == Tstruct && !e.isLvalue()) { @@ -555,7 +555,10 @@ bool checkRvalueAssign(Scope *sc, Expression e, const char *op) // nested struct may assign data outside of the struct, e.g. ae.utils.array.list(args) if (!ts.sym.isNested()) { - error(e.loc, "cannot %s struct rvalue `%s`", op, e.toChars()); + const char* action = op == Id.opAssign ? "assign to" : "modify"; + error(e.loc, "cannot %s struct rvalue `%s`", action, e.toChars()); + errorSupplemental(e.loc, "if the assignment is used for side-effects, call `%s` directly", + op.toChars()); return true; } } @@ -1024,7 +1027,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt if (e.e1.type.isTypeError() || e.e2.type.isTypeError()) return ErrorExp.get(); - if (checkRvalueAssign(sc, e.e1, "modify")) + if (checkRvalueAssign(sc, e.e1, Id.opOpAssign)) { return ErrorExp.get(); } From 5a19c54673baff29d748173847d3cabbc04f5cec Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 13 Dec 2025 12:46:40 +0000 Subject: [PATCH 9/9] Enable error from 2024 edition --- compiler/src/dmd/opover.d | 3 ++- .../test/fail_compilation/struct_rvalue_assign.d | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index d01fde1be8e4..a85675d1036f 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -549,7 +549,8 @@ Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop) bool checkRvalueAssign(Scope *sc, Expression e, Identifier op) { - if (!sc.intypeof && e.type && e.type.ty == Tstruct && !e.isLvalue()) + if (!sc.intypeof && sc.hasEdition(Edition.v2024) && + e.type && e.type.ty == Tstruct && !e.isLvalue()) { TypeStruct ts = cast(TypeStruct)e.type; // nested struct may assign data outside of the struct, e.g. ae.utils.array.list(args) diff --git a/compiler/test/fail_compilation/struct_rvalue_assign.d b/compiler/test/fail_compilation/struct_rvalue_assign.d index a725223b5d2b..81cc6a2d94d9 100644 --- a/compiler/test/fail_compilation/struct_rvalue_assign.d +++ b/compiler/test/fail_compilation/struct_rvalue_assign.d @@ -1,13 +1,17 @@ /* TEST_OUTPUT: --- -fail_compilation/struct_rvalue_assign.d(12): Error: cannot assign to struct rvalue `foo()` -fail_compilation/struct_rvalue_assign.d(13): Error: cannot modify struct rvalue `foo()` -fail_compilation/struct_rvalue_assign.d(14): Error: cannot modify struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(16): Error: cannot assign to struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(16): if the assignment is used for side-effects, call `opAssign` directly +fail_compilation/struct_rvalue_assign.d(17): Error: cannot modify struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(17): if the assignment is used for side-effects, call `opOpAssign` directly +fail_compilation/struct_rvalue_assign.d(18): Error: cannot modify struct rvalue `foo()` +fail_compilation/struct_rvalue_assign.d(18): if the assignment is used for side-effects, call `opUnary` directly --- */ +module sra 2024; -void main () +void main() { foo() = S.init; foo() += 5;