Skip to content

co_await in a decltype expression causes clang to crash #58133

@jacobsa

Description

@jacobsa

Here is a simple C++20 program that contains the expression decltype(co_await 0), reduced from a more realistic example in a real codebase:

#include <coroutine>
#include <type_traits>
#include <optional>

struct MyTask{
  struct promise_type {
    MyTask get_return_object() { return {std::coroutine_handle<promise_type>::from_promise(*this)}; }
    std::suspend_always initial_suspend() { return {}; }

    void unhandled_exception();
    void return_void() {} 

    auto await_transform(MyTask task) {
      struct Awaiter {
        bool await_ready() { return false; }
        std::coroutine_handle<promise_type> await_suspend(std::coroutine_handle<promise_type> h) {
          caller.resume_when_done = h;
          return std::coroutine_handle<promise_type>::from_promise(callee);
        }

        void await_resume() {
          std::coroutine_handle<promise_type>::from_promise(callee).destroy();
        }

        promise_type& caller;
        promise_type& callee;
      };

      return Awaiter{*this, task.handle.promise()};
    }
    
    auto final_suspend() noexcept {
      struct Awaiter {
        bool await_ready() noexcept { return false; }
        std::coroutine_handle<promise_type> await_suspend(std::coroutine_handle<promise_type> h) noexcept {
          return to_resume;
        }

        void await_resume() noexcept;

        std::coroutine_handle<promise_type> to_resume;
      };

      return Awaiter{resume_when_done};
    }

    // The coroutine to resume when we're done.
    std::coroutine_handle<promise_type> resume_when_done;
  };


  // A handle for the coroutine that returned this task.
  std::coroutine_handle<promise_type> handle;
};

MyTask DoSomething() {
  static_assert(std::is_same_v<void, decltype(co_await 0)>);
  co_return;
}

When compiled with -std=c++20, it causes clang to crash:

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-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++20 <source>
1.	<source>:57:57: current parser token ')'
2.	<source>:56:22: parsing function body 'DoSomething'
3.	<source>:56:22: in compound statement ('{}')
 #0 0x000055952e63f324 PrintStackTraceSignalHandler(void*) Signals.cpp:0:0
 #1 0x000055952e63d18c llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3a8a18c)
 #2 0x000055952e57af58 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007f2119b57420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #4 0x00005595319d31c0 clang::CallExpr::getCallReturnType(clang::ASTContext const&) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x6e201c0)
 #5 0x0000559530d2f88c buildCoawaitCalls(clang::Sema&, clang::VarDecl*, clang::SourceLocation, clang::Expr*) SemaCoroutine.cpp:0:0
 #6 0x0000559530d35877 clang::Sema::BuildResolvedCoawaitExpr(clang::SourceLocation, clang::Expr*, clang::Expr*, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x6182877)
 #7 0x0000559530d37e7d clang::Sema::ActOnCoroutineBodyStart(clang::Scope*, clang::SourceLocation, llvm::StringRef) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x6184e7d)
 #8 0x0000559530d382ad clang::Sema::ActOnCoawaitExpr(clang::Scope*, clang::SourceLocation, clang::Expr*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x61852ad)
 #9 0x0000559530ab6223 clang::Parser::ParseCastExpression(clang::Parser::CastParseKind, bool, bool&, clang::Parser::TypeCastState, bool, bool*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f03223)
#10 0x0000559530ab879e clang::Parser::ParseCastExpression(clang::Parser::CastParseKind, bool, clang::Parser::TypeCastState, bool, bool*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f0579e)
#11 0x0000559530ab898d clang::Parser::ParseAssignmentExpression(clang::Parser::TypeCastState) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f0598d)
#12 0x0000559530abd74d clang::Parser::ParseExpression(clang::Parser::TypeCastState) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f0a74d)
#13 0x0000559530a9a37e clang::Parser::ParseDecltypeSpecifier(clang::DeclSpec&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ee737e)
#14 0x0000559530ad35b3 clang::Parser::ParseOptionalCXXScopeSpecifier(clang::CXXScopeSpec&, clang::OpaquePtr<clang::QualType>, bool, bool, bool*, bool, clang::IdentifierInfo**, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f205b3)
#15 0x0000559530a5338d clang::Parser::TryAnnotateTypeOrScopeToken(clang::ImplicitTypenameContext) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ea038d)
#16 0x0000559530b6078a clang::Parser::isCXXDeclarationSpecifier(clang::ImplicitTypenameContext, clang::Parser::TPResult, bool*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5fad78a)
#17 0x0000559530b634db clang::Parser::isCXXTypeId(clang::Parser::TentativeCXXTypeIdContext, bool&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5fb04db)
#18 0x0000559530b4f998 clang::Parser::ParseTemplateArgument() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f9c998)
#19 0x0000559530b5996e clang::Parser::ParseTemplateArgumentList(llvm::SmallVector<clang::ParsedTemplateArgument, 16u>&, clang::OpaquePtr<clang::TemplateName>, clang::SourceLocation) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5fa696e)
#20 0x0000559530b59ccf clang::Parser::ParseTemplateIdAfterTemplateName(bool, clang::SourceLocation&, llvm::SmallVector<clang::ParsedTemplateArgument, 16u>&, clang::SourceLocation&, clang::OpaquePtr<clang::TemplateName>) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5fa6ccf)
#21 0x0000559530b5a03e clang::Parser::AnnotateTemplateIdToken(clang::OpaquePtr<clang::TemplateName>, clang::TemplateNameKind, clang::CXXScopeSpec&, clang::SourceLocation, clang::UnqualifiedId&, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5fa703e)
#22 0x0000559530ad3c54 clang::Parser::ParseOptionalCXXScopeSpecifier(clang::CXXScopeSpec&, clang::OpaquePtr<clang::QualType>, bool, bool, bool*, bool, clang::IdentifierInfo**, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f20c54)
#23 0x0000559530a5338d clang::Parser::TryAnnotateTypeOrScopeToken(clang::ImplicitTypenameContext) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ea038d)
#24 0x0000559530ab6a3f clang::Parser::ParseCastExpression(clang::Parser::CastParseKind, bool, bool&, clang::Parser::TypeCastState, bool, bool*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f03a3f)
#25 0x0000559530ac45ed clang::Parser::ParseConstantExpressionInExprEvalContext(clang::Parser::TypeCastState) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f115ed)
#26 0x0000559530a9c416 clang::Parser::ParseStaticAssertDeclaration(clang::SourceLocation&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ee9416)
#27 0x0000559530a8beef clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::ParsedAttributes&, clang::SourceLocation*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ed8eef)
#28 0x0000559530b36e0e clang::Parser::ParseStatementOrDeclarationAfterAttributes(llvm::SmallVector<clang::Stmt*, 32u>&, clang::Parser::ParsedStmtContext, clang::SourceLocation*, clang::ParsedAttributes&, clang::ParsedAttributes&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f83e0e)
#29 0x0000559530b376b3 clang::Parser::ParseStatementOrDeclaration(llvm::SmallVector<clang::Stmt*, 32u>&, clang::Parser::ParsedStmtContext, clang::SourceLocation*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f846b3)
#30 0x0000559530b385d6 clang::Parser::ParseCompoundStatementBody(bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f855d6)
#31 0x0000559530b39992 clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f86992)
#32 0x0000559530a596a4 clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&, clang::Parser::ParsedTemplateInfo const&, clang::Parser::LateParsedAttrList*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ea66a4)
#33 0x0000559530a8a93f clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, clang::DeclaratorContext, clang::ParsedAttributes&, clang::SourceLocation*, clang::Parser::ForRangeInit*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ed793f)
#34 0x0000559530a53cbf clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, clang::ParsingDeclSpec&, clang::AccessSpecifier) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ea0cbf)
#35 0x0000559530a54c40 clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::ParsingDeclSpec*, clang::AccessSpecifier) (.part.0) Parser.cpp:0:0
#36 0x0000559530a5c70d clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsingDeclSpec*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5ea970d)
#37 0x0000559530a5dbba clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5eaabba)
#38 0x0000559530a4d3ea clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5e9a3ea)
#39 0x000055952f8b4975 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x4d01975)
#40 0x000055952f1b9d21 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x4606d21)
#41 0x000055952f13faa3 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x458caa3)
#42 0x000055952f29d1fb clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x46ea1fb)
#43 0x000055952be591d4 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x12a61d4)
#44 0x000055952be527cb ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) driver.cpp:0:0
#45 0x000055952efaa529 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#46 0x000055952e57b6c7 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x39c86c7)
#47 0x000055952efaa75c clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#48 0x000055952ef754a9 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x43c24a9)
#49 0x000055952ef75e9d clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x43c2e9d)
#50 0x000055952ef8067c clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x43cd67c)
#51 0x000055952be56f01 clang_main(int, char**) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x12a3f01)
#52 0x00007f2119605083 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24083)
#53 0x000055952be5240e _start (/opt/compiler-explorer/clang-trunk/bin/clang+++0x129f40e)
clang-16: error: clang frontend command failed with exit code 139 (use -v to see invocation)
Compiler returned: 139

I wouldn't be surprised to find that decltype(<co_await expression>) is not well-formed, but either way it probably shouldn't cause clang to crash.

Metadata

Metadata

Assignees

Labels

c++20coroutinesC++20 coroutinescrashPrefer [crash-on-valid] or [crash-on-invalid]

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions