Bug 22092 – [REG2.067] for loop over range with closure loops infinitely

Status
NEW
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-06-29T19:38:22Z
Last change time
2024-12-13T19:17:28Z
Keywords
wrong-code
Assigned to
No Owner
Creator
Vladimir Panteleev
Moved to GitHub: dmd#18044 →

Comments

Comment #0 by dlang-bugzilla — 2021-06-29T19:38:22Z
///////////////////// test.d ///////////////////// void formatRange(T)(T val) { for (size_t i; !val.empty; val.popFront, i) {} } void fun() {} auto makeRange()() { int pos; struct R { bool empty() { return pos == 3; } void popFront() const { ++pos; version (no_bug) fun(); } } return R(); } void main() { auto r = makeRange; formatRange(r); } ////////////////////////////////////////////////// Note that with -version=no_bug (i.e. adding a call to an empty function), the bug does not manifest. Introduced in https://github.com/dlang/dmd/pull/3956
Comment #1 by pro.mathias.lang — 2021-07-01T01:25:30Z
> Note that with -version=no_bug (i.e. adding a call to an empty function), the bug does not manifest. Looking at the PR that introduced the regression, I think that is because it prevents the compiler from inferring "pure" on `popFront`. Currently `popFront` compiles to: ``` % nm bug.o| ddemangle | grep popFront 00000000000001d0 S const pure nothrow @nogc @safe void bug.makeRange!().makeRange().R.popFront() 0000000000000130 S _bug.makeRange!().makeRange.R.popFront.eh ``` But it is *not* `const pure`, because it obviously modify its context! Brainstorming, I think that, to solve this, we could: 1) Reject `const`: Consider that `const` applies to the captured context as well. This is good old https://issues.dlang.org/show_bug.cgi?id=1983 2) Do not infer `pure`: Consider that the context as inherently non-pure. I don't think that's the right thing to do, however, the context should be non-pure if the function from which the context is taken isn't pure. Currently you can bypass `pure` by taking a pointer to a global, and accessing that pointer from `popFront`: ```D void formatRange(T)(T val) { for (size_t i; !val.empty; val.popFront, i) {} } int pos; // This changed auto makeRange()() { int* p = &pos; // This changed struct R { bool empty() { return pos == 3; } void popFront() const { ++(*p); // This changed } } return R(); } void main() { auto r = makeRange; formatRange(r); } ```
Comment #2 by robert.schadek — 2024-12-13T19:17:28Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18044 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB