Bug 21197 – Wrong lifetime inference with DIP1000 in dmd 2.093.0
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2020-08-25T14:26:37Z
Last change time
2022-08-31T09:35:31Z
Keywords
pull, safe
Assigned to
No Owner
Creator
Atila Neves
Comments
Comment #0 by atila.neves — 2020-08-25T14:26:37Z
This is a regression compared to 2.092.1. I don't know how this got past CI since it broke unit-threaded.
This test compiled with 2.092.1 but fails to do so with 2.092.1:
https://github.com/atilaneves/unit-threaded/blob/42d517a9bbdfc216fcedf65440c1ec71b437a175/tests/unit_threaded/ut/property.d#L7
The reason is the @safe inference done on this template function:
https://github.com/atilaneves/unit-threaded/blob/42d517a9bbdfc216fcedf65440c1ec71b437a175/subpackages/property/source/unit_threaded/property.d#L21
After investigating and adding @safe to it, the compiler fails to compile it with this:
subpackages/property/source/unit_threaded/property.d(48,21): Error: address of struct temporary returned by createGenerator() assigned to longer lived variable gen
This is obviously false. Applying this diff makes the problem go away, which is a valid workaround but that shouldn't be needed:
// See https://github.com/atilaneves/unit-threaded/issues/187 for why
- auto createGenerator() {
+ auto createGenerator(ref Random random) {
return RndValueGen!(Parameters!F)(&random);
}
// It might be that some projects don't use dip1000 and so
// createGenerator isn't safe
static if(isSafe!createGenerator)
- scope gen = createGenerator;
+ scope gen = createGenerator(random);
else
- scope gen = () @trusted { return createGenerator; }();
+ scope gen = () @trusted { return createGenerator(random); }();
auto input(Flag!"shrink" shrink = Yes.shrink) {
Comment #1 by moonlightsentinel — 2020-08-25T17:33:12Z
Reduced example:
==========================================
@safe void check()
{
int random;
auto createGenerator() {
return RndValueGen(&random);
}
scope gen = createGenerator;
}
struct RndValueGen
{
int* rnd;
}
==========================================
Comment #2 by moonlightsentinel — 2020-08-25T21:41:55Z
digger: 788398ac6293f57ae78fca23de96b1653f729265 is the first bad commit
commit 788398ac6293f57ae78fca23de96b1653f729265
Author: Atila Neves <[email protected]>
Date: Wed Jun 10 10:44:17 2020 +0100
dmd: Merge pull request #10945 from WalterBright/fix20183
https://github.com/dlang/dmd/pull/10945
fix Issue 20183 - Assigning statement scope of struct literal or temp…
Comment #3 by bugzilla — 2022-07-28T08:20:56Z
If we replace the struct with an equivalent pointer:
@safe void check()
{
int random;
auto createGenerator() {
int* p = &random;
return p;
}
scope gen = createGenerator;
}
it does compile successfully. Both should compile successfully, as the struct is just a wrapper around a pointer.
Comment #4 by bugzilla — 2022-08-11T02:16:17Z
A better test case, with and without the error message:
@safe void check2() {
int random;
S create1() { return S(); }
scope S gen1 = create1; // no error
S create2() { return S(&random); }
// address of struct temporary returned by `create()` assigned to longer lived variable `gen`
scope S gen2 = create2;
}
struct S { int* r; }
Comment #5 by dlang-bot — 2022-08-11T17:04:14Z
@WalterBright updated dlang/dmd pull request #14360 "fix Issue 21197 - Wrong lifetime inference with DIP1000 in dmd 2.093.0" fixing this issue:
- fix Issue 21197 - Wrong lifetime inference with DIP1000 in dmd 2.093.0
https://github.com/dlang/dmd/pull/14360
Comment #6 by razvan.nitu1305 — 2022-08-31T09:35:31Z