xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/gdb-checked-static-cast.h (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
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