[boost::proto] bug with large (> 8) values for BOOST_PROTO_MAX_ARITY

The following piece of code compiles fine: #define BOOST_PROTO_MAX_ARITY 8 #include <boost/xpressive/proto/proto.hpp> while the following gives errors #define BOOST_PROTO_MAX_ARITY 9 #include <boost/xpressive/proto/proto.hpp> and so on for any value of BOOST_PROTO_MAX_ARITY larger than 8. If there's a real problem with more than eight, it would be good to have an #error statement in that case. I'm really interested in having patterns with those many arguments, so once the variable controlling the maximum arity and the one controlling the maximum number of subpatterns in a pattern get decoupled I may be fine, but still giving a clear error message would be helpful. I only need BOOST_PROTO_MAX_ARITY=8. I tried 9 just because I was getting ambiguous conversions, which in the past were due to this. Best regards, Maurizio

Maurizio Vitale <mav@cuma.polymath-solutions.lan> writes:
The following piece of code compiles fine:
#define BOOST_PROTO_MAX_ARITY 8 #include <boost/xpressive/proto/proto.hpp>
while the following gives errors
#define BOOST_PROTO_MAX_ARITY 9 #include <boost/xpressive/proto/proto.hpp>
and so on for any value of BOOST_PROTO_MAX_ARITY larger than 8.
Another data point: even though the above code compile with 8 and 7, in my real code I get a match failure on number<_,_,_,_,_,_,_,_> [8] or number<_,_,_,_,_,_,_> [7]. As far as I can tell, the only difference between the working code and the non-working code is the additional template arguments to number<>, which are not used. So it is possible that matches fail for patterns with more than 6 elements, but I still have to reproduce the problem on a small testcase. Best regards, Maurizio

Here a smallish example. Ok for ARITY==2 and 6. Fails with ARITY==8 (I suspect anything above 6) Best regards, Maurizio #include <iostream> #define ARITY 2 #if ARITY==2 #define NUMBER number<_,_> #define NUMBER_TPL_DECL template<typename A, typename B> #define NUMBER_TPL_INST number<A,B> #define NUMBER_TPL_INST1 number<mpl::int_<0>,mpl::int_<0> > #elif ARITY==6 #define BOOST_PROTO_MAX_ARITY 6 #define NUMBER number<_,_,_,_,_,_> #define NUMBER_TPL_DECL template<typename A, typename B, typename C, typename D, typename E, typename F> #define NUMBER_TPL_INST number<A,B,C,D,E,F> #define NUMBER_TPL_INST1 number<mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0> > #else #define BOOST_PROTO_MAX_ARITY 8 #define NUMBER number<_,_,_,_,_,_,_,_> #define NUMBER_TPL_DECL template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> #define NUMBER_TPL_INST number<A,B,C,D,E,F,G,H> #define NUMBER_TPL_INST1 number<mpl::int_<0>,mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0> > #endif #include <boost/xpressive/proto/proto.hpp> #include <boost/xpressive/proto/context.hpp> #include <boost/xpressive/proto/extends.hpp> #include <boost/xpressive/proto/debug.hpp> #include <boost/xpressive/proto/transform/arg.hpp> #include <boost/xpressive/proto/transform/construct.hpp> //#include <boost/xpressive/proto/transform/fold_to_list.hpp> #include <boost/typeof/typeof.hpp> #include <boost/typeof/std/ostream.hpp> #include <boost/mpl/integral_c.hpp> #include <boost/mpl/contains.hpp> #include <boost/mpl/vector.hpp> #include <boost/test/unit_test.hpp> namespace proto=boost::proto; namespace mpl=boost::mpl; struct my_domain : proto::domain<struct my_grammar> {}; template<typename> struct my_context; template <typename Expr> struct my_expr : proto::extends<Expr, my_expr<Expr>, my_domain> { typedef proto::extends<Expr, my_expr<Expr>, my_domain> base_type; my_expr (Expr const& expr = Expr()) : base_type (expr) {}; using base_type::operator =; operator int () const { return static_cast<int>(proto::eval(*this, my_context<Expr> ())); } operator unsigned int () const { return static_cast<unsigned int>(proto::eval(*this, my_context<Expr> ())); } }; NUMBER_TPL_DECL struct number; NUMBER_TPL_DECL std::ostream& operator << (std::ostream& os, const NUMBER_TPL_INST o); NUMBER_TPL_DECL struct number { friend std::ostream& operator << <> (std::ostream& os, const NUMBER_TPL_INST o); unsigned int m_data; }; NUMBER_TPL_DECL std::ostream& operator << (std::ostream& os, const NUMBER_TPL_INST n) { os << "~U~" << n.m_data << "~"; return os; } using proto::_; struct my_grammar : proto::or_ < proto::terminal< NUMBER > , proto::terminal<int>, proto::terminal<unsigned int>, proto::unary_expr<proto::_, my_grammar> , proto::binary_expr<proto::_, my_grammar, my_grammar>
{}; namespace boost { namespace proto { template<typename Expr> struct generate<my_domain, Expr> { typedef my_expr<Expr> type; static type make (Expr const& expr) { return type (expr); } }; } } // end namespace boost::proto template<typename Expr> struct my_context : proto::callable_context<const my_context<Expr> > { typedef unsigned int result_type; NUMBER_TPL_DECL unsigned int operator () (proto::tag::terminal, NUMBER_TPL_INST n) const { return n.m_data; } }; template<int N> struct my_int : my_expr<typename proto::terminal< NUMBER_TPL_INST1 >::type> { typedef NUMBER_TPL_INST1 number_type; typedef my_expr<typename proto::terminal<number_type>::type> expr_type; my_int () {} my_int (int i) : expr_type (expr_type::type::make (i)) {} template<typename Expr> my_int& operator = (const my_expr<Expr>& e) { proto::arg (*this).m_data = static_cast<int>(proto::eval(e, my_context<Expr> ())); return *this; } template<typename T> my_int& operator = (T value) { proto::arg (*this).m_data = value; return *this; } friend std::ostream& operator << (std::ostream& os, const my_int n) { os << "my_int<" << proto::arg(n).m_data << ">"; return os; } }; #include <boost/test/included/unit_test_framework.hpp> using namespace boost::unit_test; template<typename Expr> void test (const Expr& expr) { std::cout << "Expression:\n"; display_expr (expr); if (proto::matches<Expr, my_grammar>::value) std::cout << "matches my grammar\n\n"; else std::cout << "doesn't matches my grammar\n\n"; } void misc_test () { my_int<6> i4(-22); int i; unsigned int j; i4 = 5; i4 = 5*i4; i = i4/i4+4; j = i4/i4; display_expr (i4/i4+4); std::cout << "my_expr, -22/7 =" << i4 << "\n"; // std::cout << "my_expr, -22/7 =" << i4*i4 << "\n"; // ambiguous std::cout << "my_expr, -22/7 [assigned to int]=" << i << "\n"; std::cout << "my_expr, -22/7 [assigned to unsigned int]=" << j << "\n"; } test_suite* init_unit_test_suite (int, char**) { test_suite* test= BOOST_TEST_SUITE( "boost::proto sandbox" ); test->add (BOOST_TEST_CASE (&misc_test)); return test; } /// Local Variables: /// mode:c++ /// comment-column:80 /// fill-column:160 /// compilation-read-command:nil /// compile-command:"g++ -I. -ope1 pe1.cpp" /// End:

