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

[clang] Ill-formed block expressions within a lambda can yield assert-failures #109148

Closed
katzdm opened this issue Sep 18, 2024 · 5 comments · Fixed by #110762
Closed

[clang] Ill-formed block expressions within a lambda can yield assert-failures #109148

katzdm opened this issue Sep 18, 2024 · 5 comments · Fixed by #110762
Assignees
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party consteval C++20 consteval crash Prefer [crash-on-valid] or [crash-on-invalid] lambda C++11 lambda expressions

Comments

@katzdm
Copy link
Contributor

katzdm commented Sep 18, 2024

The following program produces an assert failure with a clang binary built with assertions, when compiled with -fblocks:

template<typename... Ts>
struct Cls {
  static_assert([] consteval -> void {
    (^Ts);
  });
};

The assertion:

Assertion failed: ((!Unexpanded.empty() || Visitor.containsFunctionParmPackExpr()) && "Unable to find unexpanded parameter packs"), function DiagnoseUnexpandedParameterPack, file SemaTemplateVariadic.cpp, line 467.
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: /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20 -cc1 -triple arm64-apple-macosx14.0.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -dumpdir build-llvm/main.tsk- -disable-free -clear-ast-before-backend -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -funwind-tables=1 -target-sdk-version=15.0 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fdefine-target-os-macros -fno-modulemap-allow-subdirectory-search -target-cpu apple-m1 -target-feature +zcm -target-feature +zcz -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -debug-info-kind=standalone -dwarf-version=4 -debugger-tuning=lldb -fdebug-compilation-dir=/Users/dkatz85/src/bloomberg/clang-p2996 -target-linker-version 1053.12 -fcoverage-compilation-dir=/Users/dkatz85/src/bloomberg/clang-p2996 -resource-dir /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/lib/clang/20 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -internal-isystem /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/../include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/lib/clang/20/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -std=c++26 -fdeprecated-macro -fbracket-depth 1500 -ferror-limit 30 -stack-protector 1 -freflection -freflection-new-syntax -fparameter-reflection -fannotation-attributes -fconsteval-blocks -fexpansion-statements -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -freflection-latest -fmax-type-align=16 -fcolor-diagnostics -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/cp/8xfkfz156mx13fdc89796sv40000gq/T/main-f5020e.o -x c++ main.cpp
1.	main.cpp:2:57: current parser token ')'
 #0 0x00000001026f5684 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x102609684)
 #1 0x00000001026f3748 llvm::sys::RunSignalHandlers() (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x102607748)
 #2 0x00000001026f5cf0 SignalHandler(int) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x102609cf0)
 #3 0x0000000182f3e584 (/usr/lib/system/libsystem_platform.dylib+0x18047a584)
 #4 0x0000000182f0dc20 (/usr/lib/system/libsystem_pthread.dylib+0x180449c20)
 #5 0x0000000182e1aa30 (/usr/lib/system/libsystem_c.dylib+0x180356a30)
 #6 0x0000000182e19d20 (/usr/lib/system/libsystem_c.dylib+0x180355d20)
 #7 0x00000001055ef650 clang::Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(clang::RequiresExpr*) (.cold.1) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x105503650)
 #8 0x000000010496d01c clang::Sema::DiagnoseUnexpandedParameterPack(clang::Expr*, clang::Sema::UnexpandedParameterPackContext) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x10488101c)
 #9 0x00000001043569d8 clang::Sema::ActOnParamDefaultArgument(clang::Decl*, clang::SourceLocation, clang::Expr*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x10426a9d8)
