Skip to content

Commit 3a4d364

Browse files
committed
Add checked_cast signatures
1 parent 47a13c7 commit 3a4d364

File tree

1 file changed

+111
-25
lines changed

1 file changed

+111
-25
lines changed

src/util/expr_cast.h

+111-25
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,24 @@ Author: Nathan Phillips <[email protected]>
3030
/// \return true if \a base is of type \a T
3131
template<typename T> bool can_cast_expr(const exprt &base);
3232

33-
/// Called after casting. Provides a point to assert on the structure of the
33+
/// Called after casting. Provides a point to assert on the structure of the
3434
/// expr. By default, this is a no-op, but you can provide an overload to
35-
/// validate particular types.
35+
/// validate particular types. Should always succeed unless the program has
36+
/// entered an invalid state. We validate objects at cast time as that is when
37+
/// these checks have been used historically, but it would be reasonable to
38+
/// validate objects in this way at any time.
3639
inline void validate_expr(const exprt &) {}
3740

3841
namespace detail // NOLINT
3942
{
4043

41-
// We hide this in a namespace so that only functions that it only
42-
// participates in overload resolution when explicitly requested.
44+
// We hide these functions in a namespace so that only functions that they only
45+
// participate in overload resolution when explicitly requested.
4346

4447
/// \brief Try to cast a reference to a generic exprt to a specific derived
4548
/// class
4649
/// \tparam T The reference or const reference type to \a TUnderlying to cast
4750
/// to
48-
/// \tparam TUnderlying An exprt-derived class type
4951
/// \tparam TExpr The original type to cast from, either exprt or const exprt
5052
/// \param base Reference to a generic \ref exprt
5153
/// \return Reference to object of type \a TUnderlying
@@ -54,22 +56,39 @@ template <typename T, typename TExpr>
5456
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
5557
expr_try_dynamic_cast(TExpr &base)
5658
{
57-
typedef typename std::decay<T>::type TUnderlying;
58-
typedef typename std::remove_reference<T>::type TConst;
59+
typedef typename std::decay<T>::type TUnderlyingt;
60+
typedef typename std::remove_reference<T>::type TConstt;
5961
static_assert(
6062
std::is_same<typename std::remove_const<TExpr>::type, exprt>::value,
6163
"Tried to expr_try_dynamic_cast from something that wasn't an exprt");
6264
static_assert(
6365
std::is_reference<T>::value,
6466
"Tried to convert exprt & to non-reference type");
6567
static_assert(
66-
std::is_base_of<exprt, TUnderlying>::value,
68+
std::is_base_of<exprt, TUnderlyingt>::value,
6769
"The template argument T must be derived from exprt.");
68-
if(!can_cast_expr<TUnderlying>(base))
70+
if(!can_cast_expr<TUnderlyingt>(base))
6971
return {};
70-
T value=static_cast<T>(base);
71-
validate_expr(value);
72-
return std::reference_wrapper<TConst>(value);
72+
T ret=static_cast<T>(base);
73+
validate_expr(ret);
74+
return std::reference_wrapper<TConstt>(ret);
75+
}
76+
77+
/// \brief Try to cast a reference to a generic exprt to a specific derived
78+
/// class
79+
/// \tparam T The reference or const reference type to \a TUnderlying to cast
80+
/// to
81+
/// \tparam TExpr The original type to cast from, either exprt or const exprt
82+
/// \param base Reference to a generic \ref exprt
83+
/// \return Reference to object of type \a TUnderlying
84+
/// or valueless optional if \a base is not an instance of \a TUnderlying
85+
template <typename T, typename TExpr>
86+
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
87+
expr_try_checked_cast(TExpr &base)
88+
{
89+
typedef typename std::decay<T>::type TUnderlyingt;
90+
PRECONDITION(can_cast_expr<TUnderlyingt>(base));
91+
return expr_try_checked_cast<T>(base);
7392
}
7493

7594
} // namespace detail
@@ -100,40 +119,79 @@ expr_try_dynamic_cast(exprt &base)
100119
return detail::expr_try_dynamic_cast<T>(base);
101120
}
102121

