RosettaCommons/binder

Function reference + second var with default -> cannot compile

zwimer opened this issue · 8 comments

I am running binder on a decently sized project and found an issue; I tried to minimize it for this bug report to make things easier on the devs. Running binder on this:

namespace Util::Backtrace {
    using AA=void();
    struct BB {
        static inline void cc(AA & x, int y = 0) {
            (void) x; (void) y;
        }
    };
}

Yields:

void bind_unknown_unknown_1(std::function< pybind11::module &(std::string const &namespace_) > &M)
{
	{ // Util::Backtrace::BB file: line:19
		pybind11::class_<Util::Backtrace::BB, std::shared_ptr<Util::Backtrace::BB>> cl(M("Util::Backtrace"), "BB", "");
		cl.def( pybind11::init( [](){ return new Util::Backtrace::BB(); } ) );
		cl.def_static("cc", [](void (&)(void) a0) -> void { return Util::Backtrace::BB::cc(a0); }, "", pybind11::arg("x"));
		cl.def_static("cc", (void (*)(void (&)(void), int)) &Util::Backtrace::BB::cc, "C++: Util::Backtrace::BB::cc(void (&)(void), int) --> void", pybind11::arg("x"), pybind11::arg("y"));
	}
}

Trying to compile it with clang++ on macOS I get:

/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:252:41: error: expected ')'
                cl.def_static("cc", [](void (&)(void) a0) -> void { return Util::Backtrace::BB::cc(a0); }, "", pybind11::arg("x"));
                                                      ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:252:25: note: to match this '('
                cl.def_static("cc", [](void (&)(void) a0) -> void { return Util::Backtrace::BB::cc(a0); }, "", pybind11::arg("x"));
                                      ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:252:86: error: use of undeclared identifier 'a0'
                cl.def_static("cc", [](void (&)(void) a0) -> void { return Util::Backtrace::BB::cc(a0); }, "", pybind11::arg("x"));
                                                                                                   ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:85: error: expected ')'
                cl.def_static("create", [](void (&)(std::ostream &, unsigned int, short) noexcept a0, const unsigned short & a1) -> std::shared_ptr<const class Util::Backtrace::Lazy> { return Util::Backtrace::Lazy::create(a0, a1); }, "", pybind11::arg("gen"), pybind11::arg("ignore_frames"));
                                                                                                  ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:29: note: to match this '('
                cl.def_static("create", [](void (&)(std::ostream &, unsigned int, short) noexcept a0, const unsigned short & a1) -> std::shared_ptr<const class Util::Backtrace::Lazy> { return Util::Backtrace::Lazy::create(a0, a1); }, "", pybind11::arg("gen"), pybind11::arg("ignore_frames"));
                                          ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:209: error: use of undeclared identifier 'a0'
                cl.def_static("create", [](void (&)(std::ostream &, unsigned int, short) noexcept a0, const unsigned short & a1) -> std::shared_ptr<const class Util::Backtrace::Lazy> { return Util::Backtrace::Lazy::create(a0, a1); }, "", pybind11::arg("gen"), pybind11::arg("ignore_frames"));
                                                                                                                                                                                                                              ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:213: error: use of undeclared identifier 'a1'
                cl.def_static("create", [](void (&)(std::ostream &, unsigned int, short) noexcept a0, const unsigned short & a1) -> std::shared_ptr<const class Util::Backtrace::Lazy> { return Util::Backtrace::Lazy::create(a0, a1); }, "", pybind11::arg("gen"), pybind11::arg("ignore_frames"));
                                                                                                                                                                                                                                  ^