#10 0x000000010401ec1c clang::Parser::ParseParameterDeclarationClause(clang::DeclaratorContext, clang::ParsedAttributes&, llvm::SmallVectorImpl<clang::DeclaratorChunk::ParamInfo>&, clang::SourceLocation&, bool) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f32c1c)
#11 0x000000010401bd88 clang::Parser::ParseFunctionDeclarator(clang::Declarator&, clang::ParsedAttributes&, clang::BalancedDelimiterTracker&, bool, bool) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f2fd88)
#12 0x0000000104019cb8 clang::Parser::ParseDirectDeclarator(clang::Declarator&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f2dcb8)
#13 0x0000000104017fb8 clang::Parser::ParseDeclaratorInternal(clang::Declarator&, void (clang::Parser::*)(clang::Declarator&)) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f2bfb8)
#14 0x0000000104171358 clang::Sema::runWithSufficientStackSpace(clang::SourceLocation, llvm::function_ref<void ()>) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x104085358)
#15 0x0000000104008520 clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, clang::DeclaratorContext, clang::ParsedAttributes&, clang::Parser::ParsedTemplateInfo&, clang::SourceLocation*, clang::Parser::ForRangeInit*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f1c520)
#16 0x00000001040af4ec clang::Parser::ParseDeclarationAfterTemplate(clang::DeclaratorContext, clang::Parser::ParsedTemplateInfo&, clang::ParsingDeclRAIIObject&, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fc34ec)
#17 0x00000001040ae744 clang::Parser::ParseTemplateDeclarationOrSpecialization(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fc2744)
#18 0x00000001040ae070 clang::Parser::ParseDeclarationStartingWithTemplate(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fc2070)
#19 0x0000000104007374 clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::ParsedAttributes&, clang::SourceLocation*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f1b374)
#20 0x00000001040be608 clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fd2608)
#21 0x00000001040bcee8 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fd0ee8)
#22 0x00000001040bc6b8 clang::Parser::ParseFirstTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fd06b8)
#23 0x0000000103ff1510 clang::ParseAST(clang::Sema&, bool, bool) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f05510)
#24 0x00000001031a35c4 clang::FrontendAction::Execute() (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x1030b75c4)
#25 0x0000000103132998 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103046998)
#26 0x000000010321e8e8 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x1031328e8)
#27 0x00000001000f5844 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x100009844)
#28 0x00000001000f2ee8 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x100006ee8)
#29 0x00000001000f236c clang_main(int, char**, llvm::ToolContext const&) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x10000636c)
#30 0x00000001000fe674 main (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x100012674)
#31 0x0000000182b83154 
clang++: error: unable to execute command: Abort trap: 6
clang++: error: clang frontend command failed due to signal (use -v to see invocation)

Here is another example that fails the same assertion:

template <typename... Ts>
void fn(int = [] consteval -> int { (^Ts); return 0; }());

Both have the same root cause:

  1. While parsing the CompoundStmt body of the lambda, clang begins to parse ^Ts as a BlockExpr.
  2. The Sema::ActOnBlockArguments function invokes DiagnoseUnexpandedParameterPacks, which sets LambdaScopeInfo::ContainsUnexpandedParameterPacks to true, prior to recognizing that the BlockExpr is ill-formed.
  3. The ill-formed BlockExpr is diagnosed, and is subsequently discarded from the CompoundStmt representing the body of the lambda.
  4. The LambdaScopeInfo is used to initialize the LambdaExpr, resulting in LambdaExpr::ContainsUnexpandedParameterPack being set to true.
  5. The LambdaExpr becomes an argument to some other semantic construct (e.g., StaticAssertDecl, ParameterDecl), whose semantic analysis calls DiagnoseUnexpandedParameterPack.
  6. The above assertion triggers because the LambdaExpr reports that it contains an unexpanded parameter pack, but the tree walk fails to find any pack (since the ill-formed BlockExpr was discarded from the CompoundStmt).

Although I can imagine a few ways to patch this (e.g., keep an "error" representation of the ill-formed BlockExpr in CompoundStmt, rollback the setting of LambdaScopeInfo::ContainsUnexpandedParameterPack when the BlockExpr is ill-formed, just remove the assertion from DiagnoseUnexpandedParameterPacks), I'm not sure I love any of them. For now, I figured I'd just report the issue.

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Sep 18, 2024
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" crash Prefer [crash-on-valid] or [crash-on-invalid] consteval C++20 consteval lambda C++11 lambda expressions and removed clang Clang issues not falling into any other category labels Sep 18, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 18, 2024

@llvm/issue-subscribers-clang-frontend

Author: Daniel M. Katz (katzdm)

The following program produces an assert failure with a `clang` binary built with assertions, when compiled with `-fblocks`:
template&lt;typename... Ts&gt;
struct Cls {
  static_assert([] consteval -&gt; void {
    (^Ts);
  });
};

The assertion:

Assertion failed: ((!Unexpanded.empty() || Visitor.containsFunctionParmPackExpr()) &amp;&amp; "Unable to find unexpanded parameter packs"), function DiagnoseUnexpandedParameterPack, file SemaTemplateVariadic.cpp, line 467.
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: /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20 -cc1 -triple arm64-apple-macosx14.0.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -dumpdir build-llvm/main.tsk- -disable-free -clear-ast-before-backend -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -funwind-tables=1 -target-sdk-version=15.0 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fdefine-target-os-macros -fno-modulemap-allow-subdirectory-search -target-cpu apple-m1 -target-feature +zcm -target-feature +zcz -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -debug-info-kind=standalone -dwarf-version=4 -debugger-tuning=lldb -fdebug-compilation-dir=/Users/dkatz85/src/bloomberg/clang-p2996 -target-linker-version 1053.12 -fcoverage-compilation-dir=/Users/dkatz85/src/bloomberg/clang-p2996 -resource-dir /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/lib/clang/20 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -internal-isystem /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/../include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/lib/clang/20/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -std=c++26 -fdeprecated-macro -fbracket-depth 1500 -ferror-limit 30 -stack-protector 1 -freflection -freflection-new-syntax -fparameter-reflection -fannotation-attributes -fconsteval-blocks -fexpansion-statements -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -freflection-latest -fmax-type-align=16 -fcolor-diagnostics -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/cp/8xfkfz156mx13fdc89796sv40000gq/T/main-f5020e.o -x c++ main.cpp
1.	main.cpp:2:57: current parser token ')'
 #<!-- -->0 0x00000001026f5684 llvm::sys::PrintStackTrace(llvm::raw_ostream&amp;, int) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x102609684)
 #<!-- -->1 0x00000001026f3748 llvm::sys::RunSignalHandlers() (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x102607748)
 #<!-- -->2 0x00000001026f5cf0 SignalHandler(int) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x102609cf0)
 #<!-- -->3 0x0000000182f3e584 (/usr/lib/system/libsystem_platform.dylib+0x18047a584)
 #<!-- -->4 0x0000000182f0dc20 (/usr/lib/system/libsystem_pthread.dylib+0x180449c20)
 #<!-- -->5 0x0000000182e1aa30 (/usr/lib/system/libsystem_c.dylib+0x180356a30)
 #<!-- -->6 0x0000000182e19d20 (/usr/lib/system/libsystem_c.dylib+0x180355d20)
 #<!-- -->7 0x00000001055ef650 clang::Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(clang::RequiresExpr*) (.cold.1) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x105503650)
 #<!-- -->8 0x000000010496d01c clang::Sema::DiagnoseUnexpandedParameterPack(clang::Expr*, clang::Sema::UnexpandedParameterPackContext) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x10488101c)
 #<!-- -->9 0x00000001043569d8 clang::Sema::ActOnParamDefaultArgument(clang::Decl*, clang::SourceLocation, clang::Expr*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x10426a9d8)
#<!-- -->10 0x000000010401ec1c clang::Parser::ParseParameterDeclarationClause(clang::DeclaratorContext, clang::ParsedAttributes&amp;, llvm::SmallVectorImpl&lt;clang::DeclaratorChunk::ParamInfo&gt;&amp;, clang::SourceLocation&amp;, bool) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f32c1c)
#<!-- -->11 0x000000010401bd88 clang::Parser::ParseFunctionDeclarator(clang::Declarator&amp;, clang::ParsedAttributes&amp;, clang::BalancedDelimiterTracker&amp;, bool, bool) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f2fd88)
#<!-- -->12 0x0000000104019cb8 clang::Parser::ParseDirectDeclarator(clang::Declarator&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f2dcb8)
#<!-- -->13 0x0000000104017fb8 clang::Parser::ParseDeclaratorInternal(clang::Declarator&amp;, void (clang::Parser::*)(clang::Declarator&amp;)) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f2bfb8)
#<!-- -->14 0x0000000104171358 clang::Sema::runWithSufficientStackSpace(clang::SourceLocation, llvm::function_ref&lt;void ()&gt;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x104085358)
#<!-- -->15 0x0000000104008520 clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&amp;, clang::DeclaratorContext, clang::ParsedAttributes&amp;, clang::Parser::ParsedTemplateInfo&amp;, clang::SourceLocation*, clang::Parser::ForRangeInit*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f1c520)
#<!-- -->16 0x00000001040af4ec clang::Parser::ParseDeclarationAfterTemplate(clang::DeclaratorContext, clang::Parser::ParsedTemplateInfo&amp;, clang::ParsingDeclRAIIObject&amp;, clang::SourceLocation&amp;, clang::ParsedAttributes&amp;, clang::AccessSpecifier) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fc34ec)
#<!-- -->17 0x00000001040ae744 clang::Parser::ParseTemplateDeclarationOrSpecialization(clang::DeclaratorContext, clang::SourceLocation&amp;, clang::ParsedAttributes&amp;, clang::AccessSpecifier) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fc2744)
#<!-- -->18 0x00000001040ae070 clang::Parser::ParseDeclarationStartingWithTemplate(clang::DeclaratorContext, clang::SourceLocation&amp;, clang::ParsedAttributes&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fc2070)
#<!-- -->19 0x0000000104007374 clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&amp;, clang::ParsedAttributes&amp;, clang::ParsedAttributes&amp;, clang::SourceLocation*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f1b374)
#<!-- -->20 0x00000001040be608 clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&amp;, clang::ParsedAttributes&amp;, clang::ParsingDeclSpec*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fd2608)
#<!-- -->21 0x00000001040bcee8 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr&lt;clang::DeclGroupRef&gt;&amp;, clang::Sema::ModuleImportState&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fd0ee8)
#<!-- -->22 0x00000001040bc6b8 clang::Parser::ParseFirstTopLevelDecl(clang::OpaquePtr&lt;clang::DeclGroupRef&gt;&amp;, clang::Sema::ModuleImportState&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103fd06b8)
#<!-- -->23 0x0000000103ff1510 clang::ParseAST(clang::Sema&amp;, bool, bool) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103f05510)
#<!-- -->24 0x00000001031a35c4 clang::FrontendAction::Execute() (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x1030b75c4)
#<!-- -->25 0x0000000103132998 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x103046998)
#<!-- -->26 0x000000010321e8e8 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x1031328e8)
#<!-- -->27 0x00000001000f5844 cc1_main(llvm::ArrayRef&lt;char const*&gt;, char const*, void*) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x100009844)
#<!-- -->28 0x00000001000f2ee8 ExecuteCC1Tool(llvm::SmallVectorImpl&lt;char const*&gt;&amp;, llvm::ToolContext const&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x100006ee8)
#<!-- -->29 0x00000001000f236c clang_main(int, char**, llvm::ToolContext const&amp;) (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x10000636c)
#<!-- -->30 0x00000001000fe674 main (/Users/dkatz85/src/bloomberg/clang-p2996/build-llvm/bin/clang-20+0x100012674)
#<!-- -->31 0x0000000182b83154 
clang++: error: unable to execute command: Abort trap: 6
clang++: error: clang frontend command failed due to signal (use -v to see invocation)

