https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92679

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |INVALID

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Non-preprocessed testcase:

#include <iostream>
#include <typeindex>
#include <functional>
#include <any>
#include <unordered_map>

template <typename TReturn>
struct any_visitor {
  using function = std::function<TReturn(std::any &)>;
  std::unordered_map<std::type_index, function> functions;

  template <typename TArg>
  void accept(std::function<TReturn(TArg &)> f) {
    functions.insert(std::make_pair(std::type_index(typeid(TArg)),
                                    function([&f](std::any &x) -> TReturn {
                                      return f(std::any_cast<TArg &>(x));
                                    })));
  }

  TReturn operator()(std::any &x) {
    try {
      auto function = functions.at(std::type_index(x.type()));

      return function(x);
    } catch (...) {
      throw std::runtime_error("No visitor registered");
    }
  }
};

int main() {
  auto visitor = any_visitor<std::string>();

  visitor.accept<int>([](int x) { return std::to_string(x); });
  visitor.accept<double>([](double x) { return std::to_string(x); });
  visitor.accept<std::string>([](std::string &x) { return x; });
  visitor.accept<std::vector<double>>(
      [](std::vector<double>&) { return "VECTOR"; });

  std::any x;

  x = 1;
  std::cout << visitor(x) << "\n";

  x = 1.;
  std::cout << visitor(x) << "\n";

  x = std::string("STRING");
  std::cout << visitor(x) << "\n";

  x = std::vector<double>{0., 1., 2., 3., 4., 5.};
  std::cout << visitor(x) << "\n";
}

The bug is here:

  void accept(std::function<TReturn(TArg &)> f) {
    functions.insert(std::make_pair(std::type_index(typeid(TArg)),
                                    function([&f](std::any &x) -> TReturn {
                                             ^^^^

You're binding a reference to a function parameter, which goes out of scope as
soon as the function returns. When you later invoke the std::function it uses a
dangling reference.

Reply via email to