Maurizio Vitale wrote:
Another data point: even though the above code compile with 8 and 7, in my real code I get a match failure on number<_,_,_,_,_,_,_,_> [8] or number<_,_,_,_,_,_,_> [7]. As far as I can tell, the only difference between the working code and the non-working code is the additional template arguments to number<>, which are not used.
This is only a problem on GCC because of a compiler bug wrt template template parameters. Proto reuses a work-around from the MPL, which is conditioned on an MPL macro called BOOST_MPL_LIMIT_METAFUNCTION_ARITY. If you define this to be at least as large as BOOST_PROTO_MAX_ARITY, the problem goes away. I've added some code to check for this condition and fail loudly at compile time. Also, in another mail, you say:
I'm really interested in having patterns with those many arguments, so once the variable controlling the maximum arity and the one controlling the maximum number of subpatterns in a pattern get decoupled I may be fine, but still giving a clear error message would be helpful.
Depending on what "number of subpatterns in a pattern" means, you may already have what you want. There is a separate macro called BOOST_PROTO_MAX_LOGICAL_ARITY which controls how many parameters proto::or_ and proto::and_ accept. It is independent of BOOST_PROTO_MAX_ARITY. For the time being, whether a pattern such as number<_,_,_,_,_,_,_,_> is accepted is controlled by BOOST_PROTO_MAX_ARITY. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler <eric@boost-consulting.com> writes:
This is only a problem on GCC because of a compiler bug wrt template template parameters. Proto reuses a work-around from the MPL, which is conditioned on an MPL macro called BOOST_MPL_LIMIT_METAFUNCTION_ARITY. If you define this to be at least as large as BOOST_PROTO_MAX_ARITY, the problem goes away.
Mmmh, does the code I sent compile for you when ARITY==8? It still doesn't for me. (I get "ambiguous overload of operator OP", which is jargon for "your expression doesn't match the grammar") I've synched up and I see your change in matches.hpp for checking the proper settings of BOOST_MPL_LIMIT_METAFUNCTION_ARITY.
Also, in another mail, you say:
I'm really interested in having patterns with those many arguments, so once the variable controlling the maximum arity and the one controlling the maximum number of subpatterns in a pattern get decoupled I may be fine, but still giving a clear error message would be helpful.
Depending on what "number of subpatterns in a pattern" means, you may already have what you want. There is a separate macro called BOOST_PROTO_MAX_LOGICAL_ARITY which controls how many parameters proto::or_ and proto::and_ accept. It is independent of BOOST_PROTO_MAX_ARITY. For the time being, whether a pattern such as number<_,_,_,_,_,_,_,_> is accepted is controlled by BOOST_PROTO_MAX_ARITY.
I mean number<_,_,_,_,_,_,_,_>. I'll probably try to reduce the number of arguments by grouping even more of them in other structs, but for now I haven't come up with the right ones, which is why I prefer to have them lined up and do the grouping only once. Regards, Maurizio