Here is another example that fails the same assertion:

template &lt;typename... Ts&gt;
void fn(int = [] consteval -&gt; int { (^Ts); return 0; }());

Both have the same root cause:

  1. While parsing the CompoundStmt body of the lambda, clang begins to parse ^Ts as a BlockExpr.
  2. The Sema::ActOnBlockArguments function invokes DiagnoseUnexpandedParameterPacks, which sets LambdaScopeInfo::ContainsUnexpandedParameterPacks to true, prior to recognizing that the BlockExpr is ill-formed.
  3. The ill-formed BlockExpr is diagnosed, and is subsequently discarded from the CompoundStmt representing the body of the lambda.
  4. The LambdaScopeInfo is used to initialize the LambdaExpr, resulting in LambdaExpr::ContainsUnexpandedParameterPack being set to true.
  5. The LambdaExpr becomes an argument to some other semantic construct (e.g., StaticAssertDecl, ParameterDecl), whose semantic analysis calls DiagnoseUnexpandedParameterPack.
  6. The above assertion triggers because the LambdaExpr reports that it contains an unexpanded parameter pack, but the tree walk fails to find any pack (since the ill-formed BlockExpr was discarded from the CompoundStmt).

Although I can imagine a few ways to patch this (e.g., keep an "error" representation of the ill-formed BlockExpr in CompoundStmt, rollback the setting of LambdaScopeInfo::ContainsUnexpandedParameterPack when the BlockExpr is ill-formed, just remove the assertion from DiagnoseUnexpandedParameterPacks), I'm not sure I love any of them. For now, I figured I'd just report the issue.

@shafik
Copy link
Collaborator

shafik commented Sep 18, 2024

Looks like this goes back to clang-13: https://godbolt.org/z/PMshGMY3E

It does not require -fblocks if we use assertions build, they are usually more useful b/c they crash earlier and usually are closer to the core problem.

@shafik shafik added the confirmed Verified by a second party label Sep 18, 2024
@Sirraide
Copy link
Contributor

Sirraide commented Oct 1, 2024

I haven’t tried messing with this yet, but this feels like it might be the issue:

// FIXME: We should allow unexpanded parameter packs here, but that would,
// in turn, make the block expression contain unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) {
// Drop the parameters.
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals.addConst();
T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}

