Skip to content

Commit 2c63a33

Browse files
committed
[𝘀𝗽𝗿] changes introduced through rebase
Created using spr 1.3.6-beta.1 [skip ci]
2 parents b94b3e0 + e67f323 commit 2c63a33

File tree

552 files changed

+16831
-6905
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

552 files changed

+16831
-6905
lines changed

.github/workflows/premerge.yaml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ jobs:
3434
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3535
with:
3636
fetch-depth: 2
37-
- name: Setup ccache
38-
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
39-
with:
40-
variant: "sccache"
41-
max-size: "2000M"
4237
- name: Build and Test
4338
# Mark the job as a success even if the step fails so that people do
4439
# not get notified while the new premerge pipeline is in an
@@ -62,6 +57,13 @@ jobs:
6257
export CC=/opt/llvm/bin/clang
6358
export CXX=/opt/llvm/bin/clang++
6459
60+
# This environment variable is passes into the container through the
61+
# runner pod definition. This differs between our two clusters which
62+
# why we do not hardcode it.
63+
export SCCACHE_GCS_BUCKET=$CACHE_GCS_BUCKET
64+
export SCCACHE_GCS_RW_MODE=READ_WRITE
65+
sccache --start-server
66+
6567
./.ci/monolithic-linux.sh "${projects_to_build}" "${project_check_targets}" "${runtimes_to_build}" "${runtimes_check_targets}" "${runtimes_check_targets_needs_reconfig}" "${enable_cir}"
6668
- name: Upload Artifacts
6769
if: '!cancelled()'
@@ -86,11 +88,6 @@ jobs:
8688
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
8789
with:
8890
fetch-depth: 2
89-
- name: Setup ccache
90-
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
91-
with:
92-
variant: "sccache"
93-
max-size: "2000M"
9491
- name: Compute Projects
9592
id: vars
9693
run: |
@@ -113,7 +110,7 @@ jobs:
113110
shell: cmd
114111
run: |
115112
call C:\\BuildTools\\Common7\\Tools\\VsDevCmd.bat -arch=amd64 -host_arch=amd64
116-
bash .ci/monolithic-windows.sh "${{ steps.vars.outputs.windows-projects }}" "${{ steps.vars.outputs.windows-check-targets }}"
113+
bash -c "export SCCACHE_GCS_BUCKET=$CACHE_GCS_BUCKET; export SCCACHE_GCS_RW_MODE=READ_WRITE; sccache --start-server; .ci/monolithic-windows.sh \"${{ steps.vars.outputs.windows-projects }}\" \"${{ steps.vars.outputs.windows-check-targets }}\""
117114
- name: Upload Artifacts
118115
if: '!cancelled()'
119116
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0

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

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,28 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
6969
cxxMethodDecl(unless(hasDescendant(cxxMemberCallExpr(callee(cxxMethodDecl(
7070
hasName("operator="), ofClass(equalsBoundNode("class"))))))));
7171

72+
// Checking that some kind of constructor is called and followed by a `swap`:
73+
// T& operator=(const T& other) {
74+
// T tmp{this->internal_data(), some, other, args};
75+
// swap(tmp);
76+
// return *this;
77+
// }
78+
const auto HasCopyAndSwap = cxxMethodDecl(
79+
ofClass(cxxRecordDecl()),
80+
hasBody(compoundStmt(
81+
hasDescendant(
82+
varDecl(hasType(cxxRecordDecl(equalsBoundNode("class"))))
83+
.bind("tmp_var")),
84+
hasDescendant(stmt(anyOf(
85+
cxxMemberCallExpr(hasArgument(
86+
0, declRefExpr(to(varDecl(equalsBoundNode("tmp_var")))))),
87+
callExpr(
88+
callee(functionDecl(hasName("swap"))), argumentCountIs(2),
89+
hasAnyArgument(
90+
declRefExpr(to(varDecl(equalsBoundNode("tmp_var"))))),
91+
hasAnyArgument(unaryOperator(has(cxxThisExpr()),
92+
hasOperatorName("*"))))))))));
93+
7294
DeclarationMatcher AdditionalMatcher = cxxMethodDecl();
7395
if (WarnOnlyIfThisHasSuspiciousField) {
7496
// Matcher for standard smart pointers.
@@ -89,14 +111,14 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
89111
hasType(arrayType())))))));
90112
}
91113

