@@ -28,6 +28,13 @@ template <class T>
2828class 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
3340void 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