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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/Sema/CheckExprLifetime.cpp