Maurizio Vitale wrote:
Eric Niebler <eric@boost-consulting.com> writes:
This is only a problem on GCC because of a compiler bug wrt template template parameters. Proto reuses a work-around from the MPL, which is conditioned on an MPL macro called BOOST_MPL_LIMIT_METAFUNCTION_ARITY. If you define this to be at least as large as BOOST_PROTO_MAX_ARITY, the problem goes away.
Mmmh, does the code I sent compile for you when ARITY==8? It still doesn't for me.
Yes, if I compile your code with: #define ARITY 8 #define BOOST_MPL_LIMIT_METAFUNCTION_ARITY 8 then it works with gcc-3.4, gcc-4.0 and gcc-4.1. I double checked that I have no pending commits lying around. I don't know what the problem could be, sorry. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler <eric@boost-consulting.com> writes:
Yes, if I compile your code with:
#define ARITY 8 #define BOOST_MPL_LIMIT_METAFUNCTION_ARITY 8
then it works with gcc-3.4, gcc-4.0 and gcc-4.1. I double checked that I have no pending commits lying around. I don't know what the problem could be, sorry.
Still not working here. I tried 3.4 and 4.1.2 on X86_64 and 4.0.1 (with Apple mods) on Mac OS X (32 bit Intel). They all fail. I've also synched up the entire boost in case something outside of proto changed. I'll let you know if I discover something. Best regards, Maurizio