122+
/// \brief Try to cast a constant reference to a generic exprt to a specific
123+
/// derived class. Also assert that the expr invariants are not violated.
124+
/// \tparam T The exprt-derived class to cast to
125+
/// \param base Reference to a generic \ref exprt
126+
/// \return Reference to object of type \a T or valueless optional if \a base
127+
/// is not an instance of \a T
128+
template<typename T>
129+
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
130+
expr_try_checked_cast(const exprt &base)
131+
{
132+
return detail::expr_try_checked_cast<T>(base);
133+
}
134+
135+
/// \brief Try to cast a reference to a generic exprt to a specific derived
136+
/// class. Also assert that the expr invariants are not violated.
137+
/// \tparam T The exprt-derived class to cast to
138+
/// \param base Reference to a generic \ref exprt
139+
/// \return Reference to object of type \a T or valueless optional if \a base is
140+
/// not an instance of \a T
141+
template<typename T>
142+
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
143+
expr_try_checked_cast(exprt &base)
144+
{
145+
return detail::expr_try_checked_cast<T>(base);
146+
}
147+
103148
namespace detail // NOLINT
104149
{
105150

106-
// We hide this in a namespace so that only functions that it only
107-
// participates in overload resolution when explicitly requested.
151+
// We hide these functions in a namespace so that only functions that they only
152+
// participate in overload resolution when explicitly requested.
108153

109-
/// \brief Cast a reference to a generic exprt to a specific derived class
154+
/// \brief Cast a reference to a generic exprt to a specific derived class.
110155
/// \tparam T The reference or const reference type to \a TUnderlying to cast to
111-
/// \tparam TUnderlying An exprt-derived class type
112156
/// \tparam TExpr The original type to cast from, either exprt or const exprt
113157
/// \param base Reference to a generic \ref exprt
114158
/// \return Reference to object of type \a T
115159
/// \throw std::bad_cast If \a base is not an instance of \a TUnderlying
116-
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
117-
/// abort rather than throw if \a base is not an instance of \a TUnderlying
118160
template<typename T, typename TExpr>
119161
T expr_dynamic_cast(TExpr &base)
120162
{
121-
typedef typename std::decay<T>::type TUnderlying;
163+
typedef typename std::decay<T>::type TUnderlyingt;
122164
static_assert(
123165
std::is_same<typename std::remove_const<TExpr>::type, exprt>::value,
124166
"Tried to expr_dynamic_cast from something that wasn't an exprt");
125167
static_assert(
126168
std::is_reference<T>::value,
127169
"Tried to convert exprt & to non-reference type");
128170
static_assert(
129-
std::is_base_of<exprt, TUnderlying>::value,
171+
std::is_base_of<exprt, TUnderlyingt>::value,
130172
"The template argument T must be derived from exprt.");
131-
PRECONDITION(can_cast_expr<TUnderlying>(base));
132-
if(!can_cast_expr<TUnderlying>(base))
173+
if(!can_cast_expr<TUnderlyingt>(base))
133174
throw std::bad_cast();
134-
T value=static_cast<T>(base);
135-
validate_expr(value);
136-
return value;
175+
T ret=static_cast<T>(base);
176+
validate_expr(ret);
177+
return ret;
178+
}
179+
180+
/// \brief Cast a reference to a generic exprt to a specific derived class.
181+
/// Also assert that the expression has the expected type.
182+
/// \tparam T The reference or const reference type to \a TUnderlying to cast to
183+
/// \tparam TExpr The original type to cast from, either exprt or const exprt
184+
/// \param base Reference to a generic \ref exprt
185+
/// \return Reference to object of type \a T
186+
/// \throw std::bad_cast If \a base is not an instance of \a TUnderlying
187+
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
188+
/// abort rather than throw if \a base is not an instance of \a TUnderlying
189+
template<typename T, typename TExpr>
190+
T expr_checked_cast(TExpr &base)
191+
{
192+
typedef typename std::decay<T>::type TUnderlyingt;
193+
PRECONDITION(can_cast_expr<TUnderlyingt>(base));
194+
return expr_dynamic_cast<T>(base);
137195
}
138196

139197
} // namespace detail
@@ -165,6 +223,34 @@ T expr_dynamic_cast(exprt &base)
165223
return detail::expr_dynamic_cast<T>(base);
166224
}
167225

226+
/// \brief Cast a constant reference to a generic exprt to a specific derived
227+
/// class. Also assert that the exprt invariants are not violated.
228+
/// \tparam T The exprt-derived class to cast to
229+
/// \param base Reference to a generic \ref exprt
230+
/// \return Reference to object of type \a T
231+
/// \throw std::bad_cast If \a base is not an instance of \a T
232+
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
233+
/// abort rather than throw if \a base is not an instance of \a T
234+
template<typename T>
235+
T expr_checked_cast(const exprt &base)
236+
{
237+
return detail::expr_checked_cast<T>(base);
238+
}
239+
240+
/// \brief Cast a reference to a generic exprt to a specific derived class.
241+
/// Also assert that the exprt invariants are not violated.
242+
/// \tparam T The exprt-derived class to cast to
243+
/// \param base Reference to a generic \ref exprt
244+
/// \return Reference to object of type \a T
245+
/// \throw std::bad_cast If \a base is not an instance of \a T
246+
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
247+
/// abort rather than throw if \a base is not an instance of \a T
248+
template<typename T>
249+
T expr_checked_cast(exprt &base)
250+
{
251+
return detail::expr_checked_cast<T>(base);
252+
}
253+
168254
inline void validate_operands(
169255
const exprt &value,
170256
exprt::operandst::size_type number,

0 commit comments

Comments
 (0)