[LifetimeAnalysis] Add support for free functions
authorGabor Horvath <xazax.hun@gmail.com>
Tue, 20 Aug 2019 16:45:06 +0000 (16:45 +0000)
committerGabor Horvath <xazax.hun@gmail.com>
Tue, 20 Aug 2019 16:45:06 +0000 (16:45 +0000)
Differential Revision: https://reviews.llvm.org/D66303

llvm-svn: 369408

clang/lib/Sema/SemaInit.cpp
clang/test/Sema/warn-lifetime-analysis-nocfg.cpp

index 457f642..289a140 100644 (file)
@@ -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<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) &&
+      !isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0)))
+    return false;
+  if (FD->getReturnType()->isPointerType() ||
+      isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+    return llvm::StringSwitch<bool>(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<bool>(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<CXXMethodDecl>(Callee)))
       VisitPointerArg(Callee, OCE->getArg(0));
     return;
+  } else if (auto *CE = dyn_cast<CallExpr>(Call)) {
+    FunctionDecl *Callee = CE->getDirectCallee();
+    if (Callee && shouldTrackFirstArgument(Callee))
+      VisitPointerArg(Callee, CE->getArg(0));
+    return;
   }
 
   if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
index c8016bf..ce633e6 100644 (file)
@@ -131,13 +131,16 @@ bool operator!=(basic_iterator<T>, basic_iterator<T>);
 }
 
 namespace std {
-template<class T> struct remove_reference       { typedef T type; };
-template<class T> struct remove_reference<T &>  { typedef T type; };
-template<class T> struct remove_reference<T &&> { typedef T type; };
+template<typename T> struct remove_reference       { typedef T type; };
+template<typename T> struct remove_reference<T &>  { typedef T type; };
+template<typename T> struct remove_reference<T &&> { typedef T type; };
 
-template<class T>
+template<typename T>
 typename remove_reference<T>::type &&move(T &&t) noexcept;
 
+template <typename C>
+auto data(const C &c) -> decltype(c.data());
+
 template <typename T>
 struct vector {
   typedef __gnu_cxx::basic_iterator<T> iterator;
@@ -180,6 +183,11 @@ template<typename T>
 struct stack {
   T &top();
 };
+
+struct any {};
+
+template<typename T>
+T any_cast(const any& operand);
 }
 
 void modelIterators() {
@@ -191,6 +199,22 @@ std::vector<int>::iterator modelIteratorReturn() {
   return std::vector<int>().begin(); // expected-warning {{returning address of local temporary object}}
 }
 
+const int *modelFreeFunctions() {
+  return std::data(std::vector<int>()); // expected-warning {{returning address of local temporary object}}
+}
+
+int &modelAnyCast() {
+  return std::any_cast<int&>(std::any{}); // expected-warning {{returning reference to local temporary object}}
+}
+
+int modelAnyCast2() {
+  return std::any_cast<int>(std::any{}); // ok
+}
+
+int modelAnyCast3() {
+  return std::any_cast<int&>(std::any{}); // ok
+}
+
 const char *danglingRawPtrFromLocal() {
   std::basic_string<char> s;
   return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}