summaryrefslogtreecommitdiffstats
path: root/test/std/utilities/tuple/tuple.tuple/tuple.cnstr
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2016-12-14 22:22:38 +0000
committerEric Fiselier <eric@efcs.ca>2016-12-14 22:22:38 +0000
commit18e56b438eefa0eb7f6019e876bf53bdcdf851ba (patch)
treef148490239387ae88772ac53efb3663e432ff0ef /test/std/utilities/tuple/tuple.tuple/tuple.cnstr
parenta793c18bae3b4d8b99b4659c2e752d94b19ef923 (diff)
downloadexternal_libcxx-18e56b438eefa0eb7f6019e876bf53bdcdf851ba.tar.gz
external_libcxx-18e56b438eefa0eb7f6019e876bf53bdcdf851ba.tar.bz2
external_libcxx-18e56b438eefa0eb7f6019e876bf53bdcdf851ba.zip
[libcxx] Fix tuple construction/assignment from types derived from tuple/pair/array.
Summary: The standard requires tuple have the following constructors: ``` tuple(tuple<OtherTypes...> const&); tuple(tuple<OtherTypes...> &&); tuple(pair<T1, T2> const&); tuple(pair<T1, T2> &&); tuple(array<T, N> const&); tuple(array<T, N> &&); ``` However libc++ implements these as a single constructor with the signature: ``` template <class TupleLike, enable_if_t<__is_tuple_like<TupleLike>::value>> tuple(TupleLike&&); ``` This causes the constructor to reject types derived from tuple-like types; Unlike if we had all of the concrete overloads, because they cause the derived->base conversion in the signature. This patch fixes this issue by detecting derived types and the tuple-like base they are derived from. It does this by creating an overloaded function with signatures for each of tuple/pair/array and checking if the possibly derived type can convert to any of them. This patch fixes [PR17550]( https://llvm.org/bugs/show_bug.cgi?id=17550) This patch Reviewers: mclow.lists, K-ballo, mpark, EricWF Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D27606 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@289727 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/std/utilities/tuple/tuple.tuple/tuple.cnstr')
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/derived_from_tuple_like.pass.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/derived_from_tuple_like.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/derived_from_tuple_like.pass.cpp
new file mode 100644
index 000000000..233a30881
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/derived_from_tuple_like.pass.cpp
@@ -0,0 +1,150 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class... UTypes>
+// tuple& operator=(const tuple<UTypes...>& u);
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <array>
+#include <string>
+#include <utility>
+#include <cassert>
+
+#include "propagate_value_category.hpp"
+
+template <bool Explicit = false>
+struct TracksIntQuals {
+ TracksIntQuals() : value(-1), value_category(VC_None), assigned(false) {}
+
+ template <
+ class Tp,
+ typename std::enable_if<Explicit &&
+ !std::is_same<typename std::decay<Tp>::type,
+ TracksIntQuals>::value,
+ bool>::type = false>
+ explicit TracksIntQuals(Tp &&x)
+ : value(x), value_category(getValueCategory<Tp &&>()), assigned(false) {
+ static_assert(std::is_same<UnCVRef<Tp>, int>::value, "");
+ }
+
+ template <
+ class Tp,
+ typename std::enable_if<!Explicit &&
+ !std::is_same<typename std::decay<Tp>::type,
+ TracksIntQuals>::value,
+ bool>::type = false>
+ TracksIntQuals(Tp &&x)
+ : value(x), value_category(getValueCategory<Tp &&>()), assigned(false) {
+ static_assert(std::is_same<UnCVRef<Tp>, int>::value, "");
+ }
+
+ template <class Tp,
+ class = typename std::enable_if<!std::is_same<
+ typename std::decay<Tp>::type, TracksIntQuals>::value>::type>
+ TracksIntQuals &operator=(Tp &&x) {
+ static_assert(std::is_same<UnCVRef<Tp>, int>::value, "");
+ value = x;
+ value_category = getValueCategory<Tp &&>();
+ assigned = true;
+ return *this;
+ }
+
+ void reset() {
+ value = -1;
+ value_category = VC_None;
+ assigned = false;
+ }
+
+ bool checkConstruct(int expect, ValueCategory expect_vc) const {
+ return value != 1 && value == expect && value_category == expect_vc &&
+ assigned == false;
+ }
+
+ bool checkAssign(int expect, ValueCategory expect_vc) const {
+ return value != 1 && value == expect && value_category == expect_vc &&
+ assigned == true;
+ }
+
+ int value;
+ ValueCategory value_category;
+ bool assigned;
+};
+
+template <class Tup>
+struct DerivedFromTup : Tup {
+ using Tup::Tup;
+};
+
+template <ValueCategory VC>
+void do_derived_construct_test() {
+ using Tup1 = std::tuple<long, TracksIntQuals</*Explicit*/ false>>;
+ {
+ DerivedFromTup<std::tuple<int, int>> d(42, 101);
+ Tup1 t = ValueCategoryCast<VC>(d);
+ assert(std::get<0>(t) == 42);
+ assert(std::get<1>(t).checkConstruct(101, VC));
+ }
+ {
+ DerivedFromTup<std::pair<int, int>> d(42, 101);
+ Tup1 t = ValueCategoryCast<VC>(d);
+ assert(std::get<0>(t) == 42);
+ assert(std::get<1>(t).checkConstruct(101, VC));
+ }
+ {
+ DerivedFromTup<std::array<int, 2>> d = {{{42, 101}}};
+ Tup1 t = ValueCategoryCast<VC>(d);
+ assert(std::get<0>(t) == 42);
+ assert(std::get<1>(t).checkConstruct(101, VC));
+ }
+
+ using Tup2 = std::tuple<long, TracksIntQuals</*Explicit*/ true>>;
+ {
+ using D = DerivedFromTup<std::tuple<int, int>>;
+ static_assert(!std::is_convertible<ApplyValueCategoryT<VC, D>, Tup2>::value,
+ "");
+ D d(42, 101);
+ Tup2 t(ValueCategoryCast<VC>(d));
+ assert(std::get<0>(t) == 42);
+ assert(std::get<1>(t).checkConstruct(101, VC));
+ }
+ {
+ using D = DerivedFromTup<std::pair<int, int>>;
+ static_assert(!std::is_convertible<ApplyValueCategoryT<VC, D>, Tup2>::value,
+ "");
+ D d(42, 101);
+ Tup2 t(ValueCategoryCast<VC>(d));
+ assert(std::get<0>(t) == 42);
+ assert(std::get<1>(t).checkConstruct(101, VC));
+ }
+ {
+ using D = DerivedFromTup<std::array<int, 2>>;
+ static_assert(!std::is_convertible<ApplyValueCategoryT<VC, D>, Tup2>::value,
+ "");
+ D d = {{{42, 101}}};
+ Tup2 t(ValueCategoryCast<VC>(d));
+ assert(std::get<0>(t) == 42);
+ assert(std::get<1>(t).checkConstruct(101, VC));
+ }
+}
+
+int main() {
+ do_derived_construct_test<VC_LVal | VC_Const>();
+ do_derived_construct_test<VC_RVal>();
+#if defined(_LIBCPP_VERSION)
+ // Supporting non-const copy and const move are libc++ extensions
+ do_derived_construct_test<VC_LVal>();
+ do_derived_construct_test<VC_RVal | VC_Const>();
+#endif
+}