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