diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1931,6 +1931,7 @@ /// Const iterator that walks over the capture initialization /// arguments. + /// FIXME: This interface is prone to being used incorrectly. using const_capture_init_iterator = Expr *const *; /// Retrieve the initialization expressions for this lambda's captures. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3629,7 +3629,7 @@ case LambdaExprClass: { const LambdaExpr *LE = cast(this); for (Expr *E : LE->capture_inits()) - if (E->HasSideEffects(Ctx, IncludePossibleEffects)) + if (E && E->HasSideEffects(Ctx, IncludePossibleEffects)) return true; return false; } diff --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt --- a/clang/unittests/AST/CMakeLists.txt +++ b/clang/unittests/AST/CMakeLists.txt @@ -26,6 +26,7 @@ DeclTest.cpp EvaluateAsRValueTest.cpp ExternalASTSourceTest.cpp + HasSideEffectsTest.cpp NamedDeclPrinterTest.cpp RecursiveASTVisitorTest.cpp SizelessTypesTest.cpp diff --git a/clang/unittests/AST/HasSideEffectsTest.cpp b/clang/unittests/AST/HasSideEffectsTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/AST/HasSideEffectsTest.cpp @@ -0,0 +1,86 @@ +//===- unittest/AST/HasSideEffectsTest.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/STLExtras.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include + +using namespace clang; + +namespace { +class ProcessASTAction : public clang::ASTFrontendAction { +public: + ProcessASTAction(llvm::unique_function Process) + : Process(std::move(Process)) { + assert(this->Process); + } + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + class Consumer : public ASTConsumer { + public: + Consumer(llvm::function_ref Process) + : Process(Process) {} + + void HandleTranslationUnit(ASTContext &Ctx) override { Process(Ctx); } + + private: + llvm::function_ref Process; + }; + + return std::make_unique(Process); + } + +private: + llvm::unique_function Process; +}; + +class RunHasSideEffects + : public RecursiveASTVisitor { +public: + RunHasSideEffects(ASTContext& Ctx) + : Ctx(Ctx) {} + + bool VisitLambdaExpr(LambdaExpr *LE) { + LE->HasSideEffects(Ctx); + return true; + } + + ASTContext& Ctx; +}; +} // namespace + +TEST(HasSideEffectsTest, All) { + llvm::StringRef Code = R"cpp( +void Test() { + int msize = 4; + float arr[msize]; + [&arr] {}; +} + )cpp"; + + ASSERT_NO_FATAL_FAILURE( + clang::tooling::runToolOnCode( + std::make_unique( + [&](clang::ASTContext &Ctx) { + RunHasSideEffects Visitor(Ctx); + Visitor.TraverseAST(Ctx); + } + ), + Code) + ); + +}