From 5e222bf96aa361b68f31d107c20ab7d55d4e7ebf Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 17 Jan 2025 23:24:44 -0800 Subject: [PATCH] fix #20644 cast(ref T) as shorthand for *cast(T*)& --- changelog/dmd.reference-cast.dd | 11 ++++++++++ compiler/src/dmd/parse.d | 28 ++++++++++++++++++++++-- compiler/test/fail_compilation/castref.d | 11 ++++++++++ compiler/test/runnable/mars1.d | 11 ++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 changelog/dmd.reference-cast.dd create mode 100644 compiler/test/fail_compilation/castref.d diff --git a/changelog/dmd.reference-cast.dd b/changelog/dmd.reference-cast.dd new file mode 100644 index 000000000000..a7dd50af4826 --- /dev/null +++ b/changelog/dmd.reference-cast.dd @@ -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 +--- diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 415d57824d14..93b3024b0e49 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -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) */ @@ -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); @@ -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) + { + /* 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; } diff --git a/compiler/test/fail_compilation/castref.d b/compiler/test/fail_compilation/castref.d new file mode 100644 index 000000000000..e30d0938e019 --- /dev/null +++ b/compiler/test/fail_compilation/castref.d @@ -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; +} diff --git a/compiler/test/runnable/mars1.d b/compiler/test/runnable/mars1.d index 1c2ae55b79c4..3c029e3f074f 100644 --- a/compiler/test/runnable/mars1.d +++ b/compiler/test/runnable/mars1.d @@ -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 @@ -2651,6 +2661,7 @@ int main() test20574(); test8(); test9(); + test10(); printf("Success\n"); return 0;