Skip to content

Commit d25e24a

Browse files
carlosgalvezpCarlos Gálvez
andauthored
[clang-tidy] Suggest using reinterpret_cast in bugprone-casting-thro… (#106784)
…ugh-void reinterpret_cast is the equivalent construct, and more clearly expresses intent. Co-authored-by: Carlos Gálvez <[email protected]>
1 parent 5a658ee commit d25e24a

File tree

4 files changed

+46
-23
lines changed

4 files changed

+46
-23
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) {
3838
const auto ST = *Result.Nodes.getNodeAs<QualType>("source_type");
3939
const auto VT = *Result.Nodes.getNodeAs<QualType>("void_type");
4040
const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
41-
diag(CE->getExprLoc(), "do not cast %0 to %1 through %2") << ST << TT << VT;
41+
diag(CE->getExprLoc(),
42+
"do not cast %0 to %1 through %2; use reinterpret_cast instead")
43+
<< ST << TT << VT;
4244
}
4345

4446
} // namespace clang::tidy::bugprone

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ New check aliases
104104
Changes in existing checks
105105
^^^^^^^^^^^^^^^^^^^^^^^^^^
106106

107+
- Improved :doc:`bugprone-casting-through-void
108+
<clang-tidy/checks/bugprone/casting-through-void>` check to suggest replacing
109+
the offending code with ``reinterpret_cast``, to more clearly express intent.
110+
107111
- Improved :doc:`modernize-use-std-format
108112
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
109113
member function calls too.

clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
bugprone-casting-through-void
44
=============================
55

6-
Detects unsafe or redundant two-step casting operations involving ``void*``.
6+
Detects unsafe or redundant two-step casting operations involving ``void*``,
7+
which is equivalent to ``reinterpret_cast`` as per the
8+
`C++ Standard <https://eel.is/c++draft/expr.reinterpret.cast#7>`_.
79

810
Two-step type conversions via ``void*`` are discouraged for several reasons.
911

@@ -16,7 +18,17 @@ Two-step type conversions via ``void*`` are discouraged for several reasons.
1618

1719
In summary, avoiding two-step type conversions through ``void*`` ensures clearer code,
1820
maintains essential compiler warnings, and prevents ambiguity and potential runtime
19-
errors, particularly in complex inheritance scenarios.
21+
errors, particularly in complex inheritance scenarios. If such a cast is wanted,
22+
it shall be done via ``reinterpret_cast``, to express the intent more clearly.
23+
24+
Note: it is expected that, after applying the suggested fix and using
25+
``reinterpret_cast``, the check :doc:`cppcoreguidelines-pro-type-reinterpret-cast
26+
<../cppcoreguidelines/pro-type-reinterpret-cast>` will emit a warning.
27+
This is intentional: ``reinterpret_cast`` is a dangerous operation that can
28+
easily break the strict aliasing rules when dereferencing the casted pointer,
29+
invoking Undefined Behavior. The warning is there to prompt users to carefuly
30+
analyze whether the usage of ``reinterpret_cast`` is safe, in which case the
31+
warning may be suppressed.
2032

2133
Examples:
2234

@@ -29,3 +41,8 @@ Examples:
2941
reinterpret_cast<IntegerPointer>(reinterpret_cast<void *>(ptr)); // WRONG
3042
(IntegerPointer)(void *)ptr; // WRONG
3143
IntegerPointer(static_cast<void *>(ptr)); // WRONG
44+
45+
reinterpret_cast<IntegerPointer>(ptr); // OK, clearly expresses intent.
46+
// NOTE: dereferencing this pointer violates
47+
// the strict aliasing rules, invoking
48+
// Undefined Behavior.

clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,54 +10,54 @@ const double cd = 100;
1010

1111
void normal_test() {
1212
static_cast<int *>(static_cast<void *>(&d));
13-
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
13+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
1414
static_cast<int *>(static_cast<V>(&d));
15-
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'V' (aka 'void *') [bugprone-casting-through-void]
15+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'V' (aka 'void *'); use reinterpret_cast instead [bugprone-casting-through-void]
1616
static_cast<int *>(static_cast<void *>(&i));
17-
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'int *' to 'int *' through 'void *' [bugprone-casting-through-void]
17+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'int *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
1818

1919
static_cast<void *>(static_cast<void *>(&i));
2020
}
2121

2222
void const_pointer_test() {
2323
static_cast<int *const>(static_cast<void *>(&d));
24-
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void *' [bugprone-casting-through-void]
24+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
2525
static_cast<int *const>(static_cast<V>(&d));
26-
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'V' (aka 'void *') [bugprone-casting-through-void]
26+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'V' (aka 'void *'); use reinterpret_cast instead [bugprone-casting-through-void]
2727
static_cast<int *const>(static_cast<void *>(&i));
28-
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'int *' to 'int *const' through 'void *' [bugprone-casting-through-void]
28+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'int *' to 'int *const' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
2929

3030
static_cast<void *const>(static_cast<void *>(&i));
3131
}
3232

3333
void const_test() {
3434
static_cast<const int *>(static_cast<const void *>(&d));
35-
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
35+
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]
3636
static_cast<const int *>(static_cast<const V>(&d));
37-
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const V' (aka 'void *const') [bugprone-casting-through-void]
37+
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const V' (aka 'void *const'); use reinterpret_cast instead [bugprone-casting-through-void]
3838
static_cast<const int *>(static_cast<const void *>(&i));
39-
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'int *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
39+
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'int *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]
4040

4141
static_cast<const void *>(static_cast<const void *>(&i));
4242

4343
static_cast<const int *>(static_cast<const void *>(&cd));
44-
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
44+
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]
4545
static_cast<const int *>(static_cast<const CV>(&cd));
46-
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const CV' (aka 'const void *const') [bugprone-casting-through-void]
46+
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const CV' (aka 'const void *const'); use reinterpret_cast instead [bugprone-casting-through-void]
4747
static_cast<const int *>(static_cast<const void *>(&ci));
48-
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const int *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
48+
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const int *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]
4949

5050
static_cast<const void *>(static_cast<const void *>(&ci));
5151
}
5252

5353

5454
void reinterpret_cast_test() {
5555
static_cast<int *>(reinterpret_cast<void *>(&d));
56-
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
56+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
5757
reinterpret_cast<int *>(static_cast<void *>(&d));
58-
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
58+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
5959
reinterpret_cast<int *>(reinterpret_cast<void *>(&d));
60-
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
60+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
6161

6262
static_cast<void *>(reinterpret_cast<void *>(&i));
6363
reinterpret_cast<void *>(reinterpret_cast<void *>(&i));
@@ -66,11 +66,11 @@ void reinterpret_cast_test() {
6666

6767
void c_style_cast_test() {
6868
static_cast<int *>((void *)&d);
69-
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
69+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
7070
(int *)(void *)&d;
71-
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
71+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
7272
static_cast<int *>((void *)&d);
73-
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
73+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
7474

7575
static_cast<void *>((void *)&i);
7676
}
@@ -82,12 +82,12 @@ using I = int *;
8282
void cxx_functional_cast() {
8383
A(static_cast<void*>(&d));
8484
I(static_cast<void*>(&d));
85-
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not cast 'double *' to 'I' (aka 'int *') through 'void *' [bugprone-casting-through-void]
85+
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not cast 'double *' to 'I' (aka 'int *') through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
8686
}
8787

8888
void bit_cast() {
8989
__builtin_bit_cast(int *, static_cast<void *>(&d));
90-
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
90+
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
9191
}
9292

9393
namespace PR87069 {

0 commit comments

Comments
 (0)