15#ifndef LLVM_CLANG_LIB_SEMA_SEMALIFETIMESAFETY_H
16#define LLVM_CLANG_LIB_SEMA_SEMALIFETIMESAFETY_H
31 constexpr unsigned DiagIDs[] = {
32 diag::warn_lifetime_safety_use_after_scope,
33 diag::warn_lifetime_safety_use_after_scope_moved,
34 diag::warn_lifetime_safety_use_after_free,
35 diag::warn_lifetime_safety_return_stack_addr,
36 diag::warn_lifetime_safety_return_stack_addr_moved,
37 diag::warn_lifetime_safety_invalidation,
38 diag::warn_lifetime_safety_dangling_field,
39 diag::warn_lifetime_safety_dangling_field_moved,
40 diag::warn_lifetime_safety_dangling_global,
41 diag::warn_lifetime_safety_dangling_global_moved,
42 diag::warn_lifetime_safety_noescape_escapes,
43 diag::warn_lifetime_safety_lifetimebound_violation,
44 diag::warn_lifetime_safety_cross_tu_misplaced_lifetimebound,
45 diag::warn_lifetime_safety_intra_tu_misplaced_lifetimebound,
46 diag::warn_lifetime_safety_invalidated_field,
47 diag::warn_lifetime_safety_invalidated_global,
48 diag::warn_lifetime_safety_cross_tu_param_suggestion,
49 diag::warn_lifetime_safety_intra_tu_param_suggestion,
50 diag::warn_lifetime_safety_cross_tu_this_suggestion,
51 diag::warn_lifetime_safety_intra_tu_this_suggestion,
52 diag::warn_lifetime_safety_inapplicable_lifetimebound};
53 for (
unsigned DiagID : DiagIDs)
67 unsigned DiagID = MovedExpr
68 ? diag::warn_lifetime_safety_use_after_scope_moved
69 : diag::warn_lifetime_safety_use_after_scope;
72 << getDiagSubjectDescription(IssueExpr) << IssueExpr->
getSourceRange();
74 S.Diag(MovedExpr->
getExprLoc(), diag::note_lifetime_safety_moved_here)
76 S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
78 reportAliasingChain(ExprChain);
80 S.Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
85 const Expr *MovedExpr)
override {
86 unsigned DiagID = MovedExpr
87 ? diag::warn_lifetime_safety_return_stack_addr_moved
88 : diag::warn_lifetime_safety_return_stack_addr;
91 << getDiagSubjectDescription(IssueExpr) << IssueExpr->
getSourceRange();
94 S.Diag(MovedExpr->
getExprLoc(), diag::note_lifetime_safety_moved_here)
96 S.Diag(ReturnExpr->
getExprLoc(), diag::note_lifetime_safety_returned_here)
102 const Expr *MovedExpr,
104 unsigned DiagID = MovedExpr
105 ? diag::warn_lifetime_safety_dangling_field_moved
106 : diag::warn_lifetime_safety_dangling_field;
109 << getDiagSubjectDescription(IssueExpr)
110 << getDiagSubjectDescription(DanglingField)
113 S.Diag(MovedExpr->
getExprLoc(), diag::note_lifetime_safety_moved_here)
116 diag::note_lifetime_safety_dangling_field_here)
122 const Expr *MovedExpr,
124 unsigned DiagID = MovedExpr
125 ? diag::warn_lifetime_safety_dangling_global_moved
126 : diag::warn_lifetime_safety_dangling_global;
129 << getDiagSubjectDescription(IssueExpr)
130 << getDiagSubjectDescription(DanglingGlobal)
133 S.Diag(MovedExpr->
getExprLoc(), diag::note_lifetime_safety_moved_here)
137 diag::note_lifetime_safety_dangling_static_here)
141 diag::note_lifetime_safety_dangling_global_here)
146 const Expr *InvalidationExpr)
override {
148 ? diag::warn_lifetime_safety_use_after_free
149 : diag::warn_lifetime_safety_invalidation;
151 ? diag::note_lifetime_safety_freed_here
152 : diag::note_lifetime_safety_invalidated_here;
155 S.Diag(InvalidationExpr->
getExprLoc(), UseDiag)
157 S.Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
161 const Expr *InvalidationExpr)
override {
164 ? diag::warn_lifetime_safety_use_after_free
165 : diag::warn_lifetime_safety_invalidation;
167 ? diag::note_lifetime_safety_freed_here
168 : diag::note_lifetime_safety_invalidated_here;
172 S.Diag(InvalidationExpr->
getExprLoc(), UseDiag)
174 S.Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
180 const Expr *InvalidationExpr)
override {
182 ? diag::note_lifetime_safety_freed_here
183 : diag::note_lifetime_safety_invalidated_here;
185 diag::warn_lifetime_safety_invalidated_field)
187 S.Diag(InvalidationExpr->
getExprLoc(), InvalidationDiag)
190 diag::note_lifetime_safety_dangling_field_here)
196 const Expr *InvalidationExpr)
override {
198 ? diag::note_lifetime_safety_freed_here
199 : diag::note_lifetime_safety_invalidated_here;
201 diag::warn_lifetime_safety_invalidated_field)
203 S.Diag(InvalidationExpr->
getExprLoc(), InvalidationDiag)
206 diag::note_lifetime_safety_dangling_field_here)
212 const Expr *InvalidationExpr)
override {
214 ? diag::note_lifetime_safety_freed_here
215 : diag::note_lifetime_safety_invalidated_here;
217 diag::warn_lifetime_safety_invalidated_global)
219 S.Diag(InvalidationExpr->
getExprLoc(), InvalidationDiag)
223 diag::note_lifetime_safety_dangling_static_here)
227 diag::note_lifetime_safety_dangling_global_here)
233 const Expr *InvalidationExpr)
override {
235 ? diag::note_lifetime_safety_freed_here
236 : diag::note_lifetime_safety_invalidated_here;
238 diag::warn_lifetime_safety_invalidated_global)
240 S.Diag(InvalidationExpr->
getExprLoc(), InvalidationDiag)
244 diag::note_lifetime_safety_dangling_static_here)
248 diag::note_lifetime_safety_dangling_global_here)
257 ? diag::warn_lifetime_safety_cross_tu_param_suggestion
258 : diag::warn_lifetime_safety_intra_tu_param_suggestion;
260 auto [InsertionPoint, FixItText] = getLifetimeBoundFixIt(ParmToAnnotate);
266 if (
const auto *EscapeExpr =
Target.dyn_cast<
const Expr *>())
267 S.Diag(EscapeExpr->getBeginLoc(),
268 diag::note_lifetime_safety_suggestion_returned_here)
269 << EscapeExpr->getSourceRange();
270 else if (
const auto *EscapeField =
Target.dyn_cast<
const FieldDecl *>())
271 S.Diag(EscapeField->getLocation(),
272 diag::note_lifetime_safety_escapes_to_field_here)
273 << EscapeField->getSourceRange();
277 const ParmVarDecl *ParmWithLifetimebound)
override {
278 const auto *
Attr = ParmWithLifetimebound->
getAttr<LifetimeBoundAttr>();
279 StringRef ParamName = ParmWithLifetimebound->
getName();
280 bool HasName = ParamName.size() > 0;
282 diag::warn_lifetime_safety_lifetimebound_violation)
290 assert(
Attr &&
"Expected lifetimebound attribute");
292 diag::warn_lifetime_safety_lifetimebound_violation)
300 assert(
Attr &&
"Expected lifetimebound attribute");
303 ? diag::warn_lifetime_safety_cross_tu_misplaced_lifetimebound
304 : diag::warn_lifetime_safety_intra_tu_misplaced_lifetimebound;
306 auto [InsertionPoint, FixItText] = getLifetimeBoundFixIt(FDecl);
312 if (IsMacro || InsertionPoint.isInvalid())
315 S.Diag(InsertionPoint, DiagID)
318 S.Diag(
Attr->
getLocation(), diag::note_lifetime_safety_lifetimebound_here)
326 const auto *
Attr = PVDDef->
getAttr<LifetimeBoundAttr>();
327 assert(
Attr &&
"Expected lifetimebound attribute");
330 ? diag::warn_lifetime_safety_cross_tu_misplaced_lifetimebound
331 : diag::warn_lifetime_safety_intra_tu_misplaced_lifetimebound;
333 auto [InsertionPoint, FixItText] = getLifetimeBoundFixIt(PVDDecl);
339 if (IsMacro || InsertionPoint.isInvalid())
346 S.Diag(
Attr->
getLocation(), diag::note_lifetime_safety_lifetimebound_here)
351 assert(PVD->
hasAttr<LifetimeBoundAttr>() &&
352 "Expected parameter to have lifetimebound attribute");
353 const auto *
Attr = PVD->
getAttr<LifetimeBoundAttr>();
355 diag::warn_lifetime_safety_inapplicable_lifetimebound)
361 const Expr *EscapeExpr)
override {
363 ? diag::warn_lifetime_safety_cross_tu_this_suggestion
364 : diag::warn_lifetime_safety_intra_tu_this_suggestion;
366 auto [InsertionPoint, FixItText] = getLifetimeBoundFixIt(MD);
368 S.Diag(InsertionPoint, DiagID)
373 diag::note_lifetime_safety_suggestion_returned_here)
378 const Expr *EscapeExpr)
override {
380 diag::warn_lifetime_safety_noescape_escapes)
384 diag::note_lifetime_safety_suggestion_returned_here)
391 diag::warn_lifetime_safety_noescape_escapes)
395 diag::note_lifetime_safety_escapes_to_field_here)
400 const VarDecl *EscapeGlobal)
override {
402 diag::warn_lifetime_safety_noescape_escapes)
406 diag::note_lifetime_safety_escapes_to_static_storage_here)
410 diag::note_lifetime_safety_escapes_to_global_here)
415 S.addLifetimeBoundToImplicitThis(
const_cast<CXXMethodDecl *
>(MD));
419 std::pair<SourceLocation, StringRef>
423 StringRef FixItText =
" [[clang::lifetimebound]]";
425 if (!
Decl->getIdentifier()) {
429 FixItText =
"[[clang::lifetimebound]] ";
430 }
else if (
Decl->hasDefaultArg()) {
436 return {InsertionPoint, FixItText};
439 std::pair<SourceLocation, StringRef>
440 getLifetimeBoundFixIt(
const CXXMethodDecl *MD) {
441 const auto MDL = MD->getTypeSourceInfo()->getTypeLoc();
443 MDL.getEndLoc(), 0, S.getSourceManager(), S.getLangOpts());
445 if (
const auto *FPT = MD->getType()->getAs<FunctionProtoType>();
446 FPT && FPT->hasTrailingReturn()) {
451 const auto FTL = MDL.getAs<FunctionTypeLoc>();
458 0, S.getSourceManager(), S.getLangOpts());
460 return {InsertionPoint,
" [[clang::lifetimebound]]"};
463 std::string getDiagSubjectDescription(
const ValueDecl *VD) {
465 llvm::raw_string_ostream
OS(Res);
470 }
else if (
const auto *Var = dyn_cast<VarDecl>(VD)) {
471 if (Var->isStaticLocal() || Var->isStaticDataMember())
472 OS <<
"static variable";
473 else if (Var->hasGlobalStorage())
474 OS <<
"global variable";
476 OS <<
"local variable";
481 VD->getNameForDiagnostic(OS, S.getPrintingPolicy(),
false);
486 std::string getDiagSubjectDescription(
const Expr *E) {
487 E = E->IgnoreImpCasts();
489 return "temporary object";
491 if (
const auto *DRE = dyn_cast<DeclRefExpr>(E))
492 return getDiagSubjectDescription(DRE->getDecl());
497 bool shouldShowInAliasChain(
const Expr *CurrExpr,
const Expr *LastExpr) {
498 CurrExpr = CurrExpr->IgnoreImpCasts();
499 LastExpr = LastExpr->IgnoreImpCasts();
506 return CurrExpr->getSourceRange() != LastExpr->getSourceRange();
509 void reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) {
510 if (OriginExprChain.empty())
513 const Expr *LastExpr = OriginExprChain.back();
514 std::string IssueStr = getDiagSubjectDescription(LastExpr);
516 for (
const Expr *CurrExpr : reverse(OriginExprChain.drop_back())) {
517 if (!shouldShowInAliasChain(CurrExpr, LastExpr))
519 S.Diag(CurrExpr->getBeginLoc(),
520 diag::note_lifetime_safety_aliases_storage)
521 << CurrExpr->getSourceRange() << getDiagSubjectDescription(CurrExpr)
Attr - This represents one attribute.
SourceLocation getLocation() const
SourceRange getRange() const
Represents a static or instance method of a struct/union/class.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getBeginLoc() const LLVM_READONLY
Concrete class used by the front-end to report problems and issues.
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
This represents one expression.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Represents a member of a struct/union/class.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
DeclarationNameInfo getNameInfo() const
static std::optional< Token > findPreviousToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments)
Finds the token that comes before the given location.
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Represents a parameter to a function.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Scope - A scope is a transient data structure that is used while parsing the program.
Sema - This implements semantic analysis and AST building for C.
DiagnosticsEngine & getDiagnostics() const
const LangOptions & getLangOpts() const
SourceManager & getSourceManager() const
Encodes a location in the source.
SourceLocation getBegin() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
Represents a variable declaration or definition.
bool isStaticDataMember() const
Determines whether this is a static data member.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
void reportUseAfterReturn(const Expr *IssueExpr, const Expr *ReturnExpr, const Expr *MovedExpr) override
void reportMisplacedLifetimebound(WarningScope Scope, const ParmVarDecl *PVDDef, const ParmVarDecl *PVDDecl) override
void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape, const Expr *EscapeExpr) override
void reportUseAfterInvalidation(const ParmVarDecl *PVD, const Expr *UseExpr, const Expr *InvalidationExpr) override
void reportInvalidatedField(const ParmVarDecl *PVD, const FieldDecl *DanglingField, const Expr *InvalidationExpr) override
void reportLifetimeboundViolation(const CXXMethodDecl *MDWithLifetimebound) override
void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape, const VarDecl *EscapeGlobal) override
void suggestLifetimeboundToImplicitThis(WarningScope Scope, const CXXMethodDecl *MD, const Expr *EscapeExpr) override
void reportInvalidatedGlobal(const ParmVarDecl *PVD, const VarDecl *DanglingGlobal, const Expr *InvalidationExpr) override
LifetimeSafetySemaHelperImpl(Sema &S)
void suggestLifetimeboundToParmVar(WarningScope Scope, const ParmVarDecl *ParmToAnnotate, EscapingTarget Target) override
void reportDanglingGlobal(const Expr *IssueExpr, const VarDecl *DanglingGlobal, const Expr *MovedExpr, SourceLocation ExpiryLoc) override
void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr, const Expr *MovedExpr, SourceLocation FreeLoc, llvm::ArrayRef< const Expr * > ExprChain) override
void reportInvalidatedField(const Expr *IssueExpr, const FieldDecl *DanglingField, const Expr *InvalidationExpr) override
void reportInapplicableLifetimebound(const ParmVarDecl *PVD) override
void reportDanglingField(const Expr *IssueExpr, const FieldDecl *DanglingField, const Expr *MovedExpr, SourceLocation ExpiryLoc) override
void addLifetimeBoundToImplicitThis(const CXXMethodDecl *MD) override
void reportUseAfterInvalidation(const Expr *IssueExpr, const Expr *UseExpr, const Expr *InvalidationExpr) override
void reportMisplacedLifetimebound(WarningScope Scope, const CXXMethodDecl *FDef, const CXXMethodDecl *FDecl) override
void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape, const FieldDecl *EscapeField) override
void reportInvalidatedGlobal(const Expr *IssueExpr, const VarDecl *DanglingGlobal, const Expr *InvalidationExpr) override
void reportLifetimeboundViolation(const ParmVarDecl *ParmWithLifetimebound) override
llvm::PointerUnion< const Expr *, const FieldDecl *, const VarDecl * > EscapingTarget
LifetimeSafetySemaHelper()=default
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
const LifetimeBoundAttr * getDirectImplicitObjectLifetimeBoundAttr(const FunctionDecl *FD)
WarningScope
Enum to track functions visible across or within TU.
const LifetimeBoundAttr * getImplicitObjectParamLifetimeBoundAttr(const FunctionDecl *FD)
bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D)
bool isa(CodeGen::Address addr)
SourceRange getSourceRange() const LLVM_READONLY
getSourceRange - The range of the declaration name.