[cfe-dev] Questions/discussions about cast types in clang

Arthur O'Dwyer via cfe-dev cfe-dev at lists.llvm.org
Sat Jun 20 15:19:19 PDT 2020

On Sat, Jun 20, 2020 at 5:33 PM Ray Zhang <peifeng2005 at gmail.com> wrote:

> Hi Arthur,
> First of all, it's an honor. I remember watching your "Allocator is a
> handle to a heap" c++now talk a while ago :)
Hey, thanks! :) Don't take anything I say as gospel when it comes to
cfe-dev, though. :)

Second, you're right - I forgot about DerivedToBase or BaseToDerived in the
> above example. Regarding the statement regarding unpresentable as a
> non-C-style cast, in the standard
> <https://en.cppreference.com/w/cpp/language/explicit_cast> it breaks down
> C-style casts as a cascading attempt to use const/static/reinterpret, or
> combinations of them. Here's an example of private base:
> https://godbolt.org/z/5STynJ.

Yes, but notice where cppreference says "static_cast *with exceptions*"; I
was talking about the exceptions.
Here's an example where C-style cast and reinterpret_cast do different
things, but any other kind of cast (e.g. static_cast) is ill-formed.
Clang gives a warning suggesting that you replace the reinterpret_cast with
a static_cast, but of course if you actually did that, the code wouldn't
compile anymore.

Third, I didn't check for C++20 for union casts, but I'm guessing it
> "working" is a side-effect of the parens-initialization of aggregates
> allowing narrowing conversions. Here's a link that shows that the example
> in the C++20 mode you showed is not equivalent to a C-style cast assignment
> which is just an alias for (union U) {.x = x}:
> https://godbolt.org/z/7LJCQy.

Ah, yes, you're right. With `(U)y`, GCC is calling the same
pseudo-constructor as `U(y)`, which is supposed to just implicitly convert
the float to an int and initialize the first member of the union,
completely ignoring the fact that `y` is a float
This appears to be actually the correct behavior in C++20, even though it
seems pretty crazy. (In other words, C++20's new union syntax doesn't
follow the same overload-resolution-ish rules as C++17's std::variant.)
Textual support:
http://eel.is/c++draft/expr.cast#4 says that (U)y should behave the same as
static_cast<U>(y) if possible, and
http://eel.is/c++draft/expr.static.cast#4 says that static_cast<U>(y)
should behave the same as U(y), which (new in C++20) should behave the same
as U{.x = y}.

Here's a pared-down example where the two fields of the union have utterly
different types, so the silent implicit conversion fails instead of
succeeding. https://godbolt.org/z/9wVX6B
Apparently Clang just doesn't implement this C++20 rule yet; once it does,
Clang's behavior should end up matching GCC's.

...Oh, and wait a minute! The first sentence of the documentation you
linked says, "A cast to a union type is *a C extension not available in C++*."
 So that explains why neither of us could reproduce the documented
behavior! :)  Now here's a Godbolt showing the same code compiled as C++
(where it initializes the first field of the union) and C-with-extensions
(where it initializes the second field because that field is a float).
And here's Clang, reproducing GCC's behavior in C-with-extensions but
failing to implement C++20 yet:


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200620/47ba537a/attachment.html>

More information about the cfe-dev mailing list