Skip to content

Commit 87e5024

Browse files
WalterBrightTurkeyMan
authored andcommitted
fix #20644 cast(ref T) as shorthand for *cast(T*)&
1 parent cdf4f5b commit 87e5024

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
@@ -8708,9 +8708,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
87088708
break;
87098709

87108710
case TOK.cast_: // cast(type) expression
8711-
{
8711+
{ // https://dlang.org/spec/expression.html#cast_expressions
87128712
nextToken();
87138713
check(TOK.leftParenthesis);
8714+
8715+
bool castRef;
8716+
if (token.value == TOK.ref_) // cast(ref ...)
8717+
{
8718+
castRef = true;
8719+
nextToken();
8720+
}
8721+
87148722
/* Look for cast(), cast(const), cast(immutable),
87158723
* cast(shared), cast(shared const), cast(wild), cast(shared wild)
87168724
*/
@@ -8754,6 +8762,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
87548762
}
87558763
if (token.value == TOK.rightParenthesis)
87568764
{
8765+
/* https://dlang.org/spec/expression.html#CastQual
8766+
*/
8767+
if (castRef)
8768+
error("`cast(ref` needs to be followed with a type");
87578769
nextToken();
87588770
e = parseUnaryExp();
87598771
e = new AST.CastExp(loc, e, m);
@@ -8764,7 +8776,19 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
87648776
t = t.addSTC(AST.ModToStc(m)); // cast( const type )
87658777
check(TOK.rightParenthesis);
87668778
e = parseUnaryExp();
8767-
e = new AST.CastExp(loc, e, t);
8779+
if (castRef)
8780+
{
8781+
/* Rewrite cast(ref T)e as *cast(T*)&e
8782+
*/
8783+
t = new AST.TypePointer(t);
8784+
e = new AST.AddrExp(loc, e);
8785+
e = new AST.CastExp(loc, e, t);
8786+
e = new AST.PtrExp(loc, e);
8787+
}
8788+
else
8789+
{
8790+
e = new AST.CastExp(loc, e, t);
8791+
}
87688792
}
87698793
break;
87708794
}
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)