Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/68...@github.com>
================ @@ -107,6 +112,14 @@ class Boolean final { return Boolean(!Value.isZero()); } + static Boolean bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) { + assert(BitWidth == 8); + bool Val = static_cast<bool>(*Buff); + return Boolean(Val); + } + + void bitcastToMemory(std::byte *Buff) { std::memcpy(Buff, &V, sizeof(V)); } ---------------- sethp wrote: There's a tradeoff to be made, here: booleans are among the primitive types that have padding bits, though I believe them to be by far the most commonly used (other contenders include `long double` and `_BitInt(4)`). The wrinkle is something like this: ```c++ constexpr bool b() { return std::bit_cast<bool, uint8_t>(0x02); } int main() { if constexpr (b() == 0) return b(); return 1; } ``` For that sample, `gcc` produces a binary that exits with code 2: https://compiler-explorer.com/z/jes71o85h , and current clang refuses to compile with a `note: value 2 cannot be represented in type 'bool'`. To preserve that behavior, I think that means here `bitcastToMemory` ought to be a fail-able operation that checks all bits above the LSB are zero. There's another question about whether it's worth giving `bool` special treatment: should _only_ `Boolean::bitcastToMemory` be a fail-able operation? In other words, given ```c++ constexpr auto a = std::bit_cast<uint8_t>(false); constexpr auto b = std::bit_cast<__int128_t>((long double)0); constexpr auto c = std::bit_cast<bool>('\x02'); constexpr auto d = std::bit_cast<long double>((__int128_t)~0); ``` Right now, `a` & `d` succeed. `b` & `c` fail to produce constant values for different reasons: `c` because the evaluator sees that it'd lose information by allowing the bit-cast, and `b` because it doesn't want to check. I see two fully consistent interpretations, here (considering both implementation & semantics): 1. `a` fails for the same reason as `b`, and then `Interp` is free to allow `c` & `d` as a simple memcpy + mask (to throw away any padding bits) 2. `a` and `b` both succeed, but then `c` and `d` must fail for the same reason. Both are backwards-incompatible changes, though: code that used to compile with the old constant interpreter would fail under the new one. The third choice preserves backwards compatibility by holding `bool` out as the [only type whose values get checked for represent-ability](https://github.com/llvm/llvm-project/blob/2e0d3f81e4f5b623bb476bfac0278cfc6d1bd4bc/clang/lib/AST/ExprConstant.cpp#L7626-L7651). (NB: that's a link to the code from #74775 (the current implementation is subtly different, but the behavior is the same because the current evaluator doesn't [fully] support `_BitInt(X)`) https://github.com/llvm/llvm-project/pull/68288 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits