[commands] Report error on C++ CommandPtr use-after-move (#4575)

This commit is contained in:
Starlight220
2022-11-15 00:20:52 +02:00
committed by GitHub
parent d07267fed1
commit 49047c85b9
3 changed files with 78 additions and 0 deletions

View File

@@ -4,6 +4,8 @@
#include "frc2/command/CommandPtr.h"
#include <frc/Errors.h>
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/ConditionalCommand.h"
#include "frc2/command/InstantCommand.h"
@@ -20,12 +22,21 @@
using namespace frc2;
void CommandPtr::AssertValid() const {
if (!m_ptr) {
throw FRC_MakeError(frc::err::CommandIllegalUse,
"Moved-from CommandPtr object used!");
}
}
CommandPtr CommandPtr::Repeatedly() && {
AssertValid();
m_ptr = std::make_unique<RepeatCommand>(std::move(m_ptr));
return std::move(*this);
}
CommandPtr CommandPtr::AsProxy() && {
AssertValid();
m_ptr = std::make_unique<ProxyScheduleCommand>(std::move(m_ptr));
return std::move(*this);
}
@@ -44,6 +55,7 @@ class RunsWhenDisabledCommand : public WrapperCommand {
};
CommandPtr CommandPtr::IgnoringDisable(bool doesRunWhenDisabled) && {
AssertValid();
m_ptr = std::make_unique<RunsWhenDisabledCommand>(std::move(m_ptr),
doesRunWhenDisabled);
return std::move(*this);
@@ -67,6 +79,7 @@ class InterruptBehaviorCommand : public WrapperCommand {
CommandPtr CommandPtr::WithInterruptBehavior(
InterruptionBehavior interruptBehavior) && {
AssertValid();
m_ptr = std::make_unique<InterruptBehaviorCommand>(std::move(m_ptr),
interruptBehavior);
return std::move(*this);
@@ -74,6 +87,7 @@ CommandPtr CommandPtr::WithInterruptBehavior(
CommandPtr CommandPtr::AndThen(std::function<void()> toRun,
std::span<Subsystem* const> requirements) && {
AssertValid();
return std::move(*this).AndThen(CommandPtr(
std::make_unique<InstantCommand>(std::move(toRun), requirements)));
}
@@ -81,11 +95,13 @@ CommandPtr CommandPtr::AndThen(std::function<void()> toRun,
CommandPtr CommandPtr::AndThen(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) && {
AssertValid();
return std::move(*this).AndThen(CommandPtr(
std::make_unique<InstantCommand>(std::move(toRun), requirements)));
}
CommandPtr CommandPtr::AndThen(CommandPtr&& next) && {
AssertValid();
std::vector<std::unique_ptr<Command>> temp;
temp.emplace_back(std::move(m_ptr));
temp.emplace_back(std::move(next).Unwrap());
@@ -95,6 +111,7 @@ CommandPtr CommandPtr::AndThen(CommandPtr&& next) && {
CommandPtr CommandPtr::BeforeStarting(
std::function<void()> toRun, std::span<Subsystem* const> requirements) && {
AssertValid();
return std::move(*this).BeforeStarting(CommandPtr(
std::make_unique<InstantCommand>(std::move(toRun), requirements)));
}
@@ -102,11 +119,13 @@ CommandPtr CommandPtr::BeforeStarting(
CommandPtr CommandPtr::BeforeStarting(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) && {
AssertValid();
return std::move(*this).BeforeStarting(CommandPtr(
std::make_unique<InstantCommand>(std::move(toRun), requirements)));
}
CommandPtr CommandPtr::BeforeStarting(CommandPtr&& before) && {
AssertValid();
std::vector<std::unique_ptr<Command>> temp;
temp.emplace_back(std::move(before).Unwrap());
temp.emplace_back(std::move(m_ptr));
@@ -115,6 +134,7 @@ CommandPtr CommandPtr::BeforeStarting(CommandPtr&& before) && {
}
CommandPtr CommandPtr::WithTimeout(units::second_t duration) && {
AssertValid();
std::vector<std::unique_ptr<Command>> temp;
temp.emplace_back(std::make_unique<WaitCommand>(duration));
temp.emplace_back(std::move(m_ptr));
@@ -123,6 +143,7 @@ CommandPtr CommandPtr::WithTimeout(units::second_t duration) && {
}
CommandPtr CommandPtr::Until(std::function<bool()> condition) && {
AssertValid();
std::vector<std::unique_ptr<Command>> temp;
temp.emplace_back(std::make_unique<WaitUntilCommand>(std::move(condition)));
temp.emplace_back(std::move(m_ptr));
@@ -131,6 +152,7 @@ CommandPtr CommandPtr::Until(std::function<bool()> condition) && {
}
CommandPtr CommandPtr::Unless(std::function<bool()> condition) && {
AssertValid();
m_ptr = std::make_unique<ConditionalCommand>(
std::make_unique<InstantCommand>(), std::move(m_ptr),
std::move(condition));
@@ -138,6 +160,7 @@ CommandPtr CommandPtr::Unless(std::function<bool()> condition) && {
}
CommandPtr CommandPtr::DeadlineWith(CommandPtr&& parallel) && {
AssertValid();
std::vector<std::unique_ptr<Command>> vec;
vec.emplace_back(std::move(parallel).Unwrap());
m_ptr =
@@ -146,6 +169,7 @@ CommandPtr CommandPtr::DeadlineWith(CommandPtr&& parallel) && {
}
CommandPtr CommandPtr::AlongWith(CommandPtr&& parallel) && {
AssertValid();
std::vector<std::unique_ptr<Command>> vec;
vec.emplace_back(std::move(m_ptr));
vec.emplace_back(std::move(parallel).Unwrap());
@@ -154,6 +178,7 @@ CommandPtr CommandPtr::AlongWith(CommandPtr&& parallel) && {
}
CommandPtr CommandPtr::RaceWith(CommandPtr&& parallel) && {
AssertValid();
std::vector<std::unique_ptr<Command>> vec;
vec.emplace_back(std::move(m_ptr));
vec.emplace_back(std::move(parallel).Unwrap());
@@ -179,11 +204,13 @@ class FinallyCommand : public WrapperCommand {
} // namespace
CommandPtr CommandPtr::FinallyDo(std::function<void(bool)> end) && {
AssertValid();
m_ptr = std::make_unique<FinallyCommand>(std::move(m_ptr), std::move(end));
return std::move(*this);
}
CommandPtr CommandPtr::HandleInterrupt(std::function<void(void)> handler) && {
AssertValid();
return std::move(*this).FinallyDo(
[handler = std::move(handler)](bool interrupted) {
if (interrupted) {
@@ -193,29 +220,39 @@ CommandPtr CommandPtr::HandleInterrupt(std::function<void(void)> handler) && {
}
Command* CommandPtr::get() const {
AssertValid();
return m_ptr.get();
}
std::unique_ptr<Command> CommandPtr::Unwrap() && {
AssertValid();
return std::move(m_ptr);
}
void CommandPtr::Schedule() const {
AssertValid();
CommandScheduler::GetInstance().Schedule(*this);
}
void CommandPtr::Cancel() const {
AssertValid();
CommandScheduler::GetInstance().Cancel(*this);
}
bool CommandPtr::IsScheduled() const {
AssertValid();
return CommandScheduler::GetInstance().IsScheduled(*this);
}
bool CommandPtr::HasRequirement(Subsystem* requirement) const {
AssertValid();
return m_ptr->HasRequirement(requirement);
}
CommandPtr::operator bool() const {
return m_ptr.operator bool();
}
std::vector<std::unique_ptr<Command>> CommandPtr::UnwrapVector(
std::vector<CommandPtr>&& vec) {
std::vector<std::unique_ptr<Command>> ptrs;