304 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// <any>12 13// template <class ValueType>14// ValueType const any_cast(any const&);15//16// template <class ValueType>17// ValueType any_cast(any &);18//19// template <class ValueType>20// ValueType any_cast(any &&);21 22#include <any>23#include <type_traits>24#include <cassert>25 26#include "any_helpers.h"27#include "count_new.h"28#include "test_macros.h"29 30// Test that the operators are NOT marked noexcept.31void test_cast_is_not_noexcept() {32 std::any a;33 static_assert(!noexcept(std::any_cast<int>(static_cast<std::any&>(a))), "");34 static_assert(!noexcept(std::any_cast<int>(static_cast<std::any const&>(a))), "");35 static_assert(!noexcept(std::any_cast<int>(static_cast<std::any&&>(a))), "");36}37 38// Test that the return type of any_cast is correct.39void test_cast_return_type() {40 std::any a;41 static_assert(std::is_same<decltype(std::any_cast<int>(a)), int>::value, "");42 static_assert(std::is_same<decltype(std::any_cast<int const>(a)), int>::value, "");43 static_assert(std::is_same<decltype(std::any_cast<int&>(a)), int&>::value, "");44 static_assert(std::is_same<decltype(std::any_cast<int const&>(a)), int const&>::value, "");45 static_assert(std::is_same<decltype(std::any_cast<int&&>(a)), int&&>::value, "");46 static_assert(std::is_same<decltype(std::any_cast<int const&&>(a)), int const&&>::value, "");47 48 static_assert(std::is_same<decltype(std::any_cast<int>(std::move(a))), int>::value, "");49 static_assert(std::is_same<decltype(std::any_cast<int const>(std::move(a))), int>::value, "");50 static_assert(std::is_same<decltype(std::any_cast<int&>(std::move(a))), int&>::value, "");51 static_assert(std::is_same<decltype(std::any_cast<int const&>(std::move(a))), int const&>::value, "");52 static_assert(std::is_same<decltype(std::any_cast<int&&>(std::move(a))), int&&>::value, "");53 static_assert(std::is_same<decltype(std::any_cast<int const&&>(std::move(a))), int const&&>::value, "");54 55 const std::any& ca = a;56 static_assert(std::is_same<decltype(std::any_cast<int>(ca)), int>::value, "");57 static_assert(std::is_same<decltype(std::any_cast<int const>(ca)), int>::value, "");58 static_assert(std::is_same<decltype(std::any_cast<int const&>(ca)), int const&>::value, "");59 static_assert(std::is_same<decltype(std::any_cast<int const&&>(ca)), int const&&>::value, "");60}61 62template <class Type, class ConstT = Type>63void checkThrows(std::any& a) {64#if !defined(TEST_HAS_NO_EXCEPTIONS)65 try {66 TEST_IGNORE_NODISCARD std::any_cast<Type>(a);67 assert(false);68 } catch (const std::bad_any_cast&) {69 // do nothing70 } catch (...) {71 assert(false);72 }73 74 try {75 TEST_IGNORE_NODISCARD std::any_cast<ConstT>(static_cast<const std::any&>(a));76 assert(false);77 } catch (const std::bad_any_cast&) {78 // do nothing79 } catch (...) {80 assert(false);81 }82 83 try {84 using RefType = typename std::85 conditional< std::is_lvalue_reference<Type>::value, typename std::remove_reference<Type>::type&&, Type >::type;86 TEST_IGNORE_NODISCARD std::any_cast<RefType>(static_cast<std::any&&>(a));87 assert(false);88 } catch (const std::bad_any_cast&) {89 // do nothing90 } catch (...) {91 assert(false);92 }93#else94 (TEST_IGNORE_NODISCARD a);95#endif96}97 98void test_cast_empty() {99 // None of these operations should allocate.100 DisableAllocationGuard g;101 (TEST_IGNORE_NODISCARD g);102 std::any a;103 checkThrows<int>(a);104}105 106template <class Type>107void test_cast_to_reference() {108 assert(Type::count == 0);109 Type::reset();110 {111 std::any a = Type(42);112 const std::any& ca = a;113 assert(Type::count == 1);114 assert(Type::copied == 0);115 assert(Type::moved == 1);116 117 // Try a cast to a bad type.118 // NOTE: Type cannot be an int.119 checkThrows<int>(a);120 checkThrows<int&, int const&>(a);121 checkThrows<Type*, Type const*>(a);122 checkThrows<Type const*>(a);123 124 // Check getting a type by reference from a non-const lvalue any.125 {126 Type& v = std::any_cast<Type&>(a);127 assert(v.value == 42);128 129 Type const& cv = std::any_cast<Type const&>(a);130 assert(&cv == &v);131 }132 // Check getting a type by reference from a const lvalue any.133 {134 Type const& v = std::any_cast<Type const&>(ca);135 assert(v.value == 42);136 137 Type const& cv = std::any_cast<Type const&>(ca);138 assert(&cv == &v);139 }140 // Check getting a type by reference from a const rvalue any.141 {142 Type const& v = std::any_cast<Type const&>(std::move(ca));143 assert(v.value == 42);144 145 Type const& cv = std::any_cast<Type const&>(std::move(ca));146 assert(&cv == &v);147 }148 // Check getting a type by reference from a const rvalue any.149 {150 Type&& v = std::any_cast<Type&&>(std::move(a));151 assert(v.value == 42);152 assert(std::any_cast<Type&>(a).value == 42);153 154 Type&& cv = std::any_cast<Type&&>(std::move(a));155 assert(&cv == &v);156 assert(std::any_cast<Type&>(a).value == 42);157 }158 // Check getting a type by reference from a const rvalue any.159 {160 Type const&& v = std::any_cast<Type const&&>(std::move(a));161 assert(v.value == 42);162 assert(std::any_cast<Type&>(a).value == 42);163 164 Type const&& cv = std::any_cast<Type const&&>(std::move(a));165 assert(&cv == &v);166 assert(std::any_cast<Type&>(a).value == 42);167 }168 // Check that the original object hasn't been changed.169 assertContains<Type>(a, 42);170 171 // Check that no objects have been created/copied/moved.172 assert(Type::count == 1);173 assert(Type::copied == 0);174 assert(Type::moved == 1);175 }176 assert(Type::count == 0);177}178 179template <class Type>180void test_cast_to_value() {181 assert(Type::count == 0);182 Type::reset();183 {184 std::any a = Type(42);185 assert(Type::count == 1);186 assert(Type::copied == 0);187 assert(Type::moved == 1);188 189 // Try a cast to a bad type.190 // NOTE: Type cannot be an int.191 checkThrows<int>(a);192 checkThrows<int&, int const&>(a);193 checkThrows<Type*, Type const*>(a);194 checkThrows<Type const*>(a);195 196 Type::reset(); // NOTE: reset does not modify Type::count197 // Check getting Type by value from a non-const lvalue any.198 // This should cause the non-const copy constructor to be called.199 {200 Type t = std::any_cast<Type>(a);201 202 assert(Type::count == 2);203 assert(Type::copied == 1);204 assert(Type::const_copied == 0);205 assert(Type::non_const_copied == 1);206 assert(Type::moved == 0);207 assert(t.value == 42);208 }209 assert(Type::count == 1);210 Type::reset();211 // Check getting const Type by value from a non-const lvalue any.212 // This should cause the const copy constructor to be called.213 {214 Type t = std::any_cast<Type const>(a);215 216 assert(Type::count == 2);217 assert(Type::copied == 1);218 assert(Type::const_copied == 0);219 assert(Type::non_const_copied == 1);220 assert(Type::moved == 0);221 assert(t.value == 42);222 }223 assert(Type::count == 1);224 Type::reset();225 // Check getting Type by value from a non-const lvalue any.226 // This should cause the const copy constructor to be called.227 {228 Type t = std::any_cast<Type>(static_cast<const std::any&>(a));229 230 assert(Type::count == 2);231 assert(Type::copied == 1);232 assert(Type::const_copied == 1);233 assert(Type::non_const_copied == 0);234 assert(Type::moved == 0);235 assert(t.value == 42);236 }237 assert(Type::count == 1);238 Type::reset();239 // Check getting Type by value from a non-const rvalue any.240 // This should cause the non-const copy constructor to be called.241 {242 Type t = std::any_cast<Type>(static_cast<std::any&&>(a));243 244 assert(Type::count == 2);245 assert(Type::moved == 1);246 assert(Type::copied == 0);247 assert(Type::const_copied == 0);248 assert(Type::non_const_copied == 0);249 assert(t.value == 42);250 assert(std::any_cast<Type&>(a).value == 0);251 std::any_cast<Type&>(a).value = 42; // reset the value252 }253 assert(Type::count == 1);254 Type::reset();255 // Check getting const Type by value from a non-const rvalue any.256 // This should cause the const copy constructor to be called.257 {258 Type t = std::any_cast<Type const>(static_cast<std::any&&>(a));259 260 assert(Type::count == 2);261 assert(Type::copied == 0);262 assert(Type::const_copied == 0);263 assert(Type::non_const_copied == 0);264 assert(Type::moved == 1);265 assert(t.value == 42);266 assert(std::any_cast<Type&>(a).value == 0);267 std::any_cast<Type&>(a).value = 42; // reset the value268 }269 assert(Type::count == 1);270 Type::reset();271 // Check getting Type by value from a const rvalue any.272 // This should cause the const copy constructor to be called.273 {274 Type t = std::any_cast<Type>(static_cast<const std::any&&>(a));275 276 assert(Type::count == 2);277 assert(Type::copied == 1);278 assert(Type::const_copied == 1);279 assert(Type::non_const_copied == 0);280 assert(Type::moved == 0);281 assert(t.value == 42);282 assert(std::any_cast<Type&>(a).value == 42);283 }284 // Ensure we still only have 1 Type object alive.285 assert(Type::count == 1);286 287 // Check that the original object hasn't been changed.288 assertContains<Type>(a, 42);289 }290 assert(Type::count == 0);291}292 293int main(int, char**) {294 test_cast_is_not_noexcept();295 test_cast_return_type();296 test_cast_empty();297 test_cast_to_reference<small>();298 test_cast_to_reference<large>();299 test_cast_to_value<small>();300 test_cast_to_value<large>();301 302 return 0;303}304