From 7d6f147592675ebe4b4ceafff78184a81773d747 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Wed, 14 Oct 2026 00:22:08 +0300 Subject: [PATCH] fix: accept bare state + event as an internal transition (#317) The row consumes the event with no action, exit or entry. --- include/boost/sml.hpp | 6 +- test/ft/CMakeLists.txt | 5 ++ .../ft/issue_317_bare_internal_transition.cpp | 65 +++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 test/ft/issue_317_bare_internal_transition.cpp diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index e4dfde27..bdff28f8 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -3167,13 +3167,13 @@ struct transition_sa, A> : transition, state, fron } }; template -struct transition, front::event> { +struct transition, front::event> : transition, state, front::event, always, none> { + constexpr transition(const state &, const front::event &) + : transition, state, front::event, always, none>{always{}, none{}} {} template constexpr auto operator=(const T &) const { return transition, front::event, always, none>{always{}, none{}}; } - const state &s2; - front::event e; }; template struct transition_eg, G> { diff --git a/test/ft/CMakeLists.txt b/test/ft/CMakeLists.txt index dc1d8393..7b4cf1e1 100644 --- a/test/ft/CMakeLists.txt +++ b/test/ft/CMakeLists.txt @@ -155,4 +155,9 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/issue_552_sub_sm_dep_identity.cpp) add_test(test_issue_552_sub_sm_dep_identity test_issue_552_sub_sm_dep_identity) endif() +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/issue_317_bare_internal_transition.cpp) + add_executable(test_issue_317_bare_internal_transition issue_317_bare_internal_transition.cpp) + add_test(test_issue_317_bare_internal_transition test_issue_317_bare_internal_transition) +endif() + add_subdirectory(errors) diff --git a/test/ft/issue_317_bare_internal_transition.cpp b/test/ft/issue_317_bare_internal_transition.cpp new file mode 100644 index 00000000..0be0be90 --- /dev/null +++ b/test/ft/issue_317_bare_internal_transition.cpp @@ -0,0 +1,65 @@ +// cppcheck-suppress missingIncludeSystem +#include + +namespace sml = boost::sml; + +namespace { +struct ignored {}; +struct leave {}; +struct come_back {}; + +struct counters { + int entries = 0; + int exits = 0; +}; +struct count_entry { + void operator()(counters &c) const { ++c.entries; } +}; +struct count_exit { + void operator()(counters &c) const { ++c.exits; } +}; + +const auto idle = sml::state; +const auto busy = sml::state; +} // namespace + +test bare_row_on_initial_state_consumes_event_without_exit_or_entry = [] { + struct c { + auto operator()() const noexcept { + using namespace sml; + return make_transition_table(*idle + event, idle + event = busy, busy + event = idle, + idle + sml::on_entry<_> / count_entry{}, idle + sml::on_exit<_> / count_exit{}); + } + }; + counters calls{}; + sml::sm sm{calls}; + expect(1 == calls.entries); + + expect(sm.process_event(ignored{})); + expect(sm.is(idle)); + expect(1 == calls.entries); + expect(0 == calls.exits); + + expect(!sm.process_event(come_back{})); + expect(sm.is(idle)); +}; + +test bare_row_on_non_initial_state_consumes_event_without_exit_or_entry = [] { + struct c { + auto operator()() const noexcept { + using namespace sml; + return make_transition_table(*idle + event = busy, busy + event, busy + sml::on_entry<_> / count_entry{}, + busy + sml::on_exit<_> / count_exit{}); + } + }; + counters calls{}; + sml::sm sm{calls}; + expect(sm.process_event(leave{})); + expect(sm.is(busy)); + expect(1 == calls.entries); + + expect(sm.process_event(ignored{})); + expect(sm.is(busy)); + expect(1 == calls.entries); + expect(0 == calls.exits); +};