[libcxx] r273334 - Fix PR27684 - std::tuple no longer accepts reference to incomplete type in some cases.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 21 16:19:13 PDT 2016


Author: ericwf
Date: Tue Jun 21 18:19:13 2016
New Revision: 273334

URL: http://llvm.org/viewvc/llvm-project?rev=273334&view=rev
Log:
Fix PR27684 - std::tuple no longer accepts reference to incomplete type in some cases.

Libc++ has to deduce the 'allocator_arg_t' parameter as 'AllocArgT' for the
following constructor:

  template <class Alloc> tuple(allocator_arg_t, Alloc const&)

Previously libc++ has tried to support tags derived from 'allocator_arg_t' by
using 'is_base_of<AllocArgT, allocator_arg_t>'. However this breaks whenever a
2-tuple contains a reference to an incomplete type as its first parameter.

See https://llvm.org/bugs/show_bug.cgi?id=27684

Added:
    libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp
Modified:
    libcxx/trunk/include/tuple
    libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp

Modified: libcxx/trunk/include/tuple
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=273334&r1=273333&r2=273334&view=diff
==============================================================================
--- libcxx/trunk/include/tuple (original)
+++ libcxx/trunk/include/tuple Tue Jun 21 18:19:13 2016
@@ -662,7 +662,7 @@ public:
 
     template <class _AllocArgT, class _Alloc, bool _Dummy = true, class = typename enable_if<
         __lazy_and<
-            is_base_of<allocator_arg_t, _AllocArgT>,
+            is_same<allocator_arg_t, _AllocArgT>,
             __lazy_all<__dependent_type<is_default_constructible<_Tp>, _Dummy>...>
        >::value
     >::type>

Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp?rev=273334&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp Tue Jun 21 18:19:13 2016
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Alloc> tuple(allocator_arg_t, Alloc const&)
+
+// Libc++ has to deduce the 'allocator_arg_t' parameter for this constructor
+// as 'AllocArgT'. Previously libc++ has tried to support tags derived from
+// 'allocator_arg_t' by using 'is_base_of<AllocArgT, allocator_arg_t>'.
+// However this breaks whenever a 2-tuple contains a reference to an incomplete
+// type as its first parameter. See PR27684.
+
+#include <tuple>
+#include <cassert>
+
+struct IncompleteType;
+extern IncompleteType inc1;
+extern IncompleteType inc2;
+IncompleteType const& cinc1 = inc1;
+IncompleteType const& cinc2 = inc2;
+
+int main() {
+    using IT = IncompleteType;
+    { // try calling tuple(Tp const&...)
+        using Tup = std::tuple<const IT&, const IT&>;
+        Tup t(cinc1, cinc2);
+        assert(&std::get<0>(t) == &inc1);
+        assert(&std::get<1>(t) == &inc2);
+    }
+    { // try calling tuple(Up&&...)
+        using Tup = std::tuple<const IT&, const IT&>;
+        Tup t(inc1, inc2);
+        assert(&std::get<0>(t) == &inc1);
+        assert(&std::get<1>(t) == &inc2);
+    }
+}
+
+struct IncompleteType {};
+IncompleteType inc1;
+IncompleteType inc2;

Modified: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp?rev=273334&r1=273333&r2=273334&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp Tue Jun 21 18:19:13 2016
@@ -7,6 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: c++98, c++03
+
 // <tuple>
 
 // template <class... Types> class tuple;
@@ -14,7 +16,9 @@
 // template <class Alloc>
 //   tuple(allocator_arg_t, const Alloc& a);
 
-// UNSUPPORTED: c++98, c++03
+// NOTE: this constructor does not currently support tags derived from
+// allocator_arg_t because libc++ has to deduce the parameter as a template
+// argument. See PR27684 (https://llvm.org/bugs/show_bug.cgi?id=27684)
 
 #include <tuple>
 #include <cassert>
@@ -42,10 +46,6 @@ int main()
         std::tuple<> t(std::allocator_arg, A1<int>());
     }
     {
-        DerivedFromAllocArgT tag;
-        std::tuple<> t(tag, A1<int>());
-    }
-    {
         std::tuple<int> t(std::allocator_arg, A1<int>());
         assert(std::get<0>(t) == 0);
     }
@@ -95,21 +95,6 @@ int main()
         assert(std::get<2>(t) == alloc_last());
     }
     {
-        // Test that allocator construction is selected when the user provides
-        // a custom tag type which derives from allocator_arg_t.
-        DerivedFromAllocArgT tag;
-        alloc_first::allocator_constructed = false;
-        alloc_last::allocator_constructed = false;
-
-        std::tuple<DefaultOnly, alloc_first, alloc_last> t(tag, A1<int>(5));
-
-        assert(std::get<0>(t) == DefaultOnly());
-        assert(alloc_first::allocator_constructed);
-        assert(std::get<1>(t) == alloc_first());
-        assert(alloc_last::allocator_constructed);
-        assert(std::get<2>(t) == alloc_last());
-    }
-    {
         // Test that the uses-allocator default constructor does not evaluate
         // it's SFINAE when it otherwise shouldn't be selected. Do this by
         // using 'NonDefaultConstructible' which will cause a compile error




More information about the cfe-commits mailing list