brintos

brintos / llvm-project-archived public Read only

0
0
Text · 61.5 KiB · c91ca75 Raw
1598 lines · cpp
1//===--- CheckExprLifetime.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CheckExprLifetime.h"10#include "clang/AST/Decl.h"11#include "clang/AST/Expr.h"12#include "clang/AST/Type.h"13#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"14#include "clang/Basic/DiagnosticSema.h"15#include "clang/Sema/Initialization.h"16#include "clang/Sema/Sema.h"17#include "llvm/ADT/PointerIntPair.h"18 19namespace clang::sema {20using lifetimes::isGslOwnerType;21using lifetimes::isGslPointerType;22 23namespace {24enum LifetimeKind {25  /// The lifetime of a temporary bound to this entity ends at the end of the26  /// full-expression, and that's (probably) fine.27  LK_FullExpression,28 29  /// The lifetime of a temporary bound to this entity is extended to the30  /// lifeitme of the entity itself.31  LK_Extended,32 33  /// The lifetime of a temporary bound to this entity probably ends too soon,34  /// because the entity is allocated in a new-expression.35  LK_New,36 37  /// The lifetime of a temporary bound to this entity ends too soon, because38  /// the entity is a return object.39  LK_Return,40 41  /// The lifetime of a temporary bound to this entity ends too soon, because42  /// the entity passed to a musttail function call.43  LK_MustTail,44 45  /// The lifetime of a temporary bound to this entity ends too soon, because46  /// the entity is the result of a statement expression.47  LK_StmtExprResult,48 49  /// This is a mem-initializer: if it would extend a temporary (other than via50  /// a default member initializer), the program is ill-formed.51  LK_MemInitializer,52 53  /// The lifetime of a temporary bound to this entity may end too soon,54  /// because the entity is a pointer and we assign the address of a temporary55  /// object to it.56  LK_Assignment,57 58  /// The lifetime of a temporary bound to this entity may end too soon,59  /// because the entity may capture the reference to a temporary object.60  LK_LifetimeCapture,61};62using LifetimeResult =63    llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>;64} // namespace65 66/// Determine the declaration which an initialized entity ultimately refers to,67/// for the purpose of lifetime-extending a temporary bound to a reference in68/// the initialization of \p Entity.69static LifetimeResult70getEntityLifetime(const InitializedEntity *Entity,71                  const InitializedEntity *InitField = nullptr) {72  // C++11 [class.temporary]p5:73  switch (Entity->getKind()) {74  case InitializedEntity::EK_Variable:75    //   The temporary [...] persists for the lifetime of the reference76    return {Entity, LK_Extended};77 78  case InitializedEntity::EK_Member:79    // For subobjects, we look at the complete object.80    if (Entity->getParent())81      return getEntityLifetime(Entity->getParent(), Entity);82 83    //   except:84    // C++17 [class.base.init]p8:85    //   A temporary expression bound to a reference member in a86    //   mem-initializer is ill-formed.87    // C++17 [class.base.init]p11:88    //   A temporary expression bound to a reference member from a89    //   default member initializer is ill-formed.90    //91    // The context of p11 and its example suggest that it's only the use of a92    // default member initializer from a constructor that makes the program93    // ill-formed, not its mere existence, and that it can even be used by94    // aggregate initialization.95    return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended96                                                         : LK_MemInitializer};97 98  case InitializedEntity::EK_Binding:99    // Per [dcl.decomp]p3, the binding is treated as a variable of reference100    // type.101    return {Entity, LK_Extended};102 103  case InitializedEntity::EK_Parameter:104  case InitializedEntity::EK_Parameter_CF_Audited:105    //   -- A temporary bound to a reference parameter in a function call106    //      persists until the completion of the full-expression containing107    //      the call.108    return {nullptr, LK_FullExpression};109 110  case InitializedEntity::EK_TemplateParameter:111    // FIXME: This will always be ill-formed; should we eagerly diagnose it112    // here?113    return {nullptr, LK_FullExpression};114 115  case InitializedEntity::EK_Result:116    //   -- The lifetime of a temporary bound to the returned value in a117    //      function return statement is not extended; the temporary is118    //      destroyed at the end of the full-expression in the return statement.119    return {nullptr, LK_Return};120 121  case InitializedEntity::EK_StmtExprResult:122    // FIXME: Should we lifetime-extend through the result of a statement123    // expression?124    return {nullptr, LK_StmtExprResult};125 126  case InitializedEntity::EK_New:127    //   -- A temporary bound to a reference in a new-initializer persists128    //      until the completion of the full-expression containing the129    //      new-initializer.130    return {nullptr, LK_New};131 132  case InitializedEntity::EK_Temporary:133  case InitializedEntity::EK_CompoundLiteralInit:134  case InitializedEntity::EK_RelatedResult:135    // We don't yet know the storage duration of the surrounding temporary.136    // Assume it's got full-expression duration for now, it will patch up our137    // storage duration if that's not correct.138    return {nullptr, LK_FullExpression};139 140  case InitializedEntity::EK_ArrayElement:141    // For subobjects, we look at the complete object.142    return getEntityLifetime(Entity->getParent(), InitField);143 144  case InitializedEntity::EK_Base:145    // For subobjects, we look at the complete object.146    if (Entity->getParent())147      return getEntityLifetime(Entity->getParent(), InitField);148    return {InitField, LK_MemInitializer};149 150  case InitializedEntity::EK_Delegating:151    // We can reach this case for aggregate initialization in a constructor:152    //   struct A { int &&r; };153    //   struct B : A { B() : A{0} {} };154    // In this case, use the outermost field decl as the context.155    return {InitField, LK_MemInitializer};156 157  case InitializedEntity::EK_BlockElement:158  case InitializedEntity::EK_LambdaToBlockConversionBlockElement:159  case InitializedEntity::EK_LambdaCapture:160  case InitializedEntity::EK_VectorElement:161  case InitializedEntity::EK_MatrixElement:162  case InitializedEntity::EK_ComplexElement:163    return {nullptr, LK_FullExpression};164 165  case InitializedEntity::EK_Exception:166    // FIXME: Can we diagnose lifetime problems with exceptions?167    return {nullptr, LK_FullExpression};168 169  case InitializedEntity::EK_ParenAggInitMember:170    //   -- A temporary object bound to a reference element of an aggregate of171    //      class type initialized from a parenthesized expression-list172    //      [dcl.init, 9.3] persists until the completion of the full-expression173    //      containing the expression-list.174    return {nullptr, LK_FullExpression};175  }176 177  llvm_unreachable("unknown entity kind");178}179 180namespace {181enum ReferenceKind {182  /// Lifetime would be extended by a reference binding to a temporary.183  RK_ReferenceBinding,184  /// Lifetime would be extended by a std::initializer_list object binding to185  /// its backing array.186  RK_StdInitializerList,187};188 189/// A temporary or local variable. This will be one of:190///  * A MaterializeTemporaryExpr.191///  * A DeclRefExpr whose declaration is a local.192///  * An AddrLabelExpr.193///  * A BlockExpr for a block with captures.194using Local = Expr *;195 196/// Expressions we stepped over when looking for the local state. Any steps197/// that would inhibit lifetime extension or take us out of subexpressions of198/// the initializer are included.199struct IndirectLocalPathEntry {200  enum EntryKind {201    DefaultInit,202    AddressOf,203    VarInit,204    LValToRVal,205    LifetimeBoundCall,206    TemporaryCopy,207    LambdaCaptureInit,208    MemberExpr,209    GslReferenceInit,210    GslPointerInit,211    GslPointerAssignment,212    DefaultArg,213    ParenAggInit,214  } Kind;215  Expr *E;216  union {217    const Decl *D = nullptr;218    const LambdaCapture *Capture;219  };220  IndirectLocalPathEntry() {}221  IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {}222  IndirectLocalPathEntry(EntryKind K, Expr *E, const Decl *D)223      : Kind(K), E(E), D(D) {}224  IndirectLocalPathEntry(EntryKind K, Expr *E, const LambdaCapture *Capture)225      : Kind(K), E(E), Capture(Capture) {}226};227 228using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>;229 230struct RevertToOldSizeRAII {231  IndirectLocalPath &Path;232  unsigned OldSize = Path.size();233  RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {}234  ~RevertToOldSizeRAII() { Path.resize(OldSize); }235};236 237using LocalVisitor = llvm::function_ref<bool(IndirectLocalPath &Path, Local L,238                                             ReferenceKind RK)>;239} // namespace240 241static bool isVarOnPath(const IndirectLocalPath &Path, VarDecl *VD) {242  for (auto E : Path)243    if (E.Kind == IndirectLocalPathEntry::VarInit && E.D == VD)244      return true;245  return false;246}247 248static bool pathContainsInit(const IndirectLocalPath &Path) {249  return llvm::any_of(Path, [=](IndirectLocalPathEntry E) {250    return E.Kind == IndirectLocalPathEntry::DefaultInit ||251           E.Kind == IndirectLocalPathEntry::VarInit;252  });253}254 255static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,256                                             Expr *Init, LocalVisitor Visit,257                                             bool RevisitSubinits);258 259static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,260                                                  Expr *Init, ReferenceKind RK,261                                                  LocalVisitor Visit);262 263static bool isPointerLikeType(QualType QT) {264  return isGslPointerType(QT) || QT->isPointerType() || QT->isNullPtrType();265}266 267// Decl::isInStdNamespace will return false for iterators in some STL268// implementations due to them being defined in a namespace outside of the std269// namespace.270static bool isInStlNamespace(const Decl *D) {271  const DeclContext *DC = D->getDeclContext();272  if (!DC)273    return false;274  if (const auto *ND = dyn_cast<NamespaceDecl>(DC))275    if (const IdentifierInfo *II = ND->getIdentifier()) {276      StringRef Name = II->getName();277      if (Name.size() >= 2 && Name.front() == '_' &&278          (Name[1] == '_' || isUppercase(Name[1])))279        return true;280    }281 282  return DC->isStdNamespace();283}284 285// Returns true if the given Record decl is a form of `GSLOwner<Pointer>`286// type, e.g. std::vector<string_view>, std::optional<string_view>.287static bool isContainerOfPointer(const RecordDecl *Container) {288  if (const auto *CTSD =289          dyn_cast_if_present<ClassTemplateSpecializationDecl>(Container)) {290    if (!CTSD->hasAttr<OwnerAttr>()) // Container must be a GSL owner type.291      return false;292    const auto &TAs = CTSD->getTemplateArgs();293    return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&294           isPointerLikeType(TAs[0].getAsType());295  }296  return false;297}298static bool isContainerOfOwner(const RecordDecl *Container) {299  const auto *CTSD =300      dyn_cast_if_present<ClassTemplateSpecializationDecl>(Container);301  if (!CTSD)302    return false;303  if (!CTSD->hasAttr<OwnerAttr>()) // Container must be a GSL owner type.304    return false;305  const auto &TAs = CTSD->getTemplateArgs();306  return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&307         isGslOwnerType(TAs[0].getAsType());308}309 310// Returns true if the given Record is `std::initializer_list<pointer>`.311static bool isStdInitializerListOfPointer(const RecordDecl *RD) {312  if (const auto *CTSD =313          dyn_cast_if_present<ClassTemplateSpecializationDecl>(RD)) {314    const auto &TAs = CTSD->getTemplateArgs();315    return isInStlNamespace(RD) && RD->getIdentifier() &&316           RD->getName() == "initializer_list" && TAs.size() > 0 &&317           TAs[0].getKind() == TemplateArgument::Type &&318           isPointerLikeType(TAs[0].getAsType());319  }320  return false;321}322 323static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {324  if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))325    if (isGslPointerType(Conv->getConversionType()) &&326        Callee->getParent()->hasAttr<OwnerAttr>())327      return true;328  if (!isInStlNamespace(Callee->getParent()))329    return false;330  if (!isGslPointerType(Callee->getFunctionObjectParameterType()) &&331      !isGslOwnerType(Callee->getFunctionObjectParameterType()))332    return false;333  if (isPointerLikeType(Callee->getReturnType())) {334    if (!Callee->getIdentifier())335      return false;336    return llvm::StringSwitch<bool>(Callee->getName())337        .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true)338        .Cases({"end", "rend", "cend", "crend"}, true)339        .Cases({"c_str", "data", "get"}, true)340        // Map and set types.341        .Cases({"find", "equal_range", "lower_bound", "upper_bound"}, true)342        .Default(false);343  }344  if (Callee->getReturnType()->isReferenceType()) {345    if (!Callee->getIdentifier()) {346      auto OO = Callee->getOverloadedOperator();347      if (!Callee->getParent()->hasAttr<OwnerAttr>())348        return false;349      return OO == OverloadedOperatorKind::OO_Subscript ||350             OO == OverloadedOperatorKind::OO_Star;351    }352    return llvm::StringSwitch<bool>(Callee->getName())353        .Cases({"front", "back", "at", "top", "value"}, true)354        .Default(false);355  }356  return false;357}358 359static bool shouldTrackFirstArgument(const FunctionDecl *FD) {360  if (!FD->getIdentifier() || FD->getNumParams() != 1)361    return false;362  const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();363  if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())364    return false;365  if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())366    return false;367  if (FD->getReturnType()->isPointerType() ||368      isGslPointerType(FD->getReturnType())) {369    return llvm::StringSwitch<bool>(FD->getName())370        .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true)371        .Cases({"end", "rend", "cend", "crend"}, true)372        .Case("data", true)373        .Default(false);374  }375  if (FD->getReturnType()->isReferenceType()) {376    return llvm::StringSwitch<bool>(FD->getName())377        .Cases({"get", "any_cast"}, true)378        .Default(false);379  }380  return false;381}382 383// Returns true if the given constructor is a copy-like constructor, such as384// `Ctor(Owner<U>&&)` or `Ctor(const Owner<U>&)`.385static bool isCopyLikeConstructor(const CXXConstructorDecl *Ctor) {386  if (!Ctor || Ctor->param_size() != 1)387    return false;388  const auto *ParamRefType =389      Ctor->getParamDecl(0)->getType()->getAs<ReferenceType>();390  if (!ParamRefType)391    return false;392 393  // Check if the first parameter type is "Owner<U>".394  if (const auto *TST =395          ParamRefType->getPointeeType()->getAs<TemplateSpecializationType>())396    return TST->getTemplateName()397        .getAsTemplateDecl()398        ->getTemplatedDecl()399        ->hasAttr<OwnerAttr>();400  return false;401}402 403// Returns true if we should perform the GSL analysis on the first argument for404// the given constructor.405static bool406shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {407  const auto *LHSRecordDecl = Ctor->getConstructor()->getParent();408 409  // Case 1, construct a GSL pointer, e.g. std::string_view410  // Always inspect when LHS is a pointer.411  if (LHSRecordDecl->hasAttr<PointerAttr>())412    return true;413 414  if (Ctor->getConstructor()->param_empty() ||415      !isContainerOfPointer(LHSRecordDecl))416    return false;417 418  // Now, the LHS is an Owner<Pointer> type, e.g., std::vector<string_view>.419  //420  // At a high level, we cannot precisely determine what the nested pointer421  // owns. However, by analyzing the RHS owner type, we can use heuristics to422  // infer ownership information. These heuristics are designed to be423  // conservative, minimizing false positives while still providing meaningful424  // diagnostics.425  //426  // While this inference isn't perfect, it helps catch common use-after-free427  // patterns.428  auto RHSArgType = Ctor->getArg(0)->getType();429  const auto *RHSRD = RHSArgType->getAsRecordDecl();430  // LHS is constructed from an intializer_list.431  //432  // std::initializer_list is a proxy object that provides access to the backing433  // array. We perform analysis on it to determine if there are any dangling434  // temporaries in the backing array.435  // E.g. std::vector<string_view> abc = {string()};436  if (isStdInitializerListOfPointer(RHSRD))437    return true;438 439  // RHS must be an owner.440  if (!isGslOwnerType(RHSArgType))441    return false;442 443  // Bail out if the RHS is Owner<Pointer>.444  //445  // We cannot reliably determine what the LHS nested pointer owns -- it could446  // be the entire RHS or the nested pointer in RHS. To avoid false positives,447  // we skip this case, such as:448  //   std::stack<std::string_view> s(std::deque<std::string_view>{});449  //450  // TODO: this also has a false negative, it doesn't catch the case like:451  //   std::optional<span<int*>> os = std::vector<int*>{}452  if (isContainerOfPointer(RHSRD))453    return false;454 455  // Assume that the nested Pointer is constructed from the nested Owner.456  // E.g. std::optional<string_view> sv = std::optional<string>(s);457  if (isContainerOfOwner(RHSRD))458    return true;459 460  // Now, the LHS is an Owner<Pointer> and the RHS is an Owner<X>,  where X is461  // neither an `Owner` nor a `Pointer`.462  //463  // Use the constructor's signature as a hint. If it is a copy-like constructor464  // `Owner1<Pointer>(Owner2<X>&&)`, we assume that the nested pointer is465  // constructed from X. In such cases, we do not diagnose, as `X` is not an466  // owner, e.g.467  //   std::optional<string_view> sv = std::optional<Foo>();468  if (const auto *PrimaryCtorTemplate =469          Ctor->getConstructor()->getPrimaryTemplate();470      PrimaryCtorTemplate &&471      isCopyLikeConstructor(dyn_cast_if_present<CXXConstructorDecl>(472          PrimaryCtorTemplate->getTemplatedDecl()))) {473    return false;474  }475  // Assume that the nested pointer is constructed from the whole RHS.476  // E.g. optional<string_view> s = std::string();477  return true;478}479 480// Visit lifetimebound or gsl-pointer arguments.481static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,482                                       LocalVisitor Visit) {483  const FunctionDecl *Callee;484  ArrayRef<Expr *> Args;485 486  if (auto *CE = dyn_cast<CallExpr>(Call)) {487    Callee = CE->getDirectCallee();488    Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());489  } else {490    auto *CCE = cast<CXXConstructExpr>(Call);491    Callee = CCE->getConstructor();492    Args = llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs());493  }494  if (!Callee)495    return;496 497  bool EnableGSLAnalysis = !Callee->getASTContext().getDiagnostics().isIgnored(498      diag::warn_dangling_lifetime_pointer, SourceLocation());499  Expr *ObjectArg = nullptr;500  if (isa<CXXOperatorCallExpr>(Call) && Callee->isCXXInstanceMember()) {501    ObjectArg = Args[0];502    Args = Args.slice(1);503  } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {504    ObjectArg = MCE->getImplicitObjectArgument();505  }506 507  auto VisitLifetimeBoundArg = [&](const Decl *D, Expr *Arg) {508    Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});509    if (Arg->isGLValue())510      visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,511                                            Visit);512    else513      visitLocalsRetainedByInitializer(Path, Arg, Visit, true);514    Path.pop_back();515  };516  auto VisitGSLPointerArg = [&](const FunctionDecl *Callee, Expr *Arg) {517    auto ReturnType = Callee->getReturnType();518 519    // Once we initialized a value with a non gsl-owner reference, it can no520    // longer dangle.521    if (ReturnType->isReferenceType() &&522        !isGslOwnerType(ReturnType->getPointeeType())) {523      for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {524        if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||525            PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)526          continue;527        if (PE.Kind == IndirectLocalPathEntry::GslPointerInit ||528            PE.Kind == IndirectLocalPathEntry::GslPointerAssignment)529          return;530        break;531      }532    }533    Path.push_back({ReturnType->isReferenceType()534                        ? IndirectLocalPathEntry::GslReferenceInit535                        : IndirectLocalPathEntry::GslPointerInit,536                    Arg, Callee});537    if (Arg->isGLValue())538      visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,539                                            Visit);540    else541      visitLocalsRetainedByInitializer(Path, Arg, Visit, true);542    Path.pop_back();543  };544 545  bool CheckCoroCall = false;546  if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) {547    CheckCoroCall = RD->hasAttr<CoroLifetimeBoundAttr>() &&548                    RD->hasAttr<CoroReturnTypeAttr>() &&549                    !Callee->hasAttr<CoroDisableLifetimeBoundAttr>();550  }551 552  if (ObjectArg) {553    bool CheckCoroObjArg = CheckCoroCall;554    // Coroutine lambda objects with empty capture list are not lifetimebound.555    if (auto *LE = dyn_cast<LambdaExpr>(ObjectArg->IgnoreImplicit());556        LE && LE->captures().empty())557      CheckCoroObjArg = false;558    // Allow `get_return_object()` as the object param (__promise) is not559    // lifetimebound.560    if (Sema::CanBeGetReturnObject(Callee))561      CheckCoroObjArg = false;562    if (lifetimes::implicitObjectParamIsLifetimeBound(Callee) ||563        CheckCoroObjArg)564      VisitLifetimeBoundArg(Callee, ObjectArg);565    else if (EnableGSLAnalysis) {566      if (auto *CME = dyn_cast<CXXMethodDecl>(Callee);567          CME && shouldTrackImplicitObjectArg(CME))568        VisitGSLPointerArg(Callee, ObjectArg);569    }570  }571 572  const FunctionDecl *CanonCallee =573      lifetimes::getDeclWithMergedLifetimeBoundAttrs(Callee);574  unsigned NP = std::min(Callee->getNumParams(), CanonCallee->getNumParams());575  for (unsigned I = 0, N = std::min<unsigned>(NP, Args.size()); I != N; ++I) {576    Expr *Arg = Args[I];577    RevertToOldSizeRAII RAII(Path);578    if (auto *DAE = dyn_cast<CXXDefaultArgExpr>(Arg)) {579      Path.push_back(580          {IndirectLocalPathEntry::DefaultArg, DAE, DAE->getParam()});581      Arg = DAE->getExpr();582    }583    if (CheckCoroCall ||584        CanonCallee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())585      VisitLifetimeBoundArg(CanonCallee->getParamDecl(I), Arg);586    else if (const auto *CaptureAttr =587                 CanonCallee->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>();588             CaptureAttr && isa<CXXConstructorDecl>(CanonCallee) &&589             llvm::any_of(CaptureAttr->params(), [](int ArgIdx) {590               return ArgIdx == LifetimeCaptureByAttr::This;591             }))592      // `lifetime_capture_by(this)` in a class constructor has the same593      // semantics as `lifetimebound`:594      //595      // struct Foo {596      //   const int& a;597      //   // Equivalent to Foo(const int& t [[clang::lifetimebound]])598      //   Foo(const int& t [[clang::lifetime_capture_by(this)]]) : a(t) {}599      // };600      //601      // In the implementation, `lifetime_capture_by` is treated as an alias for602      // `lifetimebound` and shares the same code path. This implies the emitted603      // diagnostics will be emitted under `-Wdangling`, not604      // `-Wdangling-capture`.605      VisitLifetimeBoundArg(CanonCallee->getParamDecl(I), Arg);606    else if (EnableGSLAnalysis && I == 0) {607      // Perform GSL analysis for the first argument608      if (shouldTrackFirstArgument(CanonCallee)) {609        VisitGSLPointerArg(CanonCallee, Arg);610      } else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call);611                 Ctor && shouldTrackFirstArgumentForConstructor(Ctor)) {612        VisitGSLPointerArg(Ctor->getConstructor(), Arg);613      }614    }615  }616}617 618/// Visit the locals that would be reachable through a reference bound to the619/// glvalue expression \c Init.620static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,621                                                  Expr *Init, ReferenceKind RK,622                                                  LocalVisitor Visit) {623  RevertToOldSizeRAII RAII(Path);624 625  // Walk past any constructs which we can lifetime-extend across.626  Expr *Old;627  do {628    Old = Init;629 630    if (auto *FE = dyn_cast<FullExpr>(Init))631      Init = FE->getSubExpr();632 633    if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {634      // If this is just redundant braces around an initializer, step over it.635      if (ILE->isTransparent())636        Init = ILE->getInit(0);637    }638 639    if (MemberExpr *ME = dyn_cast<MemberExpr>(Init->IgnoreImpCasts()))640      Path.push_back(641          {IndirectLocalPathEntry::MemberExpr, ME, ME->getMemberDecl()});642    // Step over any subobject adjustments; we may have a materialized643    // temporary inside them.644    Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());645 646    // Per current approach for DR1376, look through casts to reference type647    // when performing lifetime extension.648    if (CastExpr *CE = dyn_cast<CastExpr>(Init))649      if (CE->getSubExpr()->isGLValue())650        Init = CE->getSubExpr();651 652    // Per the current approach for DR1299, look through array element access653    // on array glvalues when performing lifetime extension.654    if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) {655      Init = ASE->getBase();656      auto *ICE = dyn_cast<ImplicitCastExpr>(Init);657      if (ICE && ICE->getCastKind() == CK_ArrayToPointerDecay)658        Init = ICE->getSubExpr();659      else660        // We can't lifetime extend through this but we might still find some661        // retained temporaries.662        return visitLocalsRetainedByInitializer(Path, Init, Visit, true);663    }664 665    // Step into CXXDefaultInitExprs so we can diagnose cases where a666    // constructor inherits one as an implicit mem-initializer.667    if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {668      Path.push_back(669          {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});670      Init = DIE->getExpr();671    }672  } while (Init != Old);673 674  if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {675    if (Visit(Path, Local(MTE), RK))676      visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true);677  }678 679  if (auto *M = dyn_cast<MemberExpr>(Init)) {680    // Lifetime of a non-reference type field is same as base object.681    if (auto *F = dyn_cast<FieldDecl>(M->getMemberDecl());682        F && !F->getType()->isReferenceType())683      visitLocalsRetainedByInitializer(Path, M->getBase(), Visit, true);684  }685 686  if (isa<CallExpr>(Init))687    return visitFunctionCallArguments(Path, Init, Visit);688 689  switch (Init->getStmtClass()) {690  case Stmt::DeclRefExprClass: {691    // If we find the name of a local non-reference parameter, we could have a692    // lifetime problem.693    auto *DRE = cast<DeclRefExpr>(Init);694    auto *VD = dyn_cast<VarDecl>(DRE->getDecl());695    if (VD && VD->hasLocalStorage() &&696        !DRE->refersToEnclosingVariableOrCapture()) {697      if (!VD->getType()->isReferenceType()) {698        Visit(Path, Local(DRE), RK);699      } else if (isa<ParmVarDecl>(DRE->getDecl())) {700        // The lifetime of a reference parameter is unknown; assume it's OK701        // for now.702        break;703      } else if (VD->getInit() && !isVarOnPath(Path, VD)) {704        Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});705        visitLocalsRetainedByReferenceBinding(Path, VD->getInit(),706                                              RK_ReferenceBinding, Visit);707      }708    }709    break;710  }711 712  case Stmt::UnaryOperatorClass: {713    // The only unary operator that make sense to handle here714    // is Deref.  All others don't resolve to a "name."  This includes715    // handling all sorts of rvalues passed to a unary operator.716    const UnaryOperator *U = cast<UnaryOperator>(Init);717    if (U->getOpcode() == UO_Deref)718      visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true);719    break;720  }721 722  case Stmt::ArraySectionExprClass: {723    visitLocalsRetainedByInitializer(724        Path, cast<ArraySectionExpr>(Init)->getBase(), Visit, true);725    break;726  }727 728  case Stmt::ConditionalOperatorClass:729  case Stmt::BinaryConditionalOperatorClass: {730    auto *C = cast<AbstractConditionalOperator>(Init);731    if (!C->getTrueExpr()->getType()->isVoidType())732      visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit);733    if (!C->getFalseExpr()->getType()->isVoidType())734      visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit);735    break;736  }737 738  case Stmt::CompoundLiteralExprClass: {739    if (auto *CLE = dyn_cast<CompoundLiteralExpr>(Init)) {740      if (!CLE->isFileScope())741        Visit(Path, Local(CLE), RK);742    }743    break;744  }745 746    // FIXME: Visit the left-hand side of an -> or ->*.747 748  default:749    break;750  }751}752 753/// Visit the locals that would be reachable through an object initialized by754/// the prvalue expression \c Init.755static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,756                                             Expr *Init, LocalVisitor Visit,757                                             bool RevisitSubinits) {758  RevertToOldSizeRAII RAII(Path);759 760  Expr *Old;761  do {762    Old = Init;763 764    // Step into CXXDefaultInitExprs so we can diagnose cases where a765    // constructor inherits one as an implicit mem-initializer.766    if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {767      Path.push_back(768          {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});769      Init = DIE->getExpr();770    }771 772    if (auto *FE = dyn_cast<FullExpr>(Init))773      Init = FE->getSubExpr();774 775    // Dig out the expression which constructs the extended temporary.776    Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());777 778    if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))779      Init = BTE->getSubExpr();780 781    Init = Init->IgnoreParens();782 783    // Step over value-preserving rvalue casts.784    if (auto *CE = dyn_cast<CastExpr>(Init)) {785      switch (CE->getCastKind()) {786      case CK_LValueToRValue:787        // If we can match the lvalue to a const object, we can look at its788        // initializer.789        Path.push_back({IndirectLocalPathEntry::LValToRVal, CE});790        return visitLocalsRetainedByReferenceBinding(791            Path, Init, RK_ReferenceBinding,792            [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool {793              if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {794                auto *VD = dyn_cast<VarDecl>(DRE->getDecl());795                if (VD && VD->getType().isConstQualified() && VD->getInit() &&796                    !isVarOnPath(Path, VD)) {797                  Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});798                  visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit,799                                                   true);800                }801              } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {802                if (MTE->getType().isConstQualified())803                  visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(),804                                                   Visit, true);805              }806              return false;807            });808 809        // We assume that objects can be retained by pointers cast to integers,810        // but not if the integer is cast to floating-point type or to _Complex.811        // We assume that casts to 'bool' do not preserve enough information to812        // retain a local object.813      case CK_NoOp:814      case CK_BitCast:815      case CK_BaseToDerived:816      case CK_DerivedToBase:817      case CK_UncheckedDerivedToBase:818      case CK_Dynamic:819      case CK_ToUnion:820      case CK_UserDefinedConversion:821      case CK_ConstructorConversion:822      case CK_IntegralToPointer:823      case CK_PointerToIntegral:824      case CK_VectorSplat:825      case CK_IntegralCast:826      case CK_CPointerToObjCPointerCast:827      case CK_BlockPointerToObjCPointerCast:828      case CK_AnyPointerToBlockPointerCast:829      case CK_AddressSpaceConversion:830        break;831 832      case CK_ArrayToPointerDecay:833        // Model array-to-pointer decay as taking the address of the array834        // lvalue.835        Path.push_back({IndirectLocalPathEntry::AddressOf, CE});836        return visitLocalsRetainedByReferenceBinding(837            Path, CE->getSubExpr(), RK_ReferenceBinding, Visit);838 839      default:840        return;841      }842 843      Init = CE->getSubExpr();844    }845  } while (Old != Init);846 847  // C++17 [dcl.init.list]p6:848  //   initializing an initializer_list object from the array extends the849  //   lifetime of the array exactly like binding a reference to a temporary.850  if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))851    return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),852                                                 RK_StdInitializerList, Visit);853 854  if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {855    // We already visited the elements of this initializer list while856    // performing the initialization. Don't visit them again unless we've857    // changed the lifetime of the initialized entity.858    if (!RevisitSubinits)859      return;860 861    if (ILE->isTransparent())862      return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,863                                              RevisitSubinits);864 865    if (ILE->getType()->isArrayType()) {866      for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)867        visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,868                                         RevisitSubinits);869      return;870    }871 872    if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) {873      assert(RD->isAggregate() && "aggregate init on non-aggregate");874 875      // If we lifetime-extend a braced initializer which is initializing an876      // aggregate, and that aggregate contains reference members which are877      // bound to temporaries, those temporaries are also lifetime-extended.878      if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&879          ILE->getInitializedFieldInUnion()->getType()->isReferenceType())880        visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),881                                              RK_ReferenceBinding, Visit);882      else {883        unsigned Index = 0;884        for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index)885          visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit,886                                           RevisitSubinits);887        for (const auto *I : RD->fields()) {888          if (Index >= ILE->getNumInits())889            break;890          if (I->isUnnamedBitField())891            continue;892          Expr *SubInit = ILE->getInit(Index);893          if (I->getType()->isReferenceType())894            visitLocalsRetainedByReferenceBinding(Path, SubInit,895                                                  RK_ReferenceBinding, Visit);896          else897            // This might be either aggregate-initialization of a member or898            // initialization of a std::initializer_list object. Regardless,899            // we should recursively lifetime-extend that initializer.900            visitLocalsRetainedByInitializer(Path, SubInit, Visit,901                                             RevisitSubinits);902          ++Index;903        }904      }905    }906    return;907  }908 909  // The lifetime of an init-capture is that of the closure object constructed910  // by a lambda-expression.911  if (auto *LE = dyn_cast<LambdaExpr>(Init)) {912    LambdaExpr::capture_iterator CapI = LE->capture_begin();913    for (Expr *E : LE->capture_inits()) {914      assert(CapI != LE->capture_end());915      const LambdaCapture &Cap = *CapI++;916      if (!E)917        continue;918      if (Cap.capturesVariable())919        Path.push_back({IndirectLocalPathEntry::LambdaCaptureInit, E, &Cap});920      if (E->isGLValue())921        visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding,922                                              Visit);923      else924        visitLocalsRetainedByInitializer(Path, E, Visit, true);925      if (Cap.capturesVariable())926        Path.pop_back();927    }928  }929 930  // Assume that a copy or move from a temporary references the same objects931  // that the temporary does.932  if (auto *CCE = dyn_cast<CXXConstructExpr>(Init)) {933    if (CCE->getConstructor()->isCopyOrMoveConstructor()) {934      if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(CCE->getArg(0))) {935        Expr *Arg = MTE->getSubExpr();936        Path.push_back({IndirectLocalPathEntry::TemporaryCopy, Arg,937                        CCE->getConstructor()});938        visitLocalsRetainedByInitializer(Path, Arg, Visit, true);939        Path.pop_back();940      }941    }942  }943 944  if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))945    return visitFunctionCallArguments(Path, Init, Visit);946 947  if (auto *CPE = dyn_cast<CXXParenListInitExpr>(Init)) {948    RevertToOldSizeRAII RAII(Path);949    Path.push_back({IndirectLocalPathEntry::ParenAggInit, CPE});950    for (auto *I : CPE->getInitExprs()) {951      if (I->isGLValue())952        visitLocalsRetainedByReferenceBinding(Path, I, RK_ReferenceBinding,953                                              Visit);954      else955        visitLocalsRetainedByInitializer(Path, I, Visit, true);956    }957  }958  switch (Init->getStmtClass()) {959  case Stmt::UnaryOperatorClass: {960    auto *UO = cast<UnaryOperator>(Init);961    // If the initializer is the address of a local, we could have a lifetime962    // problem.963    if (UO->getOpcode() == UO_AddrOf) {964      // If this is &rvalue, then it's ill-formed and we have already diagnosed965      // it. Don't produce a redundant warning about the lifetime of the966      // temporary.967      if (isa<MaterializeTemporaryExpr>(UO->getSubExpr()))968        return;969 970      Path.push_back({IndirectLocalPathEntry::AddressOf, UO});971      visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),972                                            RK_ReferenceBinding, Visit);973    }974    break;975  }976 977  case Stmt::BinaryOperatorClass: {978    // Handle pointer arithmetic.979    auto *BO = cast<BinaryOperator>(Init);980    BinaryOperatorKind BOK = BO->getOpcode();981    if (!BO->getType()->isPointerType() || (BOK != BO_Add && BOK != BO_Sub))982      break;983 984    if (BO->getLHS()->getType()->isPointerType())985      visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true);986    else if (BO->getRHS()->getType()->isPointerType())987      visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true);988    break;989  }990 991  case Stmt::ConditionalOperatorClass:992  case Stmt::BinaryConditionalOperatorClass: {993    auto *C = cast<AbstractConditionalOperator>(Init);994    // In C++, we can have a throw-expression operand, which has 'void' type995    // and isn't interesting from a lifetime perspective.996    if (!C->getTrueExpr()->getType()->isVoidType())997      visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true);998    if (!C->getFalseExpr()->getType()->isVoidType())999      visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true);1000    break;1001  }1002 1003  case Stmt::BlockExprClass:1004    if (cast<BlockExpr>(Init)->getBlockDecl()->hasCaptures()) {1005      // This is a local block, whose lifetime is that of the function.1006      Visit(Path, Local(cast<BlockExpr>(Init)), RK_ReferenceBinding);1007    }1008    break;1009 1010  case Stmt::AddrLabelExprClass:1011    // We want to warn if the address of a label would escape the function.1012    Visit(Path, Local(cast<AddrLabelExpr>(Init)), RK_ReferenceBinding);1013    break;1014 1015  default:1016    break;1017  }1018}1019 1020/// Whether a path to an object supports lifetime extension.1021enum PathLifetimeKind {1022  /// Lifetime-extend along this path.1023  Extend,1024  /// Do not lifetime extend along this path.1025  NoExtend1026};1027 1028/// Determine whether this is an indirect path to a temporary that we are1029/// supposed to lifetime-extend along.1030static PathLifetimeKind1031shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {1032  for (auto Elem : Path) {1033    if (Elem.Kind == IndirectLocalPathEntry::MemberExpr ||1034        Elem.Kind == IndirectLocalPathEntry::LambdaCaptureInit)1035      continue;1036    return Elem.Kind == IndirectLocalPathEntry::DefaultInit1037               ? PathLifetimeKind::Extend1038               : PathLifetimeKind::NoExtend;1039  }1040  return PathLifetimeKind::Extend;1041}1042 1043/// Find the range for the first interesting entry in the path at or after I.1044static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,1045                                      Expr *E) {1046  for (unsigned N = Path.size(); I != N; ++I) {1047    switch (Path[I].Kind) {1048    case IndirectLocalPathEntry::AddressOf:1049    case IndirectLocalPathEntry::LValToRVal:1050    case IndirectLocalPathEntry::LifetimeBoundCall:1051    case IndirectLocalPathEntry::TemporaryCopy:1052    case IndirectLocalPathEntry::GslReferenceInit:1053    case IndirectLocalPathEntry::GslPointerInit:1054    case IndirectLocalPathEntry::GslPointerAssignment:1055    case IndirectLocalPathEntry::ParenAggInit:1056    case IndirectLocalPathEntry::MemberExpr:1057      // These exist primarily to mark the path as not permitting or1058      // supporting lifetime extension.1059      break;1060 1061    case IndirectLocalPathEntry::VarInit:1062      if (cast<VarDecl>(Path[I].D)->isImplicit())1063        return SourceRange();1064      [[fallthrough]];1065    case IndirectLocalPathEntry::DefaultInit:1066      return Path[I].E->getSourceRange();1067 1068    case IndirectLocalPathEntry::LambdaCaptureInit:1069      if (!Path[I].Capture->capturesVariable())1070        continue;1071      return Path[I].E->getSourceRange();1072 1073    case IndirectLocalPathEntry::DefaultArg:1074      return cast<CXXDefaultArgExpr>(Path[I].E)->getUsedLocation();1075    }1076  }1077  return E->getSourceRange();1078}1079 1080static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {1081  for (const auto &It : llvm::reverse(Path)) {1082    switch (It.Kind) {1083    case IndirectLocalPathEntry::VarInit:1084    case IndirectLocalPathEntry::AddressOf:1085    case IndirectLocalPathEntry::LifetimeBoundCall:1086    case IndirectLocalPathEntry::MemberExpr:1087      continue;1088    case IndirectLocalPathEntry::GslPointerInit:1089    case IndirectLocalPathEntry::GslReferenceInit:1090    case IndirectLocalPathEntry::GslPointerAssignment:1091      return true;1092    default:1093      return false;1094    }1095  }1096  return false;1097}1098// Result of analyzing the Path for GSLPointer.1099enum AnalysisResult {1100  // Path does not correspond to a GSLPointer.1101  NotGSLPointer,1102 1103  // A relevant case was identified.1104  Report,1105  // Stop the entire traversal.1106  Abandon,1107  // Skip this step and continue traversing inner AST nodes.1108  Skip,1109};1110// Analyze cases where a GSLPointer is initialized or assigned from a1111// temporary owner object.1112static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path,1113                                               Local L, LifetimeKind LK) {1114  if (!pathOnlyHandlesGslPointer(Path))1115    return NotGSLPointer;1116 1117  // At this point, Path represents a series of operations involving a1118  // GSLPointer, either in the process of initialization or assignment.1119 1120  // Process  temporary base objects for MemberExpr cases, e.g. Temp().field.1121  for (const auto &E : Path) {1122    if (E.Kind == IndirectLocalPathEntry::MemberExpr) {1123      // Avoid interfering  with the local base object.1124      if (pathContainsInit(Path))1125        return Abandon;1126 1127      // We are not interested in the temporary base objects of gsl Pointers:1128      //   auto p1 = Temp().ptr; // Here p1 might not dangle.1129      // However, we want to diagnose for gsl owner fields:1130      //   auto p2 = Temp().owner; // Here p2 is dangling.1131      if (const auto *FD = llvm::dyn_cast_or_null<FieldDecl>(E.D);1132          FD && !FD->getType()->isReferenceType() &&1133          isGslOwnerType(FD->getType()) && LK != LK_MemInitializer) {1134        return Report;1135      }1136      return Abandon;1137    }1138  }1139 1140  // Note: A LifetimeBoundCall can appear interleaved in this sequence.1141  // For example:1142  //    const std::string& Ref(const std::string& a [[clang::lifetimebound]]);1143  //    string_view abc = Ref(std::string());1144  // The "Path" is [GSLPointerInit, LifetimeboundCall], where "L" is the1145  // temporary "std::string()" object. We need to check the return type of the1146  // function with the lifetimebound attribute.1147  if (Path.back().Kind == IndirectLocalPathEntry::LifetimeBoundCall) {1148    // The lifetimebound applies to the implicit object parameter of a method.1149    const FunctionDecl *FD =1150        llvm::dyn_cast_or_null<FunctionDecl>(Path.back().D);1151    // The lifetimebound applies to a function parameter.1152    if (const auto *PD = llvm::dyn_cast<ParmVarDecl>(Path.back().D))1153      FD = llvm::dyn_cast<FunctionDecl>(PD->getDeclContext());1154 1155    if (isa_and_present<CXXConstructorDecl>(FD)) {1156      // Constructor case: the parameter is annotated with lifetimebound1157      //   e.g., GSLPointer(const S& s [[clang::lifetimebound]])1158      // We still respect this case even the type S is not an owner.1159      return Report;1160    }1161    // Check the return type, e.g.1162    //   const GSLOwner& func(const Foo& foo [[clang::lifetimebound]])1163    //   GSLOwner* func(cosnt Foo& foo [[clang::lifetimebound]])1164    //   GSLPointer func(const Foo& foo [[clang::lifetimebound]])1165    if (FD && ((FD->getReturnType()->isPointerOrReferenceType() &&1166                isGslOwnerType(FD->getReturnType()->getPointeeType())) ||1167               isGslPointerType(FD->getReturnType())))1168      return Report;1169 1170    return Abandon;1171  }1172 1173  if (isa<DeclRefExpr>(L)) {1174    // We do not want to follow the references when returning a pointer1175    // originating from a local owner to avoid the following false positive:1176    //   int &p = *localUniquePtr;1177    //   someContainer.add(std::move(localUniquePtr));1178    //   return p;1179    if (!pathContainsInit(Path) && isGslOwnerType(L->getType()))1180      return Report;1181    return Abandon;1182  }1183 1184  // The GSLPointer is from a temporary object.1185  auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);1186 1187  bool IsGslPtrValueFromGslTempOwner =1188      MTE && !MTE->getExtendingDecl() && isGslOwnerType(MTE->getType());1189  // Skipping a chain of initializing gsl::Pointer annotated objects.1190  // We are looking only for the final source to find out if it was1191  // a local or temporary owner or the address of a local1192  // variable/param.1193  if (!IsGslPtrValueFromGslTempOwner)1194    return Skip;1195  return Report;1196}1197 1198static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,1199                                           const AssignedEntity &Entity) {1200  bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics().isIgnored(1201      diag::warn_dangling_lifetime_pointer_assignment, SourceLocation());1202  return (EnableGSLAssignmentWarnings &&1203          (isGslPointerType(Entity.LHS->getType()) ||1204           lifetimes::isAssignmentOperatorLifetimeBound(1205               Entity.AssignmentOperator)));1206}1207 1208static void1209checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,1210                      const InitializedEntity *ExtendingEntity, LifetimeKind LK,1211                      const AssignedEntity *AEntity,1212                      const CapturingEntity *CapEntity, Expr *Init) {1213  assert(!AEntity || LK == LK_Assignment);1214  assert(!CapEntity || LK == LK_LifetimeCapture);1215  assert(!InitEntity || (LK != LK_Assignment && LK != LK_LifetimeCapture));1216  // If this entity doesn't have an interesting lifetime, don't bother looking1217  // for temporaries within its initializer.1218  if (LK == LK_FullExpression)1219    return;1220 1221  // FIXME: consider moving the TemporaryVisitor and visitLocalsRetained*1222  // functions to a dedicated class.1223  auto TemporaryVisitor = [&](const IndirectLocalPath &Path, Local L,1224                              ReferenceKind RK) -> bool {1225    SourceRange DiagRange = nextPathEntryRange(Path, 0, L);1226    SourceLocation DiagLoc = DiagRange.getBegin();1227 1228    auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);1229 1230    bool IsGslPtrValueFromGslTempOwner = true;1231    switch (analyzePathForGSLPointer(Path, L, LK)) {1232    case Abandon:1233      return false;1234    case Skip:1235      return true;1236    case NotGSLPointer:1237      IsGslPtrValueFromGslTempOwner = false;1238      [[fallthrough]];1239    case Report:1240      break;1241    }1242 1243    switch (LK) {1244    case LK_FullExpression:1245      llvm_unreachable("already handled this");1246 1247    case LK_Extended: {1248      if (!MTE) {1249        // The initialized entity has lifetime beyond the full-expression,1250        // and the local entity does too, so don't warn.1251        //1252        // FIXME: We should consider warning if a static / thread storage1253        // duration variable retains an automatic storage duration local.1254        return false;1255      }1256 1257      switch (shouldLifetimeExtendThroughPath(Path)) {1258      case PathLifetimeKind::Extend:1259        // Update the storage duration of the materialized temporary.1260        // FIXME: Rebuild the expression instead of mutating it.1261        MTE->setExtendingDecl(ExtendingEntity->getDecl(),1262                              ExtendingEntity->allocateManglingNumber());1263        // Also visit the temporaries lifetime-extended by this initializer.1264        return true;1265 1266      case PathLifetimeKind::NoExtend:1267        if (SemaRef.getLangOpts().CPlusPlus23 && InitEntity) {1268          if (const VarDecl *VD =1269                  dyn_cast_if_present<VarDecl>(InitEntity->getDecl());1270              VD && VD->isCXXForRangeImplicitVar()) {1271            return false;1272          }1273        }1274 1275        if (IsGslPtrValueFromGslTempOwner && DiagLoc.isValid()) {1276          SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer)1277              << DiagRange;1278          return false;1279        }1280 1281        // If the path goes through the initialization of a variable or field,1282        // it can't possibly reach a temporary created in this full-expression.1283        // We will have already diagnosed any problems with the initializer.1284        if (pathContainsInit(Path))1285          return false;1286 1287        SemaRef.Diag(DiagLoc, diag::warn_dangling_variable)1288            << RK << !InitEntity->getParent()1289            << ExtendingEntity->getDecl()->isImplicit()1290            << ExtendingEntity->getDecl() << Init->isGLValue() << DiagRange;1291        break;1292      }1293      break;1294    }1295 1296    case LK_LifetimeCapture: {1297      // The captured entity has lifetime beyond the full-expression,1298      // and the capturing entity does too, so don't warn.1299      if (!MTE)1300        return false;1301      if (CapEntity->Entity)1302        SemaRef.Diag(DiagLoc, diag::warn_dangling_reference_captured)1303            << CapEntity->Entity << DiagRange;1304      else1305        SemaRef.Diag(DiagLoc, diag::warn_dangling_reference_captured_by_unknown)1306            << DiagRange;1307      return false;1308    }1309 1310    case LK_Assignment: {1311      if (!MTE || pathContainsInit(Path))1312        return false;1313      if (IsGslPtrValueFromGslTempOwner)1314        SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_assignment)1315            << AEntity->LHS << DiagRange;1316      else1317        SemaRef.Diag(DiagLoc, diag::warn_dangling_pointer_assignment)1318            << AEntity->LHS->getType()->isPointerType() << AEntity->LHS1319            << DiagRange;1320      return false;1321    }1322    case LK_MemInitializer: {1323      if (MTE) {1324        // Under C++ DR1696, if a mem-initializer (or a default member1325        // initializer used by the absence of one) would lifetime-extend a1326        // temporary, the program is ill-formed.1327        if (auto *ExtendingDecl =1328                ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {1329          if (IsGslPtrValueFromGslTempOwner) {1330            SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member)1331                << ExtendingDecl << DiagRange;1332            SemaRef.Diag(ExtendingDecl->getLocation(),1333                         diag::note_ref_or_ptr_member_declared_here)1334                << true;1335            return false;1336          }1337          bool IsSubobjectMember = ExtendingEntity != InitEntity;1338          SemaRef.Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path) !=1339                                        PathLifetimeKind::NoExtend1340                                    ? diag::err_dangling_member1341                                    : diag::warn_dangling_member)1342              << ExtendingDecl << IsSubobjectMember << RK << DiagRange;1343          // Don't bother adding a note pointing to the field if we're inside1344          // its default member initializer; our primary diagnostic points to1345          // the same place in that case.1346          if (Path.empty() ||1347              Path.back().Kind != IndirectLocalPathEntry::DefaultInit) {1348            SemaRef.Diag(ExtendingDecl->getLocation(),1349                         diag::note_lifetime_extending_member_declared_here)1350                << RK << IsSubobjectMember;1351          }1352        } else {1353          // We have a mem-initializer but no particular field within it; this1354          // is either a base class or a delegating initializer directly1355          // initializing the base-class from something that doesn't live long1356          // enough.1357          //1358          // FIXME: Warn on this.1359          return false;1360        }1361      } else {1362        // Paths via a default initializer can only occur during error recovery1363        // (there's no other way that a default initializer can refer to a1364        // local). Don't produce a bogus warning on those cases.1365        if (pathContainsInit(Path))1366          return false;1367 1368        auto *DRE = dyn_cast<DeclRefExpr>(L);1369        // Suppress false positives for code like the one below:1370        //   Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}1371        // FIXME: move this logic to analyzePathForGSLPointer.1372        if (DRE && isGslOwnerType(DRE->getType()))1373          return false;1374 1375        auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;1376        if (!VD) {1377          // A member was initialized to a local block.1378          // FIXME: Warn on this.1379          return false;1380        }1381 1382        if (auto *Member =1383                ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {1384          bool IsPointer = !Member->getType()->isReferenceType();1385          SemaRef.Diag(DiagLoc,1386                       IsPointer ? diag::warn_init_ptr_member_to_parameter_addr1387                                 : diag::warn_bind_ref_member_to_parameter)1388              << Member << VD << isa<ParmVarDecl>(VD) << DiagRange;1389          SemaRef.Diag(Member->getLocation(),1390                       diag::note_ref_or_ptr_member_declared_here)1391              << (unsigned)IsPointer;1392        }1393      }1394      break;1395    }1396 1397    case LK_New:1398      if (isa<MaterializeTemporaryExpr>(L)) {1399        if (IsGslPtrValueFromGslTempOwner)1400          SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer)1401              << DiagRange;1402        else1403          SemaRef.Diag(DiagLoc, RK == RK_ReferenceBinding1404                                    ? diag::warn_new_dangling_reference1405                                    : diag::warn_new_dangling_initializer_list)1406              << !InitEntity->getParent() << DiagRange;1407      } else {1408        // We can't determine if the allocation outlives the local declaration.1409        return false;1410      }1411      break;1412 1413    case LK_Return:1414    case LK_MustTail:1415    case LK_StmtExprResult:1416      if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {1417        // We can't determine if the local variable outlives the statement1418        // expression.1419        if (LK == LK_StmtExprResult)1420          return false;1421        SemaRef.Diag(DiagLoc, diag::warn_ret_stack_addr_ref)1422            << InitEntity->getType()->isReferenceType() << DRE->getDecl()1423            << isa<ParmVarDecl>(DRE->getDecl()) << (LK == LK_MustTail)1424            << DiagRange;1425      } else if (isa<BlockExpr>(L)) {1426        SemaRef.Diag(DiagLoc, diag::err_ret_local_block) << DiagRange;1427      } else if (isa<AddrLabelExpr>(L)) {1428        // Don't warn when returning a label from a statement expression.1429        // Leaving the scope doesn't end its lifetime.1430        if (LK == LK_StmtExprResult)1431          return false;1432        SemaRef.Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange;1433      } else if (auto *CLE = dyn_cast<CompoundLiteralExpr>(L)) {1434        SemaRef.Diag(DiagLoc, diag::warn_ret_stack_addr_ref)1435            << InitEntity->getType()->isReferenceType() << CLE->getInitializer()1436            << 2 << (LK == LK_MustTail) << DiagRange;1437      } else {1438        // P2748R5: Disallow Binding a Returned Glvalue to a Temporary.1439        // [stmt.return]/p6: In a function whose return type is a reference,1440        // other than an invented function for std::is_convertible ([meta.rel]),1441        // a return statement that binds the returned reference to a temporary1442        // expression ([class.temporary]) is ill-formed.1443        if (SemaRef.getLangOpts().CPlusPlus26 &&1444            InitEntity->getType()->isReferenceType())1445          SemaRef.Diag(DiagLoc, diag::err_ret_local_temp_ref)1446              << InitEntity->getType()->isReferenceType() << DiagRange;1447        else if (LK == LK_MustTail)1448          SemaRef.Diag(DiagLoc, diag::warn_musttail_local_temp_addr_ref)1449              << InitEntity->getType()->isReferenceType() << DiagRange;1450        else1451          SemaRef.Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)1452              << InitEntity->getType()->isReferenceType() << DiagRange;1453      }1454      break;1455    }1456 1457    for (unsigned I = 0; I != Path.size(); ++I) {1458      auto Elem = Path[I];1459 1460      switch (Elem.Kind) {1461      case IndirectLocalPathEntry::AddressOf:1462      case IndirectLocalPathEntry::LValToRVal:1463      case IndirectLocalPathEntry::ParenAggInit:1464        // These exist primarily to mark the path as not permitting or1465        // supporting lifetime extension.1466        break;1467 1468      case IndirectLocalPathEntry::LifetimeBoundCall:1469      case IndirectLocalPathEntry::TemporaryCopy:1470      case IndirectLocalPathEntry::MemberExpr:1471      case IndirectLocalPathEntry::GslPointerInit:1472      case IndirectLocalPathEntry::GslReferenceInit:1473      case IndirectLocalPathEntry::GslPointerAssignment:1474        // FIXME: Consider adding a note for these.1475        break;1476 1477      case IndirectLocalPathEntry::DefaultInit: {1478        auto *FD = cast<FieldDecl>(Elem.D);1479        SemaRef.Diag(FD->getLocation(),1480                     diag::note_init_with_default_member_initializer)1481            << FD << nextPathEntryRange(Path, I + 1, L);1482        break;1483      }1484 1485      case IndirectLocalPathEntry::VarInit: {1486        const VarDecl *VD = cast<VarDecl>(Elem.D);1487        SemaRef.Diag(VD->getLocation(), diag::note_local_var_initializer)1488            << VD->getType()->isReferenceType() << VD->isImplicit()1489            << VD->getDeclName() << nextPathEntryRange(Path, I + 1, L);1490        break;1491      }1492 1493      case IndirectLocalPathEntry::LambdaCaptureInit: {1494        if (!Elem.Capture->capturesVariable())1495          break;1496        // FIXME: We can't easily tell apart an init-capture from a nested1497        // capture of an init-capture.1498        const ValueDecl *VD = Elem.Capture->getCapturedVar();1499        SemaRef.Diag(Elem.Capture->getLocation(),1500                     diag::note_lambda_capture_initializer)1501            << VD << VD->isInitCapture() << Elem.Capture->isExplicit()1502            << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD1503            << nextPathEntryRange(Path, I + 1, L);1504        break;1505      }1506 1507      case IndirectLocalPathEntry::DefaultArg: {1508        const auto *DAE = cast<CXXDefaultArgExpr>(Elem.E);1509        const ParmVarDecl *Param = DAE->getParam();1510        SemaRef.Diag(Param->getDefaultArgRange().getBegin(),1511                     diag::note_init_with_default_argument)1512            << Param << nextPathEntryRange(Path, I + 1, L);1513        break;1514      }1515      }1516    }1517 1518    // We didn't lifetime-extend, so don't go any further; we don't need more1519    // warnings or errors on inner temporaries within this one's initializer.1520    return false;1521  };1522 1523  llvm::SmallVector<IndirectLocalPathEntry, 8> Path;1524  switch (LK) {1525  case LK_Assignment: {1526    if (shouldRunGSLAssignmentAnalysis(SemaRef, *AEntity))1527      Path.push_back({lifetimes::isAssignmentOperatorLifetimeBound(1528                          AEntity->AssignmentOperator)1529                          ? IndirectLocalPathEntry::LifetimeBoundCall1530                          : IndirectLocalPathEntry::GslPointerAssignment,1531                      Init});1532    break;1533  }1534  case LK_LifetimeCapture: {1535    if (isPointerLikeType(Init->getType()))1536      Path.push_back({IndirectLocalPathEntry::GslPointerInit, Init});1537    break;1538  }1539  default:1540    break;1541  }1542 1543  if (Init->isGLValue())1544    visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,1545                                          TemporaryVisitor);1546  else1547    visitLocalsRetainedByInitializer(1548        Path, Init, TemporaryVisitor,1549        // Don't revisit the sub inits for the intialization case.1550        /*RevisitSubinits=*/!InitEntity);1551}1552 1553void checkInitLifetime(Sema &SemaRef, const InitializedEntity &Entity,1554                       Expr *Init) {1555  auto LTResult = getEntityLifetime(&Entity);1556  LifetimeKind LK = LTResult.getInt();1557  const InitializedEntity *ExtendingEntity = LTResult.getPointer();1558  checkExprLifetimeImpl(SemaRef, &Entity, ExtendingEntity, LK,1559                        /*AEntity=*/nullptr, /*CapEntity=*/nullptr, Init);1560}1561 1562void checkExprLifetimeMustTailArg(Sema &SemaRef,1563                                  const InitializedEntity &Entity, Expr *Init) {1564  checkExprLifetimeImpl(SemaRef, &Entity, nullptr, LK_MustTail,1565                        /*AEntity=*/nullptr, /*CapEntity=*/nullptr, Init);1566}1567 1568void checkAssignmentLifetime(Sema &SemaRef, const AssignedEntity &Entity,1569                             Expr *Init) {1570  bool EnableDanglingPointerAssignment = !SemaRef.getDiagnostics().isIgnored(1571      diag::warn_dangling_pointer_assignment, SourceLocation());1572  bool RunAnalysis = (EnableDanglingPointerAssignment &&1573                      Entity.LHS->getType()->isPointerType()) ||1574                     shouldRunGSLAssignmentAnalysis(SemaRef, Entity);1575 1576  if (!RunAnalysis)1577    return;1578 1579  checkExprLifetimeImpl(SemaRef, /*InitEntity=*/nullptr,1580                        /*ExtendingEntity=*/nullptr, LK_Assignment, &Entity,1581                        /*CapEntity=*/nullptr, Init);1582}1583 1584void checkCaptureByLifetime(Sema &SemaRef, const CapturingEntity &Entity,1585                            Expr *Init) {1586  if (SemaRef.getDiagnostics().isIgnored(diag::warn_dangling_reference_captured,1587                                         SourceLocation()) &&1588      SemaRef.getDiagnostics().isIgnored(1589          diag::warn_dangling_reference_captured_by_unknown, SourceLocation()))1590    return;1591  return checkExprLifetimeImpl(SemaRef, /*InitEntity=*/nullptr,1592                               /*ExtendingEntity=*/nullptr, LK_LifetimeCapture,1593                               /*AEntity=*/nullptr,1594                               /*CapEntity=*/&Entity, Init);1595}1596 1597} // namespace clang::sema1598