From: Gabor Horvath Date: Tue, 20 Aug 2019 16:45:06 +0000 (+0000) Subject: [LifetimeAnalysis] Add support for free functions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bbd15f7e03db6a69820db614bbb0d527f6fbe8fb;p=clang [LifetimeAnalysis] Add support for free functions Differential Revision: https://reviews.llvm.org/D66303 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369408 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 457f642497..289a1403cd 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -6616,6 +6616,30 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { return false; } +static bool shouldTrackFirstArgument(const FunctionDecl *FD) { + if (!FD->getIdentifier() || FD->getNumParams() != 1) + return false; + const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl(); + if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace()) + return false; + if (!isRecordWithAttr(QualType(RD->getTypeForDecl(), 0)) && + !isRecordWithAttr(QualType(RD->getTypeForDecl(), 0))) + return false; + if (FD->getReturnType()->isPointerType() || + isRecordWithAttr(FD->getReturnType())) { + return llvm::StringSwitch(FD->getName()) + .Cases("begin", "rbegin", "cbegin", "crbegin", true) + .Cases("end", "rend", "cend", "crend", true) + .Case("data", true) + .Default(false); + } else if (FD->getReturnType()->isReferenceType()) { + return llvm::StringSwitch(FD->getName()) + .Cases("get", "any_cast", true) + .Default(false); + } + return false; +} + static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, LocalVisitor Visit) { auto VisitPointerArg = [&](const Decl *D, Expr *Arg) { @@ -6639,6 +6663,11 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, shouldTrackImplicitObjectArg(cast(Callee))) VisitPointerArg(Callee, OCE->getArg(0)); return; + } else if (auto *CE = dyn_cast(Call)) { + FunctionDecl *Callee = CE->getDirectCallee(); + if (Callee && shouldTrackFirstArgument(Callee)) + VisitPointerArg(Callee, CE->getArg(0)); + return; } if (auto *CCE = dyn_cast(Call)) { diff --git a/test/Sema/warn-lifetime-analysis-nocfg.cpp b/test/Sema/warn-lifetime-analysis-nocfg.cpp index c8016bf55c..ce633e649f 100644 --- a/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ b/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -131,13 +131,16 @@ bool operator!=(basic_iterator, basic_iterator); } namespace std { -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; -template +template typename remove_reference::type &&move(T &&t) noexcept; +template +auto data(const C &c) -> decltype(c.data()); + template struct vector { typedef __gnu_cxx::basic_iterator iterator; @@ -180,6 +183,11 @@ template struct stack { T &top(); }; + +struct any {}; + +template +T any_cast(const any& operand); } void modelIterators() { @@ -191,6 +199,22 @@ std::vector::iterator modelIteratorReturn() { return std::vector().begin(); // expected-warning {{returning address of local temporary object}} } +const int *modelFreeFunctions() { + return std::data(std::vector()); // expected-warning {{returning address of local temporary object}} +} + +int &modelAnyCast() { + return std::any_cast(std::any{}); // expected-warning {{returning reference to local temporary object}} +} + +int modelAnyCast2() { + return std::any_cast(std::any{}); // ok +} + +int modelAnyCast3() { + return std::any_cast(std::any{}); // ok +} + const char *danglingRawPtrFromLocal() { std::basic_string s; return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}