Skip to content

Commit

Permalink
fix #20644 cast(ref T) as shorthand for *cast(T*)&
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Jan 18, 2025
1 parent d6f693b commit 07d16f7
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 2 deletions.
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 @@ -8754,9 +8754,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 @@ -8800,6 +8808,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 @@ -8810,7 +8822,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)

Check warning on line 8825 in compiler/src/dmd/parse.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/parse.d#L8825

Added line #L8825 was not covered by tests
{
/* Rewrite cast(ref T)e as *cast(T*)&e

Check warning on line 8827 in compiler/src/dmd/parse.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/parse.d#L8827

Added line #L8827 was not covered by tests
*/
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

0 comments on commit 07d16f7

Please sign in to comment.