Thread overview
[Issue 19763] Cannot construct immutable struct from pure mutable struct
Mar 26, 2019
ag0aep6g
Mar 26, 2019
ag0aep6g
Mar 26, 2019
Jacob Carlborg
March 26, 2019
https://issues.dlang.org/show_bug.cgi?id=19763

ag0aep6g <ag0aep6g@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ag0aep6g@gmail.com

--- Comment #1 from ag0aep6g <ag0aep6g@gmail.com> ---
(In reply to Jacob Carlborg from comment #0)
> The following example fails to compile:
> 
> struct Foo
> {
>     const(char)* filename;
>     this(const(char)*) pure { }
> }
> 
> void main()
> {
>     immutable a = Foo(null);
> }
> 
> Error:

I think it's correct that this is rejected.

The compiler could maybe realize that `null` poses no threat, or that the constructor doesn't actually set `filename`, but it's obviously not that smart.

Generally, code like this must be rejected, because `main` still has access to the pointer that's passed to the constructor:

----
struct Foo
{
    const(char)* filename;
    this(const(char)* f) pure { filename = f; }
}
void main()
{
    char* p = new char;
    immutable a = Foo(p);
    *p = '!'; /* would mutate a.filename which is supposed to be immutable */
}
----


> But this code compiles:
> 
> struct Foo
> {
>     const(char)* filename;
>     this(const(char)*) pure { }
> }
> 
> Foo newFoo() pure
> {
>     return Foo(null);
> }
> 
> void main()
> {
>     immutable a = newFoo();
> }

This is ok, because newFoo is `pure` and it immediately returns the constructed Foo. So it's guaranteed that the only mutable reference to the data ceases to exist right as the immutable one is created.


> Also if "const(char)* filename" is changed to "char* filename" the first
> example compiles.

The constructor cannot possibly use the const(char)* parameter to set the char* field. So there is no way that the constructed Foo can refer to mutable data.

If you make the parameter mutable, too, then the code will be rejected again.

As far as I can tell, there's no bug here.

--
March 26, 2019
https://issues.dlang.org/show_bug.cgi?id=19763

--- Comment #2 from ag0aep6g <ag0aep6g@gmail.com> ---
(In reply to ag0aep6g from comment #1)
> (In reply to Jacob Carlborg from comment #0)
[...]
> > Foo newFoo() pure
> > {
> >     return Foo(null);
> > }
[...]
> 
> This is ok, because newFoo [...] immediately returns the constructed Foo.

Correction: That doesn't matter. newFoo returns a mutable Foo, so it could create the Foo, modify the data, and only then return the Foo. The important bit is that the data is guaranteed to be newly created inside newFoo. It can't come from a global or parameter. Any mutable references cease to exist when newFoo returns.

--
March 26, 2019
https://issues.dlang.org/show_bug.cgi?id=19763

Jacob Carlborg <doob@me.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |INVALID

--- Comment #3 from Jacob Carlborg <doob@me.com> ---
Hmm, I see.

--