Skip to content

Commit 9f53e90

Browse files
committed
Return pointer from expr_try_dynamic_cast
1 parent d19e737 commit 9f53e90

File tree

3 files changed

+63
-132
lines changed

3 files changed

+63
-132
lines changed

src/util/expr_cast.h

+52-120
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Author: Nathan Phillips <Nathan.Phillips@diffblue.com>
1818

1919
#include "invariant.h"
2020
#include "expr.h"
21-
#include "optional.h"
2221

2322
/// \brief Check whether a reference to a generic \ref exprt is of a specific
2423
/// derived class.
@@ -41,71 +40,70 @@ inline void validate_expr(const exprt &) {}
4140
namespace detail // NOLINT
4241
{
4342

44-
// We hide these functions in a namespace so that they only participate in
45-
// overload resolution when explicitly requested.
43+
template<typename Ret, typename T>
44+
struct expr_try_dynamic_cast_return_typet final
45+
{
46+
static_assert(
47+
!std::is_reference<Ret>::value,
48+
"Ret must be non-qualified");
49+
50+
typedef
51+
typename std::conditional<
52+
std::is_const<T>::value,
53+
typename std::add_const<Ret>::type,
54+
Ret>::type *
55+
type;
56+
};
57+
58+
} // namespace detail
4659

4760
/// \brief Try to cast a reference to a generic exprt to a specific derived
4861
/// class
4962
/// \tparam T The reference or const reference type to \a TUnderlying to cast
5063
/// to
5164
/// \tparam TExpr The original type to cast from, either exprt or const exprt
5265
/// \param base Reference to a generic \ref exprt
53-
/// \return Reference to object of type \a TUnderlying
54-
/// or valueless optional if \a base is not an instance of \a TUnderlying
66+
/// \return Ptr to object of type \a TUnderlying
67+
/// or nullptr if \a base is not an instance of \a TUnderlying
5568
template <typename T, typename TExpr>
56-
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
57-
expr_try_dynamic_cast(TExpr &base)
69+
auto expr_try_dynamic_cast(TExpr &base)
70+
-> typename detail::expr_try_dynamic_cast_return_typet<T, TExpr>::type
5871
{
59-
typedef typename std::decay<T>::type decayt;
72+
typedef
73+
typename detail::expr_try_dynamic_cast_return_typet<T, TExpr>::type
74+
returnt;
6075
static_assert(
61-
std::is_same<typename std::remove_const<TExpr>::type, exprt>::value,
76+
std::is_same<typename std::decay<TExpr>::type, exprt>::value,
6277
"Tried to expr_try_dynamic_cast from something that wasn't an exprt");
6378
static_assert(
64-
std::is_reference<T>::value,
65-
"Tried to convert exprt & to non-reference type");
66-
static_assert(
67-
std::is_base_of<exprt, decayt>::value,
79+
std::is_base_of<exprt, T>::value,
6880
"The template argument T must be derived from exprt.");
69-
if(!can_cast_expr<decayt>(base))
70-
return {};
71-
T ret=static_cast<T>(base);
72-
validate_expr(ret);
73-
return std::reference_wrapper<typename std::remove_reference<T>::type>(ret);
81+
if(!can_cast_expr<T>(base))
82+
return nullptr;
83+
const auto ret=static_cast<returnt>(&base);
84+
validate_expr(*ret);
85+
return ret;
7486
}
7587

76-
} // namespace detail
77-
78-
/// \brief Try to cast a constant reference to a generic exprt to a specific
79-
/// derived class
80-
/// \tparam T The exprt-derived class to cast to
81-
/// \param base Reference to a generic \ref exprt
82-
/// \return Reference to object of type \a T or valueless optional if \a base
83-
/// is not an instance of \a T
84-
template<typename T>
85-
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
86-
expr_try_dynamic_cast(const exprt &base)
88+
namespace detail // NOLINT
8789
{
88-
return detail::expr_try_dynamic_cast<T>(base);
89-
}
9090

91-
/// \brief Try to cast a reference to a generic exprt to a specific derived
92-
/// class
93-
/// \tparam T The exprt-derived class to cast to
94-
/// \param base Reference to a generic \ref exprt
95-
/// \return Reference to object of type \a T or valueless optional if \a base is
96-
/// not an instance of \a T
97-
template<typename T>
98-
optionalt<std::reference_wrapper<typename std::remove_reference<T>::type>>
99-
expr_try_dynamic_cast(exprt &base)
91+
template<typename Ret, typename T>
92+
struct expr_dynamic_cast_return_typet final
10093
{
101-
return detail::expr_try_dynamic_cast<T>(base);
102-
}
94+
static_assert(
95+
!std::is_reference<Ret>::value,
96+
"Ret must be non-qualified");
10397

