clang 22.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/Type.h"
15#include "clang/AST/TypeLoc.h"
16
17namespace clang::lifetimes {
18
19const FunctionDecl *
21 return FD != nullptr ? FD->getMostRecentDecl() : nullptr;
22}
23
24const CXXMethodDecl *
26 const FunctionDecl *FD = CMD;
27 return cast_if_present<CXXMethodDecl>(
29}
30
33 bool IsAssignment = OO == OO_Equal || isCompoundAssignmentOperator(OO);
34 if (!IsAssignment)
35 return false;
36 QualType RetT = FD->getReturnType();
37 if (!RetT->isLValueReferenceType())
38 return false;
39 ASTContext &Ctx = FD->getASTContext();
40 QualType LHST;
41 auto *MD = dyn_cast<CXXMethodDecl>(FD);
42 if (MD && MD->isCXXInstanceMember())
43 LHST = Ctx.getLValueReferenceType(MD->getFunctionObjectParameterType());
44 else
45 LHST = FD->getParamDecl(0)->getType();
46 return Ctx.hasSameType(RetT, LHST);
47}
48
51 return CMD && isNormalAssignmentOperator(CMD) && CMD->param_size() == 1 &&
52 CMD->getParamDecl(0)->hasAttr<clang::LifetimeBoundAttr>();
53}
54
57 const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
58 if (!TSI)
59 return false;
60 // Don't declare this variable in the second operand of the for-statement;
61 // GCC miscompiles that by ending its lifetime before evaluating the
62 // third operand. See gcc.gnu.org/PR86769.
64 for (TypeLoc TL = TSI->getTypeLoc();
65 (ATL = TL.getAsAdjusted<AttributedTypeLoc>());
66 TL = ATL.getModifiedLoc()) {
67 if (ATL.getAttrAs<clang::LifetimeBoundAttr>())
68 return true;
69 }
70
72}
73
74bool isInStlNamespace(const Decl *D) {
75 const DeclContext *DC = D->getDeclContext();
76 if (!DC)
77 return false;
78 if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
79 if (const IdentifierInfo *II = ND->getIdentifier()) {
80 StringRef Name = II->getName();
81 if (Name.size() >= 2 && Name.front() == '_' &&
82 (Name[1] == '_' || isUppercase(Name[1])))
83 return true;
84 }
85 return DC->isStdNamespace();
86}
87
89 return isGslPointerType(QT) || QT->isPointerType() || QT->isNullPtrType();
90}
91
93 if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
94 if (isGslPointerType(Conv->getConversionType()) &&
95 Callee->getParent()->hasAttr<OwnerAttr>())
96 return true;
97 if (!isInStlNamespace(Callee->getParent()))
98 return false;
99 if (!isGslPointerType(Callee->getFunctionObjectParameterType()) &&
100 !isGslOwnerType(Callee->getFunctionObjectParameterType()))
101 return false;
102 if (isPointerLikeType(Callee->getReturnType())) {
103 if (!Callee->getIdentifier())
104 return false;
105 return llvm::StringSwitch<bool>(Callee->getName())
106 .Cases(
107 {// Begin and end iterators.
108 "begin", "end", "rbegin", "rend", "cbegin", "cend", "crbegin",
109 "crend",
110 // Inner pointer getters.
111 "c_str", "data", "get",
112 // Map and set types.
113 "find", "equal_range", "lower_bound", "upper_bound"},
114 true)
115 .Default(false);
116 }
117 if (Callee->getReturnType()->isReferenceType()) {
118 if (!Callee->getIdentifier()) {
119 auto OO = Callee->getOverloadedOperator();
120 if (!Callee->getParent()->hasAttr<OwnerAttr>())
121 return false;
122 return OO == OverloadedOperatorKind::OO_Subscript ||
123 OO == OverloadedOperatorKind::OO_Star;
124 }
125 return llvm::StringSwitch<bool>(Callee->getName())
126 .Cases({"front", "back", "at", "top", "value"}, true)
127 .Default(false);
128 }
129 return false;
130}
131
133 if (!FD->getIdentifier() || FD->getNumParams() != 1)
134 return false;
135 const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
136 if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
137 return false;
138 if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
139 return false;
140 if (FD->getReturnType()->isPointerType() ||
142 return llvm::StringSwitch<bool>(FD->getName())
143 .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true)
144 .Cases({"end", "rend", "cend", "crend"}, true)
145 .Case("data", true)
146 .Default(false);
147 }
148 if (FD->getReturnType()->isReferenceType()) {
149 return llvm::StringSwitch<bool>(FD->getName())
150 .Cases({"get", "any_cast"}, true)
151 .Default(false);
152 }
153 return false;
154}
155
156template <typename T> static bool isRecordWithAttr(QualType Type) {
157 auto *RD = Type->getAsCXXRecordDecl();
158 if (!RD)
159 return false;
160 // Generally, if a primary template class declaration is annotated with an
161 // attribute, all its specializations generated from template instantiations
162 // should inherit the attribute.
163 //
164 // However, since lifetime analysis occurs during parsing, we may encounter
165 // cases where a full definition of the specialization is not required. In
166 // such cases, the specialization declaration remains incomplete and lacks the
167 // attribute. Therefore, we fall back to checking the primary template class.
168 //
169 // Note: it is possible for a specialization declaration to have an attribute
170 // even if the primary template does not.
171 //
172 // FIXME: What if the primary template and explicit specialization
173 // declarations have conflicting attributes? We should consider diagnosing
174 // this scenario.
175 bool Result = RD->hasAttr<T>();
176
177 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
178 Result |= CTSD->getSpecializedTemplate()->getTemplatedDecl()->hasAttr<T>();
179
180 return Result;
181}
182
185
186} // 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::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:220
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.
Type source information for an attributed type.
Definition TypeLoc.h:1008
TypeLoc getModifiedLoc() const
The modified type, which is generally canonically different from the attribute type.
Definition TypeLoc.h:1022
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2129
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
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:546
DeclContext * getDeclContext()
Definition DeclBase.h:448
bool hasAttr() const
Definition DeclBase.h:577
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:809
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
FunctionDecl * getMostRecentDecl()
Returns the most recent (re)declaration of this declaration.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3826
size_t param_size() const
Definition Decl.h:2790
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: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
A (possibly-)qualified type.
Definition TypeBase.h:937
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:2706
A container of type source information.
Definition TypeBase.h:8263
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:1833
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:8529
bool isReferenceType() const
Definition TypeBase.h:8553
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:1910
bool isLValueReferenceType() const
Definition TypeBase.h:8557
bool isNullPtrType() const
Definition TypeBase.h:8928
QualType getType() const
Definition Decl.h:723
static bool isRecordWithAttr(QualType Type)
bool isGslPointerType(QualType QT)
bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee)
bool shouldTrackFirstArgument(const FunctionDecl *FD)
bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD)
bool isPointerLikeType(QualType QT)
bool isNormalAssignmentOperator(const FunctionDecl *FD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isGslOwnerType(QualType QT)
bool isInStlNamespace(const Decl *D)
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
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
@ Result
The result type of a method or function.
Definition TypeBase.h:905
const FunctionProtoType * T