Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suppress the "read-modify-write" error if type is a struct or a class #10281

Merged
merged 1 commit into from Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions changelog/no-readmodify-error-if-struct-class.dd
@@ -0,0 +1,23 @@
Suppress the "read-modify-write" error if type is a struct or a class

If a struct or class with shared type implements the opUnary or opOpAssign
operator then it is possible to perform "read-modify-write" operations
because the operator's implementation is supposed to perform atomic operations.

The purpose of this modification is to allow the creation of wrappers
(with structs or classes) to run atomic operations silently, for example:

---
shared struct Atomic {
int a;

int opUnary(string s)() if (s == "++")
{
import core.atomic : atomicOp;
return atomicOp!"+="(a, 1);
}
}

Atomic atomicvar;
atomicvar++; // Safe! Atomic struct implements opUnary
---
2 changes: 1 addition & 1 deletion src/dmd/expression.d
Expand Up @@ -1353,7 +1353,7 @@ extern (C++) abstract class Expression : ASTNode
extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null)
{
//printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
if (!type || !type.isShared())
if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't look right. It's blindly allowing struct / class

Copy link
Contributor Author

@ErnyTech ErnyTech Aug 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the class/struct does not implement the operator the compiler will give the error "is not a scalar"

if (exp.e1.checkScalar() ||

So I don't think further checks are necessary

return false;

// atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
Expand Down
35 changes: 35 additions & 0 deletions test/compilable/readmodify_structclass.d
@@ -0,0 +1,35 @@
/*
REQUIRED_ARGS:
TEST_OUTPUT:
---
---
*/
shared struct S
{
int x = 0;

int opUnary(string s)() if (s == "++")
{
import core.atomic : atomicOp;
return atomicOp!"+="(x, 1);
}
}

shared class C
{
int x = 0;

int opUnary(string s)() if (s == "++")
{
import core.atomic : atomicOp;
return atomicOp!"+="(x, 1);
}
}

void main()
{
S s;
s++;
shared(C) c = new C();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be shared if C is a shared class ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using shared in the class declaration does not seem to make the class type "implicitly" shared unlike what it does in a struct

c++;
}