Thread overview
[Issue 21109] Possibly wrong codegen when using enum arrays
Aug 04, 2020
Andrej Mitrovic
Aug 04, 2020
Andrej Mitrovic
Aug 04, 2020
Andrej Mitrovic
Aug 04, 2020
Andrej Mitrovic
[Issue 21109] Wrong result when using sort() on enum arrays
Aug 04, 2020
Andrej Mitrovic
Aug 04, 2020
Boris Carvajal
Aug 07, 2020
Andrej Mitrovic
Aug 07, 2020
Simen Kjaeraas
Dec 17, 2022
Iain Buclaw
August 04, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

--- Comment #1 from Andrej Mitrovic <andrej.mitrovich@gmail.com> ---
Using DMD v2.093.0.

--
August 04, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

--- Comment #2 from Andrej Mitrovic <andrej.mitrovich@gmail.com> ---
I've confirmed the issue with ldc2 as well. So it looks like it's a front-end bug.

--
August 04, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

--- Comment #3 from Andrej Mitrovic <andrej.mitrovich@gmail.com> ---
I think this is related to `sort`. It's possible that sort compares by pointers if two structs are otherwise equivalent.

And then using `enum` has a different effect on arrays, possibly optimizing and storing the same pointer in two structs (making them equal).

--
August 04, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

--- Comment #4 from Andrej Mitrovic <andrej.mitrovich@gmail.com> ---
(In reply to Andrej Mitrovic from comment #3)
> I think this is related to `sort`. It's possible that sort compares by pointers if two structs are otherwise equivalent.
> 
> And then using `enum` has a different effect on arrays, possibly optimizing and storing the same pointer in two structs (making them equal).

Sorry the actual reasoning should be: `enum` always allocates a new array, therefore the pointer addresses change each time.

It's possible opCmp does a value comparison first, and then a pointer comparison.

But I don't think pointers should be compared at all.. at least not when dealing with arrays and not naked pointers in a struct.

--
August 04, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

Andrej Mitrovic <andrej.mitrovich@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|Possibly wrong codegen when |Wrong result when using
                   |using enum arrays           |sort() on enum arrays

--
August 04, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

Boris Carvajal <boris2.9@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |boris2.9@gmail.com

--- Comment #5 from Boris Carvajal <boris2.9@gmail.com> ---
There is no 'opCmp' defined for the struct so the runtime just use a memcmp for
the comparison.
The code itself calls '__cmp' from core/internal/array/comparison.d (because
the element are an array '[S(2, [0, 0])]') and there the 3 'static if'
conditions fail but if you define 'opCmp' the second path is taken.

So the following works:

struct S
{
    int[] arr;
    int opCmp(ref const S s) const { return arr < s.arr; }
}

There is a comment on clone.d file that says:

"Essentially, a struct which does not define opCmp is not comparable."

This concise phrase should be on the spec.

--
August 07, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

--- Comment #6 from Andrej Mitrovic <andrej.mitrovich@gmail.com> ---
(In reply to Boris Carvajal from comment #5)
> There is no 'opCmp' defined for the struct so the runtime just use a memcmp
> for the comparison.
> The code itself calls '__cmp' from core/internal/array/comparison.d (because
> the element are an array '[S(2, [0, 0])]') and there the 3 'static if'
> conditions fail but if you define 'opCmp' the second path is taken.
> 
> So the following works:
> 
> struct S
> {
>     int[] arr;
>     int opCmp(ref const S s) const { return arr < s.arr; }
> }
> 
> There is a comment on clone.d file that says:
> 
> "Essentially, a struct which does not define opCmp is not comparable."
> 
> This concise phrase should be on the spec.

Hmm.

In the past the compiler would also do memcmp when a struct didn't define `opEquals`, but we changed it so it does member-by-member `==` comparison.

I wonder if we can do something similar for opCmp, or if that wouldn't make sense..

--
August 07, 2020
https://issues.dlang.org/show_bug.cgi?id=21109

Simen Kjaeraas <simen.kjaras@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |simen.kjaras@gmail.com

--- Comment #7 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
We can reduce this issue down to this code:

struct S {
    int[] arr;
}

unittest {
    import std.stdio;
    foreach (idx; 0 .. 10) {
        writeln([S([0])] < [S([0])]);
    }
}

I'm not convinced that being able to compare two arrays like this should be possible at all - the rule that for any T where T.init < T.init does not compile, [T.init] < [T.init] should not compile seems sensible to me.

If we need it to work, it should definitely do a member-by-member comparison. Not least, this should be documented.

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=21109

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P2

--