Skip to content

Commit 5bd5962

Browse files
Merge pull request diffblue#1667 from romainbrenguier/feature/type_cast
type_dynamic_cast (extension of expr_cast)
2 parents 8ecb55a + 2064849 commit 5bd5962

File tree

3 files changed

+83
-8
lines changed

3 files changed

+83
-8
lines changed

src/solvers/flattening/boolbv_width.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,7 @@ const boolbv_widtht::entryt &boolbv_widtht::get_entry(const typet &type) const
194194
// no width
195195
}
196196
else if(type_id==ID_pointer)
197-
{
198-
entry.total_width=to_pointer_type(type).get_width();
199-
DATA_INVARIANT(entry.total_width!=0, "pointer must have width");
200-
}
197+
entry.total_width = type_checked_cast<pointer_typet>(type).get_width();
201198
else if(type_id==ID_symbol)
202199
entry=get_entry(ns.follow(type));
203200
else if(type_id==ID_struct_tag)

src/util/expr_cast.h

+63
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ Author: Nathan Phillips <[email protected]>
2929
/// \return true if \a base is of type \a T
3030
template<typename T> inline bool can_cast_expr(const exprt &base);
3131

32+
/// \brief Check whether a reference to a generic \ref typet is of a specific
33+
/// derived class.
34+
///
35+
/// Implement template specializations of this function to enable casting
36+
///
37+
/// \tparam T The typet-derived class to check for
38+
/// \param base Reference to a generic \ref typet
39+
/// \return true if \a base is of type \a T
40+
template <typename T>
41+
inline bool can_cast_type(const typet &base);
42+
3243
/// Called after casting. Provides a point to assert on the structure of the
3344
/// expr. By default, this is a no-op, but you can provide an overload to
3445
/// validate particular types. Should always succeed unless the program has
@@ -37,6 +48,16 @@ template<typename T> inline bool can_cast_expr(const exprt &base);
3748
/// validate objects in this way at any time.
3849
inline void validate_expr(const exprt &) {}
3950

51+
/// Called after casting. Provides a point to check data invariants on the
52+
/// structure of the typet. By default, this is a no-op, but you can provide an
53+
/// overload to validate particular types. Should always succeed unless the
54+
/// program has entered an invalid state. We validate objects at cast time as
55+
/// that is when these checks have been used historically, but it would be
56+
/// reasonable to validate objects in this way at any time.
57+
inline void validate_type(const typet &)
58+
{
59+
}
60+
4061
namespace detail // NOLINT
4162
{
4263

@@ -86,6 +107,33 @@ auto expr_try_dynamic_cast(TExpr &base)
86107
return ret;
87108
}
88109

110+
/// \brief Try to cast a reference to a generic typet to a specific derived
111+
/// class
112+
/// \tparam T The reference or const reference type to \a TUnderlying to cast
113+
/// to
114+
/// \tparam TType The original type to cast from, either typet or const typet
115+
/// \param base Reference to a generic \ref typet
116+
/// \return Ptr to object of type \a TUnderlying
117+
/// or nullptr if \a base is not an instance of \a TUnderlying
118+
template <typename T, typename TType>
119+
auto type_try_dynamic_cast(TType &base) ->
120+
typename detail::expr_try_dynamic_cast_return_typet<T, TType>::type
121+
{
122+
typedef
123+
typename detail::expr_try_dynamic_cast_return_typet<T, TType>::type returnt;
124+
static_assert(
125+
std::is_base_of<typet, typename std::decay<TType>::type>::value,
126+
"Tried to type_try_dynamic_cast from something that wasn't an typet");
127+
static_assert(
128+
std::is_base_of<typet, T>::value,
129+
"The template argument T must be derived from typet.");
130+
if(!can_cast_type<typename std::remove_const<T>::type>(base))
131+
return nullptr;
132+
const auto ret = static_cast<returnt>(&base);
133+
validate_type(*ret);
134+
return ret;
135+
}
136+
89137
namespace detail // NOLINT
90138
{
91139

@@ -140,6 +188,21 @@ auto expr_checked_cast(TExpr &base)
140188
return expr_dynamic_cast<T>(base);
141189
}
142190

191+
/// \brief Cast a reference to a generic typet to a specific derived class and
192+
/// checks that the type could be converted.
193+
/// \tparam T The reference or const reference type to \a TUnderlying to cast to
194+
/// \tparam TType The original type to cast from, either typet or const typet
195+
/// \param base Reference to a generic \ref typet
196+
/// \return Reference to object of type \a T
197+
template <typename T, typename TType>
198+
auto type_checked_cast(TType &base) ->
199+
typename detail::expr_dynamic_cast_return_typet<T, TType>::type
200+
{
201+
auto result = type_try_dynamic_cast<T>(base);
202+
CHECK_RETURN(result != nullptr);
203+
return *result;
204+
}
205+
143206
inline void validate_operands(
144207
const exprt &value,
145208
exprt::operandst::size_type number,

src/util/std_types.h

+19-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Author: Daniel Kroening, [email protected]
2020
#include "expr.h"
2121
#include "mp_arith.h"
2222
#include "invariant.h"
23+
#include "expr_cast.h"
2324

2425
class constant_exprt;
2526

@@ -1400,8 +1401,9 @@ class pointer_typet:public bitvector_typet
14001401
inline const pointer_typet &to_pointer_type(const typet &type)
14011402
{
14021403
PRECONDITION(type.id()==ID_pointer);
1403-
PRECONDITION(!type.get(ID_width).empty());
1404-
return static_cast<const pointer_typet &>(type);
1404+
const pointer_typet &ret = static_cast<const pointer_typet &>(type);
1405+
validate_type(ret);
1406+
return ret;
14051407
}
14061408

14071409
/*! \copydoc to_pointer_type(const typet &)
@@ -1410,8 +1412,21 @@ inline const pointer_typet &to_pointer_type(const typet &type)
14101412
inline pointer_typet &to_pointer_type(typet &type)
14111413
{
14121414
PRECONDITION(type.id()==ID_pointer);
1413-
PRECONDITION(!type.get(ID_width).empty());
1414-
return static_cast<pointer_typet &>(type);
1415+
pointer_typet &ret = static_cast<pointer_typet &>(type);
1416+
validate_type(ret);
1417+
return ret;
1418+
}
1419+
1420+
template <>
1421+
inline bool can_cast_type<pointer_typet>(const typet &type)
1422+
{
1423+
return type.id() == ID_pointer;
1424+
}
1425+
1426+
inline void validate_type(const pointer_typet &type)
1427+
{
1428+
DATA_INVARIANT(!type.get(ID_width).empty(), "pointer must have width");
1429+
DATA_INVARIANT(type.get_width() > 0, "pointer must have non-zero width");
14151430
}
14161431

14171432
/*! \brief The reference type

0 commit comments

Comments
 (0)