From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 1F44B3858D1E; Mon, 1 Jan 2024 17:00:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1F44B3858D1E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1704128447; bh=p8Cy8lZGxffgOgkEcXlOxrkbdZmR+J+koVD7Gcf3TSg=; h=From:To:Subject:Date:From; b=HEWn06p4HFhM7EPtjkkWgPY9K5KHpI6HRDwGRZgSCHEVeLUNETnrrTuE6UE4fG87E GZiwMBOXyRtCnksPRyrh15zV2Ohc4wu7GeZW7v0Hf7l95SxL1MYgrJewpuIgFrAW4H JCNJrw5L1SrkPR6CySMHxtlCHOqnWxxWIv/3h9FQ= From: "waffl3x at protonmail dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/113191] New: [10.1/11/12/13/14 Regression] Incorrect overload resolution when base class function introduced with a using declaration is more constrained than a function declared in the derived class Date: Mon, 01 Jan 2024 17:00:45 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 10.1.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: waffl3x at protonmail dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D113191 Bug ID: 113191 Summary: [10.1/11/12/13/14 Regression] Incorrect overload resolution when base class function introduced with a using declaration is more constrained than a function declared in the derived class Product: gcc Version: 10.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/91esEGhj4 template struct B { constexpr int f() requires true { return 5; } }; template struct S : B<> { using B::f; constexpr int f() { return 10; } }; static_assert(S<>{}.f() =3D=3D 5); The bug does not occur in this case: https://godbolt.org/z/dPM1Gfc1c We do the right thing in more_specialized_fn (which is why the second case works fine), but that doesn't apply in this case. Perhaps we should be lifting that work from more_specialized_fn to joust? Unfortunately, the changes in more_specialized_fn do not properly handle the following case. struct B { template requires true int g(T) { return 5; } }; struct S : B { using B::g; template int g(this S&, T) { return 10; } }; int main() { S s{}; s.g(0); } This case is ambiguous, I believe the main issue is that more_specialized_fn does not implement [over.match.funcs.general.4]. This is kind of a separate bug but they are connected, and it's relevant to how we decide to fix it. I'm mildly of the opinion that we should be rewriting iobj member functions that are introduced with a using declaration to have an object parameter matching that of the class it was introduced into. This might open a can of worms, but it more closely matches the behavior specified by the standard. [over.match.funcs.general.4] For non-conversion functions that are implicit object member functions nominated by a using-declaration in a derived class, the function is considered to be a member of the derived class for the purpose of defining the type of the implicit object parameter. This wasn't really as relevant before, but it does become relevant now because of the following case. https://godbolt.org/z/MjP5nrd8q template struct S; template struct B { constexpr int f(this S<> const&) { return 5; } constexpr int g() const { return 5; } }; template struct S : B<> { using B<>::f; using B<>::g; constexpr int f() const { return 10; } constexpr int g(this S const&) { return 10; } }; inline constexpr S<> s{}; static_assert(s.f() =3D=3D 5); static_assert(s.g() =3D=3D 5); I am not 100% sure what the correct behavior here is, but my interpretation is that the constraints should be taken into account. Again, this is slightly unrelated to this bug report, but it's more evidence that we should just overhaul everything with iobj member functions, and follow the standard to the letter. I think it's going to be simpler in the long run, trying to hack it in this way or that is just going to keep introducing problems. With that said, I recognize theres potential implementation difficulties with doing it this way too. Ultimately, it's a big decision so I don't mean to declare that we need to do it this way, I merely intend to present it as food for thought. My implementation currently does not do either of these correct at all, and as you can see in the godbolt link, clang does not exhibit the behavior I believe to be correct either. One last note, despite this being a regression, I don't believe that the previous implementation will be ideal (not that I've found the divergence yet.) Previous versions had the liberty of making different assumptions, and as demonstrated in the examples with xobj member functions, we have some new issues we need to work around here as well. I've spent the better part of 6 hours investigating this issue and the issues related to it, trying to figure out how to handle it for my patch. I have concluded that I'm not going to try to fix this bug for xobj member functions, and instead going to wait for this bug to be fixed to try to handle it. So the behavior for xobj member functions and iobj member functions will both be equally incorrect. Anyway, since I have spent so much time staring at this I might have made some mistakes in this report, or it will just be more confusing and disjointed than I hoped. Hopefully not though!=