Maurizio Vitale wrote:
Still not working here. I tried 3.4 and 4.1.2 on X86_64 and 4.0.1 (with Apple mods) on Mac OS X (32 bit Intel). They all fail. I've also synched up the entire boost in case something outside of proto changed. I'll let you know if I discover something.
Send me a complete .cpp that reproduces the problem. Note that I only have x86 here, so I can't test on X86_64 or OSX. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler <eric@boost-consulting.com> writes:
Maurizio Vitale wrote:
Still not working here. I tried 3.4 and 4.1.2 on X86_64 and 4.0.1 (with Apple mods) on Mac OS X (32 bit Intel). They all fail. I've also synched up the entire boost in case something outside of proto changed. I'll let you know if I discover something.
Send me a complete .cpp that reproduces the problem. Note that I only have x86 here, so I can't test on X86_64 or OSX.
So between the two of us we have an healthy mix of machines. The reason I tried Mac OS is not much because I'm interested in it for development, rather it happens to be the only 32 bit machine I have. There was oveload ambiguity between signed and unsigned int, so size was probably not the reason, but still it was a cheap test. Please find attached a small piece of code which has problems. It is basically what I sent before , preprocessed for ARITY==8 and with a few other things that didn't contribute to the error removed. With GCC 4.1.2 on X86_64 (but it is the same everywhere I tried), I get the following: -*- mode: compilation; default-directory: "~/dev/proto_pdl/" -*- Compilation started at Thu May 3 14:28:41 g++ -I. -ope1 pe1.cpp pe1.cpp: In function ‘int main(int, char**)’: pe1.cpp:101: error: ambiguous overload for ‘operator*’ in ‘5 * i4’ pe1.cpp:101: note: candidates are: operator*(int, int) <built-in> pe1.cpp:101: note: operator*(int, unsigned int) <built-in> pe1.cpp:103: error: ambiguous overload for ‘operator/’ in ‘i4 / i4’ pe1.cpp:103: note: candidates are: operator/(int, int) <built-in> pe1.cpp:103: note: operator/(int, unsigned int) <built-in> pe1.cpp:103: note: operator/(unsigned int, int) <built-in> pe1.cpp:103: note: operator/(unsigned int, unsigned int) <built-in> pe1.cpp:104: error: ambiguous overload for ‘operator/’ in ‘i4 / i4’ pe1.cpp:104: note: candidates are: operator/(int, int) <built-in> pe1.cpp:104: note: operator/(int, unsigned int) <built-in> pe1.cpp:104: note: operator/(unsigned int, int) <built-in> pe1.cpp:104: note: operator/(unsigned int, unsigned int) <built-in> Compilation exited abnormally with code 1 at Thu May 3 14:28:42 If I either: - reduce the arguments to the template number<...> down to 6, or - declare my_domain as struct my_domain : proto::domain<> {}; [no grammar] then everything is ok.
From past experience this is an indication that expressions don't match the grammar and that, further, the reason for this is number<_,_,_,_,_,_,_,_>.
Hope this helps. In the mean time I'll cut the number of arguments to number<...>. That's good regardless. Best regards, Maurizio Here's the file: #include <iostream> #define BOOST_PROTO_MAX_ARITY 8 #define BOOST_MPL_LIMIT_METAFUNCTION_ARITY 8 // GCC bug workaround, needs to be at least BOOST_PROTO_MAX_ARITY #include <boost/xpressive/proto/proto.hpp> #include <boost/xpressive/proto/context.hpp> #include <boost/xpressive/proto/extends.hpp> #include <boost/xpressive/proto/transform/arg.hpp> #include <boost/xpressive/proto/transform/construct.hpp> namespace proto=boost::proto; namespace mpl=boost::mpl; using proto::_; struct my_domain : proto::domain<struct my_grammar> {}; //struct my_domain : proto::domain<> {}; template<typename> struct my_context; template <typename Expr> struct my_expr : proto::extends<Expr, my_expr<Expr>, my_domain> { typedef proto::extends<Expr, my_expr<Expr>, my_domain> base_type; my_expr (Expr const& expr = Expr()) : base_type (expr) {}; using base_type::operator =; operator int () const { return static_cast<int>(proto::eval(*this, my_context<Expr> ())); } operator unsigned int () const { return static_cast<unsigned int>(proto::eval(*this, my_context<Expr> ())); } }; template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> struct number { unsigned int m_data; }; struct my_grammar : proto::or_ < proto::terminal< number<_,_,_,_,_,_,_,_> > , proto::terminal<int>, proto::terminal<unsigned int>, proto::unary_expr<proto::_, my_grammar> , proto::binary_expr<proto::_, my_grammar, my_grammar>
{}; namespace boost { namespace proto { template<typename Expr> struct generate<my_domain, Expr> { typedef my_expr<Expr> type; static type make (Expr const& expr) { return type (expr); } }; } } // end namespace boost::proto template<typename Expr> struct my_context : proto::callable_context<const my_context<Expr> > { typedef unsigned int result_type; template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> unsigned int operator () (proto::tag::terminal, number<A,B,C,D,E,F,G,H> n) const { return n.m_data; } }; template<int N> struct my_int : my_expr<typename proto::terminal< number<mpl::int_<0>,mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0> > >::type> { typedef number<mpl::int_<0>,mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0> > number_type; typedef my_expr<typename proto::terminal<number_type>::type> expr_type; my_int () {} my_int (int i) : expr_type (expr_type::type::make (i)) {} template<typename Expr> my_int& operator = (const my_expr<Expr>& e) { proto::arg (*this).m_data = static_cast<int>(proto::eval(e, my_context<Expr> ())); return *this; } template<typename T> my_int& operator = (T value) { proto::arg (*this).m_data = value; return *this; } }; int main (int,char**) { my_int<6> i4(-22); int i; unsigned int j; i4 = 5; i4 = 5*i4; i = i4/i4+4; j = i4/i4; } /// Local Variables: /// mode:c++ /// comment-column:80 /// fill-column:160 /// compilation-read-command:nil /// compile-command:"g++ -I. -ope1 pe1.cpp" /// End:

Maurizio Vitale wrote:
Eric Niebler <eric@boost-consulting.com> writes:
Maurizio Vitale wrote:
Still not working here. I tried 3.4 and 4.1.2 on X86_64 and 4.0.1 (with Apple mods) on Mac OS X (32 bit Intel). They all fail. I've also synched up the entire boost in case something outside of proto changed. I'll let you know if I discover something. Send me a complete .cpp that reproduces the problem. Note that I only have x86 here, so I can't test on X86_64 or OSX.
Please find attached a small piece of code which has problems. It is basically what I sent before , preprocessed for ARITY==8 and with a few other things that didn't contribute to the error removed.
I think you're probably picking up MPL's preprocessed headers, so "#define BOOST_MPL_LIMIT_METAFUNCTION_ARITY 8" is having no effect. Can you try adding: #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS ? -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler <eric@boost-consulting.com> writes:
I think you're probably picking up MPL's preprocessed headers, so "#define BOOST_MPL_LIMIT_METAFUNCTION_ARITY 8" is having no effect. Can you try adding:
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
That was it. Sorry for the noise. Thanks, Maurizio
participants (2)
-
Eric Niebler
-
Maurizio Vitale