Opened 9 years ago

Last modified 8 years ago

#8564 new Bugs

Variable hiding errors within nested let blocks in Phoenix

Reported by: miremare@… Owned by: Thomas Heller
Milestone: To Be Determined Component: phoenix
Version: Boost 1.53.0 Severity: Problem
Keywords: Cc:

Description

I encounter errors when using nested let blocks in Phoenix whenever an "inner" local variable hides an "outer" local variable. The "Visibility" example from the documentation at http://www.boost.org/doc/libs/1_53_0/libs/phoenix/doc/html/phoenix/modules/scope/let.html also fails. Here is that "Visibility" example as a standalone module which fails:

#include <iostream>
#include <boost/phoenix.hpp>

namespace phoenix = boost::phoenix;
using namespace phoenix::local_names;

int main(int argc, char *argv[])
{
  phoenix::let(_x = 1, _y = ", World")
  [
    phoenix::let(_x = "Hello") // hides the outer _x
    [
      std::cout << _x << _y // prints "Hello, World"
    ]
  ]();

  return 0;
}

The errors I receive from GCC 4.7.2, GCC 4.8 snapshot, and Clang 3.2, with any of Boost 1.49, 1.53, or trunk, begin as follows:

GCC: "error: function returning an array"

Clang: "error: function cannot return array type 'result_type' (aka 'char [6]')"

Another failing example provided in Eric Niebler's Stack Overflow answer here is:

int y = 0;
int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = 3)[ _a ]])(y);

...which contrasts with the following example; which does compile:

int y = 0;
int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = _1)[ _a ]])(y);

Change History (4)

comment:1 by John Fletcher <J.P.Fletcher@…>, 9 years ago

This is indeed a bug and the examples given do not work. The solution is to use either an argument e.g _1 or a local variable e.g. _a to assign value to the local variable in the inner let.

These examples both work with the definitions

namespace phoenix = boost::phoenix;
using namespace phoenix::local_names;
using boost::phoenix::arg_names::_1;
using boost::phoenix::arg_names::_2;
using boost::phoenix::arg_names::_3;
using std::cout;
  phoenix::let(_x = _1, _y = _2)
  [
      let(_x = _3) // hides the outer _x
      [
       cout << _x << _y // prints "Hello, World"
      ]
  ](1," World","Hello,");
  cout << std::endl;
  phoenix::let(_x = _1, _y = _2, _z = _3)
  [
      let(_x = _z) // hides the outer _x
      [
       cout << _x << _y // prints "Hello, World"
      ]
  ](1," World","Hello,");
  cout << std::endl;

I will investigate further and also change the documentation. John

comment:2 by John Fletcher <J.P.Fletcher@…>, 9 years ago

Further work has shown that these cases work as expected:

  {
    int z = 3;
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = _a)[ _a ]])(y);
  }
  {
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = _1)[ _a ]])(y);
  }
  {
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = 1)[_b]])();
  }  // This works....

but this case fails:

  {
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = 1)[_a]])();
  }

Reference to _a in the inner loop is the problem, but only when _b is set to a constant!!

Further investigation is in progress.

in reply to:  2 comment:3 by John Fletcher <J.P.Fletcher@…>, 9 years ago

Replying to John Fletcher <J.P.Fletcher@…>:

Further work has shown that these cases work as expected

  {
    int z = 3;
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = _a)[ _a ]])(y);
  }
  {
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = _1)[ _a ]])(y);
  }
  {
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = 1)[_b]])();
  }  // This works....

but this case fails:

  {
    int y = 0;
    int x = (phoenix::let(_a = 1, _b = 2)[phoenix::let(_b = 1)[_a]])();
  }

Reference to _a in the inner loop is the problem, but only when _b is set to a constant!!

Further investigation is in progress.

Unfortunately it is not as easy as that. The 'working' cases above fail for some compilers e.g. clang 3.4 in C++03 but not C++11. gcc 4.8.2 works for C++03 and C++11. Work is in progress.

comment:4 by John Fletcher <J.P.Fletcher@…>, 8 years ago

Apologies for the delay in giving further information. There is certainly a problem in Boost Phoenix V3 in the implementation of let and lambda. This shows up in various ways. In some cases code works when not optimised but fails when optimised - gcc 4.9.0 on -O1 and clang 3.5 on -O2. I know this is serious and I am working on it. The documentation is being revised and will be much more up to date with the next release of Boost.

Note: See TracTickets for help on using tickets.