Skip to content

Commit 5e222bf

Browse files
committed
fix #20644 cast(ref T) as shorthand for *cast(T*)&
1 parent d6f693b commit 5e222bf

File tree

4 files changed

+59
-2
lines changed

4 files changed

+59
-2
lines changed

changelog/dmd.reference-cast.dd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Add cast(ref T)e as shorthand for *cast(T*)&e
2+
3+
A `cast(ref T)e` takes `e` representing an lvalue and forcibly changes
4+
its type to `T`. It is equivalent to the expression `*cast(T*)&e`.
5+
)
6+
7+
---
8+
int i = 73;
9+
float f = *cast(float*)&i; // reinterprets the integer bit pattern as a float
10+
float g = cast(ref float)i; // equivalent to the previous statement
11+
---

compiler/src/dmd/parse.d

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8754,9 +8754,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
87548754
break;
87558755

87568756
case TOK.cast_: // cast(type) expression
8757-
{
8757+
{ // https://dlang.org/spec/expression.html#cast_expressions
87588758
nextToken();
87598759
check(TOK.leftParenthesis);
8760+
8761+
bool castRef;
8762+
if (token.value == TOK.ref_) // cast(ref ...)
8763+
{
8764+
castRef = true;
8765+
nextToken();
8766+
}
8767+
87608768
/* Look for cast(), cast(const), cast(immutable),
87618769
* cast(shared), cast(shared const), cast(wild), cast(shared wild)
87628770
*/
@@ -8800,6 +8808,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
88008808
}
88018809
if (token.value == TOK.rightParenthesis)
88028810
{
8811+
/* https://dlang.org/spec/expression.html#CastQual
8812+
*/
8813+
if (castRef)
8814+
error("`cast(ref` needs to be followed with a type");
88038815
nextToken();
88048816
e = parseUnaryExp();
88058817
e = new AST.CastExp(loc, e, m);
@@ -8810,7 +8822,19 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
88108822
t = t.addSTC(AST.ModToStc(m)); // cast( const type )
88118823
check(TOK.rightParenthesis);
88128824
e = parseUnaryExp();
8813-
e = new AST.CastExp(loc, e, t);
8825+
if (castRef)
8826+
{
8827+
/* Rewrite cast(ref T)e as *cast(T*)&e
8828+
*/
8829+
t = new AST.TypePointer(t);
8830+
e = new AST.AddrExp(loc, e);
8831+
e = new AST.CastExp(loc, e, t);
8832+
e = new AST.PtrExp(loc, e);
8833+
}
8834+
else
8835+
{
8836+
e = new AST.CastExp(loc, e, t);
8837+
}
88148838
}
88158839
break;
88168840
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* TEST_OUTPUT:
2+
---
3+
fail_compilation/castref.d(10): Error: `cast(ref` needs to be followed with a type
4+
---
5+
*/
6+
7+
void test()
8+
{
9+
int* p;
10+
char* q = cast(ref const)p;
11+
}

compiler/test/runnable/mars1.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,6 +2549,16 @@ void test9()
25492549

25502550
////////////////////////////////////////////////////////////////////////
25512551

2552+
void test10()
2553+
{
2554+
int v = 0x12345678;
2555+
float f = cast(ref float)v;
2556+
float g = *cast(float*)&v;
2557+
assert(f == g);
2558+
}
2559+
2560+
////////////////////////////////////////////////////////////////////////
2561+
25522562
int main()
25532563
{
25542564
// All the various integer divide tests
@@ -2651,6 +2661,7 @@ int main()
26512661
test20574();
26522662
test8();
26532663
test9();
2664+
test10();
26542665

26552666
printf("Success\n");
26562667
return 0;

0 commit comments

Comments
 (0)