================
@@ -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:
I found a cheap way to handle this without searching for operator declarations
or reproducing overload resolution. Clang considers overloaded binary operators
only when an operand is dependent or has an overloadable type.
The fix now omits `(void)` for scalar and pointer operands. It adds `(void)`
when the assignment result or a comma sibling has a dependent, class, or enum
type. Tests cover nested comma expressions and ADL cases.
https://github.com/llvm/llvm-project/pull/189962
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits