<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - By-reference variadic init-capture copies objects in lambda"
   href="https://bugs.llvm.org/show_bug.cgi?id=49922">49922</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>By-reference variadic init-capture copies objects in lambda
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>C++2a
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>andrey458641387@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>blitzrakete@gmail.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Overview:
In a by-reference capture with an initializer that is a pack expansion (of the
form "&... identifier initializer") the result of the initializer is stored in
the lambda object by-copy instead of by-reference.

Steps to reproduce: build and run the following code in C++20 mode.

    void print_arg_addresses(auto &...args) {
        (std::cout << ... << static_cast<const void *>(&args)) << '\n';
    }

    void pass_arg_refs_through_lambda(auto &...args) {
        [&...args = args] { // <-- THE BUG IS HERE!
            print_arg_addresses(args...);
        }();
    }

    int main() {
        auto a = 0;
        print_arg_addresses(a);
        pass_arg_refs_through_lambda(a);
    }

Here is a Compiler Explorer link with more variants of the code:
<a href="https://godbolt.org/z/Ycaejs9jd">https://godbolt.org/z/Ycaejs9jd</a>

Actual Results: the printed addresses are NOT equal.
Expected Results: the printed addresses are equal.

This bug is reproducible on all versions of Clang starting with 9.0 (when the
feature was first implemented) and including the "trunk" version from Compiler
Explorer. It has been reproduced on both Linux and Windows (with the clang-cl
driver).

GCC and MSVC both compile the code as expected - capture by-reference (MSVC
requires an explicit "template<typename... Args>" instead of just "auto &..."
though).

Also, normal by-reference captures with initializers (i.e. "&arg = arg") work
correctly (see CE example).
Optimization flags don't appear to affect the behavior.

<speculation>
Judging by the behavior of some real-world code, the ref-qualifier is simply
ignored, and the capture is treated as if it was "by-copy".
</speculation></pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>