diff --git a/src/util/expr_cast.h b/src/util/expr_cast.h index 694c5e47106..862e764bda8 100644 --- a/src/util/expr_cast.h +++ b/src/util/expr_cast.h @@ -18,7 +18,6 @@ Author: Nathan Phillips #include "invariant.h" #include "expr.h" -#include "optional.h" /// \brief Check whether a reference to a generic \ref exprt is of a specific /// derived class. @@ -41,8 +40,22 @@ inline void validate_expr(const exprt &) {} namespace detail // NOLINT { -// We hide these functions in a namespace so that they only participate in -// overload resolution when explicitly requested. +template +struct expr_try_dynamic_cast_return_typet final +{ + static_assert( + !std::is_reference::value, + "Ret must be non-qualified"); + + typedef + typename std::conditional< + std::is_const::value, + typename std::add_const::type, + Ret>::type * + type; +}; + +} // namespace detail /// \brief Try to cast a reference to a generic exprt to a specific derived /// class @@ -50,62 +63,47 @@ namespace detail // NOLINT /// to /// \tparam TExpr The original type to cast from, either exprt or const exprt /// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a TUnderlying -/// or valueless optional if \a base is not an instance of \a TUnderlying +/// \return Ptr to object of type \a TUnderlying +/// or nullptr if \a base is not an instance of \a TUnderlying template -optionalt::type>> -expr_try_dynamic_cast(TExpr &base) +auto expr_try_dynamic_cast(TExpr &base) + -> typename detail::expr_try_dynamic_cast_return_typet::type { - typedef typename std::decay::type decayt; + typedef + typename detail::expr_try_dynamic_cast_return_typet::type + returnt; static_assert( - std::is_same::type, exprt>::value, + std::is_same::type, exprt>::value, "Tried to expr_try_dynamic_cast from something that wasn't an exprt"); static_assert( - std::is_reference::value, - "Tried to convert exprt & to non-reference type"); - static_assert( - std::is_base_of::value, + std::is_base_of::value, "The template argument T must be derived from exprt."); - if(!can_cast_expr(base)) - return {}; - T ret=static_cast(base); - validate_expr(ret); - return std::reference_wrapper::type>(ret); + if(!can_cast_expr(base)) + return nullptr; + const auto ret=static_cast(&base); + validate_expr(*ret); + return ret; } -} // namespace detail - -/// \brief Try to cast a constant reference to a generic exprt to a specific -/// derived class -/// \tparam T The exprt-derived class to cast to -/// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a T or valueless optional if \a base -/// is not an instance of \a T -template -optionalt::type>> -expr_try_dynamic_cast(const exprt &base) +namespace detail // NOLINT { - return detail::expr_try_dynamic_cast(base); -} -/// \brief Try to cast a reference to a generic exprt to a specific derived -/// class -/// \tparam T The exprt-derived class to cast to -/// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a T or valueless optional if \a base is -/// not an instance of \a T -template -optionalt::type>> -expr_try_dynamic_cast(exprt &base) +template +struct expr_dynamic_cast_return_typet final { - return detail::expr_try_dynamic_cast(base); -} + static_assert( + !std::is_reference::value, + "Ret must be non-qualified"); -namespace detail // NOLINT -{ + typedef + typename std::conditional< + std::is_const::value, + typename std::add_const::type, + Ret>::type & + type; +}; -// We hide these functions in a namespace so that they only participate in -// overload resolution when explicitly requested. +} // namespace detail /// \brief Cast a reference to a generic exprt to a specific derived class. /// \tparam T The reference or const reference type to \a TUnderlying to cast to @@ -114,23 +112,13 @@ namespace detail // NOLINT /// \return Reference to object of type \a T /// \throw std::bad_cast If \a base is not an instance of \a TUnderlying template -T expr_dynamic_cast(TExpr &base) +auto expr_dynamic_cast(TExpr &base) + -> typename detail::expr_dynamic_cast_return_typet::type { - typedef typename std::decay::type decayt; - static_assert( - std::is_same::type, exprt>::value, - "Tried to expr_dynamic_cast from something that wasn't an exprt"); - static_assert( - std::is_reference::value, - "Tried to convert exprt & to non-reference type"); - static_assert( - std::is_base_of::value, - "The template argument T must be derived from exprt."); - if(!can_cast_expr(base)) + const auto ret=expr_try_dynamic_cast(base); + if(ret==nullptr) throw std::bad_cast(); - T ret=static_cast(base); - validate_expr(ret); - return ret; + return *ret; } /// \brief Cast a reference to a generic exprt to a specific derived class. @@ -143,69 +131,13 @@ T expr_dynamic_cast(TExpr &base) /// \remark If CBMC assertions (PRECONDITION) are set to abort then this will /// abort rather than throw if \a base is not an instance of \a TUnderlying template -T expr_checked_cast(TExpr &base) +auto expr_checked_cast(TExpr &base) + -> typename detail::expr_dynamic_cast_return_typet::type { - PRECONDITION(can_cast_expr::type>(base)); + PRECONDITION(can_cast_expr(base)); return expr_dynamic_cast(base); } -} // namespace detail - -/// \brief Cast a constant reference to a generic exprt to a specific derived -/// class -/// \tparam T The exprt-derived class to cast to -/// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a T -/// \throw std::bad_cast If \a base is not an instance of \a T -/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will -/// abort rather than throw if \a base is not an instance of \a T -template -T expr_dynamic_cast(const exprt &base) -{ - return detail::expr_dynamic_cast(base); -} - -/// \brief Cast a reference to a generic exprt to a specific derived class -/// \tparam T The exprt-derived class to cast to -/// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a T -/// \throw std::bad_cast If \a base is not an instance of \a T -/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will -/// abort rather than throw if \a base is not an instance of \a T -template -T expr_dynamic_cast(exprt &base) -{ - return detail::expr_dynamic_cast(base); -} - -/// \brief Cast a constant reference to a generic exprt to a specific derived -/// class. Also assert that the exprt invariants are not violated. -/// \tparam T The exprt-derived class to cast to -/// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a T -/// \throw std::bad_cast If \a base is not an instance of \a T -/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will -/// abort rather than throw if \a base is not an instance of \a T -template -T expr_checked_cast(const exprt &base) -{ - return detail::expr_checked_cast(base); -} - -/// \brief Cast a reference to a generic exprt to a specific derived class. -/// Also assert that the exprt invariants are not violated. -/// \tparam T The exprt-derived class to cast to -/// \param base Reference to a generic \ref exprt -/// \return Reference to object of type \a T -/// \throw std::bad_cast If \a base is not an instance of \a T -/// \remark If CBMC assertions (PRECONDITION) are set to abort then this will -/// abort rather than throw if \a base is not an instance of \a T -template -T expr_checked_cast(exprt &base) -{ - return detail::expr_checked_cast(base); -} - inline void validate_operands( const exprt &value, exprt::operandst::size_type number, diff --git a/src/util/std_code.h b/src/util/std_code.h index 0de8de0779f..4e3cc60d910 100644 --- a/src/util/std_code.h +++ b/src/util/std_code.h @@ -55,7 +55,7 @@ inline bool can_cast_code_impl(const exprt &expr, const Tag &tag) { try { - return expr_dynamic_cast(expr).get_statement()==tag; + return expr_dynamic_cast(expr).get_statement()==tag; } catch(const std::bad_cast &) { @@ -1246,8 +1246,7 @@ inline bool can_cast_side_effect_expr_impl(const exprt &expr, const Tag &tag) { try { - return - expr_dynamic_cast(expr).get_statement()==tag; + return expr_dynamic_cast(expr).get_statement()==tag; } catch(const std::bad_cast &) { diff --git a/unit/util/expr_cast/expr_cast.cpp b/unit/util/expr_cast/expr_cast.cpp index a39e0607398..16441a7c400 100644 --- a/unit/util/expr_cast/expr_cast.cpp +++ b/unit/util/expr_cast/expr_cast.cpp @@ -23,12 +23,12 @@ SCENARIO("expr_dynamic_cast", THEN("Try-casting from exprt reference to symbol_exprt pointer " "returns a value") { - REQUIRE(expr_try_dynamic_cast(expr).has_value()); + REQUIRE(expr_try_dynamic_cast(expr)!=nullptr); } THEN("Casting from exprt pointer to transt pointer doesn't return a value") { - REQUIRE(!expr_try_dynamic_cast(expr).has_value()); + REQUIRE(expr_try_dynamic_cast(expr)==nullptr); } } GIVEN("A exprt reference to a symbolt") @@ -38,13 +38,13 @@ SCENARIO("expr_dynamic_cast", THEN("Casting from exprt reference to symbol_exprt reference " "returns a value") { - REQUIRE(expr_try_dynamic_cast(expr).has_value()); + REQUIRE(expr_try_dynamic_cast(expr)!=nullptr); } THEN("Casting from exprt reference to transt reference " "doesn't return a value") { - REQUIRE(!expr_try_dynamic_cast(expr).has_value()); + REQUIRE(expr_try_dynamic_cast(expr)==nullptr); } } GIVEN("A const exprt reference to a symbolt") @@ -54,7 +54,7 @@ SCENARIO("expr_dynamic_cast", THEN( "Casting from exprt reference to symbol_exprt reference should not throw") { - REQUIRE_NOTHROW(expr_dynamic_cast(expr_ref)); + REQUIRE_NOTHROW(expr_dynamic_cast(expr_ref)); } THEN("Casting from exprt reference to transt reference should throw") @@ -62,7 +62,7 @@ SCENARIO("expr_dynamic_cast", // This no longer throws exceptions when our custom asserts are set to // abort the program // REQUIRE_THROWS_AS( - // expr_dynamic_cast(expr_ref), + // expr_dynamic_cast(expr_ref), // std::bad_cast); } } @@ -73,7 +73,7 @@ SCENARIO("expr_dynamic_cast", THEN( "Casting from exprt reference to symbol_exprt reference should not throw") { - REQUIRE_NOTHROW(expr_dynamic_cast(expr_ref)); + REQUIRE_NOTHROW(expr_dynamic_cast(expr_ref)); } THEN("Casting from exprt reference to transt reference should throw") @@ -81,7 +81,7 @@ SCENARIO("expr_dynamic_cast", // This no longer throws exceptions when our custom asserts are set to // abort the program // REQUIRE_THROWS_AS( - // expr_dynamic_cast(expr_ref), + // expr_dynamic_cast(expr_ref), // std::bad_cast); } @@ -89,7 +89,7 @@ SCENARIO("expr_dynamic_cast", "Casting from non-const exprt reference to const symbol_exprt reference " "should be fine") { - REQUIRE_NOTHROW(expr_dynamic_cast(expr_ref)); + REQUIRE_NOTHROW(expr_dynamic_cast(expr_ref)); } } }