clang 23.0.0git
Origins.cpp
Go to the documentation of this file.
1//===- Origins.cpp - Origin Implementation -----------------------*- 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//===----------------------------------------------------------------------===//
8
11#include "clang/AST/Attr.h"
12#include "clang/AST/DeclCXX.h"
14#include "clang/AST/Expr.h"
15#include "clang/AST/ExprCXX.h"
17#include "clang/AST/TypeBase.h"
20#include "llvm/ADT/StringMap.h"
21
23namespace {
24/// A utility class to traverse the function body in the analysis
25/// context and collect the count of expressions with missing origins.
26class MissingOriginCollector
27 : public RecursiveASTVisitor<MissingOriginCollector> {
28public:
29 MissingOriginCollector(
30 const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList,
31 LifetimeSafetyStats &LSStats)
32 : ExprToOriginList(ExprToOriginList), LSStats(LSStats) {}
33 bool VisitExpr(Expr *E) {
34 if (!hasOrigins(E))
35 return true;
36 // Check if we have an origin for this expression.
37 if (!ExprToOriginList.contains(E)) {
38 // No origin found: count this as missing origin.
39 LSStats.ExprTypeToMissingOriginCount[E->getType().getTypePtr()]++;
40 LSStats.ExprStmtClassToMissingOriginCount[std::string(
41 E->getStmtClassName())]++;
42 }
43 return true;
44 }
45
46private:
47 const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList;
48 LifetimeSafetyStats &LSStats;
49};
50} // namespace
51
54}
55
56/// Determines if an expression has origins that need to be tracked.
57///
58/// An expression has origins if:
59/// - It's a glvalue (has addressable storage), OR
60/// - Its type is pointer-like (pointer, reference, or gsl::Pointer)
61///
62/// Examples:
63/// - `int x; x` : has origin (glvalue)
64/// - `int* p; p` : has 2 origins (1 for glvalue and 1 for pointer type)
65/// - `std::string_view{}` : has 1 origin (prvalue of pointer type)
66/// - `42` : no origin (prvalue of non-pointer type)
67/// - `x + y` : (where x, y are int) → no origin (prvalue of non-pointer type)
68bool hasOrigins(const Expr *E) {
69 return E->isGLValue() || hasOrigins(E->getType());
70}
71
72/// Returns true if the declaration has its own storage that can be borrowed.
73///
74/// References generally have no storage - they are aliases to other storage.
75/// For example:
76/// int x; // has storage (can issue loans to x's storage)
77/// int& r = x; // no storage (r is an alias to x's storage)
78/// int* p; // has storage (the pointer variable p itself has storage)
79///
80/// TODO: Handle lifetime extension. References initialized by temporaries
81/// can have storage when the temporary's lifetime is extended:
82/// const int& r = 42; // temporary has storage, lifetime extended
83/// Foo&& f = Foo{}; // temporary has storage, lifetime extended
84/// Currently, this function returns false for all reference types.
86 return !D->getType()->isReferenceType();
87}
88
89OriginManager::OriginManager(ASTContext &AST, const Decl *D) : AST(AST) {
90 if (const auto *MD = llvm::dyn_cast_or_null<CXXMethodDecl>(D);
91 MD && MD->isInstance())
92 ThisOrigins = buildListForType(MD->getThisType(), MD);
93}
94
95OriginList *OriginManager::createNode(const ValueDecl *D, QualType QT) {
96 OriginID NewID = getNextOriginID();
97 AllOrigins.emplace_back(NewID, D, QT.getTypePtrOrNull());
98 return new (ListAllocator.Allocate<OriginList>()) OriginList(NewID);
99}
100
101OriginList *OriginManager::createNode(const Expr *E, QualType QT) {
102 OriginID NewID = getNextOriginID();
103 AllOrigins.emplace_back(NewID, E, QT.getTypePtrOrNull());
104 return new (ListAllocator.Allocate<OriginList>()) OriginList(NewID);
105}
106
107template <typename T>
108OriginList *OriginManager::buildListForType(QualType QT, const T *Node) {
109 assert(hasOrigins(QT) && "buildListForType called for non-pointer type");
110 OriginList *Head = createNode(Node, QT);
111
112 if (QT->isPointerOrReferenceType()) {
113 QualType PointeeTy = QT->getPointeeType();
114 // We recurse if the pointee type is pointer-like, to build the next
115 // level in the origin tree. E.g., for T*& / View&.
116 if (hasOrigins(PointeeTy))
117 Head->setInnerOriginList(buildListForType(PointeeTy, Node));
118 }
119 return Head;
120}
121
123 if (!hasOrigins(D->getType()))
124 return nullptr;
125 auto It = DeclToList.find(D);
126 if (It != DeclToList.end())
127 return It->second;
128 return DeclToList[D] = buildListForType(D->getType(), D);
129}
130
132 if (auto *ParenIgnored = E->IgnoreParens(); ParenIgnored != E)
133 return getOrCreateList(ParenIgnored);
134 // We do not see CFG stmts for ExprWithCleanups. Simply peel them.
135 if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
136 return getOrCreateList(EWC->getSubExpr());
137
138 if (!hasOrigins(E))
139 return nullptr;
140
141 auto It = ExprToList.find(E);
142 if (It != ExprToList.end())
143 return It->second;
144
145 QualType Type = E->getType();
146 // Special handling for 'this' expressions to share origins with the method's
147 // implicit object parameter.
148 if (llvm::isa<CXXThisExpr>(E)) {
149 assert(ThisOrigins && "origins for 'this' should be set for a method decl");
150 return *ThisOrigins;
151 }
152
153 // Special handling for DeclRefExpr to share origins with the underlying decl.
154 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
155 OriginList *Head = nullptr;
156 // For non-reference declarations (e.g., `int* p`), the DeclRefExpr is an
157 // lvalue (addressable) that can be borrowed, so we create an outer origin
158 // for the lvalue itself, with the pointee being the declaration's list.
159 // This models taking the address: `&p` borrows the storage of `p`, not what
160 // `p` points to.
161 if (doesDeclHaveStorage(DRE->getDecl())) {
162 Head = createNode(DRE, QualType{});
163 // This ensures origin sharing: multiple DeclRefExprs to the same
164 // declaration share the same underlying origins.
165 Head->setInnerOriginList(getOrCreateList(DRE->getDecl()));
166 } else {
167 // For reference-typed declarations (e.g., `int& r = p`) which have no
168 // storage, the DeclRefExpr directly reuses the declaration's list since
169 // references don't add an extra level of indirection at the expression
170 // level.
171 Head = getOrCreateList(DRE->getDecl());
172 }
173 return ExprToList[E] = Head;
174 }
175
176 // If E is an lvalue , it refers to storage. We model this storage as the
177 // first level of origin list, as if it were a reference, because l-values are
178 // addressable.
179 if (E->isGLValue() && !Type->isReferenceType())
180 Type = AST.getLValueReferenceType(Type);
181 return ExprToList[E] = buildListForType(Type, E);
182}
183
184void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const {
185 OS << OID << " (";
186 Origin O = getOrigin(OID);
187 if (const ValueDecl *VD = O.getDecl()) {
188 OS << "Decl: " << VD->getNameAsString();
189 } else if (const Expr *E = O.getExpr()) {
190 OS << "Expr: " << E->getStmtClassName();
191 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
192 if (const ValueDecl *VD = DRE->getDecl())
193 OS << ", Decl: " << VD->getNameAsString();
194 }
195 } else {
196 OS << "Unknown";
197 }
198 if (O.Ty)
199 OS << ", Type : " << QualType(O.Ty, 0).getAsString();
200 OS << ")";
201}
202
204 assert(ID.Value < AllOrigins.size());
205 return AllOrigins[ID.Value];
206}
207
209 LifetimeSafetyStats &LSStats) {
210 MissingOriginCollector Collector(this->ExprToList, LSStats);
211 Collector.TraverseStmt(const_cast<Stmt *>(&FunctionBody));
212}
213
214} // namespace clang::lifetimes::internal
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.
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
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition ExprCXX.h:3661
This represents one expression.
Definition Expr.h:112
bool isGLValue() const
Definition Expr.h:287
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3085
QualType getType() const
Definition Expr.h:144
A (possibly-)qualified type.
Definition TypeBase.h:937
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8296
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition TypeBase.h:1332
Stmt - This represents one statement.
Definition Stmt.h:86
const char * getStmtClassName() const
Definition Stmt.cpp:87
The base class of the type hierarchy.
Definition TypeBase.h:1833
bool isReferenceType() const
Definition TypeBase.h:8553
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:753
bool isPointerOrReferenceType() const
Definition TypeBase.h:8533
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
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:94
void setInnerOriginList(OriginList *Inner)
Definition Origins.h:101
OriginList * getOrCreateList(const ValueDecl *D)
Gets or creates the OriginList for a given ValueDecl.
Definition Origins.cpp:122
const Origin & getOrigin(OriginID ID) const
Definition Origins.cpp:203
void collectMissingOrigins(Stmt &FunctionBody, LifetimeSafetyStats &LSStats)
Collects statistics about expressions that lack associated origins.
Definition Origins.cpp:208
void dump(OriginID OID, llvm::raw_ostream &OS) const
Definition Origins.cpp:184
OriginManager(ASTContext &AST, const Decl *D)
Definition Origins.cpp:89
utils::ID< struct OriginTag > OriginID
Definition Origins.h:27
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
Definition Origins.cpp:85
bool hasOrigins(QualType QT)
Definition Origins.cpp:52
bool isGslPointerType(QualType QT)
const FunctionProtoType * T
A structure to hold the statistics related to LifetimeAnalysis.
An Origin is a symbolic identifier that represents the set of possible loans a pointer-like object co...
Definition Origins.h:39
const clang::Expr * getExpr() const
Definition Origins.h:63
const clang::ValueDecl * getDecl() const
Definition Origins.h:60
const Type * Ty
The type at this indirection level.
Definition Origins.h:53