Bug 20142 – Incorrect auto ref inference for manifest constant member

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2019-08-19T13:01:52Z
Last change time
2021-12-07T13:28:32Z
Assigned to
No Owner
Creator
Robert Schadek

Comments

Comment #0 by rschadek — 2019-08-19T13:01:52Z
This fails to compile with ``` import std.array : empty; struct Foo { string text; } Foo getFoo() { return Foo("Hello World"); } void main() { enum Foo foo = getFoo(); assert(!foo.text.empty); } ``` (13): Error: cannot modify constant expression Foo("Hello World").text
Comment #1 by simen.kjaras — 2019-08-19T13:39:40Z
Reduced example: struct S { int i; } void fun(T)(auto ref T x) {} unittest { enum s = S(); fun(s.i); } The call to fun() should infer x as int, but somehow thinks it's ref int.
Comment #2 by razvan.nitu1305 — 2019-08-19T15:19:46Z
I cannot reproduce this with the latest master branch. Also, running it on dlang.io [1] seems to successfully compile. Although on the nightly branch it is indeed failing. [1] https://run.dlang.io/is/clMnj3
Comment #3 by b2.temp — 2019-12-10T00:19:09Z
The reduced test case is not catching the problem anymore. This one does: --- void empty(T)(auto /*const*/ ref T a) { } struct Foo { int i; } void main() { enum Foo foo = Foo(0); foo.i.empty(); } --- The regression is caused by a protection on function parameters (and on assign exp too) to prevent writing member of manifest constants that are aggregates, more specifically struct literals (`enum Foo foo` from the front-end POV is actually a struct literal). Without the protection, in the past, `i` could be modified, which made no sense and could even create crashes. See https://github.com/dlang/dmd/pull/10115, which added the protection.
Comment #4 by razvan.nitu1305 — 2021-12-07T13:28:32Z
(In reply to Basile-z from comment #3) > The reduced test case is not catching the problem anymore. This one does: > > --- > void empty(T)(auto /*const*/ ref T a) { } > > > struct Foo { > int i; > } > > void main() { > enum Foo foo = Foo(0); > foo.i.empty(); > } > --- > > The regression is caused by a protection on function parameters (and on > assign exp too) to prevent writing member of manifest constants that are > aggregates, more specifically struct literals (`enum Foo foo` from the > front-end POV is actually a struct literal). > > Without the protection, in the past, `i` could be modified, which made no > sense and could even create crashes. > > See https://github.com/dlang/dmd/pull/10115, which added the protection. I cannot reproduce this. Running this code: void empty(T)(auto ref T a) { pragma(msg, __traits(isRef, a)); } struct Foo { int i; } void main() { enum Foo foo = Foo(0); foo.i.empty(); } Yields `false` which is correct. Closing as fixed, please reopen if I am missing something.