D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 20142 - Incorrect auto ref inference for manifest constant member
Summary: Incorrect auto ref inference for manifest constant member
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 regression
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-08-19 13:01 UTC by Robert Schadek
Modified: 2021-12-07 13:28 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Robert Schadek 2019-08-19 13:01:52 UTC
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 Simen Kjaeraas 2019-08-19 13:39:40 UTC
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 RazvanN 2019-08-19 15:19:46 UTC
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 basile-z 2019-12-10 00:19:09 UTC
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 RazvanN 2021-12-07 13:28:32 UTC
(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.