1*5ba1f45fSchristos /* Copyright (C) 2022-2024 Free Software Foundation, Inc. 24b169a6bSchristos 34b169a6bSchristos This file is part of GDB. 44b169a6bSchristos 54b169a6bSchristos This program is free software; you can redistribute it and/or modify 64b169a6bSchristos it under the terms of the GNU General Public License as published by 74b169a6bSchristos the Free Software Foundation; either version 3 of the License, or 84b169a6bSchristos (at your option) any later version. 94b169a6bSchristos 104b169a6bSchristos This program is distributed in the hope that it will be useful, 114b169a6bSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 124b169a6bSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 134b169a6bSchristos GNU General Public License for more details. 144b169a6bSchristos 154b169a6bSchristos You should have received a copy of the GNU General Public License 164b169a6bSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 174b169a6bSchristos 18*5ba1f45fSchristos #ifndef COMMON_GDB_CHECKED_STATIC_CAST_H 19*5ba1f45fSchristos #define COMMON_GDB_CHECKED_STATIC_CAST_H 204b169a6bSchristos 214b169a6bSchristos #include "gdbsupport/traits.h" 224b169a6bSchristos 234b169a6bSchristos namespace gdb 244b169a6bSchristos { 254b169a6bSchristos 264b169a6bSchristos /* This function can be used in place of static_cast when casting between 274b169a6bSchristos pointers of polymorphic types. The benefit of using this call is that, 284b169a6bSchristos when compiling in developer mode, dynamic_cast will be used to validate 294b169a6bSchristos the cast. This use of dynamic_cast is why this function will only 304b169a6bSchristos work for polymorphic types. 314b169a6bSchristos 324b169a6bSchristos In non-developer (i.e. production) builds, the dynamic_cast is replaced 334b169a6bSchristos with a static_cast which is usually significantly faster. */ 344b169a6bSchristos 354b169a6bSchristos template<typename T, typename V> 364b169a6bSchristos T 374b169a6bSchristos checked_static_cast (V *v) 384b169a6bSchristos { 394b169a6bSchristos /* We only support casting to pointer types. */ 404b169a6bSchristos static_assert (std::is_pointer<T>::value, "target must be a pointer type"); 414b169a6bSchristos 424b169a6bSchristos /* Check for polymorphic types explicitly in case we're in release mode. */ 434b169a6bSchristos static_assert (std::is_polymorphic<V>::value, "types must be polymorphic"); 444b169a6bSchristos 454b169a6bSchristos /* Figure out the type that T points to. */ 464b169a6bSchristos using T_no_P = typename std::remove_pointer<T>::type; 474b169a6bSchristos 484b169a6bSchristos /* In developer mode this cast uses dynamic_cast to confirm at run-time 494b169a6bSchristos that the cast from V* to T is valid. However, we can catch some 504b169a6bSchristos mistakes at compile time, this assert prevents anything other than 514b169a6bSchristos downcasts, or casts to same type. */ 524b169a6bSchristos static_assert (std::is_base_of<V, T_no_P>::value 534b169a6bSchristos || std::is_base_of<T_no_P, V>::value, 544b169a6bSchristos "types must be related"); 554b169a6bSchristos 564b169a6bSchristos #ifdef DEVELOPMENT 57*5ba1f45fSchristos gdb_assert (v == nullptr || dynamic_cast<T> (v) != nullptr); 584b169a6bSchristos #endif 594b169a6bSchristos 60*5ba1f45fSchristos /* If a base class of V is virtual then the dynamic_cast above will 61*5ba1f45fSchristos succeed, but this static_cast will fail. */ 62*5ba1f45fSchristos return static_cast<T> (v); 63*5ba1f45fSchristos } 64*5ba1f45fSchristos 65*5ba1f45fSchristos /* Same as the above, but to cast from a reference type to another. */ 66*5ba1f45fSchristos 67*5ba1f45fSchristos template<typename T, typename V, typename = gdb::Requires<std::is_reference<T>>> 68*5ba1f45fSchristos T 69*5ba1f45fSchristos checked_static_cast (V &v) 70*5ba1f45fSchristos { 71*5ba1f45fSchristos static_assert (std::is_reference<T>::value, "target must be a reference type"); 72*5ba1f45fSchristos 73*5ba1f45fSchristos using T_no_R = typename std::remove_reference<T>::type; 74*5ba1f45fSchristos using T_P = typename std::add_pointer<T_no_R>::type; 75*5ba1f45fSchristos 76*5ba1f45fSchristos using V_no_R = typename std::remove_reference<V>::type; 77*5ba1f45fSchristos 78*5ba1f45fSchristos return *checked_static_cast<T_P, V_no_R> (&v); 794b169a6bSchristos } 804b169a6bSchristos 814b169a6bSchristos } 824b169a6bSchristos 83*5ba1f45fSchristos #endif /* COMMON_GDB_CHECKED_STATIC_CAST_H */ 84