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

ICE inside nested lambdas, with reference captures, when the inner lambda is recursive using c++23s deducing this #84425

Closed
apache-hb opened this issue Mar 8, 2024 · 4 comments · Fixed by #84473
Assignees
Labels
c++23 clang:frontend Language frontend issues, e.g. anything involving "Sema" crash Prefer [crash-on-valid] or [crash-on-invalid] lambda C++11 lambda expressions

Comments

@apache-hb
Copy link

ICE inside nested lambdas, when lambdas capture by reference, and specifically when the inner lambda both captures by reference and is recursive using c++23s deducing this
https://godbolt.org/z/vbcTjKcvY

@EugeneZelenko EugeneZelenko added clang:codegen crash Prefer [crash-on-valid] or [crash-on-invalid] c++23 lambda C++11 lambda expressions and removed new issue labels Mar 8, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 8, 2024

@llvm/issue-subscribers-clang-codegen

Author: Elliot (apache-hb)

ICE inside nested lambdas, when lambdas capture by reference, and specifically when the inner lambda both captures by reference and is recursive using c++23s deducing this https://godbolt.org/z/vbcTjKcvY

@shafik
Copy link
Collaborator

shafik commented Mar 8, 2024

Greatly reduced: https://godbolt.org/z/6M1d91Es7

void do_thing(int x) {
    auto second = [&](this auto const& self, int b) -> int {
        if (x) return x;
        else return self(x);
    };

     second(1);
}

Assertion:

clang++: /root/llvm-project/clang/lib/CodeGen/CGExpr.cpp:5529:
clang::CodeGen::CGCallee clang::CodeGen::CodeGenFunction::EmitCallee(const clang::Expr*): 
Assertion `functionType->isFunctionType()' failed.

Backtrace:

PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/clang++ -gdwarf-4 -g -o /app/output.s -mllvm --x86-asm-syntax=intel -S --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot -fcolor-diagnostics -fno-crash-diagnostics -std=c++2c <source>
1.	<eof> parser at end of file
2.	Per-file LLVM IR generation
3.	<source>:2:19: Generating code for declaration 'do_thing(int)::(anonymous class)::operator()'
 #0 0x00000000038ee468 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x38ee468)
 #1 0x00000000038ec14c llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x38ec14c)
 #2 0x0000000003833fb8 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007f33c4e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007f33c4e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #5 0x00007f33c4e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #6 0x00007f33c4e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #7 0x00007f33c4e2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #8 0x00007f33c4e39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #9 0x000000000401d58f clang::CodeGen::CodeGenFunction::EmitCallee(clang::Expr const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x401d58f)
#10 0x000000000401d98d clang::CodeGen::CodeGenFunction::EmitCallExpr(clang::CallExpr const*, clang::CodeGen::ReturnValueSlot) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x401d98d)
#11 0x0000000004067f19 (anonymous namespace)::ScalarExprEmitter::VisitCallExpr(clang::CallExpr const*) CGExprScalar.cpp:0:0
#12 0x000000000405df50 clang::StmtVisitorBase<std::add_pointer, (anonymous namespace)::ScalarExprEmitter, llvm::Value*>::Visit(clang::Stmt*) CGExprScalar.cpp:0:0
#13 0x000000000406476c clang::CodeGen::CodeGenFunction::EmitScalarExpr(clang::Expr const*, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x406476c)
#14 0x0000000003c0b4a4 clang::CodeGen::CodeGenFunction::EmitReturnStmt(clang::ReturnStmt const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c0b4a4)
#15 0x0000000003c12c76 clang::CodeGen::CodeGenFunction::EmitStmt(clang::Stmt const*, llvm::ArrayRef<clang::Attr const*>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c12c76)
#16 0x0000000003c19479 clang::CodeGen::CodeGenFunction::EmitIfStmt(clang::IfStmt const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c19479)
#17 0x0000000003c12c26 clang::CodeGen::CodeGenFunction::EmitStmt(clang::Stmt const*, llvm::ArrayRef<clang::Attr const*>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c12c26)
#18 0x0000000003c1999c clang::CodeGen::CodeGenFunction::EmitCompoundStmtWithoutScope(clang::CompoundStmt const&, bool, clang::CodeGen::AggValueSlot) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c1999c)
#19 0x0000000003c7a4f2 clang::CodeGen::CodeGenFunction::EmitFunctionBody(clang::Stmt const*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c7a4f2)
#20 0x0000000003c8d884 clang::CodeGen::CodeGenFunction::GenerateCode(clang::GlobalDecl, llvm::Function*, clang::CodeGen::CGFunctionInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c8d884)
#21 0x0000000003cebb82 clang::CodeGen::CodeGenModule::EmitGlobalFunctionDefinition(clang::GlobalDecl, llvm::GlobalValue*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3cebb82)
#22 0x0000000003ce64a5 clang::CodeGen::CodeGenModule::EmitGlobalDefinition(clang::GlobalDecl, llvm::GlobalValue*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3ce64a5)
#23 0x0000000003cf1f9d clang::CodeGen::CodeGenModule::EmitDeferred() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3cf1f9d)
#24 0x0000000003cf4e63 clang::CodeGen::CodeGenModule::Release() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3cf4e63)
#25 0x00000000041869fa (anonymous namespace)::CodeGeneratorImpl::HandleTranslationUnit(clang::ASTContext&) ModuleBuilder.cpp:0:0
#26 0x000000000418551d clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x418551d)
#27 0x0000000006160d5c clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x6160d5c)
#28 0x0000000004184de8 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x4184de8)
#29 0x0000000004400319 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x4400319)
#30 0x000000000437d84e clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x437d84e)
#31 0x00000000044e246e clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x44e246e)
#32 0x0000000000c25566 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0xc25566)
#33 0x0000000000c1d2ca ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#34 0x00000000041c64d9 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#35 0x0000000003834464 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3834464)
#36 0x00000000041c6acf clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#37 0x000000000418e675 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x418e675)
#38 0x000000000418f0dd clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x418f0dd)
#39 0x0000000004197015 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x4197015)
#40 0x0000000000c22a4d clang_main(int, char**, llvm::ToolContext const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0xc22a4d)
#41 0x0000000000b17e04 main (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0xb17e04)
#42 0x00007f33c4e29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#43 0x00007f33c4e29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#44 0x0000000000c1cd8e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0xc1cd8e)
clang++: error: clang frontend command failed with exit code 134 (use -v to see invocation)
Compiler returned: 134

a little more I obtain a different crash: https://godbolt.org/z/c3d7ses1n

void do_thing(int x) {
    auto second = [&](this auto const& self)  {
        if (true) return x;
        else return x;
    };

     second();
}

CC @cor3ntin @erichkeane

@Sirraide
Copy link
Contributor

Sirraide commented Mar 8, 2024

Currently working on a bug that also involves capturing lambdas w/ explicit object parameters, so I’ll see if I can take a look at this one as well.

@Sirraide Sirraide self-assigned this Mar 8, 2024
Sirraide added a commit to Sirraide/llvm-project that referenced this issue Mar 8, 2024
Sirraide added a commit that referenced this issue Apr 9, 2024
…ect parameter (#84473)

This fixes some problems wrt dependence of captures in lambdas with
an explicit object parameter.

[temp.dep.expr] states that
> An id-expression is type-dependent if [...] its terminal name is
>   - associated by name lookup with an entity captured by copy
>     ([expr.prim.lambda.capture]) in a lambda-expression that has
>     an explicit object parameter whose type is dependent [dcl.fct].

There were several issues with our implementation of this:
1. we were treating by-reference captures as dependent rather than
   by-value captures;
2. tree transform wasn't checking whether referring to such a
   by-value capture should make a DRE dependent;
3. when checking whether a DRE refers to such a by-value capture, we
   were only looking at the immediately enclosing lambda, and not
   at any parent lambdas;
4. we also forgot to check for implicit by-value captures;
5. lastly, we were attempting to determine whether a lambda has an
   explicit object parameter by checking the `LambdaScopeInfo`'s
   `ExplicitObjectParameter`, but it seems that that simply wasn't
   set (yet) by the time we got to the check.

All of these should be fixed now.

This fixes #70604, #79754, #84163, #84425, #86054, #86398, and #86399.
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" and removed clang:codegen labels Apr 9, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Apr 9, 2024

@llvm/issue-subscribers-clang-frontend

Author: Elliot (apache-hb)

ICE inside nested lambdas, when lambdas capture by reference, and specifically when the inner lambda both captures by reference and is recursive using c++23s deducing this https://godbolt.org/z/vbcTjKcvY

erikolofsson pushed a commit to Malterlib/llvm-project that referenced this issue May 11, 2024
…ect parameter (llvm#84473)

This fixes some problems wrt dependence of captures in lambdas with
an explicit object parameter.

[temp.dep.expr] states that
> An id-expression is type-dependent if [...] its terminal name is
>   - associated by name lookup with an entity captured by copy
>     ([expr.prim.lambda.capture]) in a lambda-expression that has
>     an explicit object parameter whose type is dependent [dcl.fct].

There were several issues with our implementation of this:
1. we were treating by-reference captures as dependent rather than
   by-value captures;
2. tree transform wasn't checking whether referring to such a
   by-value capture should make a DRE dependent;
3. when checking whether a DRE refers to such a by-value capture, we
   were only looking at the immediately enclosing lambda, and not
   at any parent lambdas;
4. we also forgot to check for implicit by-value captures;
5. lastly, we were attempting to determine whether a lambda has an
   explicit object parameter by checking the `LambdaScopeInfo`'s
   `ExplicitObjectParameter`, but it seems that that simply wasn't
   set (yet) by the time we got to the check.

All of these should be fixed now.

This fixes llvm#70604, llvm#79754, llvm#84163, llvm#84425, llvm#86054, llvm#86398, and llvm#86399.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++23 clang:frontend Language frontend issues, e.g. anything involving "Sema" crash Prefer [crash-on-valid] or [crash-on-invalid] lambda C++11 lambda expressions
Projects
None yet
5 participants