d: fix ICE at convert_expr(tree_node*, Type*, Type*) (PR101490)

Both the front-end and code generator had a modulo by zero bug when testing if
a conversion from a static array to dynamic array was valid.

	PR d/101490

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 27e388b4c.
	* d-codegen.cc (build_array_index): Handle void arrays same as byte.
	* d-convert.cc (convert_expr): Handle converting to zero-sized arrays.

gcc/testsuite/ChangeLog:

	* gdc.dg/pr101490.d: New test.
This commit is contained in:
Iain Buclaw 2021-07-26 15:11:42 +02:00
parent 1a2306ffe7
commit c936c39f86
6 changed files with 57 additions and 26 deletions

View File

@ -1639,21 +1639,9 @@ build_array_index (tree ptr, tree index)
/* Array element size. */ /* Array element size. */
tree size_exp = size_in_bytes (target_type); tree size_exp = size_in_bytes (target_type);
if (integer_zerop (size_exp)) if (integer_zerop (size_exp) || integer_onep (size_exp))
{ {
/* Test for array of void. */ /* Array of void or bytes -- No need to multiply. */
if (TYPE_MODE (target_type) == TYPE_MODE (void_type_node))
index = fold_convert (type, index);
else
{
/* Should catch this earlier. */
error ("invalid use of incomplete type %qD", TYPE_NAME (target_type));
ptr_type = error_mark_node;
}
}
else if (integer_onep (size_exp))
{
/* Array of bytes -- No need to multiply. */
index = fold_convert (type, index); index = fold_convert (type, index);
} }
else else

View File

@ -473,13 +473,18 @@ convert_expr (tree exp, Type *etype, Type *totype)
tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ()); tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
if ((dim * esize) % tsize != 0) if (esize != tsize)
{ {
error ("cannot cast %qs to %qs since sizes do not line up", /* Array element sizes do not match, so we must adjust the
etype->toChars (), totype->toChars ()); dimensions. */
return error_mark_node; if (tsize == 0 || (dim * esize) % tsize != 0)
{
error ("cannot cast %qs to %qs since sizes do not line up",
etype->toChars (), totype->toChars ());
return error_mark_node;
}
dim = (dim * esize) / tsize;
} }
dim = (dim * esize) / tsize;
/* Assumes casting to dynamic array of same type or void. */ /* Assumes casting to dynamic array of same type or void. */
return d_array_value (build_ctype (totype), size_int (dim), return d_array_value (build_ctype (totype), size_int (dim),

View File

@ -1,4 +1,4 @@
f8c1ca928360dd8c9f2fbb5771e2a5e398878ca0 27e388b4c4d292cac25811496aaf79341c05c940
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository. merge done from the dlang/dmd repository.

View File

@ -1496,13 +1496,16 @@ Expression *castTo(Expression *e, Scope *sc, Type *t)
// cast(U[])sa; // ==> cast(U[])sa[]; // cast(U[])sa; // ==> cast(U[])sa[];
d_uns64 fsize = t1b->nextOf()->size(); d_uns64 fsize = t1b->nextOf()->size();
d_uns64 tsize = tob->nextOf()->size(); d_uns64 tsize = tob->nextOf()->size();
if ((((TypeSArray *)t1b)->dim->toInteger() * fsize) % tsize != 0) if (fsize != tsize)
{ {
// copied from sarray_toDarray() in e2ir.c dinteger_t dim = ((TypeSArray *)t1b)->dim->toInteger();
e->error("cannot cast expression %s of type %s to %s since sizes don't line up", if (tsize == 0 || (dim * fsize) % tsize != 0)
e->toChars(), e->type->toChars(), t->toChars()); {
result = new ErrorExp(); e->error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
return; e->toChars(), e->type->toChars(), t->toChars());
result = new ErrorExp();
return;
}
} }
goto Lok; goto Lok;
} }

View File

@ -0,0 +1,21 @@
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101490
// { dg-do compile }
struct S101490
{
int[0] arr;
}
void main()
{
S101490* t;
auto a = cast(typeof(t.arr)[0])t.arr;
write(a);
}
void write(S)(S args)
{
foreach (arg; args)
{
}
}

View File

@ -0,0 +1,14 @@
// https://issues.dlang.org/show_bug.cgi?id=22144
/* TEST_OUTPUT
---
fail_compilation/fail22144.d(12): Error: cannot cast expression `zarray1` of type `int[0]` to `int[0][]` since sizes don't line up
---
*/
void main()
{
int[0] zarray1;
int[0][0] zarray2;
auto zslice1 = cast(int[0][])zarray1; // ICE -> Error
auto zslice2 = cast(int[0][])zarray2; // ICE -> OK
}