2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-20 16:52:13 +00:00

Compare commits

..

4 Commits
1.0.1 ... 1.0.2

Author SHA1 Message Date
Antony Polukhin
0885412a7d MSVC test fix 2020-08-13 21:46:06 +03:00
Antony Polukhin
86ebac6e0c reproduced and fixed the "type without linkage" error 2020-08-13 20:38:22 +03:00
Antony Polukhin
39e9b4c5fe attempt to reproduce a "type without linkage" warning 2020-08-13 18:27:00 +03:00
Antony Polukhin
01fd8db5b4 fix warning and add more tests 2020-08-13 18:13:57 +03:00
13 changed files with 243 additions and 62 deletions

View File

@@ -49,4 +49,15 @@
# endif
#endif
#if defined(__has_cpp_attribute)
# if __has_cpp_attribute(maybe_unused)
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
# endif
#endif
#ifndef BOOST_PFR_MAYBE_UNUSED
# define BOOST_PFR_MAYBE_UNUSED
#endif
#endif // BOOST_PFR_DETAIL_CONFIG_HPP

View File

@@ -33,6 +33,7 @@
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
#include <boost/pfr/detail/unsafe_declval.hpp>
#ifdef __clang__
@@ -59,12 +60,6 @@ struct tag {
friend auto loophole(tag<T,N>);
};
// For returning non default constructible types. Never used at runtime! GCC's std::declval may not be used in potentionally evaluated contexts, so it does not work here.
template <class T> constexpr T& unsafe_declval_like() noexcept {
T* ptr = nullptr;
return *ptr;
}
// The definitions of friend functions.
template <class T, class U, std::size_t N, bool B>
struct fn_def_lref {
@@ -75,13 +70,13 @@ struct fn_def_lref {
// To workaround the issue, we check that the type U is movable, and move it in that case.
using no_extents_t = std::remove_all_extents_t<U>;
return static_cast< std::conditional_t<std::is_move_constructible<no_extents_t>::value, no_extents_t&&, no_extents_t&> >(
boost::pfr::detail::unsafe_declval_like<no_extents_t>()
boost::pfr::detail::unsafe_declval<no_extents_t&>()
);
}
};
template <class T, class U, std::size_t N, bool B>
struct fn_def_rref {
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval_like< std::remove_all_extents_t<U> >()); }
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval< std::remove_all_extents_t<U>& >()); }
};
@@ -193,7 +188,7 @@ decltype(auto) tie_or_value(T& val, std::enable_if_t<std::is_enum<std::remove_re
}
template <class T>
auto tie_or_value(T& val, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
auto tie_or_value(T& /*val*/, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
static_assert(
sizeof(T) && false,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."

View File

@@ -10,6 +10,7 @@
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/size_t_.hpp>
#include <boost/pfr/detail/unsafe_declval.hpp>
#include <climits> // CHAR_BIT
#include <type_traits>
@@ -28,13 +29,15 @@ namespace boost { namespace pfr { namespace detail {
///////////////////// Structure that can be converted to reference to anything
struct ubiq_lref_constructor {
std::size_t ignore;
template <class Type> /*constexpr*/ operator Type&() const noexcept; // Undefined, allows initialization of reference fields (T& and const T&)
template <class Type> constexpr operator Type&() const noexcept { // Allows initialization of reference fields (T& and const T&)
return detail::unsafe_declval<Type&>();
};
};
///////////////////// Structure that can be converted to rvalue reference to anything
struct ubiq_rref_constructor {
std::size_t ignore;
template <class Type> /*constexpr*/ operator Type&&() const noexcept; // Undefined, allows initialization of rvalue reference fields and move-only types
template <class Type> /*constexpr*/ operator Type&&() const noexcept {}; // Allows initialization of rvalue reference fields and move-only types
};

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2019-2020 Antony Polukhin.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
#define BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
namespace boost { namespace pfr { namespace detail {
// For returning non default constructible types. Never used at runtime! GCC's
// std::declval may not be used in potentionally evaluated contexts, so it does not work here.
template <class T> constexpr T unsafe_declval() noexcept {
typename std::remove_reference<T>::type* ptr = 0;
ptr += 42; // killing 'null pointer dereference' heuristics of static analysis tools
return static_cast<T>(*ptr);
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP

View File

@@ -54,26 +54,26 @@
/// std::size_t hash_value(const T& value) noexcept;
/// \endcode
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::flat_write(out, value); \
return out; \
} \
template <class Char, class Traits> \
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::flat_read(in, value); \
return in; \
} \
static inline std::size_t hash_value(const T& v) noexcept { \
return ::boost::pfr::flat_hash<T>{}(v); \
} \
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::flat_write(out, value); \
return out; \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::flat_read(in, value); \
return in; \
} \
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) noexcept { \
return ::boost::pfr::flat_hash<T>{}(v); \
} \
/**/
#endif // BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP

View File

@@ -52,26 +52,26 @@
/// std::size_t hash_value(const T& value);
/// \endcode
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::write(out, value); \
return out; \
} \
template <class Char, class Traits> \
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::read(in, value); \
return in; \
} \
static inline std::size_t hash_value(const T& v) { \
return ::boost::pfr::hash<T>{}(v); \
} \
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::write(out, value); \
return out; \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::read(in, value); \
return in; \
} \
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) { \
return ::boost::pfr::hash<T>{}(v); \
} \
/**/
#endif // BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2016-2019, Antony Polukhin.
# Copyright (C) 2016-2020, Antony Polukhin.
#
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -143,6 +143,7 @@ test-suite pfr
[ run precise/destructuring_tie.cpp : : : $(CLASSIC_PREC_DEF) : precise_destructuring_tie ]
[ run precise/error_pfr_c1202.cpp : : : $(CLASSIC_PREC_DEF) : precise_c1202_issue21 ]
[ compile-fail precise/non_aggregate.cpp : $(CLASSIC_PREC_DEF) : precise_non_aggregate ]
[ run precise/tie_anonymous.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_tie_anonymous ]
# See "Requirements and Limitations" section of the docs for info on following tests:
#[ compile-fail precise/template_constructor.cpp : $(CLASSIC_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_template_constructor14 ]
@@ -176,6 +177,7 @@ test-suite pfr
[ run precise/issue30.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue30 ]
[ run precise/issue33.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue33 ]
[ compile-fail precise/non_aggregate.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_non_aggregate ]
[ run precise/tie_anonymous.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_tie_anonymous ]
# See "Requirements and Limitations" section of the docs for info on following tests:
#[ compile-fail precise/template_constructor.cpp : $(LOOPHOLE_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_lh_template_constructor14 ]

View File

@@ -39,10 +39,11 @@ struct comparable_struct {
BOOST_PFR_TEST_FUNCTIONS_FOR(comparable_struct)
void test_comparable_struct() {
comparable_struct s1 {0, 1, false, 6,7,8,9,10,11};
comparable_struct s2 = s1;
comparable_struct s3 {0, 1, false, 6,7,8,9,10,11111};
template <typename Struct>
void test_some_comparable_struct() {
Struct s1 {0, 1, false, 6,7,8,9,10,11};
Struct s2 = s1;
Struct s3 {0, 1, false, 6,7,8,9,10,11111};
BOOST_TEST_EQ(s1, s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
@@ -56,7 +57,7 @@ void test_comparable_struct() {
std::cout << s1 << std::endl;
comparable_struct s4;
Struct s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
@@ -67,6 +68,10 @@ void test_comparable_struct() {
BOOST_TEST_NE(i, j);
}
void test_comparable_struct() {
test_some_comparable_struct<comparable_struct>();
}
struct empty { operator std::string() { return "empty{}"; } };
BOOST_PFR_TEST_FUNCTIONS_FOR(empty)
@@ -105,12 +110,58 @@ void test_implicit_conversions() {
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_TEST_FUNCTIONS_FOR
}
namespace {
struct anonymous_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(anonymous_comparable_struct)
struct other_anonymous_struct {
anonymous_comparable_struct a,b;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(other_anonymous_struct)
}
namespace std {
template <>
struct hash<anonymous_comparable_struct> {
std::size_t operator()(const anonymous_comparable_struct& val) const noexcept {
return hash_value(val);
}
};
}
namespace {
void test_anonymous_comparable_struct() {
test_some_comparable_struct<anonymous_comparable_struct>();
}
void test_nested_anonymous_comparable_struct() {
other_anonymous_struct s1{
{0, 1, false, 6,7,8,9,10,11},
{0, 1, false, 6,7,8,9,10,11},
};
auto s2 = s1;
BOOST_TEST_EQ(s1, s2);
}
}
int main() {
test_comparable_struct();
test_empty_struct();
test_with_contatiners<std::less<>>();
test_with_contatiners<std::greater<>>();
test_implicit_conversions();
test_anonymous_comparable_struct();
test_nested_anonymous_comparable_struct();
return boost::report_errors();
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -122,7 +122,5 @@ void test_counts_on_multiple_chars() {
int main() {
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
return 0;
}

View File

@@ -11,7 +11,7 @@ struct non_default_constructible {
T val_;
non_default_constructible() = delete;
template <class U> non_default_constructible(U&& v){}
template <class U> non_default_constructible(U&& /*v*/){}
};
struct Foo {

View File

@@ -11,7 +11,7 @@ struct optional_like {
T val_;
optional_like() = default;
template <class U> optional_like(U&& v){}
template <class U> optional_like(U&& /*v*/){}
};
struct Foo {

View File

@@ -0,0 +1,94 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <boost/pfr/precise/ops.hpp>
#include <string>
#if defined(__has_include)
# if __has_include(<optional>)
# include <optional>
# endif
#endif
namespace some {
struct struct1{ int i; };
struct struct2{ int i; };
}
namespace testing {
namespace {
#ifdef __cpp_lib_optional
struct anon_with_optional {
std::string a;
std::optional<some::struct1> b;
std::optional<some::struct2> c;
};
struct other_anon_with_optional {
std::string a;
int b;
std::optional<anon_with_optional> c;
std::optional<some::struct2> d;
};
#endif
struct other_anon {
int data;
};
struct anon {
other_anon a;
other_anon b;
};
void test_in_anon_ns() {
anon x{{1}, {2}};
auto v = boost::pfr::structure_tie(x);
BOOST_TEST_EQ(std::get<0>(v).data, 1);
BOOST_TEST_EQ(std::get<1>(v).data, 2);
#ifdef __cpp_lib_optional
other_anon_with_optional opt{"test"};
auto opt_val = boost::pfr::structure_tie(opt);
BOOST_TEST_EQ(std::get<0>(opt_val), "test");
#endif
}
} // anonymous namespace
void test_in_non_non_ns() {
anon x{{1}, {2}};
auto v = boost::pfr::structure_tie(x);
BOOST_TEST_EQ(std::get<0>(v).data, 1);
BOOST_TEST_EQ(std::get<1>(v).data, 2);
#ifdef __cpp_lib_optional
other_anon_with_optional opt{"test again"};
auto opt_val = boost::pfr::structure_tie(opt);
BOOST_TEST_EQ(std::get<0>(opt_val), "test again");
#endif
}
} // namespace testing
int main() {
testing::test_in_anon_ns();
testing::test_in_non_non_ns();
return boost::report_errors();
}