https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126510
Bug ID: 126510
Summary: [c++26] constexpr dynamic_cast wrongly returns null
when operand is a virtual base subobject
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: egas at gcc dot gnu.org
Blocks: 55004
Target Milestone: ---
Since P3533R2 (PR120777) allows virtual bases in constant evaluation,
cxx_eval_dynamic_cast_fn can now be reached with hierarchies it doesn't
handle, and returns null where the runtime __dynamic_cast succeeds.
```cpp
struct S { int s; constexpr virtual ~S () {} };
struct C : virtual S { int c; };
struct MD : private C { int d; };
constexpr bool f ()
{
MD obj;
S *s = (S *) (C *) &obj;
C *c = dynamic_cast<C *> (s);
return c != nullptr && c == (C *) &obj;
}
static_assert (f ()); // fails, should succeed
```
The cast should succeed by [expr.dynamic.cast]/9.1: s points to a public base
subobject (S) of a C object, and exactly one C derives from that S. The
private C -> MD edge only matters for /9.2. The runtime agrees with this.
basically, we need to evaluate the access from C -> S, not from MD -> C, but
the implementation does the latter.
clause 1 probably needs to find the target binfo directly instead of walking
fields, then reuse clause 2's existing convert_to_base_statically tail (which
already handles virtual bases). Restricting the new search to only targeting
virtual-base operands would be enough, since the existing walk is fine
otherwise.
Referenced Bugs:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55004
[Bug 55004] [meta-bug] constexpr issues