diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 822025a7503fe..4c65daaa63fc3 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -26,6 +26,7 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/UnresolvedSet.h" @@ -2004,8 +2005,25 @@ class LambdaExpr final : public Expr, /// Whether this is a generic lambda. bool isGenericLambda() const { return getTemplateParameterList(); } - /// Retrieve the body of the lambda. - CompoundStmt *getBody() const; + /// Retrieve the body of the lambda. This will be most of the time + /// a \p CompoundStmt, but can also be \p CoroutineBodyStmt wrapping + /// a \p CompoundStmt. Note that unlike functions, lambda-expressions + /// cannot have a function-try-block. + Stmt *getBody() const { return getStoredStmts()[capture_size()]; } + + /// Retrieve the \p CompoundStmt representing the body of the lambda. + /// This is a convenience function for callers who do not need + /// to handle node(s) which may wrap a \p CompoundStmt. + const CompoundStmt *getCompoundStmtBody() const { + Stmt *Body = getBody(); + if (const auto *CoroBody = dyn_cast(Body)) + return cast(CoroBody->getBody()); + return cast(Body); + } + CompoundStmt *getCompoundStmtBody() { + const auto *ConstThis = this; + return const_cast(ConstThis->getCompoundStmtBody()); + } /// Determine whether the lambda is mutable, meaning that any /// captures values can be modified. diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 8588e9b47d65a..f9f825b29ed07 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1118,15 +1118,6 @@ LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaExpr::LambdaExpr(EmptyShell Empty, unsigned NumCaptures) : Expr(LambdaExprClass, Empty) { LambdaExprBits.NumCaptures = NumCaptures; - - // FIXME: There is no need to do this since these members should be - // initialized during deserialization. - LambdaExprBits.CaptureDefault = LCD_None; - LambdaExprBits.ExplicitParams = false; - LambdaExprBits.ExplicitResultType = false; - - // FIXME: Remove once the bug in LambdaExpr::getBody is fixed. - getStoredStmts()[capture_size()] = nullptr; } LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, @@ -1223,17 +1214,6 @@ ArrayRef LambdaExpr::getExplicitTemplateParameters() const { return Record->getLambdaExplicitTemplateParameters(); } -CompoundStmt *LambdaExpr::getBody() const { - // FIXME: this mutation in getBody is bogus. It should be - // initialized in ASTStmtReader::VisitLambdaExpr, but for reasons I - // don't understand, that doesn't work. - if (!getStoredStmts()[capture_size()]) - *const_cast(&getStoredStmts()[capture_size()]) = - getCallOperator()->getBody(); - - return static_cast(getStoredStmts()[capture_size()]); -} - bool LambdaExpr::isMutable() const { return !getCallOperator()->isConst(); } ExprWithCleanups::ExprWithCleanups(Expr *subexpr, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index d5d025335aa2f..11e222f95176d 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2051,7 +2051,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { if (Policy.TerseOutput) OS << "{}"; else - PrintRawCompoundStmt(Node->getBody()); + PrintRawCompoundStmt(Node->getCompoundStmtBody()); } void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index e38c309da3397..d5ae8979b1e1a 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1701,6 +1701,9 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) { CEnd = E->capture_init_end(); C != CEnd; ++C) *C = Record.readSubExpr(); + + // Ok, not one past the end. + E->getStoredStmts()[NumCaptures] = Record.readSubStmt(); } void diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 11941329ad2a2..3a3b7bdfbb469 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1604,6 +1604,8 @@ void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) { Record.AddStmt(*C); } + Record.AddStmt(E->getBody()); + Code = serialization::EXPR_LAMBDA; } diff --git a/clang/test/AST/ast-dump-lambda.cpp b/clang/test/AST/ast-dump-lambda.cpp index 3f10d12bdd6f9..d5f43c114c85d 100644 --- a/clang/test/AST/ast-dump-lambda.cpp +++ b/clang/test/AST/ast-dump-lambda.cpp @@ -8,7 +8,7 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -std=gnu++17 \ // RUN: -x c++ -include-pch %t -ast-dump-all | FileCheck -strict-whitespace %s -// XFAIL: * + template void test(Ts... a) { struct V { @@ -64,7 +64,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-FieldDecl {{.*}} col:8{{( imported)?}} implicit 'V *' // CHECK-NEXT: | | |-ParenListExpr {{.*}} 'NULL TYPE' // CHECK-NEXT: | | | `-CXXThisExpr {{.*}} 'V *' this -// CHECK-NEXT: | | `-<<>> +// CHECK-NEXT: | | `-CompoundStmt {{.*}} // CHECK-NEXT: | `-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:17:7)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:7{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda standard_layout trivially_copyable can_const_default_init @@ -80,7 +80,7 @@ template void test(Ts... a) { // CHECK-NEXT: | |-ParenListExpr {{.*}} 'NULL TYPE' // CHECK-NEXT: | | `-UnaryOperator {{.*}} '' prefix '*' cannot overflow // CHECK-NEXT: | | `-CXXThisExpr {{.*}} 'V *' this -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-DeclStmt {{.*}} // CHECK-NEXT: | |-VarDecl {{.*}} col:7{{( imported)?}} referenced b 'int' // CHECK-NEXT: | `-VarDecl {{.*}} col:10{{( imported)?}} referenced c 'int' @@ -97,7 +97,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto ()' static inline -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:22:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -113,7 +113,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)(int, ...) 'auto (*() const noexcept)(int, ...)' inline // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto (int, ...)' static inline // CHECK-NEXT: | | `-ParmVarDecl {{.*}} col:10{{( imported)?}} a 'int' -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:23:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda standard_layout trivially_copyable can_const_default_init @@ -128,7 +128,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | `-FieldDecl {{.*}} col:4{{( imported)?}} implicit 'Ts...' // CHECK-NEXT: | |-ParenListExpr {{.*}} 'NULL TYPE' // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'Ts...' lvalue ParmVar {{.*}} 'a' 'Ts...' -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:24:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -140,7 +140,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-Destructor simple irrelevant trivial needs_implicit // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} operator() 'auto () const -> auto' inline // CHECK-NEXT: | | `-CompoundStmt {{.*}} -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:25:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -154,7 +154,9 @@ template void test(Ts... a) { // CHECK-NEXT: | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | `-ReturnStmt {{.*}} // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const int' lvalue Var {{.*}} 'b' 'int' -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'const int' lvalue Var {{.*}} 'b' 'int' // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:26:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -166,7 +168,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-Destructor simple irrelevant trivial needs_implicit // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} operator() 'auto () const -> auto' inline // CHECK-NEXT: | | `-CompoundStmt {{.*}} -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:27:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -180,7 +182,9 @@ template void test(Ts... a) { // CHECK-NEXT: | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | `-ReturnStmt {{.*}} // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'c' 'int' -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'c' 'int' // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:28:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda trivially_copyable literal can_const_default_init @@ -203,7 +207,13 @@ template void test(Ts... a) { // CHECK-NEXT: | |-ImplicitCastExpr {{.*}} 'int' // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'b' 'int' // CHECK-NEXT: | |-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'c' 'int' -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-BinaryOperator {{.*}} 'int' '+' +// CHECK-NEXT: | |-ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const int' lvalue Var {{.*}} 'b' 'int' +// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'c' 'int' // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:29:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda standard_layout trivially_copyable can_const_default_init @@ -220,7 +230,7 @@ template void test(Ts... a) { // CHECK-NEXT: | |-ParenListExpr {{.*}} 'NULL TYPE' // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'Ts...' lvalue ParmVar {{.*}} 'a' 'Ts...' // CHECK-NEXT: | |-IntegerLiteral {{.*}} 'int' 12 -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:30:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -234,7 +244,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto ()' static inline -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:31:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -248,7 +258,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto ()' static inline -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:32:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -262,7 +272,7 @@ template void test(Ts... a) { // CHECK-NEXT: | | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' inline // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto () noexcept' static inline -// CHECK-NEXT: | `-<<>> +// CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: `-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:33:3)' // CHECK-NEXT: |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init @@ -278,4 +288,6 @@ template void test(Ts... a) { // CHECK-NEXT: | | `-IntegerLiteral {{.*}} 'int' 0 // CHECK-NEXT: | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline // CHECK-NEXT: | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto () -> int' static inline -// CHECK-NEXT: `-<<>> +// CHECK-NEXT: `-CompoundStmt {{.*}} +// CHECK-NEXT: `-ReturnStmt {{.*}} +// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 0