[proto][variant] variant crashes proto expression

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

[proto][variant] variant crashes proto expression

Igor R.
The following code is a slightly modified Proto calc2 example. Instead
of doubles I use variant<int, double>, and the expression is just _1 =
_2.
This code triggers assertion in variant/detail/forced_return.hpp, so
it looks like some variant instance gets messed up. It happens when
the value returned from proto::eval(*this, ctx) is being copied.
It can be reproduced both with MSVC and gcc, with Boost 1.60.

Is there any workaround for this issue?

Thanks.

//////////////
#include <iostream>
#include <boost/proto/proto_typeof.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/variant.hpp>

namespace proto = boost::proto;
using proto::_;

typedef boost::variant<int, double> var_t;

template<typename Expr>
struct calculator_expression;

// Tell proto how to generate expressions in the calculator_domain
struct calculator_domain
  : proto::domain<proto::generator<calculator_expression> >
{};

// Will be used to define the placeholders _1 and _2
template<int I> struct placeholder {};

// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp)
struct calculator_context
  : proto::callable_context< calculator_context const >
{
    // The values bound to the placeholders
    var_t d[2];

    // The result of evaluating arithmetic expressions
    typedef var_t result_type;

    explicit calculator_context(const var_t &d1 = var_t(), const var_t
&d2 = var_t())
    {
        d[0] = d1;
        d[1] = d2;
    }

    // Handle the evaluation of the placeholder terminals
    template<int I>
    result_type operator ()(proto::tag::terminal, placeholder<I>) const
    {
        return d[ I - 1 ];
    }
};

// Wrap all calculator expressions in this type, which defines
// operator () to evaluate the expression.
template<typename Expr>
struct calculator_expression
  : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
    explicit calculator_expression(Expr const &expr = Expr())
      : calculator_expression::proto_extends(expr)
    {}

    BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)

    // Override operator () to evaluate the expression
    var_t operator ()() const
    {
        calculator_context const ctx;
        return proto::eval(*this, ctx);
    }

    var_t operator ()(const var_t &d1) const
    {
        calculator_context const ctx(d1);
        return proto::eval(*this, ctx);
    }

    var_t operator ()(const var_t &d1, const var_t &d2) const
    {
        calculator_context const ctx(d1, d2);
        return proto::eval(*this, ctx);

    }
};

// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1;
calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2;

// Now, our arithmetic expressions are immediately executable function objects:
int main()
{
  BOOST_PROTO_AUTO(expr, _1 = _2);
  var_t a1(1), a2(2.5);
  expr(a1, a2);
  return 0;
}

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [proto][variant] variant crashes proto expression

sehe
On 12-05-16 21:10, Igor R wrote:

> The following code is a slightly modified Proto calc2 example. Instead
> of doubles I use variant<int, double>, and the expression is just _1 =
> _2.
> This code triggers assertion in variant/detail/forced_return.hpp, so
> it looks like some variant instance gets messed up. It happens when
> the value returned from proto::eval(*this, ctx) is being copied.
> It can be reproduced both with MSVC and gcc, with Boost 1.60.
>
> Is there any workaround for this issue?
>
>
I can only reproduce it with Clang. GCC 4.9+ is fine Are you using libc++?

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [proto][variant] variant crashes proto expression

Igor R.
> > Is there any workaround for this issue?
> >
> >
> I can only reproduce it with Clang. GCC 4.9+ is fine Are you using libc++?

