Bug 88164 - Lambda is allowed to capture any constexpr variable without specifying any captures
Summary: Lambda is allowed to capture any constexpr variable without specifying any ca...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid, c++-lambda
: 95269 (view as bug list)
Depends on:
Blocks: lambdas
  Show dependency treegraph
 
Reported: 2018-11-23 09:24 UTC by Olivier Kannengieser
Modified: 2025-03-12 17:11 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-02-03 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Olivier Kannengieser 2018-11-23 09:24:38 UTC
In the code bellow the copy constructor of "a" should be called:

  struct A {
    int x=12;
    constexpr A(){}
    A(const A& x);
    };

  int f(A);

  // This function should not compile
  // And the generated code does not call the copy constructor of A
  int test() {
    constexpr A a{};
    auto lambda = []{
        return f(a); // Unexpected: does not call the copy constructor, 
                     // should not compile: a should be explicitly captured
        };
    return lambda();
    }

The the call to the copy constructor does not appear in the generated assembly:
      test():
        subq    $24, %rsp
        leaq    12(%rsp), %rdi
        movl    $12, 12(%rsp)
        call    f(A)
        addq    $24, %rsp
        ret

While without the lambda:

  int test_expect_assembly(){
    constexpr A a{};
    return f(a);
    }

the copy constructor is called:

  test_expect_assembly():
        subq    $24, %rsp
        leaq    8(%rsp), %rsi
        leaq    12(%rsp), %rdi
        movl    $12, 8(%rsp)
        call    A::A(A const&)
        leaq    12(%rsp), %rdi
        call    f(A)
        addq    $24, %rsp
        ret

This unexpected copy constructor elision
only happens for function arguments construction.
The code below produces the expected assembly
and GCC requires the explicit capture of "a":

  int test_copy_initialization() {
    constexpr A a{};
    auto lambda = [&a]{ // a must be captured
        A b=a;
        return a.x;
        };
    return lambda();
    }


Moreover there is a related bug when the variable has global scope,
the copy constructor is called, nevertheless GCC should not implicitly captures
the variable because the variable is ODR used. 
 
The capture should be explicit, the code below should not compile:

  constexpr A n_a{};
  int test_ns() {
    auto lambda = []{
        return f(n_a);// call the copy constructor so odr use n_a
                      // Unexpected: n_a should be explictly captured
        };
    return lambda();
    }
Comment 1 Andrew Pinski 2022-02-03 04:57:26 UTC
For test, clang rejects it with:
<source>:15:18: error: variable 'a' cannot be implicitly captured in a lambda with no capture-default specified
        return f(a); // Unexpected: does not call the copy constructor, 
                 ^
<source>:13:17: note: 'a' declared here
    constexpr A a{};
                ^
<source>:14:19: note: lambda expression begins here
    auto lambda = []{
                  ^
<source>:14:20: note: capture 'a' by value
    auto lambda = []{
                   ^
                   a
<source>:14:20: note: capture 'a' by reference
    auto lambda = []{
                   ^
                   &a
<source>:14:20: note: default capture by value
    auto lambda = []{
                   ^
                   =
<source>:14:20: note: default capture by reference
    auto lambda = []{
                   ^
                   &
Comment 2 Andrew Pinski 2022-02-03 05:00:34 UTC
*** Bug 95269 has been marked as a duplicate of this bug. ***
Comment 3 Andrew Pinski 2022-02-03 05:01:14 UTC
Confirmed. Though I don't know 100% this is invalid code.