c++: Fix ICE on constexpr virtual function [PR117317]

Since C++20 virtual methods can be constexpr, and if they are
constexpr evaluated, we choose tentative_decl_linkage for those
defer their output and decide at_eof again.
On the following testcases we ICE though, because if
expand_or_defer_fn_1 decides to use tentative_decl_linkage, it
returns true and the caller in that case cals emit_associated_thunks,
where use_thunk which it calls asserts DECL_INTERFACE_KNOWN on the
thunk destination, which isn't the case for tentative_decl_linkage.

The following patch fixes the ICE by not emitting the thunks
for the DECL_DEFER_OUTPUT fns just yet but waiting until at_eof
time when we return to those.
Note, the second testcase ICEs already since r0-110035 with -std=c++0x
before it gets a chance to diagnose constexpr virtual method.

2024-11-08  Jakub Jelinek  <jakub@redhat.com>

	PR c++/117317
	* semantics.cc (emit_associated_thunks): Do nothing for
	!DECL_INTERFACE_KNOWN && DECL_DEFER_OUTPUT fns.

	* g++.dg/cpp2a/pr117317-1.C: New test.
	* g++.dg/cpp2a/pr117317-2.C: New test.
This commit is contained in:
Jakub Jelinek 2024-11-08 13:36:05 +01:00 committed by Jakub Jelinek
parent ec86e87439
commit 5ff9e21c1e
3 changed files with 38 additions and 1 deletions

View file

@ -5150,7 +5150,10 @@ emit_associated_thunks (tree fn)
enabling you to output all the thunks with the function itself. */
if (DECL_VIRTUAL_P (fn)
/* Do not emit thunks for extern template instantiations. */
&& ! DECL_REALLY_EXTERN (fn))
&& ! DECL_REALLY_EXTERN (fn)
/* Do not emit thunks for tentative decls, those will be processed
again at_eof if really needed. */
&& (DECL_INTERFACE_KNOWN (fn) || !DECL_DEFER_OUTPUT (fn)))
{
tree thunk;

View file

@ -0,0 +1,19 @@
// PR c++/117317
// { dg-do compile { target c++20 } }
struct C {
constexpr bool operator== (const C &b) const { return foo (); }
constexpr virtual bool foo () const = 0;
};
class A : public C {};
class B : public C {};
template <int>
struct D : A, B
{
constexpr bool operator== (const D &) const = default;
constexpr bool foo () const override { return true; }
};
struct E : D<1> {};
constexpr E e;
constexpr E f;
static_assert (e == f, "");

View file

@ -0,0 +1,15 @@
// PR c++/117317
// { dg-do compile { target c++20 } }
struct C {
constexpr virtual bool foo () const = 0;
};
struct A : public C {};
struct B : public C {};
template <int>
struct D : A, B
{
constexpr bool foo () const override { return true; }
};
constexpr D<0> d;
static_assert (d.foo (), "");