clang 24.0.0git
LifetimeAnnotations.cpp
Go to the documentation of this file.
1//===- LifetimeAnnotations.cpp - -*--------------- C++------------------*-===//
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//===----------------------------------------------------------------------===//
10#include "clang/AST/Attr.h"
11#include "clang/AST/Decl.h"
12#include "clang/AST/DeclCXX.h"
14#include "clang/AST/Expr.h"
15#include "clang/AST/ExprCXX.h"
16#include "clang/AST/Type.h"
17#include "clang/AST/TypeLoc.h"
20#include "llvm/ADT/StringSet.h"
21
22namespace clang::lifetimes {
23
24const FunctionDecl *
26 return FD != nullptr ? FD->getMostRecentDecl() : nullptr;
27}
28
29const CXXMethodDecl *
31 const FunctionDecl *FD = CMD;
32 return cast_if_present<CXXMethodDecl>(
34}
35
38 bool IsAssignment = OO == OO_Equal || isCompoundAssignmentOperator(OO);
39 if (!IsAssignment)
40 return false;
41 QualType RetT = FD->getReturnType();
42 if (!RetT->isLValueReferenceType())
43 return false;
44 ASTContext &Ctx = FD->getASTContext();
45 QualType LHST;
46 auto *MD = dyn_cast<CXXMethodDecl>(FD);
47 if (MD && MD->isCXXInstanceMember())
48 LHST = Ctx.getLValueReferenceType(MD->getFunctionObjectParameterType());
49 else
50 LHST = FD->getParamDecl(0)->getType();
51 return Ctx.hasSameType(RetT, LHST);
52}
53
56 return CMD && isNormalAssignmentOperator(CMD) && CMD->param_size() == 1 &&
57 CMD->getParamDecl(0)->hasAttr<clang::LifetimeBoundAttr>();
58}
59
60/// Check if a function has a lifetimebound attribute on its function type
61/// (which represents the implicit 'this' parameter for methods).
62/// Returns the attribute if found, nullptr otherwise.
63static const LifetimeBoundAttr *
65 // Walk through the type layers looking for a lifetimebound attribute.
66 TypeLoc TL = TSI.getTypeLoc();
67 while (true) {
68 auto ATL = TL.getAsAdjusted<AttributedTypeLoc>();
69 if (!ATL)
70 break;
71 if (auto *LBAttr = ATL.getAttrAs<LifetimeBoundAttr>())
72 return LBAttr;
73 TL = ATL.getModifiedLoc();
74 }
75 return nullptr;
76}
77
78const LifetimeBoundAttr *
80 if (const TypeSourceInfo *TSI = FD->getTypeSourceInfo())
81 if (const auto *Attr = getLifetimeBoundAttrFromFunctionType(*TSI))
82 return Attr;
83 return nullptr;
84}
85
86const LifetimeBoundAttr *
89 // Attribute merging doesn't work well with attributes on function types (like
90 // 'this' param). We need to check all redeclarations.
91 auto CheckRedecls = [](const FunctionDecl *F) -> const LifetimeBoundAttr * {
92 for (const FunctionDecl *Redecl : F->redecls())
93 if (const auto *Attr = getDirectImplicitObjectLifetimeBoundAttr(Redecl))
94 return Attr;
95 return nullptr;
96 };
97
98 if (const auto *Attr = CheckRedecls(FD))
99 return Attr;
100 if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
101 return CheckRedecls(Pattern);
102 return nullptr;
103}
104
110
112 if (!Call)
113 return;
114
115 std::optional<AnyCall> AC = AnyCall::forExpr(Call->IgnoreParenImpCasts());
116 if (!AC)
117 return;
118
119 Args = AC->arguments();
120 FD = dyn_cast_or_null<FunctionDecl>(AC->getDecl());
121}
122
123std::optional<LifetimeBoundParamInfo>
125 unsigned I) {
127 if (!FD || I >= Args.size())
128 return std::nullopt;
129
130 const ParmVarDecl *PVD = nullptr;
131
132 if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
133 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
134 if (I == 0) {
135 // For the 'this' argument, the attribute is on the method itself.
138 /*RunningUnderLifetimeSafety=*/true))
139 return LifetimeBoundParamInfo(Method);
140 return std::nullopt;
141 }
142 if ((I - 1) < Method->getNumParams())
143 // For explicit arguments, find the corresponding parameter declaration.
144 PVD = Method->getParamDecl(I - 1);
145 } else if (I == 0 && shouldTrackFirstArgument(FD)) {
146 return LifetimeBoundParamInfo(FD->getParamDecl(I));
147 } else if (I == 1 && shouldTrackSecondArgument(FD)) {
148 return LifetimeBoundParamInfo(FD->getParamDecl(I));
149 } else if (I < FD->getNumParams()) {
150 // For free functions or static methods.
151 PVD = FD->getParamDecl(I);
152 }
153
154 if (PVD && PVD->hasAttr<clang::LifetimeBoundAttr>())
155 return LifetimeBoundParamInfo(PVD);
156
157 return std::nullopt;
158}
159
160std::optional<LifetimeBoundParamInfo>
161getTrackingInfoForCallArg(const Expr *Call, const Expr *Source) {
162 if (!Call || !Source)
163 return std::nullopt;
164
165 auto [FD, Args] = FunctionCallInfo(Call);
166 if (!FD)
167 return std::nullopt;
168
169 for (unsigned I = 0; I < Args.size(); ++I)
170 if (Args[I]->IgnoreParenImpCasts() == Source->IgnoreParenImpCasts())
171 if (std::optional<LifetimeBoundParamInfo> ParamInfo =
172 getTrackedArgInfo(FD, Args, I))
173 return ParamInfo;
174
175 return std::nullopt;
176}
177
178bool isInStlNamespace(const Decl *D) {
179 for (const DeclContext *DC = D->getDeclContext(); DC; DC = DC->getParent()) {
180 if (DC->isStdNamespace())
181 return true;
182 if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
183 if (const IdentifierInfo *II = ND->getIdentifier()) {
184 StringRef Name = II->getName();
185 if (Name.size() >= 2 && Name.front() == '_' &&
186 (Name[1] == '_' || isUppercase(Name[1])))
187 return true;
188 }
189 }
190 return false;
191}
192
194 return isGslPointerType(QT) || QT->isPointerType() || QT->isNullPtrType();
195}
196
198 return QT->isReferenceType() || isPointerLikeType(QT);
199}
200
201bool shouldTrackImplicitObjectArg(const Expr &ImplicitObjectArgument,
202 const CXXMethodDecl *Callee,
203 bool RunningUnderLifetimeSafety) {
204 if (!Callee)
205 return false;
206 // Check both the declaring class and the call-site object: a gsl::Owner
207 // may inherit its accessors from a non-Owner base (e.g. libc++ optional).
208 const bool IsGslOwnerImplicitObject =
209 isGslOwnerType(Callee->getFunctionObjectParameterType()) ||
210 (RunningUnderLifetimeSafety &&
211 isGslOwnerType(ImplicitObjectArgument.getBestDynamicClassType()));
212 if (auto *Conv = dyn_cast<CXXConversionDecl>(Callee))
213 if (isGslPointerType(Conv->getConversionType()) && IsGslOwnerImplicitObject)
214 return true;
215 if (!isGslPointerType(Callee->getFunctionObjectParameterType()) &&
216 !IsGslOwnerImplicitObject)
217 return false;
218
219 // Begin and end iterators.
220 static const llvm::StringSet<> IteratorMembers = {
221 "begin", "end", "rbegin", "rend", "cbegin", "cend", "crbegin", "crend"};
222 static const llvm::StringSet<> InnerPointerGetters = {
223 // Inner pointer getters.
224 "c_str", "data", "get"};
225 static const llvm::StringSet<> ContainerFindFns = {
226 // Map and set types.
227 "find", "equal_range", "lower_bound", "upper_bound"};
228 // Track dereference operator and transparent functions like begin(), get(),
229 // etc. for all GSL pointers. Only do so for lifetime safety analysis and not
230 // for Sema's statement-local analysis as it starts to have false-positives.
231 if (RunningUnderLifetimeSafety &&
232 isGslPointerType(Callee->getFunctionObjectParameterType()) &&
233 isReferenceOrPointerLikeType(Callee->getReturnType())) {
234 // Propagate origins through GSL pointer arithmetic and dereference
235 // operators.
236 switch (Callee->getOverloadedOperator()) {
237 case OO_Arrow:
238 case OO_Star:
239 case OO_Plus:
240 case OO_Minus:
241 case OO_PlusPlus:
242 case OO_MinusMinus:
243 return true;
244 default:
245 break;
246 }
247 if (Callee->getIdentifier() &&
248 (IteratorMembers.contains(Callee->getName()) ||
249 InnerPointerGetters.contains(Callee->getName())))
250 return true;
251 }
252
253 if (!isInStlNamespace(Callee->getParent()))
254 return false;
255
256 if (isPointerLikeType(Callee->getReturnType())) {
257 if (!Callee->getIdentifier())
258 // e.g., std::optional<T>::operator->() returns T*.
259 return RunningUnderLifetimeSafety
260 ? IsGslOwnerImplicitObject &&
261 Callee->getOverloadedOperator() ==
262 OverloadedOperatorKind::OO_Arrow
263 : false;
264 return IteratorMembers.contains(Callee->getName()) ||
265 InnerPointerGetters.contains(Callee->getName()) ||
266 ContainerFindFns.contains(Callee->getName());
267 }
268 if (Callee->getReturnType()->isReferenceType()) {
269 if (!Callee->getIdentifier()) {
270 auto OO = Callee->getOverloadedOperator();
271 if (!IsGslOwnerImplicitObject)
272 return false;
273 return OO == OverloadedOperatorKind::OO_Subscript ||
274 OO == OverloadedOperatorKind::OO_Star;
275 }
276 return llvm::StringSwitch<bool>(Callee->getName())
277 .Cases({"front", "back", "at", "top", "value"}, true)
278 .Default(false);
279 }
280 return false;
281}
282
284 if (!FD->getIdentifier() || FD->getNumParams() < 1)
285 return false;
286 if (!FD->isInStdNamespace())
287 return false;
288 // Track std:: algorithm functions that return an iterator whose lifetime is
289 // bound to the first argument.
290 if (FD->getNumParams() >= 2 && FD->isInStdNamespace() &&
292 if (llvm::StringSwitch<bool>(FD->getName())
293 .Cases(
294 {
295 "find",
296 "find_if",
297 "find_if_not",
298 "find_first_of",
299 "adjacent_find",
300 "search",
301 "find_end",
302 "lower_bound",
303 "upper_bound",
304 "partition_point",
305 },
306 true)
307 .Default(false))
308 return true;
309 }
310 const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
311 if (!RD || !RD->isInStdNamespace())
312 return false;
313 if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
314 return false;
315
316 if (FD->getNumParams() != 1)
317 return false;
318
319 if (FD->getReturnType()->isPointerType() ||
321 return llvm::StringSwitch<bool>(FD->getName())
322 .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true)
323 .Cases({"end", "rend", "cend", "crend"}, true)
324 .Case("data", true)
325 .Default(false);
326 }
327 if (FD->getReturnType()->isReferenceType()) {
328 return llvm::StringSwitch<bool>(FD->getName())
329 .Cases({"get", "any_cast"}, true)
330 .Default(false);
331 }
332 return false;
333}
334
336 if (FD->getNumParams() < 2)
337 return false;
338 const auto *RD = FD->getParamDecl(1)->getType()->getAsCXXRecordDecl();
339 if (!RD)
340 return false;
341 // For free-standing `+`/`-` operators annotated with `gsl::Pointer`, track
342 // the second parameter when its type matches the return type.
343 return RD->hasAttr<PointerAttr>() &&
344 (FD->getOverloadedOperator() == OO_Plus ||
345 FD->getOverloadedOperator() == OO_Minus) &&
347 FD->getReturnType()) &&
349}
350
351template <typename T> static bool isRecordWithAttr(const CXXRecordDecl *RD) {
352 if (!RD)
353 return false;
354 // Generally, if a primary template class declaration is annotated with an
355 // attribute, all its specializations generated from template instantiations
356 // should inherit the attribute.
357 //
358 // However, since lifetime analysis occurs during parsing, we may encounter
359 // cases where a full definition of the specialization is not required. In
360 // such cases, the specialization declaration remains incomplete and lacks the
361 // attribute. Therefore, we fall back to checking the primary template class.
362 //
363 // Note: it is possible for a specialization declaration to have an attribute
364 // even if the primary template does not.
365 //
366 // FIXME: What if the primary template and explicit specialization
367 // declarations have conflicting attributes? We should consider diagnosing
368 // this scenario.
369 bool Result = RD->hasAttr<T>();
370
371 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
372 Result |= CTSD->getSpecializedTemplate()->getTemplatedDecl()->hasAttr<T>();
373
374 return Result;
375}
376
377template <typename T> static bool isRecordWithAttr(QualType Type) {
379}
380
385}
386
387bool isOwnerPtrCtor(const CXXConstructorDecl *Ctor, const ParmVarDecl *PVD) {
388 return Ctor && PVD->getType()->isPointerType() &&
389 isGslOwnerType(Ctor->getParent());
390}
391
392static StringRef getName(const CXXRecordDecl &RD) {
393 if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(&RD))
394 return CTSD->getSpecializedTemplate()->getName();
395 if (RD.getIdentifier())
396 return RD.getName();
397 return "";
398}
399
400static StringRef getName(const FunctionDecl &FD) {
401 if (FD.getIdentifier())
402 return FD.getName();
403 return "";
404}
405
406static bool isStdUniquePtr(const CXXRecordDecl &RD) {
407 return RD.isInStdNamespace() && getName(RD) == "unique_ptr";
408}
409
411 return MD.getIdentifier() && MD.getName() == "release" &&
412 MD.getNumParams() == 0 && isStdUniquePtr(*MD.getParent());
413}
414
416 const CXXRecordDecl *RD = MD.getParent();
417 if (!isInStlNamespace(RD))
418 return false;
419
420 // `pop_back` is excluded: it only invalidates references to the removed
421 // element, not to other elements.
422 static const llvm::StringSet<> Vector = {// Insertion
423 "insert", "emplace", "emplace_back",
424 "push_back", "insert_range",
425 "append_range",
426 // Removal
427 "erase", "clear",
428 // Memory management
429 "reserve", "resize", "shrink_to_fit",
430 // Assignment
431 "assign", "assign_range"};
432
433 // `pop_*` methods are excluded: they only invalidate references to the
434 // removed element, not to other elements.
435 static const llvm::StringSet<> Deque = {// Insertion
436 "insert", "emplace", "insert_range",
437 // Removal
438 "erase", "clear",
439 // Memory management
440 "resize", "shrink_to_fit",
441 // Assignment
442 "assign", "assign_range"};
443
444 static const llvm::StringSet<> String = {
445 // Insertion
446 "insert", "push_back", "append", "replace", "replace_with_range",
447 "insert_range", "append_range",
448 // Removal
449 "pop_back", "erase", "clear",
450 // Memory management
451 "reserve", "resize", "resize_and_overwrite", "shrink_to_fit",
452 // Assignment
453 "swap", "assign", "assign_range"};
454
455 // FIXME: Add queue and stack and check for underlying container
456 // (e.g. no invalidation for std::list).
457 static const llvm::StringSet<> PriorityQueue = {// Insertion
458 "push", "emplace",
459 "push_range",
460 // Removal
461 "pop"};
462
463 // `erase` and `extract` are excluded: they only affect the removed element,
464 // not to other elements.
465 static const llvm::StringSet<> NodeBased = {// Removal
466 "clear"};
467
468 // For `flat_*` container adaptors, `try_emplace` and `insert_or_assign`
469 // only exist on `flat_map`. Listing them here is harmless since the methods
470 // won't be found on other types.
471 static const llvm::StringSet<> Flat = {// Insertion
472 "insert", "emplace", "emplace_hint",
473 "try_emplace", "insert_or_assign",
474 "insert_range", "merge",
475 // Removal
476 "extract", "erase", "clear",
477 // Assignment
478 "replace"};
479
480 static const llvm::StringSet<> UniquePtr = {// Reallocation
481 "reset"};
482
483 const StringRef RecordName = getName(*RD);
484 // TODO: Consider caching this lookup by CXXMethodDecl pointer if this
485 // StringSwitch becomes a performance bottleneck.
486 const llvm::StringSet<> *InvalidatingMethods =
487 llvm::StringSwitch<const llvm::StringSet<> *>(RecordName)
488 .Case("vector", &Vector)
489 .Case("basic_string", &String)
490 .Case("deque", &Deque)
491 .Case("priority_queue", &PriorityQueue)
492 .Cases({"set", "multiset", "map", "multimap", "unordered_set",
493 "unordered_multiset", "unordered_map", "unordered_multimap"},
494 &NodeBased)
495 .Cases({"flat_map", "flat_set", "flat_multimap", "flat_multiset"},
496 &Flat)
497 .Case("unique_ptr", &UniquePtr)
498 .Default(nullptr);
499
500 if (!InvalidatingMethods)
501 return false;
502
503 // Handle Operators via OverloadedOperatorKind
505 if (OO != OO_None) {
506 switch (OO) {
507 case OO_Equal: // operator= : Always invalidates (Assignment)
508 case OO_PlusEqual: // operator+= : Append (String/Vector)
509 return true;
510 case OO_Subscript: // operator[] : Invalidation only for
511 // `flat_map` (Insert-or-access).
512 // `map` and `unordered_map` are excluded.
513 return RecordName == "flat_map";
514 default:
515 return false;
516 }
517 }
518
519 if (!MD.getIdentifier())
520 return false;
521
522 return InvalidatingMethods->contains(MD.getName());
523}
524
527 return true;
528 return isInStlNamespace(&FD) && getName(FD) == "destroy_at";
529}
530
532 if (!RD || !isInStlNamespace(RD))
533 return false;
534 StringRef Name = getName(*RD);
535 return Name == "function" || Name == "move_only_function";
536}
537
539 if (!FD)
540 return false;
541 switch (FD->getBuiltinID()) {
542 case Builtin::BImove:
543 case Builtin::BImove_if_noexcept:
544 case Builtin::BIforward:
545 case Builtin::BIforward_like:
546 case Builtin::BIas_const:
547 return true;
548 default:
549 return false;
550 }
551}
552
553} // namespace clang::lifetimes
Defines the clang::ASTContext interface.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines an enumeration for C++ overloaded operators.
Defines the clang::TypeLoc interface and its subclasses.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
static bool hasSameUnqualifiedType(QualType T1, QualType T2)
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
static std::optional< AnyCall > forExpr(const Expr *E)
If E is a generic call (to ObjC method /function/block/etc), return a constructed AnyCall object.
Definition AnyCall.h:114
Attr - This represents one attribute.
Definition Attr.h:46
Type source information for an attributed type.
Definition TypeLoc.h:1008
Represents a C++ constructor within a class.
Definition DeclCXX.h:2642
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2150
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2293
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1466
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2126
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isInStdNamespace() const
Definition DeclBase.cpp:453
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
DeclContext * getDeclContext()
Definition DeclBase.h:456
bool hasAttr() const
Definition DeclBase.h:585
OverloadedOperatorKind getCXXOverloadedOperator() const
If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...
TypeSourceInfo * getTypeSourceInfo() const
Definition Decl.h:810
This represents one expression.
Definition Expr.h:113
const CXXRecordDecl * getBestDynamicClassType() const
For an expression of class type or pointer to class type, return the most derived class decl the expr...
Definition Expr.cpp:70
Represents a function declaration or definition.
Definition Decl.h:2059
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2928
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
Definition Decl.cpp:3804
QualType getReturnType() const
Definition Decl.h:2976
FunctionDecl * getTemplateInstantiationPattern(bool ForDefinition=true) const
Retrieve the function declaration from which this function could be instantiated, if it is an instant...
Definition Decl.cpp:4303
FunctionDecl * getMostRecentDecl()
Returns the most recent (re)declaration of this declaration.
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Definition Decl.cpp:4169
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3868
size_t param_size() const
Definition Decl.h:2921
One of these records is kept for each identifier that is lexed.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:296
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:302
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:341
Represents a parameter to a function.
Definition Decl.h:1820
A (possibly-)qualified type.
Definition TypeBase.h:938
Base wrapper for a particular "section" of type source info.
Definition TypeLoc.h:59
T getAsAdjusted() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
Definition TypeLoc.h:2766
A container of type source information.
Definition TypeBase.h:8417
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition TypeLoc.h:267
The base class of the type hierarchy.
Definition TypeBase.h:1879
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isPointerType() const
Definition TypeBase.h:8683
bool isReferenceType() const
Definition TypeBase.h:8707
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:2078
bool isLValueReferenceType() const
Definition TypeBase.h:8711
bool isNullPtrType() const
Definition TypeBase.h:9109
QualType getType() const
Definition Decl.h:724
const LifetimeBoundAttr * getDirectImplicitObjectLifetimeBoundAttr(const FunctionDecl *FD)
bool isGslPointerType(QualType QT)
bool isStdCallableWrapperType(const CXXRecordDecl *RD)
bool shouldTrackFirstArgument(const FunctionDecl *FD)
static StringRef getName(const CXXRecordDecl &RD)
bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD)
bool shouldTrackImplicitObjectArg(const Expr &ImplicitObjectArgument, const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
static const LifetimeBoundAttr * getLifetimeBoundAttrFromFunctionType(const TypeSourceInfo &TSI)
Check if a function has a lifetimebound attribute on its function type (which represents the implicit...
bool isPointerLikeType(QualType QT)
bool isOwnerPtrCtor(const CXXConstructorDecl *Ctor, const ParmVarDecl *PVD)
bool isNormalAssignmentOperator(const FunctionDecl *FD)
bool isUniquePtrRelease(const CXXMethodDecl &MD)
static bool isRecordWithAttr(const CXXRecordDecl *RD)
static bool isReferenceOrPointerLikeType(QualType QT)
bool isStdReferenceCast(const FunctionDecl *FD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const LifetimeBoundAttr * getImplicitObjectParamLifetimeBoundAttr(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isInvalidationMethod(const CXXMethodDecl &MD)
std::optional< LifetimeBoundParamInfo > getTrackingInfoForCallArg(const Expr *Call, const Expr *Source)
bool destructsFirstArg(const FunctionDecl &FD)
bool isGslOwnerType(QualType QT)
std::optional< LifetimeBoundParamInfo > getTrackedArgInfo(const FunctionDecl *FD, llvm::ArrayRef< const Expr * > Args, unsigned I)
bool isInStlNamespace(const Decl *D)
bool shouldTrackSecondArgument(const FunctionDecl *FD)
static bool isStdUniquePtr(const CXXRecordDecl &RD)
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ OO_None
Not an overloaded operator.
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool isCompoundAssignmentOperator(OverloadedOperatorKind Kind)
Determine if this is a compound assignment operator.
LLVM_READONLY bool isUppercase(unsigned char c)
Return true if this character is an uppercase ASCII letter: [A-Z].
Definition CharInfo.h:126
@ Vector
'vector' clause, allowed on 'loop', Combined, and 'routine' directives.
@ Default
Set to the current date and time.
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
llvm::SmallVector< const Expr *, 4 > Args