diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e395f5..d888ad1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,9 +25,16 @@ target_include_directories( target_compile_features(refl-cpp INTERFACE cxx_std_17) if (MSVC) - add_compile_options(/W4) + add_compile_options(/W4 /WX) else() - add_compile_options(-Wall -Wextra -pedantic) + add_compile_options(-Wall -Wextra -pedantic -Wconversion) + if ( NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "8.0") ) + add_compile_options(-pedantic-errors -Werror) + endif() + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "6.0") + # old versions of clang do not recognize invalid missing braces with templated code + add_compile_options(-Wno-missing-braces) + endif() endif() # ---- Install ---- diff --git a/bench/bench-large-pod-search.cpp b/bench/bench-large-pod-search.cpp index fe31cd8..aebdf0d 100644 --- a/bench/bench-large-pod-search.cpp +++ b/bench/bench-large-pod-search.cpp @@ -23,7 +23,7 @@ void ProcessClass() { if constexpr (refl::descriptor::is_writable(member)) { - auto reader = refl::descriptor::get_reader(member); + auto reader [[maybe_unused]] = refl::descriptor::get_reader(member); // etc. } else if constexpr (! refl::descriptor::has_writer(member)) diff --git a/bench/bench-large-pod.cpp b/bench/bench-large-pod.cpp index 6a02291..dd371cb 100644 --- a/bench/bench-large-pod.cpp +++ b/bench/bench-large-pod.cpp @@ -20,7 +20,7 @@ void ProcessClass() { if constexpr (refl::descriptor::is_writable(member)) { - auto reader = refl::descriptor::get_reader(member); + auto reader [[maybe_unused]] = refl::descriptor::get_reader(member); // etc. } else if constexpr (! refl::descriptor::has_writer(member)) diff --git a/examples/example-custom-rtti.cpp b/examples/example-custom-rtti.cpp index 5830372..fc1bc1a 100644 --- a/examples/example-custom-rtti.cpp +++ b/examples/example-custom-rtti.cpp @@ -109,7 +109,7 @@ int main() { FirstPersonController fpc; Pawn& pawn = fpc; // refer through parent type - const TypeInfo& pawnTypeInfo = pawn.GetTypeInfo(); // get custom type info + const TypeInfo& pawnTypeInfo [[maybe_unused]] = pawn.GetTypeInfo(); // get custom type info // access the name through our TypeInfo object assert(pawnTypeInfo.Name() == "FirstPersonController"); diff --git a/examples/example-dao.cpp b/examples/example-dao.cpp index f7fcc53..4ea6328 100644 --- a/examples/example-dao.cpp +++ b/examples/example-dao.cpp @@ -52,7 +52,7 @@ REFL_AUTO( type(User, Table{"Users"}), field(id, Column{"ID", DataType::ID}), field(email, Column{"Email", DataType::TEXT}) -); +) template constexpr auto make_sql_field_spec(Member) diff --git a/examples/example-partials.cpp b/examples/example-partials.cpp index e260fc6..57111a8 100644 --- a/examples/example-partials.cpp +++ b/examples/example-partials.cpp @@ -56,7 +56,7 @@ class partial : public refl::runtime::proxy, T> template auto& get() { - constexpr size_t idx = refl::trait::index_of_v; + constexpr auto idx = refl::trait::index_of_v; static_assert(idx != -1); return refl::util::get(data); } @@ -64,7 +64,7 @@ class partial : public refl::runtime::proxy, T> template const auto& get() const { - constexpr size_t idx = refl::trait::index_of_v; + constexpr auto idx = refl::trait::index_of_v; static_assert(idx != -1); return refl::util::get(data); } diff --git a/examples/example-proxy.cpp b/examples/example-proxy.cpp index 7c0945f..f40538e 100644 --- a/examples/example-proxy.cpp +++ b/examples/example-proxy.cpp @@ -99,7 +99,7 @@ using User = value_proxy; int main() { - User user{{ 10 }}; + User user{{ 10, {} }}; assert(user.id() == 10); // user.id(10) // fails with a static assertion (is_writable(member)) diff --git a/examples/example-struct-of-arrays.cpp b/examples/example-struct-of-arrays.cpp index 475337e..abe5fdb 100644 --- a/examples/example-struct-of-arrays.cpp +++ b/examples/example-struct-of-arrays.cpp @@ -1,6 +1,7 @@ #include "refl.hpp" #include #include +#include /********************************/ template @@ -22,13 +23,13 @@ struct struct_of_arrays : refl::runtime::proxy, std::remove_ using readable_members = readable_member_list>; static_assert(readable_members::size > 0, "Type has no fields!"); - struct_of_arrays(size_t capacity = 4) + struct_of_arrays() { } void push_back(const T& value) { - for_each(readable_members {}, [&](auto member, size_t index) { + for_each(readable_members {}, [&](auto member) { constexpr auto i = refl::trait::index_of_v; std::get(storage_).push_back(member(value)); }); @@ -42,15 +43,6 @@ struct struct_of_arrays : refl::runtime::proxy, std::remove_ }); } - T at(size_t index) const - { - T t{}; - for_each(readable_members{}, [&](auto member) { - constexpr auto i = refl::trait::index_of_v; - std::get(storage_).pop_back(); - }); - } - template auto& operator[](Member) { @@ -103,6 +95,10 @@ const auto& get(const struct_of_arrays& soa) return soa[member{}]; } +#if defined(__clang__) || (defined(__GNUG__) && __GNUC__ >= 10) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmismatched-tags" +#endif namespace std { template @@ -118,6 +114,9 @@ namespace std using type = decltype(std::declval>()[descriptor{}]); }; } +#if defined(__clang__) || (defined(__GNUG__) && __GNUC__ >= 10) +#pragma GCC diagnostic pop +#endif /********************************/ @@ -164,6 +163,9 @@ int main() std::cout << "size=" << colors.size() << "\n"; for (size_t i = 0; i < colors.size(); i++) { + assert(red_chan[i] == colors.red(i)); + assert(green_chan[i] == colors.green(i)); + assert(blue_chan[i] == colors.blue(i)); std::cout << "r=" << red_chan[i] << ",g=" << green_chan[i] << ",b=" << blue_chan[i] << "\n"; } } diff --git a/include/refl.hpp b/include/refl.hpp index fd51739..0a93eec 100644 --- a/include/refl.hpp +++ b/include/refl.hpp @@ -58,9 +58,15 @@ namespace std #endif -#ifdef _MSC_VER -// Disable VS warning for "Not enough arguments for macro" -// (emitted when a REFL_ macro is not provided any attributes) +// Disable warnings about non-conformant variadic macros +// There isn't any real standards compliant fix before c++20 + +// Note that gcc doesn't have a way to disable these warnings specifically, +// but they don't triggered for gnu variants of the standards (which CMake uses +// by default) with recent versions of the compiler. +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#elif defined(_MSC_VER) #pragma warning( disable : 4003 ) #endif @@ -2621,10 +2627,10 @@ namespace refl * \endcode */ template - constexpr auto get_name(Descriptor d) noexcept + constexpr auto const& get_name(Descriptor) noexcept { static_assert(trait::is_descriptor_v); - return d.name; + return Descriptor::name; } /** @@ -2638,10 +2644,10 @@ namespace refl * \endcode */ template - constexpr const auto& get_attributes(Descriptor d) noexcept + constexpr const auto& get_attributes(Descriptor) noexcept { static_assert(trait::is_descriptor_v); - return d.attributes; + return Descriptor::attributes; } /** @@ -2655,10 +2661,10 @@ namespace refl * \endcode */ template - constexpr auto get_attribute_types(Descriptor d) noexcept + constexpr auto get_attribute_types(Descriptor) noexcept { static_assert(trait::is_descriptor_v); - return trait::as_type_list_t>{}; + return trait::as_type_list_t>{}; } /** @@ -2678,10 +2684,10 @@ namespace refl * \endcode */ template - constexpr auto get_declared_base_types(TypeDescriptor t) noexcept + constexpr auto const& get_declared_base_types(TypeDescriptor) noexcept { static_assert(trait::is_type_v); - return t.declared_bases; + return TypeDescriptor::declared_bases; } /** @@ -2701,10 +2707,10 @@ namespace refl * \endcode */ template - constexpr auto get_base_types(TypeDescriptor t) noexcept + constexpr auto const& get_base_types(TypeDescriptor) noexcept { static_assert(trait::is_type_v); - return t.bases; + return TypeDescriptor::bases; } /** @@ -2722,10 +2728,10 @@ namespace refl * \endcode */ template - constexpr auto get_declared_members(TypeDescriptor t) noexcept + constexpr auto const& get_declared_members(TypeDescriptor) noexcept { static_assert(trait::is_type_v); - return t.declared_members; + return TypeDescriptor::declared_members; } /** @@ -2743,10 +2749,10 @@ namespace refl * \endcode */ template - constexpr auto get_members(TypeDescriptor t) noexcept + constexpr auto const& get_members(TypeDescriptor) noexcept { static_assert(trait::is_type_v); - return t.members; + return TypeDescriptor::members; } /** @@ -2761,10 +2767,10 @@ namespace refl * \endcode */ template - constexpr auto get_declarator(MemberDescriptor d) noexcept + constexpr auto const& get_declarator(MemberDescriptor) noexcept { static_assert(trait::is_member_v); - return d.declarator; + return MemberDescriptor::declarator; } /** @@ -2786,10 +2792,10 @@ namespace refl * \endcode */ template - constexpr auto get_pointer(MemberDescriptor d) noexcept + constexpr auto const& get_pointer(MemberDescriptor) noexcept { static_assert(trait::is_member_v); - return d.pointer; + return MemberDescriptor::pointer; } /** @@ -2829,10 +2835,10 @@ namespace refl * \endcode */ template - constexpr auto is_static(FieldDescriptor d) noexcept + constexpr auto const& is_static(FieldDescriptor) noexcept { static_assert(trait::is_field_v); - return d.is_static; + return FieldDescriptor::is_static; } /** @@ -2849,10 +2855,10 @@ namespace refl * \endcode */ template - constexpr auto is_const(FieldDescriptor d) noexcept + constexpr auto is_const(FieldDescriptor) noexcept { static_assert(trait::is_field_v); - return d.is_const; + return FieldDescriptor::is_const; } /** @@ -2877,10 +2883,10 @@ namespace refl * \endcode */ template - constexpr auto is_resolved(FunctionDescriptor d) noexcept + constexpr auto const& is_resolved(FunctionDescriptor) noexcept { static_assert(trait::is_function_v); - return d.is_resolved; + return FunctionDescriptor::is_resolved; } /** @@ -2899,10 +2905,10 @@ namespace refl * \endcode */ template - constexpr auto can_resolve(FunctionDescriptor d) noexcept + constexpr auto can_resolve(FunctionDescriptor) noexcept { static_assert(trait::is_function_v); - return d.template can_resolve(); + return FunctionDescriptor::template can_resolve(); } /** @@ -2920,10 +2926,10 @@ namespace refl * \endcode */ template - constexpr auto resolve(FunctionDescriptor d) noexcept + constexpr auto resolve(FunctionDescriptor) noexcept { static_assert(trait::is_function_v); - return d.template resolve(); + return FunctionDescriptor::template resolve(); } /** @@ -3018,10 +3024,10 @@ namespace refl * \endcode */ template - constexpr const A& get_attribute(Descriptor d) noexcept + constexpr const A& get_attribute(Descriptor) noexcept { static_assert(trait::is_descriptor_v); - return util::get(d.attributes); + return util::get(Descriptor::attributes); } /** @@ -3033,10 +3039,10 @@ namespace refl * \endcode */ template typename A, typename Descriptor> - constexpr const auto& get_attribute(Descriptor d) noexcept + constexpr const auto& get_attribute(Descriptor) noexcept { static_assert(trait::is_descriptor_v); - return util::get_instance(d.attributes); + return util::get_instance(Descriptor::attributes); } /** @@ -3181,8 +3187,14 @@ namespace refl [[deprecated]] constexpr auto get_bases(TypeDescriptor t) noexcept { static_assert(trait::is_type_v); +#ifdef __GNUG__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif static_assert(has_bases(t), "Target type does not have a bases attribute."); - +#ifdef __GNUG__ +#pragma GCC diagnostic pop +#endif constexpr auto bases = get_attribute(t); using base_types = typename decltype(bases)::list_type; return trait::map_t{}; @@ -3196,16 +3208,16 @@ namespace refl * \endcode */ template - constexpr auto get_simple_name(TypeDescriptor t) + constexpr auto get_simple_name(TypeDescriptor) { static_assert(trait::is_type_v); - constexpr size_t template_start = t.name.find('<'); - constexpr size_t scope_last = t.name.rfind(':', template_start); + constexpr size_t template_start = TypeDescriptor::name.find('<'); + constexpr size_t scope_last = TypeDescriptor::name.rfind(':', template_start); if constexpr (scope_last == const_string<0>::npos) { - return t.name; + return TypeDescriptor::name; } else { - return t.name.template substr(); + return TypeDescriptor::name.template substr(); } } @@ -3218,10 +3230,10 @@ namespace refl * \endcode */ template - constexpr auto get_debug_name_const(MemberDescriptor d) + constexpr auto get_debug_name_const(MemberDescriptor) { static_assert(trait::is_member_v); - return d.declarator.name + "::" + d.name; + return MemberDescriptor::declarator.name + "::" + MemberDescriptor::name; } /** diff --git a/test/050-Attributes.hpp b/test/050-Attributes.hpp index 93b3974..ae066c8 100644 --- a/test/050-Attributes.hpp +++ b/test/050-Attributes.hpp @@ -103,9 +103,20 @@ TEST_CASE( "attributes" ) { } SECTION( "built-in attributes" ) { - SECTION( "bases<>" ) { +#if defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#elif defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4996 ) +#endif using bases_t = decltype(get_bases(reflect())); +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning( pop ) +#endif REQUIRE( bases_t::size == 1 ); REQUIRE( std::is_same_v::type, Base> ); } diff --git a/test/060-Utils.hpp b/test/060-Utils.hpp index c0ac15a..940bc00 100644 --- a/test/060-Utils.hpp +++ b/test/060-Utils.hpp @@ -48,7 +48,7 @@ TEST_CASE( "utilities" ) { // Do nothing. }); - std::array fe{}; + std::array fe{}; util::for_each(type_list{}, [&](auto, size_t i) { fe[i] = i; }); @@ -63,7 +63,7 @@ TEST_CASE( "utilities" ) { } SECTION( "count_if" ) { - constexpr int cnt = util::count_if(type_list{}, [](auto x) { + constexpr auto cnt = util::count_if(type_list{}, [](auto x) { return std::is_integral_v; }); REQUIRE( cnt == 1 );