misc: fix some down_cast issues

We had new failure on MinGW with GCC believing that some pointer
returned by down_cast could be NULL; and the down_cast function was in
the global namespace.

* spot/misc/casts.hh: Rewrite.
* NEWS: Mention the small issues.
* tests/core/ikwiad.cc, tests/core/ngraph.cc: Adjust to use
spot::down_cast instead of down_cast.
This commit is contained in:
Alexandre Duret-Lutz 2018-01-10 17:30:25 +01:00
parent 91fdc5ecb2
commit 8a74ae6c9d
4 changed files with 30 additions and 102 deletions

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2015-2017 Laboratoire de Recherche et Développement
// Copyright (C) 2011, 2015-2018 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
@ -34,112 +34,36 @@
// If an error occurs during the cast, an exception is thrown.
//
// NB: down_cast can also be used on shared_ptr.
namespace
namespace spot
{
// A helper struct to check that downcasts are performed down an inheritance
// hierarchy, not between unrelated types.
template<typename Base, typename Derived>
struct is_base_of : std::is_base_of<Base, Derived>
{};
template<typename Base, typename Derived>
struct is_base_of<Base*, Derived*> : is_base_of<Base, Derived>
{};
// Also handle smart pointers.
template<typename Base, typename Derived>
struct is_base_of<std::shared_ptr<Base>, std::shared_ptr<Derived>>
: is_base_of<Base, Derived>
{};
// std::is_pointer does not detect smart pointers.
// Make our own version that detects pointer, plain or smart.
template<typename T>
struct is_pointer : std::is_pointer<T>
{};
template<typename T>
struct is_pointer<std::shared_ptr<T>> : std::true_type
{};
template<typename T, typename U, bool check>
struct _downcast;
// A down-cast on non-pointer type is legitimate, e.g. down_cast<Derived&>(m);
// An error in the dynamic_cast will throw an exception.
template<typename T, typename U>
struct _downcast<T, U, false>
inline
T down_cast(U* u) noexcept
{
static_assert(is_base_of<U, T>::value, "invalid downcast");
SPOT_ASSERT(dynamic_cast<T>(u));
return static_cast<T>(u);
}
static
inline
T
cast(U u)
template<typename T, typename U>
inline
T down_cast(const std::shared_ptr<U>& u) noexcept
{
SPOT_ASSERT(std::dynamic_pointer_cast<typename T::element_type>(u));
return std::static_pointer_cast<typename T::element_type>(u);
}
template<typename T, typename U>
inline
T down_cast(U u)
#ifdef NDEBUG
noexcept
#else
noexcept(is_pointer<T>::value)
#endif
{
#ifdef NDEBUG
return static_cast<T>(u);
#else
return dynamic_cast<T>(u);
#endif
}
};
// A specialization for smart pointer, so that down_cast can be used
// uniformly.
// NB: Use
// auto d = down_cast<std::shared_ptr<T>>(b);
// instead of
// auto d = std::dynamic_pointer_cast<T>(b);
template<typename T, typename U>
struct _downcast<std::shared_ptr<T>, U, false>
{
static_assert(is_base_of<U, std::shared_ptr<T>>::value, "invalid downcast");
static
inline
std::shared_ptr<T>
cast(U u) noexcept
{
#ifdef NDEBUG
return std::static_pointer_cast<T>(u);
return static_cast<T>(u);
#else
return std::dynamic_pointer_cast<T>(u);
return dynamic_cast<T>(u);
#endif
}
};
// Pointer type specialization.
// Cast errors are caught by an assertion, no exception is thrown.
template<typename T, typename U>
struct _downcast<T, U, true>
{
static
inline
T
cast(U u) noexcept
{
T t = _downcast<T, U, false>::cast(u);
SPOT_ASSERT(t);
return t;
}
};
} // anonymous namespace
// The actual function to call.
template<typename T, typename U>
inline
T
down_cast(U u)
#ifdef NDEBUG
noexcept
#else
noexcept(is_pointer<T>::value)
#endif
{
return _downcast<T, U, is_pointer<T>::value>::cast(u);
}
}
} // namespace spot