Skip to content

Commit d4ff298

Browse files
author
Carlos Gálvez
committed
Detect std::bit_cast only in C++20 mode
1 parent 1b1d54e commit d4ff298

File tree

4 files changed

+77
-32
lines changed

4 files changed

+77
-32
lines changed

clang-tools-extra/clang-tidy/bugprone/BitwisePointerCastCheck.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ using namespace clang::ast_matchers;
1414
namespace clang::tidy::bugprone {
1515

1616
void BitwisePointerCastCheck::registerMatchers(MatchFinder *Finder) {
17-
auto IsPointerType = refersToType(qualType(isAnyPointer()));
18-
Finder->addMatcher(callExpr(hasDeclaration(functionDecl(allOf(
19-
hasName("::std::bit_cast"),
20-
hasTemplateArgument(0, IsPointerType),
21-
hasTemplateArgument(1, IsPointerType)))))
22-
.bind("bit_cast"),
23-
this);
17+
if (getLangOpts().CPlusPlus20) {
18+
auto IsPointerType = refersToType(qualType(isAnyPointer()));
19+
Finder->addMatcher(callExpr(hasDeclaration(functionDecl(allOf(
20+
hasName("::std::bit_cast"),
21+
hasTemplateArgument(0, IsPointerType),
22+
hasTemplateArgument(1, IsPointerType)))))
23+
.bind("bit_cast"),
24+
this);
25+
}
2426

2527
auto IsDoublePointerType =
2628
hasType(qualType(pointsTo(qualType(isAnyPointer()))));

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ Changes in existing checks
174174

175175
- Improved :doc:`modernize-avoid-c-arrays
176176
<clang-tidy/checks/modernize/avoid-c-arrays>` check to suggest using ``std::span``
177-
as a replacement for parameters of incomplete C array type in C++20 and
177+
as a replacement for parameters of incomplete C array type in C++20 and
178178
``std::array`` or ``std::vector`` before C++20.
179179

180180
- Improved :doc:`modernize-min-max-use-initializer-list
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %check_clang_tidy -std=c++20 %s bugprone-bitwise-pointer-cast %t
2+
3+
void memcpy(void* to, void* dst, unsigned long long size)
4+
{
5+
// Dummy implementation for the purpose of the test
6+
}
7+
8+
namespace std
9+
{
10+
template <typename To, typename From>
11+
To bit_cast(From from)
12+
{
13+
// Dummy implementation for the purpose of the test
14+
To to{};
15+
return to;
16+
}
17+
18+
using ::memcpy;
19+
}
20+
21+
void pointer2pointer()
22+
{
23+
int x{};
24+
float bad = *std::bit_cast<float*>(&x); // UB, but looks safe due to std::bit_cast
25+
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::bit_cast' to cast between pointers [bugprone-bitwise-pointer-cast]
26+
float good = std::bit_cast<float>(x); // Well-defined
27+
28+
using IntPtr = int*;
29+
using FloatPtr = float*;
30+
IntPtr x2{};
31+
float bad2 = *std::bit_cast<FloatPtr>(x2);
32+
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::bit_cast' to cast between pointers [bugprone-bitwise-pointer-cast]
33+
}
34+
35+
void pointer2pointer_memcpy()
36+
{
37+
int x{};
38+
int* px{};
39+
float y{};
40+
float* py{};
41+
42+
memcpy(&py, &px, sizeof(px));
43+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'memcpy' to cast between pointers [bugprone-bitwise-pointer-cast]
44+
std::memcpy(&py, &px, sizeof(px));
45+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'memcpy' to cast between pointers [bugprone-bitwise-pointer-cast]
46+
47+
std::memcpy(&y, &x, sizeof(x));
48+
}
49+
50+
// Pointer-integer conversions are allowed by this check
51+
void int2pointer()
52+
{
53+
unsigned long long addr{};
54+
float* p = std::bit_cast<float*>(addr);
55+
std::memcpy(&p, &addr, sizeof(addr));
56+
}
57+
58+
void pointer2int()
59+
{
60+
float* p{};
61+
auto addr = std::bit_cast<unsigned long long>(p);
62+
std::memcpy(&addr, &p, sizeof(p));
63+
}

clang-tools-extra/test/clang-tidy/checkers/bugprone/bitwise-pointer-cast.cpp

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,10 @@ void memcpy(void* to, void* dst, unsigned long long size)
77

88
namespace std
99
{
10-
template <typename To, typename From>
11-
To bit_cast(From from)
12-
{
13-
// Dummy implementation for the purpose of the test
14-
To to{};
15-
return to;
16-
}
17-
1810
using ::memcpy;
1911
}
2012

2113
void pointer2pointer()
22-
{
23-
int x{};
24-
float bad = *std::bit_cast<float*>(&x); // UB, but looks safe due to std::bit_cast
25-
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::bit_cast' to cast between pointers [bugprone-bitwise-pointer-cast]
26-
float good = std::bit_cast<float>(x); // Well-defined
27-
28-
using IntPtr = int*;
29-
using FloatPtr = float*;
30-
IntPtr x2{};
31-
float bad2 = *std::bit_cast<FloatPtr>(x2);
32-
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::bit_cast' to cast between pointers [bugprone-bitwise-pointer-cast]
33-
}
34-
35-
void pointer2pointer_memcpy()
3614
{
3715
int x{};
3816
int* px{};
@@ -51,11 +29,13 @@ void pointer2pointer_memcpy()
5129
void int2pointer()
5230
{
5331
unsigned long long addr{};
54-
float* p = std::bit_cast<float*>(addr);
32+
float* p{};
33+
std::memcpy(&p, &addr, sizeof(addr));
5534
}
5635

5736
void pointer2int()
5837
{
38+
unsigned long long addr{};
5939
float* p{};
60-
auto addr = std::bit_cast<unsigned long long>(p);
40+
std::memcpy(&addr, &p, sizeof(p));
6141
}

0 commit comments

Comments
 (0)