1*6881a400Schristos /* Copyright (C) 2022-2023 Free Software Foundation, Inc. 2*6881a400Schristos 3*6881a400Schristos This file is part of GDB. 4*6881a400Schristos 5*6881a400Schristos This program is free software; you can redistribute it and/or modify 6*6881a400Schristos it under the terms of the GNU General Public License as published by 7*6881a400Schristos the Free Software Foundation; either version 3 of the License, or 8*6881a400Schristos (at your option) any later version. 9*6881a400Schristos 10*6881a400Schristos This program is distributed in the hope that it will be useful, 11*6881a400Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 12*6881a400Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*6881a400Schristos GNU General Public License for more details. 14*6881a400Schristos 15*6881a400Schristos You should have received a copy of the GNU General Public License 16*6881a400Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17*6881a400Schristos 18*6881a400Schristos #ifndef COMMON_GDB_CHECKED_DYNAMIC_CAST_H 19*6881a400Schristos #define COMMON_GDB_CHECKED_DYNAMIC_CAST_H 20*6881a400Schristos 21*6881a400Schristos #include "gdbsupport/traits.h" 22*6881a400Schristos 23*6881a400Schristos namespace gdb 24*6881a400Schristos { 25*6881a400Schristos 26*6881a400Schristos /* This function can be used in place of static_cast when casting between 27*6881a400Schristos pointers of polymorphic types. The benefit of using this call is that, 28*6881a400Schristos when compiling in developer mode, dynamic_cast will be used to validate 29*6881a400Schristos the cast. This use of dynamic_cast is why this function will only 30*6881a400Schristos work for polymorphic types. 31*6881a400Schristos 32*6881a400Schristos In non-developer (i.e. production) builds, the dynamic_cast is replaced 33*6881a400Schristos with a static_cast which is usually significantly faster. */ 34*6881a400Schristos 35*6881a400Schristos template<typename T, typename V> 36*6881a400Schristos T 37*6881a400Schristos checked_static_cast (V *v) 38*6881a400Schristos { 39*6881a400Schristos /* We only support casting to pointer types. */ 40*6881a400Schristos static_assert (std::is_pointer<T>::value, "target must be a pointer type"); 41*6881a400Schristos 42*6881a400Schristos /* Check for polymorphic types explicitly in case we're in release mode. */ 43*6881a400Schristos static_assert (std::is_polymorphic<V>::value, "types must be polymorphic"); 44*6881a400Schristos 45*6881a400Schristos /* Figure out the type that T points to. */ 46*6881a400Schristos using T_no_P = typename std::remove_pointer<T>::type; 47*6881a400Schristos 48*6881a400Schristos /* In developer mode this cast uses dynamic_cast to confirm at run-time 49*6881a400Schristos that the cast from V* to T is valid. However, we can catch some 50*6881a400Schristos mistakes at compile time, this assert prevents anything other than 51*6881a400Schristos downcasts, or casts to same type. */ 52*6881a400Schristos static_assert (std::is_base_of<V, T_no_P>::value 53*6881a400Schristos || std::is_base_of<T_no_P, V>::value, 54*6881a400Schristos "types must be related"); 55*6881a400Schristos 56*6881a400Schristos #ifdef DEVELOPMENT 57*6881a400Schristos T result = dynamic_cast<T> (v); 58*6881a400Schristos gdb_assert (result != nullptr); 59*6881a400Schristos #else 60*6881a400Schristos T result = static_cast<T> (v); 61*6881a400Schristos #endif 62*6881a400Schristos 63*6881a400Schristos return result; 64*6881a400Schristos } 65*6881a400Schristos 66*6881a400Schristos } 67*6881a400Schristos 68*6881a400Schristos #endif /* COMMON_GDB_CHECKED_DYNAMIC_CAST_H */ 69