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

            Bug ID: 83470
           Summary: Type morphing nested lambda capture
           Product: gcc
           Version: 7.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: patrick.a.moran at gmail dot com
  Target Milestone: ---

Created attachment 42908
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=42908&action=edit
The minimal reproduction as a separate file

I found this compiling with gcc 7.2.0 with

  --std=c++1z -Wall -Wextra


Including my very-minimal repro inline here because I don't know how else to
explain the issue.

--------------
#include <type_traits>
// This has to be templated, but the argument doesn't need to be
// used for anything
template <class T> double& g();

template <class T>
int f() {
  auto& v = g<T>();
  static_assert(std::is_same<decltype(v), T&>::value);
  [](auto inner) {
    inner(true);
  }([&](auto) {
      static_assert(std::is_same<decltype(v), bool&>::value);
    });
  return 0;
}

int dummy = f<double>();
--------------

As you can see, in this very specific circumstance, the type of v morphs from
double& to bool& in the inner lambda. It isn't that bool is special - whatever
type we pass as the ignored argument to the inner lambda, v will become that
type (lvalue-ref'ed).  Changing any of the following will cause the bug to go
away:

* Making f() not a template
* Making g() not a template, or giving g() a template argument that isn't the
template argument to f().
* Changing the declaration of v to explicitly spell out double& rather than
letting auto& deduce it.
* Eliminating the lambda-wrapping. If you directly call the inner lambda, it
won't reproduce.

Reply via email to