Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -10747,6 +10747,13 @@ 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())
{
error(exp.e1.loc, "cannot modify struct rvalue `%s`",
exp.e1.toChars());
e = ErrorExp.get();
}
result = e;
return;
}
Expand Down
14 changes: 13 additions & 1 deletion compiler/src/dmd/opover.d
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -1004,6 +1011,11 @@ 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())
{
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()))
Expand Down
8 changes: 4 additions & 4 deletions compiler/test/fail_compilation/fail9936.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
---
Expand All @@ -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();
Expand Down
33 changes: 33 additions & 0 deletions compiler/test/fail_compilation/struct_rvalue_assign.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
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(14): Error: cannot modify struct rvalue `foo()`
---
*/

void main ()
{
foo() = S.init;
foo() += 5;
++foo();
}

S foo()
{
return S.init;
}

struct S
{
int i;

void opAssign(S s)
{
this.i = s.i;
}

void opOpAssign(string op : "+")(int) {}
void opUnary(string op : "++")() {}
}
Loading