================
@@ -0,0 +1,344 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-bit-cast %t
+
+// CHECK-FIXES: #include <bit>
+
+void *memcpy(void *To, const void *From, unsigned long long Size);
+
+namespace std {
+template <typename T, unsigned long long N>
+struct array {
+ T Storage[N];
+};
+
+using ::memcpy;
+}
+
+template <typename T>
+struct identity {
+ using type = T;
+};
+
+struct NonTrivial {
+ NonTrivial();
+ NonTrivial(const NonTrivial &);
+ int Value;
+};
+
+extern unsigned long long n;
+
+void basic_case() {
+ float src = 1.0f;
+ unsigned int dst;
+ std::memcpy(&dst, &src, sizeof(src));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning [modernize-use-bit-cast]
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void unqualified_case() {
+ float src = 1.0f;
+ unsigned int dst;
+ memcpy(&dst, &src, sizeof(dst));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void global_case() {
+ float src = 1.0f;
+ unsigned int dst;
+ ::memcpy(&dst, &src, sizeof(unsigned int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void explicit_cast_case() {
+ float src = 1.0f;
+ unsigned int dst = 0;
+ std::memcpy(static_cast<void *>(&dst), static_cast<const void *>(&src),
+ sizeof(dst));
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void alias_case() {
+ using U = identity<unsigned int>::type;
+ using F = identity<float>::type;
+ F src = 1.0f;
+ U dst;
+ std::memcpy(&dst, &src, sizeof(U));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<U>(src);
+}
+
+void const_source_case() {
+ const float src = 1.0f;
+ unsigned int dst;
+ std::memcpy(&dst, &src, sizeof(src));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void sizeof_type_source_case() {
+ float src = 1.0f;
+ unsigned int dst;
+ std::memcpy(&dst, &src, sizeof(float));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void sizeof_type_destination_case() {
+ float src = 1.0f;
+ unsigned int dst;
+ std::memcpy(&dst, &src, sizeof(unsigned int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+}
+
+void std_array_case() {
+ std::array<float, 1> src{{1.0f}};
+ std::array<unsigned int, 1> dst{};
+ std::memcpy(&dst, &src, sizeof(src));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<std::array<unsigned int, 1>>(src);
+}
+
+void raw_array_source_case() {
+ float src[1] = {1.0f};
+ std::array<unsigned int, 1> dst{};
+ std::memcpy(&dst, &src, sizeof(src));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<std::array<unsigned int, 1>>(src);
+}
+
+void lambda_case() {
+ auto L = [] {
+ float src = 1.0f;
+ unsigned int dst;
+ std::memcpy(&dst, &src, sizeof(src));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: dst = std::bit_cast<unsigned int>(src);
+ };
+ L();
+}
+
+void if_body_case(bool Cond) {
+ float src = 1.0f;
+ unsigned int dst;
+ if (Cond)
+ std::memcpy(&dst, &src, sizeof(src));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: if (Cond)
+ // CHECK-FIXES-NEXT: dst = std::bit_cast<unsigned int>(src);
+}
+
+void comma_lhs_case() {
+ float src = 1.0f;
+ unsigned int dst;
+ int value = (std::memcpy(&dst, &src, sizeof(src)), 42);
+ (void)value;
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: use 'std::bit_cast' instead of
'memcpy' for type punning
+ // CHECK-FIXES: int value = ((void)(dst = std::bit_cast<unsigned int>(src)),
42);
----------------
unterumarmung wrote:
Here, `void`-cast is only needed in the situations where destination type has
overloaded `operator,` and only then the fix-it without the void-cast can
change the code behaviour.
Since, this situation is very unlikely, I'm considering removing the cast from
fix-it.
If there is a cheap way to check whether a type has any `operator,` overloads,
then we can preemptively insert the void cast (even if it does not change the
overload set). I think it is the best approach here, but I'm not sure how to
implement it.
https://github.com/llvm/llvm-project/pull/189962
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits