diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 2f4ed082a0c7a..732749ad305e1 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -252,6 +252,8 @@ class TextNodeDumper void VisitGotoStmt(const GotoStmt *Node); void VisitCaseStmt(const CaseStmt *Node); void VisitReturnStmt(const ReturnStmt *Node); + void VisitCoawaitExpr(const CoawaitExpr *Node); + void VisitCoreturnStmt(const CoreturnStmt *Node); void VisitCompoundStmt(const CompoundStmt *Node); void VisitConstantExpr(const ConstantExpr *Node); void VisitCallExpr(const CallExpr *Node); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index e8274fcd5cfe9..369ff66ac4dbc 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1094,6 +1094,16 @@ void clang::TextNodeDumper::VisitReturnStmt(const ReturnStmt *Node) { } } +void clang::TextNodeDumper::VisitCoawaitExpr(const CoawaitExpr *Node) { + if (Node->isImplicit()) + OS << " implicit"; +} + +void clang::TextNodeDumper::VisitCoreturnStmt(const CoreturnStmt *Node) { + if (Node->isImplicit()) + OS << " implicit"; +} + void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) { if (Node->hasAPValueResult()) AddChild("value", diff --git a/clang/test/AST/ast-dump-coroutine.cpp b/clang/test/AST/ast-dump-coroutine.cpp new file mode 100644 index 0000000000000..5e7736300f9fe --- /dev/null +++ b/clang/test/AST/ast-dump-coroutine.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -std=c++20 \ +// RUN: -fsyntax-only -ast-dump -ast-dump-filter test | FileCheck %s + +#include "Inputs/std-coroutine.h" + +using namespace std; + +struct Task { + struct promise_type { + std::suspend_always initial_suspend() { return {}; } + Task get_return_object() { + return std::coroutine_handle::from_promise(*this); + } + std::suspend_always final_suspend() noexcept { return {}; } + std::suspend_always return_void() { return {}; } + void unhandled_exception() {} + + auto await_transform(int s) { + struct awaiter { + promise_type *promise; + bool await_ready() { return true; } + int await_resume() { return 1; } + void await_suspend(std::coroutine_handle<>) {} + }; + + return awaiter{this}; + } + }; + + Task(std::coroutine_handle promise); + + std::coroutine_handle handle; +}; + +Task test() { + co_await 1; +// Writen souce code, verify no implicit bit for the co_await expr. +// CHECK: CompoundStmt {{.*}} +// CHECK-NEXT: | `-ExprWithCleanups {{.*}} 'int' +// CHECK-NEXT: | `-CoawaitExpr {{.*}} 'int'{{$}} +// CHECK-NEXT: | |-IntegerLiteral {{.*}} 'int' 1 +// CHECK-NEXT: | |-MaterializeTemporaryExpr {{.*}} 'awaiter' +// CHECK-NEXT: | | `-CXXMemberCallExpr {{.*}} 'awaiter' +// CHECK-NEXT: | | |-MemberExpr {{.*}} .await_transform +} +// Verify the implicit AST nodes for coroutines. +// CHECK: |-DeclStmt {{.*}} +// CHECK-NEXT: | `-VarDecl {{.*}} implicit used __promise +// CHECK-NEXT: | `-CXXConstructExpr {{.*}} +// CHECK-NEXT: |-ExprWithCleanups {{.*}} 'void' +// CHECK-NEXT: | `-CoawaitExpr {{.*}} 'void' implicit +// CHECK-NEXT: |-CXXMemberCallExpr {{.*}} 'std::suspend_always' +// CHECK-NEXT: | | `-MemberExpr {{.*}} .initial_suspend +// ... +// FIXME: the CoreturnStmt should be marked as implicit +// CHECK: CoreturnStmt {{.*}} {{$}} + +Task test2() { +// Writen souce code, verify no implicit bit for the co_return expr. +// CHECK: CompoundStmt {{.*}} +// CHECK-NEXT: | `-CoreturnStmt {{.*}} {{$}} + co_return; +} +// Verify the implicit AST nodes for coroutines. +// CHECK: |-DeclStmt {{.*}} +// CHECK-NEXT: | `-VarDecl {{.*}} implicit used __promise +// ... +// FIXME: the CoreturnStmt should be marked as implicit +// CHECK: CoreturnStmt {{.*}} {{$}}