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

fix #20644 cast(ref T) as shorthand for *cast(T*)& #20728

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
11 changes: 11 additions & 0 deletions changelog/dmd.reference-cast.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Add cast(ref T)e as shorthand for *cast(T*)&e

A `cast(ref T)e` takes `e` representing an lvalue and forcibly changes
its type to `T`. It is equivalent to the expression `*cast(T*)&e`.
)

---
int i = 73;
float f = *cast(float*)&i; // reinterprets the integer bit pattern as a float
float g = cast(ref float)i; // equivalent to the previous statement
---
28 changes: 26 additions & 2 deletions compiler/src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -8708,9 +8708,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
break;

case TOK.cast_: // cast(type) expression
{
{ // https://dlang.org/spec/expression.html#cast_expressions
nextToken();
check(TOK.leftParenthesis);

bool castRef;
if (token.value == TOK.ref_) // cast(ref ...)
{
castRef = true;
nextToken();
}

/* Look for cast(), cast(const), cast(immutable),
* cast(shared), cast(shared const), cast(wild), cast(shared wild)
*/
Expand Down Expand Up @@ -8754,6 +8762,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
if (token.value == TOK.rightParenthesis)
{
/* https://dlang.org/spec/expression.html#CastQual
*/
if (castRef)
error("`cast(ref` needs to be followed with a type");
nextToken();
e = parseUnaryExp();
e = new AST.CastExp(loc, e, m);
Expand All @@ -8764,7 +8776,19 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
t = t.addSTC(AST.ModToStc(m)); // cast( const type )
check(TOK.rightParenthesis);
e = parseUnaryExp();
e = new AST.CastExp(loc, e, t);
if (castRef)
{
/* Rewrite cast(ref T)e as *cast(T*)&e
*/
t = new AST.TypePointer(t);
e = new AST.AddrExp(loc, e);
e = new AST.CastExp(loc, e, t);
e = new AST.PtrExp(loc, e);
}
else
{
e = new AST.CastExp(loc, e, t);
}
}
break;
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/test/fail_compilation/castref.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* TEST_OUTPUT:
---
fail_compilation/castref.d(10): Error: `cast(ref` needs to be followed with a type
---
*/

void test()
{
int* p;
char* q = cast(ref const)p;
}
11 changes: 11 additions & 0 deletions compiler/test/runnable/mars1.d
Original file line number Diff line number Diff line change
Expand Up @@ -2549,6 +2549,16 @@ void test9()

////////////////////////////////////////////////////////////////////////

void test10()
{
int v = 0x12345678;
float f = cast(ref float)v;
float g = *cast(float*)&v;
assert(f == g);
}

////////////////////////////////////////////////////////////////////////

int main()
{
// All the various integer divide tests
Expand Down Expand Up @@ -2651,6 +2661,7 @@ int main()
test20574();
test8();
test9();
test10();

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