Search code examples
c++language-lawyerc++20downcaststatic-cast

Why is this value downcast (static_cast to object type) allowed in C++20?


To my surprise, gcc 11.2 accepts this code, but only in C++20 mode:

struct Base {};
struct Derived : Base { int i; };
int f(Base& b) { return static_cast<Derived>(b).i; }
//                                  ^~~~~~~ oops, forgot the `&`

Likewise, MSVC 19.29 accepts it in C++20 mode and rejects it in C++17 mode, but clang rejects it even in C++20 mode.

Looking at the assembler output, f always returns 0, so it's ignoring the actual data of any potential Derived passed to f.

Is this UB, or is it legal in C++20, and if so, why?


Solution

  • It is legal in C++20.

    [expr.static.cast]/4:

    An expression E can be explicitly converted to a type T [...] if T is an aggregate type ([dcl.init.aggr]) having a first element x and there is an implicit conversion sequence from E to the type of x.

    [dcl.init.aggr]/2:

    The elements of an aggregate are: [...] for a class, the direct base classes in declaration order, followed by the direct non-static data members ([class.mem]) that are not members of an anonymous union, in declaration order.

    So Derived is an aggregate whose first element is Base, and since C++20, it is permitted to create an aggregate from its first element.

    This feature is introduced in P1975R0 "Fixing the wording of parenthesized aggregate-initialization".