Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower _d_arraycast to object.__ArrayCast #8531

Closed
wants to merge 1 commit into from
Closed
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
7 changes: 2 additions & 5 deletions src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
46 changes: 46 additions & 0 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can I fully qualify this to object.__ArrayCast?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at how the comparison lowering is done to __cmp.

dmd/src/dmd/expressionsem.d

Lines 9794 to 9798 in 03e7693

// Lower to object.__cmp(e1, e2)
Expression al = new IdentifierExp(exp.loc, Id.empty);
al = new DotIdExp(exp.loc, al, Id.object);
al = new DotIdExp(exp.loc, al, Id.__cmp);
al = al.expressionSemantic(sc);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I need an Identifer, not an Expression, for the TemplateInstance, later. How do I create a fully-qualified Identifier?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I create a fully-qualified Identifier?

I don't think that is possible. To get the fully qualified name inside the compiler one needs to walk up the parent chain and build up the name that way. In your case, I think you need to use the overload of the TemplateInstance constructor that takes a TemplateDeclaration. Perhaps you can store the TemplateDeclaration when it's analyzed in the same way as the Object class declaration (and others) is stored:

dmd/src/dmd/dclass.d

Lines 367 to 372 in 03e7693

if (id == Id.Object)
{
if (!inObject)
error("%s", msg);
object = this;
}


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;
}

Expand Down
2 changes: 2 additions & 0 deletions src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ immutable Msgtable[] msgtable =
{ "FALSE" },
{ "unsigned" },
{ "wchar_t" },

{ "__ArrayCast"}
];


Expand Down
34 changes: 34 additions & 0 deletions test/runnable/betterc.d
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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);
}
34 changes: 34 additions & 0 deletions test/runnable/betterc_array_cast.d
Original file line number Diff line number Diff line change
@@ -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;
}