]> gcc.gnu.org Git - gcc.git/commitdiff
PR libstdc++/90220 Fix std::any_cast for array types
authorJonathan Wakely <jwakely@redhat.com>
Wed, 24 Apr 2019 15:17:43 +0000 (16:17 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 24 Apr 2019 15:17:43 +0000 (16:17 +0100)
Although the std::any constructors use decay_t to determine the type of
the contained value, std::any_cast should use the un-decayed type (and
so always fail for function and array types that decay to pointers).

Using remove_cv_t is correct, because the condition for std::any_cast
to return non-null is operand.type() == typeid(T) and typeid ignores
top-level cv-qualifiers.

PR libstdc++/90220
* include/std/any (__any_caster): Use remove_cv_t instead of decay_t.
Avoid a runtime check for types that can never be stored in std::any.
* testsuite/20_util/any/misc/any_cast.cc: Test std::any_cast with
array types.

From-SVN: r270547

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/any
libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc

index 8be3dcc860b9100a50c82f45e7ad8cdeb7bbf97e..2ab686ba3bb346ae8a7ea2c9659b027f59135aea 100644 (file)
@@ -1,5 +1,11 @@
 2019-04-24  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/90220
+       * include/std/any (__any_caster): Use remove_cv_t instead of decay_t.
+       Avoid a runtime check for types that can never be stored in std::any.
+       * testsuite/20_util/any/misc/any_cast.cc: Test std::any_cast with
+       array types.
+
        PR libstdc++/90220 (partial)
        * include/std/any (any_cast<T>(any*), any_cast<T>(const any*)): Do
        not attempt ill-formed static_cast to pointers to non-object types.
index 792db27b061e7e3d9734b41d0cce7de48dc24f0d..29fe03e2b82a5f562d7bd9fdeb5ea27c04ac424b 100644 (file)
@@ -506,14 +506,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     void* __any_caster(const any* __any)
     {
-      if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
+      // any_cast<T> returns non-null if __any->type() == typeid(T) and
+      // typeid(T) ignores cv-qualifiers so remove them:
+      using _Up = remove_cv_t<_Tp>;
+      // The contained value has a decayed type, so if decay_t<U> is not U,
+      // then it's not possible to have a contained value of type U:
+      if constexpr (!is_same_v<decay_t<_Up>, _Up>)
+       return nullptr;
+      // Only copy constructible types can be used for contained values:
+      else if constexpr (!is_copy_constructible_v<_Up>)
+       return nullptr;
+      // This check is equivalent to __any->type() == typeid(_Tp)
+      else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage)
        {
-         if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
-           {
-             any::_Arg __arg;
-             __any->_M_manager(any::_Op_access, __any, &__arg);
-             return __arg._M_obj;
-           }
+         any::_Arg __arg;
+         __any->_M_manager(any::_Op_access, __any, &__arg);
+         return __arg._M_obj;
        }
       return nullptr;
     }
index c9aeaae336684d3f46b1f3c71330016a57f743d8..b7fbbc5ee9503766ed2e73e2a7798c12cf340aee 100644 (file)
@@ -154,6 +154,22 @@ void test06()
   }
 }
 
+void test07()
+{
+  int arr[3];
+  any a(arr);
+  VERIFY( a.type() == typeid(int*) );  // contained value is decayed
+
+  int (*p1)[3] = any_cast<int[3]>(&a);
+  VERIFY( a.type() != typeid(int[3]) ); // so any_cast should return nullptr
+  VERIFY( p1 == nullptr );
+  int (*p2)[] = any_cast<int[]>(&a);
+  VERIFY( a.type() != typeid(int[]) ); // so any_cast should return nullptr
+  VERIFY( p2 == nullptr );
+  const int (*p3)[] = any_cast<int[]>(&std::as_const(a));
+  VERIFY( p3 == nullptr );
+}
+
 int main()
 {
   test01();
@@ -162,4 +178,5 @@ int main()
   test04();
   test05();
   test06();
+  test07();
 }
This page took 0.069512 seconds and 5 git commands to generate.