Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Can't capture outer variable in nested function expression #880

Open
JohelEGP opened this issue Dec 8, 2023 · 0 comments
Open

[BUG] Can't capture outer variable in nested function expression #880

JohelEGP opened this issue Dec 8, 2023 · 0 comments
Labels
bug Something isn't working

Comments

@JohelEGP
Copy link
Contributor

JohelEGP commented Dec 8, 2023

Title: Can't capture outer variable in nested function expression.

Description:

I suspect (test_case$)$ could be made to work here, but that ICEs.
test_case$$ errors with $ (capture) can appear at most once in a single postfix-expression (at '$').

There are two possible interpretations for (test_case$)$:

  1. test_case$ is the name of an outer capture, and (test_case$)$ captures that.
  2. (test_case$)$ captures (test_case$), and that captures test_case in the outer context.

Both mean the same thing to the inner context.
In 1., test_case$ is already captured in the outer context, and the inner context uses it.
In 2., (test_case$) is captured, which makes the outer context capture test_case.

Minimal reproducer (https://cpp2.godbolt.org/z/jGWaqj3hq):

f: () = {
  test_case := :(_...) = { };
  test_int := :(count: int) = {
    (test_case := test_case$) {
      test := :(_) test_case$(count$);
      test(0);
      test(1);
    }
    // GCC: error: 'test_case' is not captured
    // Clang: error: variable 'test_case' cannot be implicitly captured in a lambda with no capture-default specified
    test := :(_) test_case$(count$);
    test(0);
    test(1);
  };
  test_int(17);
  test_case(29);
}
main: () = { }
Commands:
cppfront main.cpp2
clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -Werror=unused-value -Werror=unused-parameter -Werror=unused-variable -I . main.cpp

Expected result: Some way for capturing expressions not captured in the outer context.

Actual result and error:

Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"

#line 1 "/app/example.cpp2"


//=== Cpp2 type definitions and function declarations ===========================

#line 1 "/app/example.cpp2"
auto f() -> void;

#line 18 "/app/example.cpp2"
auto main() -> int;

//=== Cpp2 function definitions =================================================

#line 1 "/app/example.cpp2"
auto f() -> void{
#line 2 "/app/example.cpp2"
  auto test_case {[]([[maybe_unused]] auto const& ...unnamed_param_1) mutable -> void{}}; 
  auto test_int {[_0 = test_case](cpp2::in<int> count) mutable -> void{
{
auto const& test_case = _0;
#line 4 "/app/example.cpp2"
    {
      auto test {[_0 = test_case, _1 = count]([[maybe_unused]] auto const& unnamed_param_1) mutable -> auto { return _0(_1);  }}; 
      test(0);
      std::move(test)(1);
    }
}
    // GCC: error: 'test_case' is not captured
    // Clang: error: variable 'test_case' cannot be implicitly captured in a lambda with no capture-default specified
#line 11 "/app/example.cpp2"
    auto test {[_0 = test_case, _1 = count]([[maybe_unused]] auto const& unnamed_param_1) mutable -> auto { return _0(_1);  }}; 
    test(0);
    std::move(test)(1);
  }}; 
  std::move(test_int)(17);
  std::move(test_case)(29);
}
auto main() -> int{}
Output:
Step cmake returned: 0
-- The CXX compiler identification is Clang 18.0.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /opt/compiler-explorer/clang-trunk/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /app/build
Step build returned: 1
[1/3] Generating main.cpp
main.cpp2... ok (all Cpp2, passes safety checks)

[2/3] Building CXX object CMakeFiles/main.dir/main.cpp.o
FAILED: CMakeFiles/main.dir/main.cpp.o 
/opt/compiler-explorer/clang-trunk/bin/clang++ --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot  -I/app -I/app -std=c++23 -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -Werror=unused-value -Werror=unused-parameter -stdlib=libc++ -Wno-read-modules-implicitly -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /app/build/main.cpp
main.cpp2:11:22: error: variable 'test_case' cannot be implicitly captured in a lambda with no capture-default specified
   11 |     auto test {[_0 = test_case, _1 = count]([[maybe_unused]] auto const& unnamed_param_1) mutable -> auto { return _0(_1);  }}; 
      |                      ^
main.cpp2:2:8: note: 'test_case' declared here
    2 |   auto test_case {[]([[maybe_unused]] auto const& ...unnamed_param_1) mutable -> void{}}; 
      |        ^
main.cpp2:3:18: note: lambda expression begins here
    3 |   auto test_int {[_0 = test_case](cpp2::in<int> count) mutable -> void{
      |                  ^
main.cpp2:3:33: note: capture 'test_case' by value
    3 |   auto test_int {[_0 = test_case](cpp2::in<int> count) mutable -> void{
      |                                 ^
      |                                 , test_case
main.cpp2:3:33: note: capture 'test_case' by reference
    3 |   auto test_int {[_0 = test_case](cpp2::in<int> count) mutable -> void{
      |                                 ^
      |                                 , &test_case
main.cpp2:3:19: note: default capture by value
    3 |   auto test_int {[_0 = test_case](cpp2::in<int> count) mutable -> void{
      |                   ^
      |                   =, 
main.cpp2:3:19: note: default capture by reference
    3 |   auto test_int {[_0 = test_case](cpp2::in<int> count) mutable -> void{
      |                   ^
      |                   &, 
1 error generated.
ninja: build stopped: subcommand failed.

See also:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant