Thread overview
Cast converts AA to rvalue?
Aug 09, 2022
Johan
Aug 10, 2022
Johan
Aug 10, 2022
ag0aep6g
Aug 10, 2022
Johan
Aug 10, 2022
ag0aep6g
August 09, 2022

Testcase:

shared int[int] aa;
void main () {
    cast()aa[1] = 1;
}

Up to dlang 2.097, this program runs and works fine.
Since dlang 2.098, the program errors with:
core.exception.RangeError@/app/example.d(3): Range violation

I think the 2.098+ behavior is correct, but I cannot find anything about the change of this language behavior in the release notes.

Please enlighten me,
Johan

related discussion: https://forum.dlang.org/post/etxuhqzlkofitxswsxel@forum.dlang.org

August 09, 2022

On 8/9/22 7:02 PM, Johan wrote:

>

Testcase:

shared int[int] aa;
void main () {
     cast()aa[1] = 1;
}

Up to dlang 2.097, this program runs and works fine.
Since dlang 2.098, the program errors with:
core.exception.RangeError@/app/example.d(3): Range violation

I think the 2.098+ behavior is correct, but I cannot find anything about the change of this language behavior in the release notes.

So what is happening is you are casting away shared on the expression aa[1]. This expression by itself is an access of a value, not an assignment. This is consistent for structs defining both opIndex and opIndexAssign (the expression calls opIndex, not opIndexAssign), as far back as I can test.

If you use cast()(aa[1]) = 1, it has a range error even on older versions.

That it ever worked is puzzling.

-Steve

August 10, 2022

On Wednesday, 10 August 2022 at 00:28:53 UTC, Steven Schveighoffer wrote:

>

On 8/9/22 7:02 PM, Johan wrote:

>

Testcase:

shared int[int] aa;
void main () {
     cast()aa[1] = 1;
}

If you use cast()(aa[1]) = 1, it has a range error even on older versions.

That it ever worked is puzzling.

I think old compilers parsed it as (cast()aa)[1], which works on newer compilers too without range error.

In my case, aa is also immutable. The only way I know how to make it work is now pretty ugly (casting away immutable should be ugly, so perhaps it's OK...):

shared immutable int[int] aa;
void main () {
    // (cast()aa)[1] = 1; // works without immutable
    (*cast(int[int]*)(&aa))[1] = 1;
}
August 10, 2022
On 10.08.22 10:20, Johan wrote:
> ```
> shared immutable int[int] aa;
> void main () {
>      // (cast()aa)[1] = 1; // works without immutable
>      (*cast(int[int]*)(&aa))[1] = 1;
> }
> ```

We have shared static constructors for that:

shared static this()
{
    aa[1] = 1; /* no cast needed */
}
August 10, 2022

On Wednesday, 10 August 2022 at 09:52:10 UTC, ag0aep6g wrote:

>

On 10.08.22 10:20, Johan wrote:

>
shared immutable int[int] aa;
void main () {
     // (cast()aa)[1] = 1; // works without immutable
     (*cast(int[int]*)(&aa))[1] = 1;
}

We have shared static constructors for that:

shared static this()
{
aa[1] = 1; /* no cast needed */
}

But our code is not a toy example ;-) (sorry for unnecessary snarky remark)

void f() {
    aa[1] = 1; // error
}
shared static this()
{
    f();
}

I had considered it, but discarded it... f is also a template in our code. Your remark made me check again, and the call chain is short, perhaps I'll convert f to a template mixin... Unfortunately doesn't work: "immutable variable aa initialization is not allowed in nested function f".

-Johan

August 10, 2022

On Wednesday, 10 August 2022 at 17:14:08 UTC, Johan wrote:

>
void f() {
    aa[1] = 1; // error
}
shared static this()
{
    f();
}

I had considered it, but discarded it... f is also a template in our code. Your remark made me check again, and the call chain is short, perhaps I'll convert f to a template mixin... Unfortunately doesn't work: "immutable variable aa initialization is not allowed in nested function f".

If you can build a mutable version of the array in a pure function, you can do it like this:

int[int] make_aa() pure
{
    int[int] maa;
    maa[1] = 1; /* or function calls, or whatever */
    return maa;
}
immutable int[int] aa;
shared static this()
{
    aa = make_aa();
}

If you can't do it in a pure function, you can do it with a cast: aa = cast(immutable) make_aa();.

Casting from mutable to immutable is better, because it does not have undefined behavior (as long as you don't use a mutable reference later). Your casting away immutable and then mutating does have undefined behavior.