From 5703f608d7d0074aebb57996f68df7f25f655a97 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Fri, 24 Apr 2026 09:02:27 -0600 Subject: [PATCH] [wpiutil] Struct: fix is_constexpr check in constexpr functions (#8798) Capturing the info parameter pack explicitly is required for the is_constexpr check to work. Add some basic tests. Fixes #8789. --- .../native/include/wpi/util/struct/Struct.hpp | 8 +-- .../src/test/native/cpp/struct/StructTest.cpp | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 wpiutil/src/test/native/cpp/struct/StructTest.cpp diff --git a/wpiutil/src/main/native/include/wpi/util/struct/Struct.hpp b/wpiutil/src/main/native/include/wpi/util/struct/Struct.hpp index ea3ab28950..c290e9312e 100644 --- a/wpiutil/src/main/native/include/wpi/util/struct/Struct.hpp +++ b/wpiutil/src/main/native/include/wpi/util/struct/Struct.hpp @@ -314,7 +314,7 @@ template constexpr auto GetStructTypeString(const I&... info) { using S = Struct...>; if constexpr (sizeof...(I) == 0 && - is_constexpr([&] { S::GetTypeName(info...); })) { + is_constexpr([&info...] { S::GetTypeName(info...); })) { constexpr auto typeName = S::GetTypeName(info...); using namespace literals; return Concat( @@ -344,7 +344,7 @@ template constexpr auto MakeStructArrayTypeName(const I&... info) { using S = Struct...>; if constexpr (sizeof...(I) == 0 && - is_constexpr([&] { S::GetTypeName(info...); })) { + is_constexpr([&info...] { S::GetTypeName(info...); })) { constexpr auto typeName = S::GetTypeName(info...); using namespace literals; if constexpr (N == std::dynamic_extent) { @@ -370,7 +370,7 @@ template constexpr auto MakeStructArrayTypeString(const I&... info) { using S = Struct...>; if constexpr (sizeof...(I) == 0 && - is_constexpr([&] { S::GetTypeName(info...); })) { + is_constexpr([&info...] { S::GetTypeName(info...); })) { using namespace literals; return Concat("struct:"_ct_string, MakeStructArrayTypeName(info...)); } else { @@ -383,7 +383,7 @@ template constexpr auto MakeStructArraySchema(const I&... info) { using S = Struct...>; if constexpr (sizeof...(I) == 0 && - is_constexpr([&] { S::GetSchema(info...); })) { + is_constexpr([&info...] { S::GetSchema(info...); })) { constexpr auto schema = S::GetSchema(info...); using namespace literals; if constexpr (N == std::dynamic_extent) { diff --git a/wpiutil/src/test/native/cpp/struct/StructTest.cpp b/wpiutil/src/test/native/cpp/struct/StructTest.cpp new file mode 100644 index 0000000000..87567baa7d --- /dev/null +++ b/wpiutil/src/test/native/cpp/struct/StructTest.cpp @@ -0,0 +1,66 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include "wpi/util/struct/Struct.hpp" + +#include + +#include +#include +#include + +#include + +using namespace wpi::util; + +static_assert(StructSerializable); +static_assert(StructSerializable>); +static_assert(!StructSerializable>); +static_assert(!StructSerializable); + +namespace { +struct TestStruct { + int32_t a; + int32_t b; +}; +} // namespace + +template <> +struct wpi::util::Struct { + static constexpr std::string_view GetTypeName() { return "TestStruct"; } + static constexpr size_t GetSize() { return 8; } + static constexpr std::string_view GetSchema() { return "int32 a;int32 b"; } + static TestStruct Unpack(std::span data) { + return {wpi::util::UnpackStruct(data), + wpi::util::UnpackStruct(data)}; + } + static void Pack(std::span data, TestStruct value) { + wpi::util::PackStruct<0>(data, value.a); + wpi::util::PackStruct<4>(data, value.b); + } +}; + +TEST(StructTest, Basic) { + constexpr auto typeName = GetStructTypeName(); + EXPECT_EQ(typeName, "TestStruct"); + + constexpr auto typeString = GetStructTypeString(); + EXPECT_EQ(typeString, "struct:TestStruct"); + + constexpr auto schema = GetStructSchema(); + EXPECT_EQ(schema, "int32 a;int32 b"); + + constexpr auto arrayTypeName = MakeStructArrayTypeName(); + EXPECT_EQ(arrayTypeName, "TestStruct[5]"); + + constexpr auto arrayTypeString = MakeStructArrayTypeString(); + EXPECT_EQ(arrayTypeString, "struct:TestStruct[5]"); + + TestStruct s{12345, 67890}; + std::array data; + Struct::Pack(data, s); + auto s2 = Struct::Unpack(data); + EXPECT_EQ(s.a, s2.a); + EXPECT_EQ(s.b, s2.b); +}