92-
Finder->addMatcher(cxxMethodDecl(ofClass(cxxRecordDecl().bind("class")),
93-
isCopyAssignmentOperator(), IsUserDefined,
94-
HasReferenceParam, HasNoSelfCheck,
95-
unless(HasNonTemplateSelfCopy),
96-
unless(HasTemplateSelfCopy),
97-
HasNoNestedSelfAssign, AdditionalMatcher)
98-
.bind("copyAssignmentOperator"),
99-
this);
114+
Finder->addMatcher(
115+
cxxMethodDecl(
116+
ofClass(cxxRecordDecl().bind("class")), isCopyAssignmentOperator(),
117+
IsUserDefined, HasReferenceParam, HasNoSelfCheck,
118+
unless(HasNonTemplateSelfCopy), unless(HasTemplateSelfCopy),
119+
unless(HasCopyAndSwap), HasNoNestedSelfAssign, AdditionalMatcher)
120+
.bind("copyAssignmentOperator"),
121+
this);
100122
}
101123

102124
void UnhandledSelfAssignmentCheck::check(

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ Changes in existing checks
114114
<clang-tidy/checks/bugprone/infinite-loop>` check by adding detection for
115115
variables introduced by structured bindings.
116116

117+
- Improved :doc:`bugprone-unhandled-self-assignment
118+
<clang-tidy/checks/bugprone/unhandled-self-assignment>` check by adding
119+
an additional matcher that generalizes the copy-and-swap idiom pattern
120+
detection.
121+
117122
Removed checks
118123
^^^^^^^^^^^^^^
119124

clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-self-assignment.cpp

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ template <class T>
2828
class auto_ptr {
2929
};
3030

31+
namespace pmr {
32+
template <typename TYPE = void>
33+
class allocator {};
34+
}
35+
36+
struct allocator_arg_t {} allocator_arg;
37+
3138
} // namespace std
3239

3340
void assert(int expression){};
@@ -229,6 +236,122 @@ bool operator!=(Foo2 &, Foo2 &) {
229236
};
230237
}
231238

239+
// Missing call to `swap` function
240+
class AllocatorAwareClassNoSwap {
241+
// pointer member to trigger bugprone-unhandled-self-assignment
242+
void *foo = nullptr;
243+
244+
public:
245+
using allocator_type = std::pmr::allocator<>;
246+
247+
AllocatorAwareClassNoSwap(const AllocatorAwareClassNoSwap& other) {
248+
}
249+
250+
AllocatorAwareClassNoSwap(const AllocatorAwareClassNoSwap& other, const allocator_type& alloc) {
251+
}
252+
253+
AllocatorAwareClassNoSwap& operator=(const AllocatorAwareClassNoSwap& other) {
254+
// CHECK-MESSAGES: [[@LINE-1]]:32: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
255+
AllocatorAwareClassNoSwap tmp(other, get_allocator());
256+
return *this;
257+
}
258+
259+
allocator_type get_allocator() const {
260+
return allocator_type();
261+
}
262+
};
263+
264+
// "Wrong" type is passed to member `swap` function
265+
class AllocatorAwareClassSwapWrongArgType {
266+
// pointer member to trigger bugprone-unhandled-self-assignment
267+
void *foo = nullptr;
268+
269+
public:
270+
using allocator_type = std::pmr::allocator<>;
271+
272+
AllocatorAwareClassSwapWrongArgType(const AllocatorAwareClassSwapWrongArgType& other) {
273+
}
274+
275+
AllocatorAwareClassSwapWrongArgType(const AllocatorAwareClassSwapWrongArgType& other, const allocator_type& alloc) {
276+
}
277+
278+
AllocatorAwareClassSwapWrongArgType& operator=(const AllocatorAwareClassSwapWrongArgType& other) {
279+
// CHECK-MESSAGES: [[@LINE-1]]:42: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
280+
int tmp = 0;
281+
swap(tmp);
282+
283+
return *this;
284+
}
285+
286+
void swap(int&) noexcept {
287+
}
288+
289+
allocator_type get_allocator() const {
290+
return allocator_type();
291+
}
292+
};
293+
294+
295+
// Making ADL `swap` call but with wrong argument type
296+
class AllocatorAwareClassAdlSwapWrongArgType {
297+
// pointer member to trigger bugprone-unhandled-self-assignment
298+
void *foo = nullptr;
299+
300+
public:
301+
using allocator_type = std::pmr::allocator<>;
302+
303+
AllocatorAwareClassAdlSwapWrongArgType(const AllocatorAwareClassAdlSwapWrongArgType& other) {
304+
}
305+
306+
AllocatorAwareClassAdlSwapWrongArgType(const AllocatorAwareClassAdlSwapWrongArgType& other, const allocator_type& alloc) {
307+
}
308+
309+
AllocatorAwareClassAdlSwapWrongArgType& operator=(const AllocatorAwareClassAdlSwapWrongArgType& other) {
310+
// CHECK-MESSAGES: [[@LINE-1]]:45: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
311+
int tmp = 0;
312+
swap(*this, tmp);
313+
314+
return *this;
315+
}
316+
317+
allocator_type get_allocator() const {
318+
return allocator_type();
319+
}
320+
321+
friend void swap(AllocatorAwareClassAdlSwapWrongArgType&, int&) {
322+
}
323+
};
324+
325+
// `this` isn't passed to `swap`
326+
class AllocatorAwareClassAdlSwapWrongArgs {
327+
// pointer member to trigger bugprone-unhandled-self-assignment
328+
void *foo = nullptr;
329+
330+
public:
331+
using allocator_type = std::pmr::allocator<>;
332+
333+
AllocatorAwareClassAdlSwapWrongArgs(const AllocatorAwareClassAdlSwapWrongArgs& other) {
334+
}
335+
336+
AllocatorAwareClassAdlSwapWrongArgs(const AllocatorAwareClassAdlSwapWrongArgs& other, const allocator_type& alloc) {
337+
}
338+
339+
AllocatorAwareClassAdlSwapWrongArgs& operator=(const AllocatorAwareClassAdlSwapWrongArgs& other) {
340+
// CHECK-MESSAGES: [[@LINE-1]]:42: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
341+
AllocatorAwareClassAdlSwapWrongArgs tmp1(other, get_allocator());
342+
AllocatorAwareClassAdlSwapWrongArgs tmp2(*this, get_allocator());
343+
swap(tmp1, tmp2);
344+
return *this;
345+
}
346+
347+
allocator_type get_allocator() const {
348+
return allocator_type();
349+
}
350+
351+
friend void swap(AllocatorAwareClassAdlSwapWrongArgs&, AllocatorAwareClassAdlSwapWrongArgs&) {
352+
}
353+
};
354+
232355
///////////////////////////////////////////////////////////////////
233356
/// Test cases correctly ignored by the check.
234357

@@ -540,6 +663,89 @@ class NotACopyAssignmentOperator {
540663
Uy *getUy() const { return Ptr2; }
541664
};
542665

666+
// Support "extended" copy/move constructors
667+
class AllocatorAwareClass {
668+
// pointer member to trigger bugprone-unhandled-self-assignment
669+
void *foo = nullptr;
670+
671+
public:
672+
using allocator_type = std::pmr::allocator<>;
673+
674+
AllocatorAwareClass(const AllocatorAwareClass& other) {
675+
}
676+
677+
AllocatorAwareClass(const AllocatorAwareClass& other, const allocator_type& alloc) {
678+
}
679+
680+
AllocatorAwareClass& operator=(const AllocatorAwareClass& other) {
681+
AllocatorAwareClass tmp(other, get_allocator());
682+
swap(tmp);
683+
return *this;
684+
}
685+
686+
void swap(AllocatorAwareClass& other) noexcept {
687+
}
688+
689+
allocator_type get_allocator() const {
690+
return allocator_type();
691+
}
692+
};
693+
694+
// Support "extended" copy/move constructors + std::swap
695+
class AllocatorAwareClassStdSwap {
696+
// pointer member to trigger bugprone-unhandled-self-assignment
697+
void *foo = nullptr;
698+
699+
public:
700+
using allocator_type = std::pmr::allocator<>;
701+
702+
AllocatorAwareClassStdSwap(const AllocatorAwareClassStdSwap& other) {
703+
}
704+
705+
AllocatorAwareClassStdSwap(const AllocatorAwareClassStdSwap& other, const allocator_type& alloc) {
706+
}
707+
708+
AllocatorAwareClassStdSwap& operator=(const AllocatorAwareClassStdSwap& other) {
709+
using std::swap;
710+
711+
AllocatorAwareClassStdSwap tmp(other, get_allocator());
712+
swap(*this, tmp);
713+
return *this;
714+
}
715+
716+
allocator_type get_allocator() const {
717+
return allocator_type();
718+
}
719+
};
720+
721+
// Support "extended" copy/move constructors + ADL swap
722+
class AllocatorAwareClassAdlSwap {
723+
// pointer member to trigger bugprone-unhandled-self-assignment
724+
void *foo = nullptr;
725+
726+
public:
727+
using allocator_type = std::pmr::allocator<>;
728+
729+
AllocatorAwareClassAdlSwap(const AllocatorAwareClassAdlSwap& other) {
730+
}
731+
732+
AllocatorAwareClassAdlSwap(const AllocatorAwareClassAdlSwap& other, const allocator_type& alloc) {
733+
}
734+
735+
AllocatorAwareClassAdlSwap& operator=(const AllocatorAwareClassAdlSwap& other) {
736+
AllocatorAwareClassAdlSwap tmp(other, get_allocator());
737+
swap(*this, tmp);
738+
return *this;
739+
}
740+
741+
allocator_type get_allocator() const {
742+
return allocator_type();
743+
}
744+
745+
friend void swap(AllocatorAwareClassAdlSwap&, AllocatorAwareClassAdlSwap&) {
746+
}
747+
};
748+
543749
///////////////////////////////////////////////////////////////////
544750
/// Test cases which should be caught by the check.
545751

0 commit comments

Comments
 (0)