Bug 21856 – Mutable base object returned as immutable from weakly pure function

Status
NEW
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-04-23T23:00:03Z
Last change time
2024-12-13T19:15:55Z
Keywords
safe
Assigned to
No Owner
Creator
thomas.bockman
Moved to GitHub: dmd#19910 →

Comments

Comment #0 by thomas.bockman — 2021-04-23T23:00:03Z
f!() below is incorrectly inferred as @safe, and the invalid implicit cast to immutable is permitted. ///////////////////////////////////// module app; class D { } class DA : D { } immutable(D) f()(DA right) { D ret = right; return ret; } void main() { import std.stdio : writeln; writeln(typeof(f!()).stringof); } ///////////////////////////////////// Up to 2.062 : Failure with output: ----- onlineapp.d(8): Error: cannot implicitly convert expression (ret) of type app.D to immutable(D) onlineapp.d(13): Error: template instance app.f!() error instantiating ----- 2.063 to 2.065.0: Success with output: pure nothrow @safe immutable(D)(DA right) Since 2.066.0: Success with output: pure nothrow @nogc @safe immutable(D)(DA right)
Comment #1 by razvan.nitu1305 — 2021-04-27T10:26:44Z
The error does not have anything to do with `@safe`. The fundamental issue is that the implicit conversion is not signaled appropriately. If `f` is not templated: immutable(D) f(DA right) { D ret = right; return ret; } The compiler correctly errors: test.d(6): Error: cannot implicitly convert expression `ret` of type `test.D` to `immutable(D)`
Comment #2 by razvan.nitu1305 — 2021-04-27T13:51:19Z
There seems to be a confusion in the compiler with regards to implicit conversions and unique objects. If a pure functions creates a mutable object and then it returns it, then the object is implicitly convertible to immutable because nobody else could possibly modify. That is why: immutable(D) f(DA right) pure { D ret = right; return ret; } will compile. The compiler will consider that the function is pure, therefore immutability cannot be broken. I think that this is a bug, since the conversion should work only if the function is strongly pure, not any kind of purity. But there is also the case of: immutable(D) f(DA) pure { D ret = new D(); return ret; } In the above case, it is fine to convert ret to immutable since nobody can actually modify it. The safest and most restrictive solution would be to simply allow the conversion only if the function is strongly pure, thus dissalowing the latter case, however, this may break code out there.
Comment #3 by dfj1esp02 — 2021-04-28T16:59:17Z
>however, this may break code out there. That's expected, it's a fix of a flaky type check.
Comment #4 by nick — 2024-06-15T11:19:01Z
(In reply to RazvanN from comment #2) > The safest and most restrictive solution would be to simply allow the > conversion only if the function is strongly pure, thus disallowing the > latter case, however, this may break code out there. The fix for issue 15660 is related, which was changed to only disallow the conversion with the -preview=fixImmutableConv switch: https://dlang.org/changelog/2.101.0.html#dmd.fix-immutable-conv That switch could be used to disallow this case too.
Comment #5 by robert.schadek — 2024-12-13T19:15:55Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19910 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB