CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
399 lines
13 KiB
C++
399 lines
13 KiB
C++
// RUN: %check_clang_tidy %s performance-use-std-move %t
|
|
|
|
// Definitions used in the tests
|
|
// -----------------------------
|
|
|
|
#include <utility>
|
|
|
|
struct NonTrivialMoveAssign {
|
|
NonTrivialMoveAssign() = default;
|
|
NonTrivialMoveAssign(const NonTrivialMoveAssign&) = default;
|
|
|
|
NonTrivialMoveAssign& operator=(const NonTrivialMoveAssign&);
|
|
NonTrivialMoveAssign& operator=(NonTrivialMoveAssign&&);
|
|
|
|
NonTrivialMoveAssign& operator+=(const NonTrivialMoveAssign&);
|
|
NonTrivialMoveAssign& operator+=(NonTrivialMoveAssign&&);
|
|
void stuff();
|
|
};
|
|
|
|
struct TrivialMoveAssign {
|
|
TrivialMoveAssign& operator=(const TrivialMoveAssign&);
|
|
TrivialMoveAssign& operator=(TrivialMoveAssign&&) = default;
|
|
};
|
|
|
|
struct NoMoveAssign {
|
|
NoMoveAssign& operator=(const NoMoveAssign&);
|
|
NoMoveAssign& operator=(NoMoveAssign&&) = delete;
|
|
};
|
|
|
|
struct NoDefaultedMoveAssign {
|
|
NoDefaultedMoveAssign& operator=(const NoDefaultedMoveAssign&);
|
|
NoDefaultedMoveAssign& operator=(NoDefaultedMoveAssign&&) = default;
|
|
NoMoveAssign Field;
|
|
};
|
|
|
|
struct PrivateMoveAssign {
|
|
PrivateMoveAssign& operator=(const PrivateMoveAssign&);
|
|
private:
|
|
PrivateMoveAssign& operator=(PrivateMoveAssign&&);
|
|
};
|
|
|
|
template<class T>
|
|
void use(T&) {}
|
|
|
|
// Check moving from various reference/pointer type
|
|
// ------------------------------------------------
|
|
|
|
void ConvertibleNonTrivialMoveAssign(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
|
|
void NonProfitableNonTrivialMoveAssignPointer(NonTrivialMoveAssign*& target, NonTrivialMoveAssign* source) {
|
|
// No message expected, moving is possible but non profitable for pointer.
|
|
target = source;
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignFromLValue(NonTrivialMoveAssign& target, NonTrivialMoveAssign&& source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
|
|
// Check moving already moved values
|
|
// ---------------------------------
|
|
|
|
void NonConvertibleNonTrivialMoveAssignAlreadyMoved(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// No message expected, it's already moved
|
|
target = std::move(source);
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignFromLValueAlreadyMoved(NonTrivialMoveAssign& target, NonTrivialMoveAssign&& source) {
|
|
// No message expected, it's already moved
|
|
target = std::move(source);
|
|
}
|
|
|
|
// Check moving within different context
|
|
// -------------------------------------
|
|
|
|
struct SomeRecord {
|
|
void ConvertibleNonTrivialMoveAssignWithinMethod(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
};
|
|
|
|
auto ConvertibleNonTrivialMoveAssignWithinLambda = [](NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
};
|
|
|
|
void SomeFunction(NonTrivialMoveAssign source0, NonTrivialMoveAssign const &source1) {
|
|
|
|
auto NonConvertibleNonTrivialMoveAssignWithinLambdaAsCaptureByRef = [&](NonTrivialMoveAssign& target) {
|
|
// No message expected, cannot move a non-local variable.
|
|
target = source0;
|
|
// No message expected, cannot move a non-local variable.
|
|
target = source1;
|
|
};
|
|
|
|
auto ConvertibleNonTrivialMoveAssignWithinLambdaAsCapture = [=](NonTrivialMoveAssign& target) {
|
|
// No message expected, cannot move a non-local variable.
|
|
target = source0;
|
|
// No message expected, cannot move a non-local variable.
|
|
target = source1;
|
|
};
|
|
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignShadowing(NonTrivialMoveAssign& target, NoMoveAssign source) {
|
|
{
|
|
NonTrivialMoveAssign source;
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignShadowed(NoMoveAssign& target, NonTrivialMoveAssign source) {
|
|
{
|
|
NoMoveAssign source;
|
|
// No message expected, `source' refers to a non-movable variable.
|
|
target = source;
|
|
}
|
|
}
|
|
|
|
#define ASSIGN(x, y) x = y
|
|
void ConvertibleNonTrivialMoveAssignWithinMacro(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// No message expected, assignment within a macro.
|
|
ASSIGN(target, source);
|
|
}
|
|
|
|
template<class T>
|
|
void ConvertibleNonTrivialMoveAssignWithTemplateSource(NonTrivialMoveAssign& target, T source) {
|
|
// No message expected, type of source cannot be matched against `target's type.
|
|
target = source;
|
|
}
|
|
|
|
template<class T>
|
|
void ConvertibleNonTrivialMoveAssignWithTemplateTarget(T& target, NonTrivialMoveAssign source) {
|
|
// No message expected, type of target cannot be matched against `source's type.
|
|
target = source;
|
|
}
|
|
|
|
// Check moving from various storage
|
|
// ---------------------------------
|
|
|
|
void NonConvertibleNonTrivialMoveAssignFromLocal(NonTrivialMoveAssign& target) {
|
|
const NonTrivialMoveAssign source;
|
|
// No message, moving a const-qualified value is not valid.
|
|
target = source;
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignFromConst(NonTrivialMoveAssign& target) {
|
|
NonTrivialMoveAssign source;
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignFromStatic(NonTrivialMoveAssign& target) {
|
|
static NonTrivialMoveAssign source;
|
|
// No message, the lifetime of `source' does not end with the scope of the function.
|
|
target = source;
|
|
}
|
|
|
|
struct NonConvertibleNonTrivialMoveAssignFromMember {
|
|
NonTrivialMoveAssign source;
|
|
void NonConvertibleNonTrivialMoveAssignFromStatic(NonTrivialMoveAssign& target) {
|
|
// No message, `source' is not a local variable.
|
|
target = source;
|
|
}
|
|
};
|
|
|
|
void NonConvertibleNonTrivialMoveAssignFromExtern(NonTrivialMoveAssign& target) {
|
|
extern NonTrivialMoveAssign source;
|
|
// No message, the lifetime of `source' does not end with the scope of the function.
|
|
target = source;
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignFromTLS(NonTrivialMoveAssign& target) {
|
|
thread_local NonTrivialMoveAssign source;
|
|
// No message, the lifetime of `source' does not end with the scope of the function.
|
|
target = source;
|
|
}
|
|
|
|
NonTrivialMoveAssign global_source;
|
|
void NonConvertibleNonTrivialMoveAssignToGlobal(NonTrivialMoveAssign& target) {
|
|
// No message, the lifetime of `source' does not end with the scope of the function.
|
|
target = global_source;
|
|
}
|
|
|
|
|
|
// Check moving to various storage
|
|
// -------------------------------
|
|
|
|
void ConvertibleNonTrivialMoveAssignToStatic(NonTrivialMoveAssign source) {
|
|
static NonTrivialMoveAssign target;
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
|
|
struct ConvertibleNonTrivialMoveAssignToMember {
|
|
NonTrivialMoveAssign target;
|
|
void NonConvertibleNonTrivialMoveAssignFromStatic(NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
};
|
|
|
|
void ConvertibleNonTrivialMoveAssignToExtern(NonTrivialMoveAssign source) {
|
|
extern NonTrivialMoveAssign target;
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignToTLS(NonTrivialMoveAssign source) {
|
|
thread_local NonTrivialMoveAssign target;
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
|
|
NonTrivialMoveAssign global_target;
|
|
void ConvertibleNonTrivialMoveAssignToGlobal(NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:19: warning: 'source' could be moved here [performance-use-std-move]
|
|
global_target = source;
|
|
// CHECK-FIXES: global_target = std::move(source);
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignRValue(NonTrivialMoveAssign& target, NonTrivialMoveAssign const& source) {
|
|
// No message expected, moving a reference is invalid there.
|
|
target = source;
|
|
}
|
|
|
|
void NonProfitableTrivialMoveAssign(TrivialMoveAssign& target, TrivialMoveAssign source) {
|
|
// No message expected, moving is possible but pedantic.
|
|
target = source;
|
|
}
|
|
|
|
// Check moving in presence of control flow or use
|
|
// -----------------------------------------------
|
|
|
|
void ConvertibleNonTrivialMoveAssignWithBranching(bool cond, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
if(cond) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignWithBranchingAndUse(bool cond, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
if(cond) {
|
|
// No message expected, moving would make use invalid.
|
|
target = source;
|
|
}
|
|
use(source);
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignBothBranches(bool cond, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
if(cond) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
else {
|
|
source.stuff();
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignWithExtraUse(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// No message expected, moving would make the call to `stuff' invalid.
|
|
target = source;
|
|
source.stuff();
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignInLoop(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// No message expected, moving would make the next iteration invalid.
|
|
for(int i = 0; i < 10; ++i)
|
|
target = source;
|
|
}
|
|
|
|
// Check moving incomplete definition
|
|
// ----------------------------------
|
|
|
|
struct fwd_cls;
|
|
struct fwd_cls {
|
|
void ConvertibleNonTrivialMoveAssignReferecingForwardDecl(fwd_cls src) {
|
|
// CHECK-MESSAGES: [[@LINE+2]]:13: warning: 'src' could be moved here [performance-use-std-move]
|
|
// CHECK-FIXES: *this = std::move(src);
|
|
*this = src;
|
|
}
|
|
fwd_cls &operator=(const fwd_cls &C);
|
|
fwd_cls &operator=(fwd_cls &&);
|
|
};
|
|
|
|
|
|
// Check moving for invalid / non profitable type or operation
|
|
// -----------------------------------------------------------
|
|
|
|
void NonConvertibleNonTrivialMoveUpdateAssign(NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// No message currently expected, we only consider assignment.
|
|
target += source;
|
|
}
|
|
|
|
void NonProfitableTrivialTypeAssign(int& target, int source) {
|
|
// No message needed, it's correct to move but pedantic.
|
|
target = source;
|
|
}
|
|
|
|
void InvalidMoveAssign(NoMoveAssign& target, NoMoveAssign source) {
|
|
// No message expected, moving is deleted.
|
|
target = source;
|
|
}
|
|
|
|
void InvalidPrivateMoveAssign(PrivateMoveAssign& target, PrivateMoveAssign source) {
|
|
// No message expected, moving is private.
|
|
target = source;
|
|
}
|
|
|
|
void DeletedDefaultMoveAssign(NoDefaultedMoveAssign& target, NoDefaultedMoveAssign source) {
|
|
// No message expected, default move is invalid.
|
|
target = source;
|
|
}
|
|
|
|
// Check moving within control-flow
|
|
// --------------------------------
|
|
|
|
void ConvertibleNonTrivialMoveAssignWithinTestPred(bool pred, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
if (pred)
|
|
target = target;
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignWithinTestPred(bool pred, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
target = source;
|
|
if (pred)
|
|
source.stuff();
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignWithinTestBothPred(bool pred, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:12: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
if (pred)
|
|
target = target;
|
|
else
|
|
target.stuff();
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignWithinLoop(unsigned count, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
while(--count)
|
|
target = source;
|
|
}
|
|
|
|
void ConvertibleNonTrivialMoveAssignWithinTestMultiplePred(bool pred0, bool pred1, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
if(pred0) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
else {
|
|
if (pred1) {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:16: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
}
|
|
else {
|
|
target.stuff();
|
|
}
|
|
}
|
|
}
|
|
|
|
void NonConvertibleNonTrivialMoveAssignWithinTestMultiplePred(bool pred0, bool pred1, NonTrivialMoveAssign& target, NonTrivialMoveAssign source) {
|
|
target = source;
|
|
if(pred0) {
|
|
target.stuff();
|
|
}
|
|
else {
|
|
// CHECK-MESSAGES: [[@LINE+1]]:14: warning: 'source' could be moved here [performance-use-std-move]
|
|
target = source;
|
|
// CHECK-FIXES: target = std::move(source);
|
|
if (pred1) {
|
|
target.stuff();
|
|
}
|
|
}
|
|
}
|