Thread overview
[Issue 22239] Can't migrate from postblits if they are used without frame pointer
Aug 26, 2021
RazvanN
Aug 26, 2021
RazvanN
Aug 26, 2021
Ate Eskola
Nov 30, 2021
RazvanN
Dec 17, 2022
Iain Buclaw
August 26, 2021
https://issues.dlang.org/show_bug.cgi?id=22239

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |razvan.nitu1305@gmail.com

--- Comment #1 from RazvanN <razvan.nitu1305@gmail.com> ---
This affects normal constructors as well (copy constructors are just a particularization of a normal constructor):

struct Normal(alias al)
{
    this(int a) {}
    void x() {}
}

void main()
{
    Normal!(x => x) a;

    a.f;
}

void f(T)(T x)
{
    T y = 6;
}

--
August 26, 2021
https://issues.dlang.org/show_bug.cgi?id=22239

--- Comment #2 from RazvanN <razvan.nitu1305@gmail.com> ---
Hmmm, this code fails also:

struct PostBlitted(alias al)
{
  this(this){}
  void x(){} //a member function so that an instance contains a frame pointer
}

void main()
{
  PostBlitted!(x => x) a;
  a.f;
}

void f(T)(T x)
{
    T y;
}

--
August 26, 2021
https://issues.dlang.org/show_bug.cgi?id=22239

--- Comment #3 from Ate Eskola <Ajieskola@gmail.com> ---
That last example is supposed to fail. `PostBlitted!(x => x)` contains a hidden context pointer to `main` to construct, so they can be default-initialized only at `main`. Not at `f`.

(It could be argued that no frame pointer should be needed because `x => x` does not use any variables from `main`, but that's a different issue)

Default blittings, and thus postblits, work, because the hidden context pointer gets copied from the original instance.

But I can't come up with a way to do the same with a copy constructor. Well, I suppose I could devise a workaround with `static opCall`, but we're supposed to replace postblits with copy constructors, not with hackish workarounds.

--
November 30, 2021
https://issues.dlang.org/show_bug.cgi?id=22239

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |timon.gehr@gmx.ch

--- Comment #4 from RazvanN <razvan.nitu1305@gmail.com> ---
*** Issue 22499 has been marked as a duplicate of this issue. ***

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=22239

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P3

--
March 28
https://issues.dlang.org/show_bug.cgi?id=22239

Jonathan M Davis <issues.dlang@jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |issues.dlang@jmdavisProg.co
                   |                            |m

--- Comment #5 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
When trying to add a copy constructor to a type in an existing code base, I've been seeing a lot of errors about not having a frame pointer (particularly from std.algorithm code), which has been incredibly annoying to deal with, and it has made no sense to me that a frame pointer would even be needed, since the only difference is that a copy constructor has been added (though honestly, the whole frame pointer stuff is incredibly confusing in general). So, I'm _guessing_ that this is the issue that I've been hitting, but man, it would be nice if the compiler didn't decide that it needed a frame pointer that it can't have just because a type that's involved got a copy constructor added to it.

--
April 02
https://issues.dlang.org/show_bug.cgi?id=22239

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla@digitalmars.com

--- Comment #6 from Walter Bright <bugzilla@digitalmars.com> ---
The reason for the frame pointer is:

void test(int i)
{
    struct S
    {
        int x;
        int f() { return x + i; } // reference to `i`
    }
    pragma(msg, S.sizeof); // prints 16
}

so member functions can access variables in the function the struct is nested in. To avoid this, use `static`:

void test(int i)
{
    static struct S
    {
        int x;
        int f() { return x + i; }
    }
    pragma(msg, S.sizeof); // prints 4
}

test2.d(7): Error: function `test2.test.S.f` cannot access variable `i` in
frame of function `test2.test`
test2.d(2):        `i` declared here

The compiler does a conservative guess as to whether a frame pointer is needed. A non-static member function will trip that. The compiler does not look at the body of the function to determine this, because the body may be defined elsewhere.

The alias parameter also trips the "needs a frame pointer" for similar reasons.

To resolve the problem, declare the template as `static`:

static struct PostBlitted(alias al){
  this(this){}
  void x(){} //a member function so that an instance contains a frame pointer
}

static struct CopyConstructed(alias al){
  this(ref typeof(this)){};
  void x(){} //a member function so that an instance contains a frame pointer
}

The fix for this bug should be to point this out in the spec.

--