cxx icon indicating copy to clipboard operation
cxx copied to clipboard

Prevent emitting const const on C++ codegen when using a Slice with a reference

Open andfoy opened this issue 4 years ago • 7 comments

Fixes https://github.com/dtolnay/cxx/issues/830

andfoy avatar Apr 13 '21 22:04 andfoy

It seems that a container cannot hold references either: https://stackoverflow.com/questions/1155142/why-do-i-get-an-error-in-forming-reference-to-reference-type-map, instead one should wrap a reference around std::reference_wrapper, however, I don't know how to extend Slice to convert a reference into a reference_wrapper

andfoy avatar Apr 13 '21 23:04 andfoy

Maybe with a partial template specialization in cxx.h which applies to instantiations of rust::Slice<T &>?

template <typename T>
class Slice<T &> final {
    /* uses reference_wrapper internally for this specialization */
};

Alternatively it's possible we can fix this purely by using the existing partial specialized helpers that already exist in <type_traits>. For example instead of:

https://github.com/dtolnay/cxx/blob/064cf12b7850e4a3e2e09134eeea8fc619e60792/include/cxx.h#L170

we'd have:

-   T &operator[](std::size_t n) const noexcept;
+   std::add_lvalue_reference<T>::type operator[](std::size_t n) const noexcept;

According to https://en.cppreference.com/w/cpp/types/add_reference that has the semantics we want.

If T is a function type that has no cv- or ref- qualifier or an object type, provides a member typedef type which is T&. If T is an rvalue reference to some type U, then type is U&. Otherwise, type is T.

In other words rust::Slice<const Struct>::operator[] would return const Struct &, whereas rust::Slice<const Struct &>::operator[] would also return const Struct &, because add_lvalue_reference is instantiated with a type that is already a reference.

dtolnay avatar Apr 13 '21 23:04 dtolnay

In other words rust::Slice<const Struct>::operator[] would return const Struct &, whereas rust::Slice<const Struct &>::operator[] would also return const Struct &, because add_lvalue_reference is instantiated with a type that is already a reference.

Sounds like it would fix the issue, let me update the PR!

andfoy avatar Apr 14 '21 00:04 andfoy

I think it is necessary to update the generated cxx.cc file to consider add_lvalue_reference

error: no declaration matches ‘T& rust::cxxbridge1::Slice<T>::operator[](std::size_t) const

Do you know where I should do the corresponding modifications?

andfoy avatar Apr 14 '21 18:04 andfoy

I tried this change locally, and it seems to work, although I have to use std::reference_wrapper on the signature

match &slice.inner {
    Type::Ref(r) => {
        // let inner_ref = r.inner;
        write!(out, "std::reference_wrapper<");
        write_type(out, &r.inner);
        write!(out, ">");
    }
    _ => {
        write!(out, "const ");
        write_type(out, &slice.inner);
    }
}
std::shared_ptr<CrossTensor> index(
    const std::shared_ptr<CrossTensor> &tensor,
    rust::Slice<std::reference_wrapper<CrossTensorRef>> indices);

andfoy avatar Apr 14 '21 20:04 andfoy

@dtolnay, do you prefer using std::reference_wrapper here?

andfoy avatar Apr 19 '21 19:04 andfoy

Any chance of this being merged? I ran into the issue described in #830 so having a fix would be nice. I'd be happy to help out if some work is needed to get it done :)

TheZoq2 avatar Aug 24 '21 13:08 TheZoq2