104-
namespace detail // NOLINT
105-
{
98+
typedef
99+
typename std::conditional<
100+
std::is_const<T>::value,
101+
typename std::add_const<Ret>::type,
102+
Ret>::type &
103+
type;
104+
};
106105

107-
// We hide these functions in a namespace so that they only participate in
108-
// overload resolution when explicitly requested.
106+
} // namespace detail
109107

110108
/// \brief Cast a reference to a generic exprt to a specific derived class.
111109
/// \tparam T The reference or const reference type to \a TUnderlying to cast to
@@ -114,23 +112,13 @@ namespace detail // NOLINT
114112
/// \return Reference to object of type \a T
115113
/// \throw std::bad_cast If \a base is not an instance of \a TUnderlying
116114
template<typename T, typename TExpr>
117-
T expr_dynamic_cast(TExpr &base)
115+
auto expr_dynamic_cast(TExpr &base)
116+
-> typename detail::expr_dynamic_cast_return_typet<T, TExpr>::type
118117
{
119-
typedef typename std::decay<T>::type decayt;
120-
static_assert(
121-
std::is_same<typename std::remove_const<TExpr>::type, exprt>::value,
122-
"Tried to expr_dynamic_cast from something that wasn't an exprt");
123-
static_assert(
124-
std::is_reference<T>::value,
125-
"Tried to convert exprt & to non-reference type");
126-
static_assert(
127-
std::is_base_of<exprt, decayt>::value,
128-
"The template argument T must be derived from exprt.");
129-
if(!can_cast_expr<decayt>(base))
118+
const auto ret=expr_try_dynamic_cast<T>(base);
119+
if(ret==nullptr)
130120
throw std::bad_cast();
131-
T ret=static_cast<T>(base);
132-
validate_expr(ret);
133-
return ret;
121+
return *ret;
134122
}
135123

136124
/// \brief Cast a reference to a generic exprt to a specific derived class.
@@ -143,69 +131,13 @@ T expr_dynamic_cast(TExpr &base)
143131
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
144132
/// abort rather than throw if \a base is not an instance of \a TUnderlying
145133
template<typename T, typename TExpr>
146-
T expr_checked_cast(TExpr &base)
134+
auto expr_checked_cast(TExpr &base)
135+
-> typename detail::expr_dynamic_cast_return_typet<T, TExpr>::type
147136
{
148-
PRECONDITION(can_cast_expr<typename std::decay<T>::type>(base));
137+
PRECONDITION(can_cast_expr<T>(base));
149138
return expr_dynamic_cast<T>(base);
150139
}
151140

