Skip to content
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 @@ -8754,9 +8754,17 @@
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 @@
}
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 @@
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