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 FD = dyn_cast_or_null<FunctionDecl>(AC->getDecl());
120 if (!FD)
121 return;
122
123 Args = AC->arguments();
124}
125
126std::optional<LifetimeBoundParamInfo>
128 unsigned I) {
130 if (!FD || I >= Args.size())
131 return std::nullopt;
132
133 const ParmVarDecl *PVD = nullptr;
134
135 if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
136 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
137 if (I == 0) {
138 // For the 'this' argument, the attribute is on the method itself.
141 /*RunningUnderLifetimeSafety=*/true))
142 return LifetimeBoundParamInfo(Method);
143 return std::nullopt;
144 }
145 if ((I - 1) < Method->getNumParams())
146 // For explicit arguments, find the corresponding parameter declaration.
147 PVD = Method->getParamDecl(I - 1);
148 } else if (I == 0 && shouldTrackFirstArgument(FD)) {
149 return LifetimeBoundParamInfo(FD->getParamDecl(I));
150 } else if (I == 1 && shouldTrackSecondArgument(FD)) {
151 return LifetimeBoundParamInfo(FD->getParamDecl(I));
152 } else if (I < FD->getNumParams()) {
153 // For free functions or static methods.
154 PVD = FD->getParamDecl(I);
155 }
156
157 if (PVD && PVD->hasAttr<clang::LifetimeBoundAttr>())
158 return LifetimeBoundParamInfo(PVD);
159
160 return std::nullopt;
161}
162
163std::optional<LifetimeBoundParamInfo>
164getTrackingInfoForCallArg(const Expr *Call, const Expr *Source) {
165 if (!Call || !Source)
166 return std::nullopt;
167
168 auto [FD, Args] = FunctionCallInfo(Call);
169 if (!FD)
170 return std::nullopt;
171
172 for (unsigned I = 0; I < Args.size(); ++I)
173 if (Args[I]->IgnoreParenImpCasts() == Source->IgnoreParenImpCasts())
174 if (std::optional<LifetimeBoundParamInfo> ParamInfo =
175 getTrackedArgInfo(FD, Args, I))
176 return ParamInfo;
177
178 return std::nullopt;
179}
180
181bool isInStlNamespace(const Decl *D) {
182 for (const DeclContext *DC = D->getDeclContext(); DC; DC = DC->getParent()) {
183 if (DC->isStdNamespace())
184 return true;
185 if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
186 if (const IdentifierInfo *II = ND->getIdentifier()) {
187 StringRef Name = II->getName();
188 if (Name.size() >= 2 && Name.front() == '_' &&
189 (Name[1] == '_' || isUppercase(Name[1])))
190 return true;
191 }
192 }
193 return false;
194}
195
197 return isGslPointerType(QT) || QT->isPointerType() || QT->isNullPtrType();
198}
199
201 return QT->isReferenceType() || isPointerLikeType(QT);
202}
203
204bool shouldTrackImplicitObjectArg(const Expr &ImplicitObjectArgument,
205 const CXXMethodDecl *Callee,
206 bool RunningUnderLifetimeSafety) {
207 if (!Callee)
208 return false;
209 // Check both the declaring class and the call-site object: a gsl::Owner
210 // may inherit its accessors from a non-Owner base (e.g. libc++ optional).
211 const bool IsGslOwnerImplicitObject =
212 isGslOwnerType(Callee->getFunctionObjectParameterType()) ||
213 (RunningUnderLifetimeSafety &&
214 isGslOwnerType(ImplicitObjectArgument.getBestDynamicClassType()));
215 if (auto *Conv = dyn_cast<CXXConversionDecl>(Callee))
216 if (isGslPointerType(Conv->getConversionType()) && IsGslOwnerImplicitObject)
217 return true;
218 if (!isGslPointerType(Callee->getFunctionObjectParameterType()) &&
219 !IsGslOwnerImplicitObject)
220 return false;
221
222 // Begin and end iterators.
223 static const llvm::StringSet<> IteratorMembers = {
224 "begin", "end", "rbegin", "rend", "cbegin", "cend", "crbegin", "crend"};
225 static const llvm::StringSet<> InnerPointerGetters = {
226 // Inner pointer getters.
227 "c_str", "data", "get"};
228 static const llvm::StringSet<> ContainerFindFns = {
229 // Map and set types.
230 "find", "equal_range", "lower_bound", "upper_bound"};
231 // Track dereference operator and transparent functions like begin(), get(),
232 // etc. for all GSL pointers. Only do so for lifetime safety analysis and not
233 // for Sema's statement-local analysis as it starts to have false-positives.
234 if (RunningUnderLifetimeSafety &&
235 isGslPointerType(Callee->getFunctionObjectParameterType()) &&
236 isReferenceOrPointerLikeType(Callee->getReturnType())) {
237 // Propagate origins through GSL pointer arithmetic and dereference
238 // operators.
239 switch (Callee->getOverloadedOperator()) {
240 case OO_Arrow:
241 case OO_Star:
242 case OO_Plus:
243 case OO_Minus:
244 case OO_PlusPlus:
245 case OO_MinusMinus:
246 return true;
247 default:
248 break;
249 }
250 if (Callee->getIdentifier() &&
251 (IteratorMembers.contains(Callee->getName()) ||
252 InnerPointerGetters.contains(Callee->getName())))
253 return true;
254 }
255
256 if (!isInStlNamespace(Callee->getParent()))
257 return false;
258
259 if (isPointerLikeType(Callee->getReturnType())) {
260 if (!Callee->getIdentifier())
261 // e.g., std::optional<T>::operator->() returns T*.
262 return RunningUnderLifetimeSafety
263 ? IsGslOwnerImplicitObject &&
264 Callee->getOverloadedOperator() ==
265 OverloadedOperatorKind::OO_Arrow
266 : false;
267 return IteratorMembers.contains(Callee->getName()) ||
268 InnerPointerGetters.contains(Callee->getName()) ||
269 ContainerFindFns.contains(Callee->getName());
270 }
271 if (Callee->getReturnType()->isReferenceType()) {
272 if (!Callee->getIdentifier()) {
273 auto OO = Callee->getOverloadedOperator();
274 if (!IsGslOwnerImplicitObject)
275 return false;
276 return OO == OverloadedOperatorKind::OO_Subscript ||
277 OO == OverloadedOperatorKind::OO_Star;
278 }
279 return llvm::StringSwitch<bool>(Callee->getName())
280 .Cases({"front", "back", "at", "top", "value"}, true)
281 .Default(false);
282 }
283 return false;
284}
285
287 if (!FD->getIdentifier() || FD->getNumParams() < 1)
288 return false;
289 if (!FD->isInStdNamespace())
290 return false;
291 // Track std:: algorithm functions that return an iterator whose lifetime is
292 // bound to the first argument.
293 if (FD->getNumParams() >= 2 && FD->isInStdNamespace() &&
295 if (llvm::StringSwitch<bool>(FD->getName())
296 .Cases(
297 {
298 "find",
299 "find_if",
300 "find_if_not",
301 "find_first_of",
302 "adjacent_find",
303 "search",
304 "find_end",
305 "lower_bound",
306 "upper_bound",
307 "partition_point",
308 },
309 true)
310 .Default(false))
311 return true;
312 }
313 const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
314 if (!RD || !RD->isInStdNamespace())
315 return false;
316 if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
317 return false;
318
319 if (FD->getNumParams() != 1)
320 return false;
321
322 if (FD->getReturnType()->isPointerType() ||
324 return llvm::StringSwitch<bool>(FD->getName())
325 .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true)
326 .Cases({"end", "rend", "cend", "crend"}, true)
327 .Case("data", true)
328 .Default(false);
329 }
330 if (FD->getReturnType()->isReferenceType()) {
331 return llvm::StringSwitch<bool>(FD->getName())
332 .Cases({"get", "any_cast"}, true)
333 .Default(false);
334 }
335 return false;
336}
337
339 if (FD->getNumParams() < 2)
340 return false;
341 const auto *RD = FD->getParamDecl(1)->getType()->getAsCXXRecordDecl();
342 if (!RD)
343 return false;
344 // For free-standing `+`/`-` operators annotated with `gsl::Pointer`, track
345 // the second parameter when its type matches the return type.
346 return RD->hasAttr<PointerAttr>() &&
347 (FD->getOverloadedOperator() == OO_Plus ||
348 FD->getOverloadedOperator() == OO_Minus) &&
350 FD->getReturnType()) &&
352}
353
354template <typename T> static bool isRecordWithAttr(const CXXRecordDecl *RD) {
355 if (!RD)
356 return false;
357 // Generally, if a primary template class declaration is annotated with an
358 // attribute, all its specializations generated from template instantiations
359 // should inherit the attribute.
360 //
361 // However, since lifetime analysis occurs during parsing, we may encounter
362 // cases where a full definition of the specialization is not required. In
363 // such cases, the specialization declaration remains incomplete and lacks the
364 // attribute. Therefore, we fall back to checking the primary template class.
365 //
366 // Note: it is possible for a specialization declaration to have an attribute
367 // even if the primary template does not.
368 //
369 // FIXME: What if the primary template and explicit specialization
370 // declarations have conflicting attributes? We should consider diagnosing
371 // this scenario.
372 bool Result = RD->hasAttr<T>();
373
374 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
375 Result |= CTSD->getSpecializedTemplate()->getTemplatedDecl()->hasAttr<T>();
376
377 return Result;
378}
379
380template <typename T> static bool isRecordWithAttr(QualType Type) {
382}
383
388}
389
390static StringRef getName(const CXXRecordDecl &RD) {
391 if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(&RD))
392 return CTSD->getSpecializedTemplate()->getName();
393 if (RD.getIdentifier())
394 return RD.getName();
395 return "";
396}
397
398static StringRef getName(const FunctionDecl &FD) {
399 if (FD.getIdentifier())
400 return FD.getName();
401 return "";
402}
403
404static bool isStdUniquePtr(const CXXRecordDecl &RD) {
405 return RD.isInStdNamespace() && getName(RD) == "unique_ptr";
406}
407
409 return MD.getIdentifier() && MD.getName() == "release" &&
410 MD.getNumParams() == 0 && isStdUniquePtr(*MD.getParent());
411}
412
414 const CXXRecordDecl *RD = MD.getParent();
415 if (!isInStlNamespace(RD))
416 return false;
417
418 // `pop_back` is excluded: it only invalidates references to the removed
419 // element, not to other elements.
420 static const llvm::StringSet<> Vector = {// Insertion
421 "insert", "emplace", "emplace_back",
422 "push_back", "insert_range",
423 "append_range",
424 // Removal
425 "erase", "clear",
426 // Memory management
427 "reserve", "resize", "shrink_to_fit",
428 // Assignment
429 "assign", "assign_range"};
430
431 // `pop_*` methods are excluded: they only invalidate references to the
432 // removed element, not to other elements.
433 static const llvm::StringSet<> Deque = {// Insertion
434 "insert", "emplace", "insert_range",
435 // Removal
436 "erase", "clear",
437 // Memory management
438 "resize", "shrink_to_fit",
439 // Assignment
440 "assign", "assign_range"};
441
442 static const llvm::StringSet<> String = {
443 // Insertion
444 "insert", "push_back", "append", "replace", "replace_with_range",
445 "insert_range", "append_range",
446 // Removal
447 "pop_back", "erase", "clear",
448 // Memory management
449 "reserve", "resize", "resize_and_overwrite", "shrink_to_fit",
450 // Assignment
451 "swap", "assign", "assign_range"};
452
453 // FIXME: Add queue and stack and check for underlying container
454 // (e.g. no invalidation for std::list).
455 static const llvm::StringSet<> PriorityQueue = {// Insertion
456 "push", "emplace",
457 "push_range",
458 // Removal
459 "pop"};
460
461 // `erase` and `extract` are excluded: they only affect the removed element,
462 // not to other elements.
463 static const llvm::StringSet<> NodeBased = {// Removal
464 "clear"};
465
466 // For `flat_*` container adaptors, `try_emplace` and `insert_or_assign`
467 // only exist on `flat_map`. Listing them here is harmless since the methods
468 // won't be found on other types.
469 static const llvm::StringSet<> Flat = {// Insertion
470 "insert", "emplace", "emplace_hint",
471 "try_emplace", "insert_or_assign",
472 "insert_range", "merge",
473 // Removal
474 "extract", "erase", "clear",
475 // Assignment
476 "replace"};
477
478 static const llvm::StringSet<> UniquePtr = {// Reallocation
479 "reset"};
480
481 const StringRef RecordName = getName(*RD);
482 // TODO: Consider caching this lookup by CXXMethodDecl pointer if this
483 // StringSwitch becomes a performance bottleneck.
484 const llvm::StringSet<> *InvalidatingMethods =
485 llvm::StringSwitch<const llvm::StringSet<> *>(RecordName)
486 .Case("vector", &Vector)
487 .Case("basic_string", &String)
488 .Case("deque", &Deque)
489 .Case("priority_queue", &PriorityQueue)
490 .Cases({"set", "multiset", "map", "multimap", "unordered_set",
491 "unordered_multiset", "unordered_map", "unordered_multimap"},
492 &NodeBased)
493 .Cases({"flat_map", "flat_set", "flat_multimap", "flat_multiset"},
494 &Flat)
495 .Case("unique_ptr", &UniquePtr)
496 .Default(nullptr);
497
498 if (!InvalidatingMethods)
499 return false;
500
501 // Handle Operators via OverloadedOperatorKind
503 if (OO != OO_None) {
504 switch (OO) {
505 case OO_Equal: // operator= : Always invalidates (Assignment)
506 case OO_PlusEqual: // operator+= : Append (String/Vector)
507 return true;
508 case OO_Subscript: // operator[] : Invalidation only for
509 // `flat_map` (Insert-or-access).
510 // `map` and `unordered_map` are excluded.
511 return RecordName == "flat_map";
512 default:
513 return false;
514 }
515 }
516
517 if (!MD.getIdentifier())
518 return false;
519
520 return InvalidatingMethods->contains(MD.getName());
521}
522
525 return true;
526 return isInStlNamespace(&FD) && getName(FD) == "destroy_at";
527}
528
530 if (!RD || !isInStlNamespace(RD))
531 return false;
532 StringRef Name = getName(*RD);
533 return Name == "function" || Name == "move_only_function";
534}
535
537 if (!FD)
538 return false;
539 switch (FD->getBuiltinID()) {
540 case Builtin::BImove:
541 case Builtin::BImove_if_noexcept:
542 case Builtin::BIforward:
543 case Builtin::BIforward_like:
544 case Builtin::BIas_const:
545 return true;
546 default:
547 return false;
548 }
549}
550
551} // 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 static or instance method of a struct/union/class.
Definition DeclCXX.h:2149
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2292
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:3806
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:4305
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:4171
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3870
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:8389
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:8655
bool isReferenceType() const
Definition TypeBase.h:8679
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:1984
bool isLValueReferenceType() const
Definition TypeBase.h:8683
bool isNullPtrType() const
Definition TypeBase.h:9064
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 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