[PATCH] D62825: [C++2a] Add __builtin_bit_cast, used to implement std::bit_cast

Richard Smith - zygoloid via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 21 14:15:41 PDT 2019


rsmith added inline comments.


================
Comment at: clang/include/clang/Basic/DiagnosticASTKinds.td:223
+def note_constexpr_bit_cast_invalid_type : Note<
+  "cannot constexpr evaluate a bit_cast with a "
+  "%select{union|pointer|member pointer|volatile|struct with a reference member}0"
----------------
"constexpr evaluate" doesn't really mean anything. Also, the "struct with a reference member type X" case seems a bit strangely phrased (and it need not be a struct anyway...).

Maybe "cannot bit_cast {from|to}0 a {|type with a}1 {union|pointer|member pointer|volatile|reference}2 {type|member}1 in a constant expression"?


================
Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:9732
+def err_bit_cast_type_size_mismatch : Error<
+  "__builtin_bit_cast source size does not equal destination size (%0 and %1)">;
 } // end of sema component.
----------------
We would usually use `vs` rather than `and` here.


================
Comment at: clang/lib/AST/ExprConstant.cpp:5454-5457
+    case APValue::Indeterminate:
+      Info.FFDiag(BCE->getExprLoc(), diag::note_constexpr_access_uninit)
+          << 0 << 1;
+      return false;
----------------
I've checked the intent on the reflectors, and we should drop both this and the `APValue::None` check here. Bits corresponding to uninitialized or out-of-lifetime subobjects should just be left uninitialized (exactly like padding bits).

Example:

```
struct X { char c; int n; };
struct Y { char data[sizeof(X)]; };
constexpr bool test() {
  X x = {1, 2};
  Y y = __builtin_bit_cast(Y, x); // OK, y.data[1] - y.data[3] are APValue::Indeterminate
  X z = __builtin_bit_cast(X, y); // OK, both members are initialized
  return x.c == z.c && x.n == z.n;
}
static_assert(test());
```


================
Comment at: clang/lib/AST/ExprConstant.cpp:5614-5615
+    SmallVector<uint8_t, 8> Bytes;
+    if (!Buffer.readObject(Offset, SizeOf, Bytes))
+      return APValue::IndeterminateValue();
+
----------------
This should fail with a diagnostic if `T` is not a byte-like type (an unsigned narrow character type or `std::byte`), due to [basic.indet]p2.


================
Comment at: clang/lib/CodeGen/CGExprComplex.cpp:472-475
+    Address Temp = CGF.CreateTempAlloca(CGF.ConvertType(Op->getType()), Align,
+                                        "bit_cast.temp");
+    CGF.EmitAnyExprToMem(Op, Temp, Op->getType().getQualifiers(),
+                         /*isInit=*/false);
----------------
This seems to unnecessarily force an extra round-trip through memory. `Op` is an lvalue, so it already describes a value in memory, and you should be able to use `EmitLValue(Op)` to get the lvalue you want to load from.


================
Comment at: clang/lib/CodeGen/CGExprScalar.cpp:2045-2048
+    Address Temp = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), Align,
+                                        "bit_cast.temp");
+    CGF.EmitAnyExprToMem(E, Temp, E->getType().getQualifiers(),
+                         /*isInit=*/false);
----------------
Likewise here.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62825/new/

https://reviews.llvm.org/D62825





More information about the cfe-commits mailing list