Jakub's partial implementation of consteval virtual had trouble with the current ABI requirement that we omit the vtable slot for a consteval virtual function; it's difficult to use the normal code for constant evaluation and also magically make the slots disappear if the vtables get written out. I notice that Clang trunk also doesn't implement that requirement, and it seems unnecessary to me; I expect consteval virtual functions to be extremely rare, so it should be fine to just give them a vtable slot as normal but put zero in it if the vtable gets emitted. I've commented as much to the ABI committee. One of Jakub's testcases points out that we weren't handling thunks in our constexpr virtual handling; that is fixed here as well. Incidentally, being able to use C++11 range-for definitely simplified clear_consteval_vfns. gcc/c-family/ChangeLog: * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_consteval. gcc/cp/ChangeLog: * decl.c (grokfndecl): Allow consteval virtual. * search.c (check_final_overrider): Check consteval mismatch. * constexpr.c (cxx_eval_thunk_call): New. (cxx_eval_call_expression): Call it. * cvt.c (cp_get_fndecl_from_callee): Handle FDESC_EXPR. * decl2.c (mark_vtable_entries): Track vtables with consteval. (maybe_emit_vtables): Pass consteval_vtables through. (clear_consteval_vfns): Replace consteval with nullptr. (c_parse_final_cleanups): Call it. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/consteval-virtual1.C: New test. * g++.dg/cpp2a/consteval-virtual2.C: New test. * g++.dg/cpp2a/consteval-virtual3.C: New test. * g++.dg/cpp2a/consteval-virtual4.C: New test. * g++.dg/cpp2a/consteval-virtual5.C: New test. Co-authored-by: Jakub Jelinek <jakub@redhat.com>
54 lines
1.2 KiB
C
54 lines
1.2 KiB
C
// { dg-do compile { target c++20 } }
|
|
|
|
struct S {
|
|
constexpr S () : s (0) {}
|
|
virtual int foo () const { return 42; }
|
|
consteval virtual int bar () const { return 43; }
|
|
consteval virtual int baz () const { return 44; }
|
|
consteval virtual int qux () const { return 47; }
|
|
int s;
|
|
};
|
|
struct T : public S {
|
|
constexpr T () : t (0) {}
|
|
consteval int bar () const { return 45; }
|
|
consteval virtual int baz () const { return 46; }
|
|
consteval virtual int grault () const { return 48; }
|
|
int t;
|
|
};
|
|
|
|
consteval int
|
|
foo ()
|
|
{
|
|
S s;
|
|
T t;
|
|
S *u = (S *) &t;
|
|
T *v = &t;
|
|
if (s.bar () != 43) throw 1;
|
|
if (s.baz () != 44) throw 2;
|
|
if (t.bar () != 45) throw 3;
|
|
if (t.baz () != 46) throw 4;
|
|
if (u->bar () != 45) throw 5;
|
|
if (u->baz () != 46) throw 6;
|
|
if (s.qux () != 47) throw 7;
|
|
if (t.qux () != 47) throw 8;
|
|
if (u->qux () != 47) throw 9;
|
|
if (v->qux () != 47) throw 10;
|
|
if (v->grault () != 48) throw 11;
|
|
return 0;
|
|
}
|
|
|
|
constexpr S s;
|
|
constexpr T t;
|
|
|
|
constexpr const S *
|
|
bar (bool x)
|
|
{
|
|
return x ? &s : (const S *) &t;
|
|
}
|
|
|
|
int a = foo ();
|
|
int b = bar (false)->bar ();
|
|
int c = bar (true)->baz ();
|
|
static_assert (bar (false)->bar () == 45);
|
|
static_assert (bar (true)->baz () == 44);
|