public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/110122] New: using an aggregate with a member variable with a user defined copy constructor in a class NTTP causes capture and use of the `this` pointer in a generic lambda to produce the following error "-copy constructor- used before its definition"
@ 2023-06-05  9:27 waffl3x at protonmail dot com
  2023-06-05 14:08 ` [Bug c++/110122] [13/14 Regression] using an aggregate with a member variable with a user defined copy constructor in a class NTTP causes capture and use of the `this` pointer in a generic lambda to produce the following error "-copy ctor- " ppalka at gcc dot gnu.org
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: waffl3x at protonmail dot com @ 2023-06-05  9:27 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110122

            Bug ID: 110122
           Summary: using an aggregate with a member variable with a user
                    defined copy constructor in a class NTTP causes
                    capture and use of the `this` pointer in a generic
                    lambda to produce the following error "-copy
                    constructor- used before its definition"
           Product: gcc
           Version: 13.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: waffl3x at protonmail dot com
  Target Milestone: ---

https://godbolt.org/z/c7nnfjzGK

struct Foo {
    constexpr Foo() = default;
    constexpr Foo(Foo const&) {}
};

struct Bar {
    Foo _;
};

template<Bar v = Bar{}>
struct Doppelganger
{
    void disguise() {
        [this]<typename = void>(){ this; }();
    }
};

void execute() {
    Doppelganger<>{}.disguise();
}

error: 'constexpr Bar::Bar(const Bar&)' used before its definition

The bug is present in GCC 13.0 and 13.1 and in the current trunk.
This was a dreadful one, I am pretty sure there are 2 different bugs at play
here. It took a while to whittle it down to this example, as I was reducing my
code, I was shocked to find that removing a innocuous looking copy constructor
"fixed" the bug. It seemed like the user declared copy constructor is being
produced late.
The bug does not manifest when passing `Foo` directly to `Doppelganger`'s
non-type template parameter, which I also found odd.
Finally, capturing and using the `this` pointer in the body of a generic lambda
(the bug does not manifest with a regular lambda) finally causes the bug to pop
up. I was not able to find a more reduced version.
I found it strange that a generic lambda is required, I would have thought that
it being a generic lambda would delay when the copy constructor definition was
required, but instead it seems to speed it up. As far as I've observed this
seems to be what's happening, as omitting the call to the member function
avoids triggering the bug. 
One final thing to note, declaring the copy constructor as default also avoids
the bug, while a user declared default constructor has no effect at all.

If anyone manages to reduce it further I would be very interested to see it, I
spent a lot of time at it and couldn't seem to find any way to get it to work
when passing an object of `Foo` directly to `Doppelganger` despite that it
feels like it should be irrelevant. Perhaps it being a member of `Bar` moves up
when the definition of the copy constructor is required?

As an aside, even when deleting the copy constructor, the diagnostic for the
correctly rejected code is still rather unhelpful. It confused me for quite a
while as it points to the use of the `this` pointer, or any uses of member
variables, almost as if the compiler was mistaking the expression for the non
type template parameter, `Bar` in this case. I now realize that use of the
`this` pointer probably requires the full type be instantiated from the class
template, or I should say thats my guess.
My point is, perhaps the compiler should be bailing out earlier, like when the
class template is being instantiated with a NTTP that would be invalid.
Upon saying that I realized I should test whether it does or not, and I found
that it was previously the case, maybe not as early as it could be, but I'm
sure the trade off was made for a reason.
Unfortunately, this is not the case in GCC 13.1 and GCC trunk.
https://godbolt.org/z/8b7Mj91xM
I haven't checked if this bug was reported yet, or if it is a bug at all, I
will have to look into whether the decision to require copy constructors for
NTTP's got overturned or not. You can find that topic being discussed here,
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104577 , as of a few months ago it
seems like NTTP's require copy constructors. Once I have confirmed that I can
make another report for this bug if there are no objections, as despite being
relevant to this bug, it seems to be slightly different.

To recap, I believe there are at least 2 bugs here, the first being the delayed
(or perhaps completely omitted) definition of class `Foo`'s user defined copy
constructor. The second being a class with an undefined copy constructor is
incorrectly accepted as a NTTP, even when an object of that type is
initialized. (I have also confirmed that accessing said object does not change
that outcome. https://godbolt.org/z/fhsoPGEda )
And finally, there is a 3rd possible bug here involving generic lambdas (as a
regular lambda does not trigger the bug), however, despite how problematic
generic lambdas seem to be, I am not confident that it is actually responsible
for any problems here. It might just be that the time the generic lambda's call
operator is instantiated is before the delayed definition of the copy
constructor of `Foo`, which isn't because the lambda is instantiating things
too early, it's just that the copy constructor is being instantiated too late.

I apologize for the long winded write up, I spent about 4 hours trying to
troubleshoot my original code (not including yesterday) and another 4 hours
trying to reduce it once I confirmed that the bug was with GCC, so I wanted to
be thorough with relaying my thoughts of it. Hopefully my musings on it are
somewhat helpful rather than not at all.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-07-19 19:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-05  9:27 [Bug c++/110122] New: using an aggregate with a member variable with a user defined copy constructor in a class NTTP causes capture and use of the `this` pointer in a generic lambda to produce the following error "-copy constructor- used before its definition" waffl3x at protonmail dot com
2023-06-05 14:08 ` [Bug c++/110122] [13/14 Regression] using an aggregate with a member variable with a user defined copy constructor in a class NTTP causes capture and use of the `this` pointer in a generic lambda to produce the following error "-copy ctor- " ppalka at gcc dot gnu.org
2023-06-05 14:11 ` ppalka at gcc dot gnu.org
2023-06-06  0:18 ` waffl3x at protonmail dot com
2023-06-06 18:53 ` ppalka at gcc dot gnu.org
2023-06-07  8:13 ` waffl3x at protonmail dot com
2023-06-11 15:27 ` cvs-commit at gcc dot gnu.org
2023-06-11 15:27 ` cvs-commit at gcc dot gnu.org
2023-07-19 19:21 ` cvs-commit at gcc dot gnu.org
2023-07-19 19:26 ` ppalka at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).