152-
} // namespace detail
153-
154-
/// \brief Cast a constant reference to a generic exprt to a specific derived
155-
/// class
156-
/// \tparam T The exprt-derived class to cast to
157-
/// \param base Reference to a generic \ref exprt
158-
/// \return Reference to object of type \a T
159-
/// \throw std::bad_cast If \a base is not an instance of \a T
160-
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
161-
/// abort rather than throw if \a base is not an instance of \a T
162-
template<typename T>
163-
T expr_dynamic_cast(const exprt &base)
164-
{
165-
return detail::expr_dynamic_cast<T>(base);
166-
}
167-
168-
/// \brief Cast a reference to a generic exprt to a specific derived class
169-
/// \tparam T The exprt-derived class to cast to
170-
/// \param base Reference to a generic \ref exprt
171-
/// \return Reference to object of type \a T
172-
/// \throw std::bad_cast If \a base is not an instance of \a T
173-
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
174-
/// abort rather than throw if \a base is not an instance of \a T
175-
template<typename T>
176-
T expr_dynamic_cast(exprt &base)
177-
{
178-
return detail::expr_dynamic_cast<T>(base);
179-
}
180-
181-
/// \brief Cast a constant reference to a generic exprt to a specific derived
182-
/// class. Also assert that the exprt invariants are not violated.
183-
/// \tparam T The exprt-derived class to cast to
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 T
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 T
189-
template<typename T>
190-
T expr_checked_cast(const exprt &base)
191-
{
192-
return detail::expr_checked_cast<T>(base);
193-
}
194-
195-
/// \brief Cast a reference to a generic exprt to a specific derived class.
196-
/// Also assert that the exprt invariants are not violated.
197-
/// \tparam T The exprt-derived class to cast to
198-
/// \param base Reference to a generic \ref exprt
199-
/// \return Reference to object of type \a T
200-
/// \throw std::bad_cast If \a base is not an instance of \a T
201-
/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will
202-
/// abort rather than throw if \a base is not an instance of \a T
203-
template<typename T>
204-
T expr_checked_cast(exprt &base)
205-
{
206-
return detail::expr_checked_cast<T>(base);
207-
}
208-
209141
inline void validate_operands(
210142
const exprt &value,
211143
exprt::operandst::size_type number,

src/util/std_code.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ inline bool can_cast_code_impl(const exprt &expr, const Tag &tag)
5555
{
5656
try
5757
{
58-
return expr_dynamic_cast<const codet &>(expr).get_statement()==tag;
58+
return expr_dynamic_cast<codet>(expr).get_statement()==tag;
5959
}
6060
catch(const std::bad_cast &)
6161
{
@@ -1246,8 +1246,7 @@ inline bool can_cast_side_effect_expr_impl(const exprt &expr, const Tag &tag)
12461246
{
12471247
try
12481248
{
1249-
return
1250-
expr_dynamic_cast<const side_effect_exprt &>(expr).get_statement()==tag;
1249+
return expr_dynamic_cast<side_effect_exprt>(expr).get_statement()==tag;
12511250
}
12521251
catch(const std::bad_cast &)
12531252
{

unit/util/expr_cast/expr_cast.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ SCENARIO("expr_dynamic_cast",
2323
THEN("Try-casting from exprt reference to symbol_exprt pointer "
2424
"returns a value")
2525
{
26-
REQUIRE(expr_try_dynamic_cast<const symbol_exprt &>(expr).has_value());
26+
REQUIRE(expr_try_dynamic_cast<symbol_exprt>(expr)!=nullptr);
2727
}
2828

2929
THEN("Casting from exprt pointer to transt pointer doesn't return a value")
3030
{
31-
REQUIRE(!expr_try_dynamic_cast<const transt &>(expr).has_value());
31+
REQUIRE(expr_try_dynamic_cast<transt>(expr)==nullptr);
3232
}
3333
}
3434
GIVEN("A exprt reference to a symbolt")
@@ -38,13 +38,13 @@ SCENARIO("expr_dynamic_cast",
3838
THEN("Casting from exprt reference to symbol_exprt reference "
3939
"returns a value")
4040
{
41-
REQUIRE(expr_try_dynamic_cast<symbol_exprt &>(expr).has_value());
41+
REQUIRE(expr_try_dynamic_cast<symbol_exprt>(expr)!=nullptr);
4242
}
4343

4444
THEN("Casting from exprt reference to transt reference "
4545
"doesn't return a value")
4646
{
47-
REQUIRE(!expr_try_dynamic_cast<transt &>(expr).has_value());
47+
REQUIRE(expr_try_dynamic_cast<transt>(expr)==nullptr);
4848
}
4949
}
5050
GIVEN("A const exprt reference to a symbolt")
@@ -54,15 +54,15 @@ SCENARIO("expr_dynamic_cast",
5454
THEN(
5555
"Casting from exprt reference to symbol_exprt reference should not throw")
5656
{
57-
REQUIRE_NOTHROW(expr_dynamic_cast<const symbol_exprt &>(expr_ref));
57+
REQUIRE_NOTHROW(expr_dynamic_cast<symbol_exprt>(expr_ref));
5858
}
5959

6060
THEN("Casting from exprt reference to transt reference should throw")
6161
{
6262
// This no longer throws exceptions when our custom asserts are set to
6363
// abort the program
6464
// REQUIRE_THROWS_AS(
65-
// expr_dynamic_cast<const transt &>(expr_ref),
65+
// expr_dynamic_cast<transt>(expr_ref),
6666
// std::bad_cast);
6767
}
6868
}
@@ -73,23 +73,23 @@ SCENARIO("expr_dynamic_cast",
7373
THEN(
7474
"Casting from exprt reference to symbol_exprt reference should not throw")
7575
{
76-
REQUIRE_NOTHROW(expr_dynamic_cast<symbol_exprt &>(expr_ref));
76+
REQUIRE_NOTHROW(expr_dynamic_cast<symbol_exprt>(expr_ref));
7777
}
7878

7979
THEN("Casting from exprt reference to transt reference should throw")
8080
{
8181
// This no longer throws exceptions when our custom asserts are set to
8282
// abort the program
8383
// REQUIRE_THROWS_AS(
84-
// expr_dynamic_cast<transt &>(expr_ref),
84+
// expr_dynamic_cast<transt>(expr_ref),
8585
// std::bad_cast);
8686
}
8787

8888
THEN(
8989
"Casting from non-const exprt reference to const symbol_exprt reference "
9090
"should be fine")
9191
{
92-
REQUIRE_NOTHROW(expr_dynamic_cast<const symbol_exprt &>(expr_ref));
92+
REQUIRE_NOTHROW(expr_dynamic_cast<symbol_exprt>(expr_ref));
9393
}
9494
}
9595
}

0 commit comments

Comments
 (0)