![]() |
Boost : |
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2025-05-09 02:57:45
AMDG
On 5/8/25 8:13 PM, Jean-Louis Leroy via Boost wrote:
>
>> 343: if (*method.vp_end == 0) {
>> Since this is inside the loop, won't it only resolve the first type?
>> Actually, I'm really confused about the whole loop. Do we
>> want to process the overriders for each virtual parameter?
>
> That code has nothing to do with resolving overriders. It is for deferred RTTI.
> For interfacing with custom RTTI schemes that also use static ctors. If the
> deferred_static_rtti is present, I store a pointer to a function that returns a
> type_id, instead of the type_id itself. initialize() calls the function and then
> replaces the function pointer with the type_id. Since initialize() can be called
> multiple times, I add a flag just after method.vp_end.
>
For reference here's the code in question:
for (auto& method : Policy::methods) {
for (auto& ti : range{method.vp_begin, method.vp_end}) {
if (*method.vp_end == 0) {
resolve(&ti);
*method.vp_end = 1;
}
for (auto& overrider : method.specs) {
if (*overrider.vp_end == 0) {
for (auto& ti :
range{overrider.vp_begin, overrider.vp_end}) {
resolve(&ti);
}
*overrider.vp_end = 1;
}
}
}
}
There are four nested loops. The outer and innermost loops look sane to
me. The two middle loops do not. The second loop is iterating over the
parameter types of the base method and resolving them. However, because
it sets *method.vp_end = 1 on the first iteration, only the type of the
first parameter will be resolved. I think this will fail for
multimethods (See below for a program that fails). The third loop, I
think should be directly inside the outer loop, instead of being nested
inside the second, but it looks harmless because *overrider.vp_end == 0
will deduplicate.
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/policies.hpp>
namespace bom = boost::openmethod;
struct B {
virtual ~B() = default;
bom::type_id type = static_type;
static bom::type_id static_type;
};
struct D : B {
D() { type = static_type; }
static bom::type_id static_type;
};
bom::type_id B::static_type;
bom::type_id D::static_type;
struct deferred_rtti : bom::policies::deferred_static_rtti {
template <class T>
static constexpr bool is_polymorphic = std::is_base_of_v<B, T>;
template <typename T> static auto static_type() -> bom::type_id {
if constexpr (is_polymorphic<T>) {
return T::static_type;
} else {
return 0;
}
}
template <typename T> static auto dynamic_type(const T &obj) ->
bom::type_id {
if constexpr (is_polymorphic<T>) {
return obj.type;
} else {
return 0;
}
}
};
struct deferred_rtti_policy
:
boost::openmethod::policies::debug::fork<deferred_rtti_policy>::replace<
boost::openmethod::policies::rtti, deferred_rtti> {};
BOOST_OPENMETHOD_CLASSES(B, D, deferred_rtti_policy)
BOOST_OPENMETHOD(foo,
(virtual_ptr<B, deferred_rtti_policy>,
virtual_ptr<B, deferred_rtti_policy>),
void, deferred_rtti_policy);
BOOST_OPENMETHOD_OVERRIDE(foo,
(virtual_ptr<D, deferred_rtti_policy>,
virtual_ptr<D, deferred_rtti_policy>),
void) {}
int main() {
B::static_type = 23;
D::static_type = 4;
bom::initialize<deferred_rtti_policy>();
D d;
B &b(d);
foo(b, b);
}
$ BOOST_OPENMETHOD_TRACE=1 ./a.out
Static class info:
type_id(4): (type_id(23), type_id(4))
type_id(23): (type_id(23))
Inheritance lattice:
type_id(4)
bases: (type_id(23))
derived: ()
covariant: (type_id(4))
type_id(23)
bases: ()
derived: (type_id(4))
covariant: (type_id(4), type_id(23))
Methods:
type_id(0) (type_id(23), type_id(4227983))
unkown class 4227983(type_id(4227983)) for parameter #1
unknown class type_id(4227983)
Aborted (core dumped)
In Christ,
Steven Watanabe
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk