[P0936R0] add [[clang::lifetimebound]] attribute

This patch adds support for a new attribute, [[clang::lifetimebound]], that
indicates that the lifetime of a function result is related to one of the
function arguments. When walking an initializer to make sure that the lifetime
of the initial value is at least as long as the lifetime of the initialized
object, we step through parameters (including the implicit object parameter of
a non-static member function) that are marked with this attribute.

There's nowhere to write an attribute on the implicit object parameter, so in
lieu of that, it may be applied to a function type (where it appears
immediately after the cv-qualifiers and ref-qualifier, which is as close to a
declaration of the implicit object parameter as we have). I'm currently
modeling this in the AST as the attribute appertaining to the function type.

Differential Revision: https://reviews.llvm.org/D49922

llvm-svn: 338464
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index cbb9f78..5fa8a3c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6322,12 +6322,14 @@
     AddressOf,
     VarInit,
     LValToRVal,
+    LifetimeBoundCall,
   } Kind;
   Expr *E;
-  Decl *D = nullptr;
+  const Decl *D = nullptr;
   IndirectLocalPathEntry() {}
   IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {}
-  IndirectLocalPathEntry(EntryKind K, Expr *E, Decl *D) : Kind(K), E(E), D(D) {}
+  IndirectLocalPathEntry(EntryKind K, Expr *E, const Decl *D)
+      : Kind(K), E(E), D(D) {}
 };
 
 using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>;
@@ -6361,6 +6363,68 @@
                                              Expr *Init, LocalVisitor Visit,
                                              bool RevisitSubinits);
 
+static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
+                                                  Expr *Init, ReferenceKind RK,
+                                                  LocalVisitor Visit);
+
+static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
+  const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
+  if (!TSI)
+    return false;
+  for (TypeLoc TL = TSI->getTypeLoc();
+       auto ATL = TL.getAsAdjusted<AttributedTypeLoc>();
+       TL = ATL.getModifiedLoc()) {
+    if (ATL.getAttrKind() == AttributedType::attr_lifetimebound)
+      return true;
+  }
+  return false;
+}
+
+static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
+                                        LocalVisitor Visit) {
+  const FunctionDecl *Callee;
+  ArrayRef<Expr*> Args;
+
+  if (auto *CE = dyn_cast<CallExpr>(Call)) {
+    Callee = CE->getDirectCallee();
+    Args = llvm::makeArrayRef(CE->getArgs(), CE->getNumArgs());
+  } else {
+    auto *CCE = cast<CXXConstructExpr>(Call);
+    Callee = CCE->getConstructor();
+    Args = llvm::makeArrayRef(CCE->getArgs(), CCE->getNumArgs());
+  }
+  if (!Callee)
+    return;
+
+  Expr *ObjectArg = nullptr;
+  if (isa<CXXOperatorCallExpr>(Call) && Callee->isCXXInstanceMember()) {
+    ObjectArg = Args[0];
+    Args = Args.slice(1);
+  } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
+    ObjectArg = MCE->getImplicitObjectArgument();
+  }
+
+  auto VisitLifetimeBoundArg = [&](const Decl *D, Expr *Arg) {
+    Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});
+    if (Arg->isGLValue())
+      visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
+                                            Visit);
+    else
+      visitLocalsRetainedByInitializer(Path, Arg, Visit, true);
+    Path.pop_back();
+  };
+
+  if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee))
+    VisitLifetimeBoundArg(Callee, ObjectArg);
+
+  for (unsigned I = 0,
+                N = std::min<unsigned>(Callee->getNumParams(), Args.size());
+       I != N; ++I) {
+    if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
+      VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
+  }
+}
+
 /// Visit the locals that would be reachable through a reference bound to the
 /// glvalue expression \c Init.
 static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
@@ -6420,6 +6484,9 @@
                                        true);
   }
 
+  if (isa<CallExpr>(Init))
+    return visitLifetimeBoundArguments(Path, Init, Visit);
+
   switch (Init->getStmtClass()) {
   case Stmt::DeclRefExprClass: {
     // If we find the name of a local non-reference parameter, we could have a
@@ -6483,21 +6550,90 @@
                                              bool RevisitSubinits) {
   RevertToOldSizeRAII RAII(Path);
 
-  // Step into CXXDefaultInitExprs so we can diagnose cases where a
-  // constructor inherits one as an implicit mem-initializer.
-  if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
-    Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
-    Init = DIE->getExpr();
-  }
+  Expr *Old;
+  do {
+    Old = Init;
 
-  if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
-    Init = EWC->getSubExpr();
+    // Step into CXXDefaultInitExprs so we can diagnose cases where a
+    // constructor inherits one as an implicit mem-initializer.
+    if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
+      Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
+      Init = DIE->getExpr();
+    }
 
-  // Dig out the expression which constructs the extended temporary.
-  Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+    if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+      Init = EWC->getSubExpr();
 
-  if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
-    Init = BTE->getSubExpr();
+    // Dig out the expression which constructs the extended temporary.
+    Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+
+    if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
+      Init = BTE->getSubExpr();
+
+    Init = Init->IgnoreParens();
+
+    // Step over value-preserving rvalue casts.
+    if (auto *CE = dyn_cast<CastExpr>(Init)) {
+      switch (CE->getCastKind()) {
+      case CK_LValueToRValue:
+        // If we can match the lvalue to a const object, we can look at its
+        // initializer.
+        Path.push_back({IndirectLocalPathEntry::LValToRVal, CE});
+        return visitLocalsRetainedByReferenceBinding(
+            Path, Init, RK_ReferenceBinding,
+            [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool {
+          if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {
+            auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
+            if (VD && VD->getType().isConstQualified() && VD->getInit() &&
+                !isVarOnPath(Path, VD)) {
+              Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
+              visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true);
+            }
+          } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
+            if (MTE->getType().isConstQualified())
+              visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
+                                               Visit, true);
+          }
+          return false;
+        });
+
+        // We assume that objects can be retained by pointers cast to integers,
+        // but not if the integer is cast to floating-point type or to _Complex.
+        // We assume that casts to 'bool' do not preserve enough information to
+        // retain a local object.
+      case CK_NoOp:
+      case CK_BitCast:
+      case CK_BaseToDerived:
+      case CK_DerivedToBase:
+      case CK_UncheckedDerivedToBase:
+      case CK_Dynamic:
+      case CK_ToUnion:
+      case CK_UserDefinedConversion:
+      case CK_ConstructorConversion:
+      case CK_IntegralToPointer:
+      case CK_PointerToIntegral:
+      case CK_VectorSplat:
+      case CK_IntegralCast:
+      case CK_CPointerToObjCPointerCast:
+      case CK_BlockPointerToObjCPointerCast:
+      case CK_AnyPointerToBlockPointerCast:
+      case CK_AddressSpaceConversion:
+        break;
+
+      case CK_ArrayToPointerDecay:
+        // Model array-to-pointer decay as taking the address of the array
+        // lvalue.
+        Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
+        return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
+                                                     RK_ReferenceBinding, Visit);
+
+      default:
+        return;
+      }
+
+      Init = CE->getSubExpr();
+    }
+  } while (Old != Init);
 
   // C++17 [dcl.init.list]p6:
   //   initializing an initializer_list object from the array extends the
@@ -6558,67 +6694,9 @@
     return;
   }
 
-  // Step over value-preserving rvalue casts.
-  while (auto *CE = dyn_cast<CastExpr>(Init)) {
-    switch (CE->getCastKind()) {
-    case CK_LValueToRValue:
-      // If we can match the lvalue to a const object, we can look at its
-      // initializer.
-      Path.push_back({IndirectLocalPathEntry::LValToRVal, CE});
-      return visitLocalsRetainedByReferenceBinding(
-          Path, Init, RK_ReferenceBinding,
-          [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool {
-        if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {
-          auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
-          if (VD && VD->getType().isConstQualified() && VD->getInit() &&
-              !isVarOnPath(Path, VD)) {
-            Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
-            visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true);
-          }
-        } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
-          if (MTE->getType().isConstQualified())
-            visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
-                                             Visit, true);
-        }
-        return false;
-      });
+  if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
+    return visitLifetimeBoundArguments(Path, Init, Visit);
 
-      // We assume that objects can be retained by pointers cast to integers,
-      // but not if the integer is cast to floating-point type or to _Complex.
-      // We assume that casts to 'bool' do not preserve enough information to
-      // retain a local object.
-    case CK_NoOp:
-    case CK_BitCast:
-    case CK_BaseToDerived:
-    case CK_DerivedToBase:
-    case CK_UncheckedDerivedToBase:
-    case CK_Dynamic:
-    case CK_ToUnion:
-    case CK_IntegralToPointer:
-    case CK_PointerToIntegral:
-    case CK_VectorSplat:
-    case CK_IntegralCast:
-    case CK_CPointerToObjCPointerCast:
-    case CK_BlockPointerToObjCPointerCast:
-    case CK_AnyPointerToBlockPointerCast:
-    case CK_AddressSpaceConversion:
-      break;
-
-    case CK_ArrayToPointerDecay:
-      // Model array-to-pointer decay as taking the address of the array
-      // lvalue.
-      Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
-      return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
-                                                   RK_ReferenceBinding, Visit);
-
-    default:
-      return;
-    }
-
-    Init = CE->getSubExpr();
-  }
-
-  Init = Init->IgnoreParens();
   switch (Init->getStmtClass()) {
   case Stmt::UnaryOperatorClass: {
     auto *UO = cast<UnaryOperator>(Init);
@@ -6698,6 +6776,7 @@
     switch (Path[I].Kind) {
     case IndirectLocalPathEntry::AddressOf:
     case IndirectLocalPathEntry::LValToRVal:
+    case IndirectLocalPathEntry::LifetimeBoundCall:
       // These exist primarily to mark the path as not permitting or
       // supporting lifetime extension.
       break;
@@ -6876,6 +6955,10 @@
         // supporting lifetime extension.
         break;
 
+      case IndirectLocalPathEntry::LifetimeBoundCall:
+        // FIXME: Consider adding a note for this.
+        break;
+
       case IndirectLocalPathEntry::DefaultInit: {
         auto *FD = cast<FieldDecl>(Elem.D);
         Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)