Well, I didn't try it with clang/libc++ prior to posting it here, but it looks
like it fails with any possible compiler (http://melpon.org/wandbox).



_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [proto][variant] variant crashes proto expression

llonesmiz
This post has NOT been accepted by the mailing list yet.
In reply to this post by Igor R.
Igor R. wrote
The following code is a slightly modified Proto calc2 example. Instead
of doubles I use variant<int, double>, and the expression is just _1 =
_2.
This code triggers assertion in variant/detail/forced_return.hpp, so
it looks like some variant instance gets messed up. It happens when
the value returned from proto::eval(*this, ctx) is being copied.
It can be reproduced both with MSVC and gcc, with Boost 1.60.

Is there any workaround for this issue?

Thanks.

//////////////
#include <iostream>
#include <boost/proto/proto_typeof.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/variant.hpp>

namespace proto = boost::proto;
using proto::_;

typedef boost::variant<int, double> var_t;

template<typename Expr>
struct calculator_expression;

// Tell proto how to generate expressions in the calculator_domain
struct calculator_domain
  : proto::domain<proto::generator<calculator_expression> >
{};

// Will be used to define the placeholders _1 and _2
template<int I> struct placeholder {};

// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp)
struct calculator_context
  : proto::callable_context< calculator_context const >
{
    // The values bound to the placeholders
    var_t d[2];

    // The result of evaluating arithmetic expressions
    typedef var_t result_type;

    explicit calculator_context(const var_t &d1 = var_t(), const var_t
&d2 = var_t())
    {
        d[0] = d1;
        d[1] = d2;
    }

    // Handle the evaluation of the placeholder terminals
    template<int I>
    result_type operator ()(proto::tag::terminal, placeholder) const
    {
        return d[ I - 1 ];
    }
};

// Wrap all calculator expressions in this type, which defines
// operator () to evaluate the expression.
template<typename Expr>
struct calculator_expression
  : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
    explicit calculator_expression(Expr const &expr = Expr())
      : calculator_expression::proto_extends(expr)
    {}

    BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)

    // Override operator () to evaluate the expression
    var_t operator ()() const
    {
        calculator_context const ctx;
        return proto::eval(*this, ctx);
    }

    var_t operator ()(const var_t &d1) const
    {
        calculator_context const ctx(d1);
        return proto::eval(*this, ctx);
    }

    var_t operator ()(const var_t &d1, const var_t &d2) const
    {
        calculator_context const ctx(d1, d2);
        return proto::eval(*this, ctx);

    }
};

// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1;
calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2;

// Now, our arithmetic expressions are immediately executable function objects:
int main()
{
  BOOST_PROTO_AUTO(expr, _1 = _2);
  var_t a1(1), a2(2.5);
  expr(a1, a2);
  return 0;
}

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Do you expect that "a1==a2"  after the call to "expr(a1,a2)"? Because then there are several "const"s that should be removed (In fact the original "Calc2" example fails at compile time when you use the same expression "_1 = _2"). I don't know if this is the best approach but the following seems to work:

//----------------------------------------------------------------------
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/variant.hpp>

namespace proto = boost::proto;
using proto::_;

//typedef double Value;
typedef boost::variant<int,double> Value;

template<typename Expr>
struct calculator_expression;

// Tell proto how to generate expressions in the calculator_domain
struct calculator_domain
  : proto::domain<proto::generator<calculator_expression> >
{};

// Will be used to define the placeholders _1 and _2
template<int I> struct placeholder {};

// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp)
struct calculator_context
  : proto::callable_context< calculator_context const >
{
    // The values bound to the placeholders
    Value *d[2];

    // The result of evaluating arithmetic expressions
    typedef Value& result_type;

    calculator_context(Value& d1, Value& d2)
    {
        d[0] = &d1;
        d[1] = &d2;
    }

    // Handle the evaluation of the placeholder terminals
    template<int I>
    Value& operator ()(proto::tag::terminal, placeholder) const
    {
        return *d[ I - 1 ];
    }
};

// Wrap all calculator expressions in this type, which defines
// operator () to evaluate the expression.
template<typename Expr>
struct calculator_expression
  : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
    explicit calculator_expression(Expr const &expr = Expr())
      : calculator_expression::proto_extends(expr)
    {}

    BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression)

    // Override operator () to evaluate the expression
    Value operator ()() const
    {
        Value d1,d2;
        calculator_context const ctx(d1,d2);
        return proto::eval(*this, ctx);
    }

    Value operator ()(Value& d1) const
    {
        Value d2;
        calculator_context const ctx(d1,d2);
        return proto::eval(*this, ctx);
    }

    Value operator ()(Value& d1, Value d2) const
    {
        calculator_context const ctx(d1, d2);
        return proto::eval(*this, ctx);
    }
};

// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1;
calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2;

// Now, our arithmetic expressions are immediately executable function objects:
int main()
{

    Value a(2), b(3.5);
   
    std::cout << a << ", " << b << std::endl;
   
    std::cout << ( _1 = _2 )( a, b) << std::endl;

    std::cout << a << ", " << b << std::endl;
   
    std::cout << ( _1 = _2 )( a) << std::endl;

    std::cout << a << ", " << b << std::endl;

    return 0;
}
//---------------------------------------------

On Wandbox => http://melpon.org/wandbox/permlink/h2G0EOkatroEmoVA
Reply | Threaded
Open this post in threaded view
|

Re: [proto][variant] variant crashes proto expression

Igor R.
>   // The values bound to the placeholders
>    Value *d[2];
<...>
> // The result of evaluating arithmetic expressions
> typedef Value& result_type;


So, you store pointers to the variants and return references, thus preventing copying.
But why does the copying cause the aforementioned crash? Does it look like a bug in Proto?
That's quite weird, because I never encountered any issue with variant copying...