Thread overview
Segfault upon modifying immutable AA in static this
Jan 24, 2015
Nordlöw
Jan 24, 2015
Nordlöw
Jan 24, 2015
Nordlöw
Jan 24, 2015
Kenji Hara
Jan 24, 2015
anonymous
Jan 25, 2015
Jonathan M Davis
January 24, 2015
This snippet

    static immutable words = [ `zero`, `one`, `two` ];

    static immutable ubyte[string] wordsAA;

    static this()
    {
        foreach (ubyte i, e; words) { wordsAA[e] = i; }
    }

compiles and links on dmd git master but run segfaults.

Removing immutable qualifier from wordsAA avoids the segfeault.

Are static module ctors allowed to modify immutable data or this a DMD bug?
January 24, 2015
The issue originates from module level intialization of static immutable AAs at

https://github.com/nordlow/justd/blob/master/conv_ex.d

Do I have to change the initialization of the AAs to be explicitly inline at definition of the AAs or can I preserve my convenient foreach over the AAs in the `static this` to automatically get the integer value to be stored?

Note that this does not segdefault on latest stable DMD 2.066.
January 24, 2015
On Saturday, 24 January 2015 at 13:29:36 UTC, Nordlöw wrote:
> The issue originates from module level intialization of static immutable AAs at
>
> https://github.com/nordlow/justd/blob/master/conv_ex.d
>
> Do I have to change the initialization of the AAs to be explicitly inline at definition of the AAs or can I preserve my convenient foreach over the AAs in the `static this` to automatically get the integer value to be stored?
>
> Note that this does not segdefault on latest stable DMD 2.066.

Also note that removing the immutable keyword from the AAs make by conversion function non-pure which I would like to avoid if possible.
January 24, 2015
On Saturday, 24 January 2015 at 13:24:02 UTC, Nordlöw wrote:
> This snippet
>
>     static immutable words = [ `zero`, `one`, `two` ];
>
>     static immutable ubyte[string] wordsAA;
>
>     static this()
>     {
>         foreach (ubyte i, e; words) { wordsAA[e] = i; }
>     }
>
> compiles and links on dmd git master but run segfaults.
>
> Removing immutable qualifier from wordsAA avoids the segfeault.
>
> Are static module ctors allowed to modify immutable data or this a DMD bug?

They are definitely allowed to initialize immutable data, i.e. write once. I don't know if you're allowed to change it repeatedly.

You can change your code to write only once:

static this()
{
    import std.exception: assumeUnique;
    ubyte[string] tmp;
    foreach (ubyte i, e; words) { tmp[e] = i; }
    wordsAA = assumeUnique(tmp); /* Don't alter tmp from here on. */
}
January 24, 2015
On Saturday, 24 January 2015 at 13:29:36 UTC, Nordlöw wrote:
> The issue originates from module level intialization of static immutable AAs at
>
> https://github.com/nordlow/justd/blob/master/conv_ex.d
>
> Do I have to change the initialization of the AAs to be explicitly inline at definition of the AAs or can I preserve my convenient foreach over the AAs in the `static this` to automatically get the integer value to be stored?
>
> Note that this does not segdefault on latest stable DMD 2.066.

It's a regression in git-head.

https://issues.dlang.org/show_bug.cgi?id=14038

Kenji Hara
January 25, 2015
On Saturday, January 24, 2015 13:24:01 Nordlöw via Digitalmars-d-learn wrote:
> This snippet
>
>      static immutable words = [ `zero`, `one`, `two` ];
>
>      static immutable ubyte[string] wordsAA;
>
>      static this()
>      {
>          foreach (ubyte i, e; words) { wordsAA[e] = i; }
>      }
>
> compiles and links on dmd git master but run segfaults.
>
> Removing immutable qualifier from wordsAA avoids the segfeault.
>
> Are static module ctors allowed to modify immutable data or this a DMD bug?

immutable variables can only be initialized and cannot be assigned to. The fact that

wordsAA[e] = i;

even compiles is most definitely a bug, but constructors are of a bit of a special place for immutable variables, since they can be initialized there rather than being directly initialized, and clearly something in how that is handled in the compiler is buggy. i.e. code like

wordsAA = value;

would be illegal outside of a constructor, because wordsAA is immutable, but it's legal, because it's inside of a constructor associated with it (in this case, a static constructor for a static variable). So, presumably, whatever in the compiler makes that legal has a bug that makes it think that

wordsAA[e] = i;

is legal when it isn't.

In any case, if you want to initialize an immutable array or AA or whatnot where you can't just directly initialize it but rather need multiple operations, then you need to create a mutable one that gets converted to an immutable one - either by casting it to immutable when assigning it to the immutable variable (in which case, you need to be sure that no mutable reference to it continues to exist) or by writing a pure function to create it and return it, in which case, it will implicitly convert to immutable, because the compiler knows that no mutuable references to it exist.  So, something like this should work

static immutable words = [ `zero`, `one`, `two` ];
static immutable ubyte[string] wordsAA;

static this()
{
    auto initWordsAA() pure
    {
        ubyte[string] retval;
        foreach(ubyte i, e; words)
            retval[e] = i;
        return retval;
    }
    wordsAA = initWordsAA();
}

You should report the segfault as a bug though. Your original code should not compile, because

wordsAA[e] = i;

is quite illegal due to wordsAA's immutability.

- Jonathan M Davis