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