We diagnose unexpanded parameter packs... and then promptly drop them. I think the ‘proper’ solution would be to resolve this fixme; This comment is from 2012, so maybe we can handle blocks with unexpanded paramter packs just fine now? I’ll try that, and if that doesn’t work, I think we can just reset the LambdaScopeInfo’s flag to whatever value it had before the DiagnoseUnexpandedParameterPack() call in here.

@Sirraide Sirraide self-assigned this Oct 1, 2024
@Sirraide
Copy link
Contributor

Sirraide commented Oct 1, 2024

Actually, that would only return true on error, so that doesn’t seem too plausible...

@Sirraide
Copy link
Contributor

Sirraide commented Oct 1, 2024

Oh wait, duh, I just confused myself: it does seem to happen here, it just returns false because we’re in a lambda, so it’s fine, and we then crash later.

Sirraide added a commit that referenced this issue Oct 11, 2024
#110762)

Consider #109148:
```c++
template <typename ...Ts>
void f() {
    [] {
        (^Ts);
    };
}
```

When we encounter `^Ts`, we try to parse a block and subsequently call
`DiagnoseUnexpandedParameterPack()` (in `ActOnBlockArguments()`), which
sees `Ts` and sets `ContainsUnexpandedParameterPack` to `true` in the
`LambdaScopeInfo` of the enclosing lambda. However, the entire block is
subsequently discarded entirely because it isn’t even syntactically
well-formed. As a result, `ContainsUnexpandedParameterPack` is `true`
despite the lambda’s body no longer containing any unexpanded packs,
which causes an assertion the next time
`DiagnoseUnexpandedParameterPack()` is called.

This pr moves handling of unexpanded parameter packs into
`CapturingScopeInfo` instead so that the same logic is used for both
blocks and lambdas. This fixes this issue since the
`ContainsUnexpandedParameterPack` flag is now part of the block (and
before that, its `CapturingScopeInfo`) and no longer affects the
surrounding lambda directly when the block is parsed. Moreover, this
change makes blocks actually usable with pack expansion.

This fixes #109148.
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this issue Oct 16, 2024
llvm#110762)

Consider llvm#109148:
```c++
template <typename ...Ts>
void f() {
    [] {
        (^Ts);
    };
}
```

When we encounter `^Ts`, we try to parse a block and subsequently call
`DiagnoseUnexpandedParameterPack()` (in `ActOnBlockArguments()`), which
sees `Ts` and sets `ContainsUnexpandedParameterPack` to `true` in the
`LambdaScopeInfo` of the enclosing lambda. However, the entire block is
subsequently discarded entirely because it isn’t even syntactically
well-formed. As a result, `ContainsUnexpandedParameterPack` is `true`
despite the lambda’s body no longer containing any unexpanded packs,
which causes an assertion the next time
`DiagnoseUnexpandedParameterPack()` is called.

This pr moves handling of unexpanded parameter packs into
`CapturingScopeInfo` instead so that the same logic is used for both
blocks and lambdas. This fixes this issue since the
`ContainsUnexpandedParameterPack` flag is now part of the block (and
before that, its `CapturingScopeInfo`) and no longer affects the
surrounding lambda directly when the block is parsed. Moreover, this
change makes blocks actually usable with pack expansion.

This fixes llvm#109148.
bricknerb pushed a commit to bricknerb/llvm-project that referenced this issue Oct 17, 2024
llvm#110762)

Consider llvm#109148:
```c++
template <typename ...Ts>
void f() {
    [] {
        (^Ts);
    };
}
```

When we encounter `^Ts`, we try to parse a block and subsequently call
`DiagnoseUnexpandedParameterPack()` (in `ActOnBlockArguments()`), which
sees `Ts` and sets `ContainsUnexpandedParameterPack` to `true` in the
`LambdaScopeInfo` of the enclosing lambda. However, the entire block is
subsequently discarded entirely because it isn’t even syntactically
well-formed. As a result, `ContainsUnexpandedParameterPack` is `true`
despite the lambda’s body no longer containing any unexpanded packs,
which causes an assertion the next time
`DiagnoseUnexpandedParameterPack()` is called.

This pr moves handling of unexpanded parameter packs into
`CapturingScopeInfo` instead so that the same logic is used for both
blocks and lambdas. This fixes this issue since the
`ContainsUnexpandedParameterPack` flag is now part of the block (and
before that, its `CapturingScopeInfo`) and no longer affects the
surrounding lambda directly when the block is parsed. Moreover, this
change makes blocks actually usable with pack expansion.

This fixes llvm#109148.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party consteval C++20 consteval crash Prefer [crash-on-valid] or [crash-on-invalid] lambda C++11 lambda expressions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants