From 7fa58d99970ab4f24653f1eddd9b47bfbdeb7633 Mon Sep 17 00:00:00 2001 From: JinShil Date: Tue, 31 Jul 2018 23:38:33 +0900 Subject: [PATCH] Lower _d_arraycast to object.__ArrayCast --- src/dmd/e2ir.d | 7 ++--- src/dmd/expressionsem.d | 46 ++++++++++++++++++++++++++++++ src/dmd/id.d | 2 ++ test/runnable/betterc.d | 34 ++++++++++++++++++++++ test/runnable/betterc_array_cast.d | 34 ++++++++++++++++++++++ 5 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 test/runnable/betterc_array_cast.d diff --git a/src/dmd/e2ir.d b/src/dmd/e2ir.d index ce4b3ac630aa..1fdd0520f288 100644 --- a/src/dmd/e2ir.d +++ b/src/dmd/e2ir.d @@ -4098,11 +4098,8 @@ elem *toElem(Expression e, IRState *irs) e = el_pair(totym(ce.type), elen2, eptr); } else - { // Runtime check needed in case arrays don't line up - if (config.exe == EX_WIN64) - e = addressElem(e, t, true); - elem *ep = el_params(e, el_long(TYsize_t, fsize), el_long(TYsize_t, tsize), null); - e = el_bin(OPcall, totym(ce.type), el_var(getRtlsym(RTLSYM_ARRAYCAST)), ep); + { + assert(false, "This case should have been rewritten to `__ArrayCast` in the semantic phase"); } } goto Lret; diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index 2918cfae61a7..fe8cbbc24d2c 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -6272,6 +6272,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.to == Type.terror) return setError(); + // Convert an expression like `cast(uint[])[]` or `cast(string[])[null]` + // to a typed array literals + if (exp.e1.op == TOK.arrayLiteral) + { + auto al = cast(ArrayLiteralExp)exp.e1.expressionSemantic(sc); + al.type = exp.to; + result = al; + return; + } + if (!exp.to.hasPointers()) exp.setNoderefOperand(); @@ -6383,6 +6393,42 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } + if (tob.ty == Tarray && t1b.ty == Tarray && exp.e1.op != TOK.string_) + { + auto tFrom = t1b.nextOf(); + auto tTo = tob.nextOf(); + + uint fromSize = cast(uint)tFrom.size(); + uint toSize = cast(uint)tTo.size(); + + if (fromSize != toSize) + { + // Array element sizes do not match, so we must adjust the dimensions + + if ((fromSize % toSize) != 0) + { + // Runtime check needed in case arrays don't line up + + // lower to `object.__ArrayCast!(TFrom, TTo)(from)` + + auto id = Identifier.idPool("__ArrayCast"); + + auto tiargs = new Objects(); + tiargs.push(tFrom); + tiargs.push(tTo); + auto ti = new TemplateInstance(exp.loc, id, tiargs); + Expression __ArrayCast = new ScopeExp(exp.loc, ti); + + auto arguments = new Expressions(); + arguments.push(exp.e1); + __ArrayCast = new CallExp(exp.loc, __ArrayCast, arguments); + + result = expressionSemantic(__ArrayCast, sc); + return; + } + } + } + result = ex; } diff --git a/src/dmd/id.d b/src/dmd/id.d index b0dd9f61fedb..6c771bf04884 100644 --- a/src/dmd/id.d +++ b/src/dmd/id.d @@ -421,6 +421,8 @@ immutable Msgtable[] msgtable = { "FALSE" }, { "unsigned" }, { "wchar_t" }, + + { "__ArrayCast"} ]; diff --git a/test/runnable/betterc.d b/test/runnable/betterc.d index d4655a24d32d..e0b7172d6c38 100644 --- a/test/runnable/betterc.d +++ b/test/runnable/betterc.d @@ -97,6 +97,12 @@ struct Sint this(int v) { x = v;} } +bool castToLongFailed = false; +extern(C) void castToLongAssertFail(int sig) nothrow @nogc +{ + castToLongFailed = true; +} + void testRuntimeLowerings() { // test call to `object.__equals` @@ -155,4 +161,32 @@ void testRuntimeLowerings() default: break; } + + // test call to `object.__ArrayCast` + import core.stdc.stdlib : malloc, free, exit; + import core.stdc.signal; + + byte[] b; + int[] i; + long[] l; + + // We can't actually create dynamic arrays in idiomatic D when + // compiling with -betterC, so we do it manually. + auto b_length = cast(size_t*)&b; + auto b_ptr = cast(void*)(b_length + 1); + *b_length = int.sizeof * 3; + b_ptr = malloc(*b_length); + + i = cast(int[])b; + assert(i.length == 3); + + // size mismatch, should result in an assertion failure + l = cast(long[])b; + signal(SIGABRT, &castToLongAssertFail); + assert(castToLongFailed); + + // No garbage collector in -betterC, we must free memory manually. + free(b_ptr); + + exit(0); } diff --git a/test/runnable/betterc_array_cast.d b/test/runnable/betterc_array_cast.d new file mode 100644 index 000000000000..a505fc64fd50 --- /dev/null +++ b/test/runnable/betterc_array_cast.d @@ -0,0 +1,34 @@ +/* REQUIRED_ARGS: -betterC + PERMUTE_ARGS: + */ + +// test call to `object.__ArrayCast` + +import core.stdc.stdlib; +import core.stdc.stdio; +import core.stdc.string; + +extern(C) void __assert(const char *msg, const char *file, int line) +{ + if (strcmp(msg, "array cast misalignment") != 0) + { + fprintf(stderr, "Assertion failure message is not correct\n"); + exit(1); + } +} + +extern(C) void main() +{ + byte[] b; + long[] l; + + // We can't actually create dynamic arrays in idiomatic D when + // compiling with -betterC, so we do it manually. + auto b_length = cast(size_t*)&b; + auto b_ptr = cast(void*)(b_length + 1); + *b_length = int.sizeof * 3; + b_ptr = malloc(*b_length); + + // size mismatch, should result in an assertion failure + l = cast(long[])b; +}