In file included from /Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:3:
In file included from /Users/zwimer/Desktop/Work/claripy/native/src/api/manual.hpp:8:
In file included from /Users/zwimer/Desktop/Work/claripy/native/src/api/constants.hpp:11:
/Users/zwimer/Desktop/Work/claripy/native/pybind11/include/pybind11/pybind11.h:157:9: error: static_assert failed due to requirement 'expected_num_args<pybind11::name, pybind11::scope, pybind11::sibling, char [1], pybind11::arg, pybind11::arg>(sizeof...(Args), argument_loader<void (&)(std::ostream &, unsigned int, short) noexcept>::has_args, argument_loader<void (&)(std::ostream &, unsigned int, short) noexcept>::has_kwargs)' "The number of argument annotations does not match the number of function arguments"
        static_assert(expected_num_args<Extra...>(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs),
        ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/zwimer/Desktop/Work/claripy/native/pybind11/include/pybind11/pybind11.h:77:9: note: in instantiation of function template specialization 'pybind11::cpp_function::initialize<(lambda at /Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:27), std::shared_ptr<const Util::Backtrace::Lazy>, void (&)(std::ostream &, unsigned int, short) noexcept, pybind11::name, pybind11::scope, pybind11::sibling, char [1], pybind11::arg, pybind11::arg>' requested here
        initialize(std::forward<Func>(f),
        ^
/Users/zwimer/Desktop/Work/claripy/native/pybind11/include/pybind11/pybind11.h:1276:22: note: in instantiation of function template specialization 'pybind11::cpp_function::cpp_function<(lambda at /Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:27), pybind11::name, pybind11::scope, pybind11::sibling, char [1], pybind11::arg, pybind11::arg, void>' requested here
        cpp_function cf(std::forward<Func>(f), name(name_), scope(*this),
                     ^
/Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:6: note: in instantiation of function template specialization 'pybind11::class_<Util::Backtrace::Lazy, std::shared_ptr<Util::Backtrace::Lazy>>::def_static<(lambda at /Users/zwimer/Desktop/Work/claripy/native/src/api/autogen.cpp:257:27), char [1], pybind11::arg, pybind11::arg>' requested here
                cl.def_static("create", [](void (&)(std::ostream &, unsigned int, short) noexcept a0, const unsigned short & a1) -> std::shared_ptr<const class Util::Backtrace::Lazy> { return Util::Backtrace::Lazy::create(a0, a1); }, "", pybind11::arg("gen"), pybind11::arg("ignore_frames"));

This error message reads as a parse error, so it likely would hold true on other compilers on other OSes as well, though I have not verified this.

Note the relatively large line numbers in the error message are because this is a snippet from a large project. If I remove the lines of source I posted though everything works as expected; it is adding those lines in which yields that small extra segment of code which leads to this compile error.

Thank you for reporting this @zwimer ! This is clearly issue with Binder and will looks this up. As immediate work around: simplest way to get around this will be to disable bindings for cc function (Binder should not have been try to bind this function in the first place!). You can do this by adding following line to your Binder config file: -function Util::Backtrace::cc.

@zwimer i just merged #195 which should fix this issue so could you please update to latests master and give it another try? Thanks,

@lyskov Why should binder not have been trying to bind the given function? Also, I will try the updated version in a bit and update this issue if it still does not work.

@zwimer i just verified and your code snipped is now could be bound without errors. Could please double check that your Binder sources and build is up-to-date with latest master? Thanks,

Also, now Binder will be able to bind given function (the one that you have in example).

@lyskov I have verified that it worked. 👍

It did, however, have the side effect of nuking one line from the autogen'd code:

cl.def("assign", (class Backend::Z3::Solver & (Backend::Z3::Solver::*)(const class Backend::Z3::Solver &)) &Backend::Z3::Solver::operator=, "C++: Backend::Z3::Solver::operator=(const class Backend::Z3::Solver &) --> class Backend::Z3::Solver &", pybind11::return_value_policy::automatic, pybind11::arg(""));

I'm not entirely sure why though, unless this was due to a previous since I last used binder.

The source file of this is:

#include <z3++.h>

namespace Backend::Z3 {
    /** A Z3 Solver object */
    class Solver final {
      public:
        /** Constructor */
        inline Solver(z3::solver sol) : s { std::move(sol) } {}
        /** Allow access to the z3::solver */
        inline z3::solver *operator->() { return &s; }
        /** Allow const access to the z3::solver */
        inline const z3::solver *operator->() const { return &s; }
      private:
        /** The z3::solver */
        z3::solver s;
    };
}

Solver is really just a wrapper for a z3::solver that binder can generate simple references to without binding all of Z3; I have +class Backend::Z3::Solver and -namespace z3 in my config so this really should only allow shared pointers to this class to be passed around and bind the assignment operator and the << operator. The call to pybind11::class_<Backend::Z3::Solver is still there, but the assignment operator is not being bound anymore.

I know this operator exists too; since I can and and compile the member function:

inline void foo(const Solver &o) { (*this) = o; }

No other functions in my codebase had their bindings change, just this one. Then again, I've been using a version of binder from github from back in early march so maybe something else is causing this; just figured I'd point it out just in case.

Hi, sorry about the above. I thought it was weird so I recompiled things a few times. I'm not sure why but when I recompiled LLVM it started working again. All is good now!

Thank you for letting me know @zwimer , - glad to hear it is is all working as expected now!