Bug 21312 – [REG 2.095] Newly triggered <expr> is not an lvalue and cannot be modified
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2020-10-15T06:57:59Z
Last change time
2020-11-01T23:57:53Z
Keywords
industry, rejects-valid
Assigned to
No Owner
Creator
Mathias LANG
Comments
Comment #0 by pro.mathias.lang — 2020-10-15T06:57:59Z
Test code:
```
public T deserializeFull (T) () @safe
{
static if (is(T : E*, E))
{
return &[ deserializeFull!(typeof(T.init[0]))() ][0];
}
return T.init;
}
struct Block { string value; }
void main ()
{
auto b = deserializeFull!(immutable(Block)*)();
}
```
Works in v2.094.0, but with master, breaks with:
```
foo.d(5): Error: [deserializeFull()][0] is not an lvalue and cannot be modified
foo.d(14): Error: template instance foo.deserializeFull!(immutable(Block)*) error instantiating
```
Introduced by https://github.com/dlang/dmd/pull/10124
Comment #1 by ibuclaw — 2020-10-15T19:29:04Z
So if looks like you are using `&[foo()][0]` to get around the fact that call expressions aren't lvalues (e.g: `&foo()`).
Two questionable aspects of this come to mind.
1. There's nothing to prevent the optimizer removing the `[ ][0]` as being redundant.
2. There's nothing to prevent the array literal being stack allocated.
I'm not entirely sure of the validity of this, but I'll stop short of saying it is invalid.
Comment #2 by pro.mathias.lang — 2020-10-16T06:40:29Z
> So if looks like you are using `&[foo()][0]` to get around the fact that call expressions aren't lvalues (e.g: `&foo()`).
The code is in a deserializer. We handle pointers as single-entry arrays, and the code follow that pattern. It recurses into itself, deserialize a single entry of whatever the element type is, and use this to build an array. It then takes the `.ptr` of this array.
It is no different in its intent from:
```
E[] result = [ deserializeFull!(...)(...) ];
return result.ptr;
```
Except that `result.ptr` is not `@safe`, so I'd have to use `return &result[0];`, but was hoping to avoid bounds checking by putting the expression inline.
> 1. There's nothing to prevent the optimizer removing the `[ ][0]` as being redundant.
`[][0]` might be redundant, but `&[][0]` is not, given `[]` does GC allocation.
> 2. There's nothing to prevent the array literal being stack allocated.
The compiler shouldn't promote it to the stack if it can't prove the address isn't escaping, which it is here.
Comment #3 by dlang-bot — 2020-11-01T23:57:53Z
dlang/dmd pull request #11873 " Fix Issue 21312 - Treat elements of (dynamic) array literals as lvalues again" was merged into master:
- eb14367b5da97657517f5b9626b01706d15b17a7 by Martin Kinkelin:
Fix Issue 21312 - Treat elements of (dynamic) array literals as lvalues again
Which entails making sure that const-folding doesn't descend into an
array literal element if an lvalue is required.
https://github.com/dlang/dmd/pull/11873