Skip to content

Commit cdc6737

Browse files
author
z1_cciauto
authored
merge main into amd-staging (llvm#3255)
2 parents 3c73b57 + 7d94f7a commit cdc6737

File tree

224 files changed

+4635
-1565
lines changed

Some content is hidden

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

224 files changed

+4635
-1565
lines changed

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

clang/docs/HIPSupport.rst

Lines changed: 19 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -545,37 +545,22 @@ The following restrictions imposed on user code apply to both modes:
545545
1. Pointers to function, and all associated features, such as e.g. dynamic
546546
polymorphism, cannot be used (directly or transitively) by the user provided
547547
callable passed to an algorithm invocation;
548-
2. Global / namespace scope / ``static`` / ``thread`` storage duration variables
549-
cannot be used (directly or transitively) in name by the user provided
550-
callable;
551-
552-
- When executing in **HMM Mode** they can be used in address e.g.:
553-
554-
.. code-block:: C++
555-
556-
namespace { int foo = 42; }
557-
558-
bool never(const std::vector<int>& v) {
559-
return std::any_of(std::execution::par_unseq, std::cbegin(v), std::cend(v), [](auto&& x) {
560-
return x == foo;
561-
});
562-
}
563-
564-
bool only_in_hmm_mode(const std::vector<int>& v) {
565-
return std::any_of(std::execution::par_unseq, std::cbegin(v), std::cend(v),
566-
[p = &foo](auto&& x) { return x == *p; });
567-
}
568-
569-
3. Only algorithms that are invoked with the ``parallel_unsequenced_policy`` are
548+
2. ``static`` (except for program-wide unique ones) / ``thread`` storage
549+
duration variables cannot be used (directly or transitively) in name by the
550+
user provided callable;
551+
3. User code must be compiled in ``-fgpu-rdc`` mode in order for global /
552+
namespace scope variables / program-wide unique ``static`` storage duration
553+
variables to be usable in name by the user provided callable;
554+
4. Only algorithms that are invoked with the ``parallel_unsequenced_policy`` are
570555
candidates for offload;
571-
4. Only algorithms that are invoked with iterator arguments that model
556+
5. Only algorithms that are invoked with iterator arguments that model
572557
`random_access_iterator <https://en.cppreference.com/w/cpp/iterator/random_access_iterator>`_
573558
are candidates for offload;
574-
5. `Exceptions <https://en.cppreference.com/w/cpp/language/exceptions>`_ cannot
559+
6. `Exceptions <https://en.cppreference.com/w/cpp/language/exceptions>`_ cannot
575560
be used by the user provided callable;
576-
6. Dynamic memory allocation (e.g. ``operator new``) cannot be used by the user
561+
7. Dynamic memory allocation (e.g. ``operator new``) cannot be used by the user
577562
provided callable;
578-
7. Selective offload is not possible i.e. it is not possible to indicate that
563+
8. Selective offload is not possible i.e. it is not possible to indicate that
579564
only some algorithms invoked with the ``parallel_unsequenced_policy`` are to
580565
be executed on the accelerator.
581566

@@ -585,15 +570,6 @@ additional restrictions:
585570
1. All code that is expected to interoperate has to be recompiled with the
586571
``--hipstdpar-interpose-alloc`` flag i.e. it is not safe to compose libraries
587572
that have been independently compiled;
588-
2. automatic storage duration (i.e. stack allocated) variables cannot be used
589-
(directly or transitively) by the user provided callable e.g.
590-
591-
.. code-block:: c++
592-
593-
bool never(const std::vector<int>& v, int n) {
594-
return std::any_of(std::execution::par_unseq, std::cbegin(v), std::cend(v),
595-
[p = &n](auto&& x) { return x == *p; });
596-
}
597573

598574
Current Support
599575
===============
@@ -626,17 +602,12 @@ Linux operating system. Support is synthesised in the following table:
626602

627603
The minimum Linux kernel version for running in HMM mode is 6.4.
628604

629-
The forwarding header can be obtained from
630-
`its GitHub repository <https://github.com/ROCm/roc-stdpar>`_.
631-
It will be packaged with a future `ROCm <https://rocm.docs.amd.com/en/latest/>`_
632-
release. Because accelerated algorithms are provided via
633-
`rocThrust <https://rocm.docs.amd.com/projects/rocThrust/en/latest/>`_, a
634-
transitive dependency on
635-
`rocPrim <https://rocm.docs.amd.com/projects/rocPRIM/en/latest/>`_ exists. Both
636-
can be obtained either by installing their associated components of the
637-
`ROCm <https://rocm.docs.amd.com/en/latest/>`_ stack, or from their respective
638-
repositories. The list algorithms that can be offloaded is available
639-
`here <https://github.com/ROCm/roc-stdpar#algorithm-support-status>`_.
605+
The forwarding header is packaged by
606+
`ROCm <https://rocm.docs.amd.com/en/latest/>`_, and is obtainable by installing
607+
the `hipstdpar` packege. The list algorithms that can be offloaded is available
608+
`here <https://github.com/ROCm/roc-stdpar#algorithm-support-status>`_. More
609+
details are available via the dedicated blog
610+
`<https://rocm.blogs.amd.com/software-tools-optimization/hipstdpar/README.html>`_.
640611

641612
HIP Specific Elements
642613
---------------------
@@ -690,9 +661,8 @@ HIP Specific Elements
690661
Open Questions / Future Developments
691662
====================================
692663

693-
1. The restriction on the use of global / namespace scope / ``static`` /
694-
``thread`` storage duration variables in offloaded algorithms will be lifted
695-
in the future, when running in **HMM Mode**;
664+
1. The restriction on the use of ``static`` / ``thread`` storage duration
665+
variables in offloaded algorithms might be lifted;
696666
2. The restriction on the use of dynamic memory allocation in offloaded
697667
algorithms will be lifted in the future.
698668
3. The restriction on the use of pointers to function, and associated features

0 commit comments

Comments
 (0)