Skip to content

Commit 335b2b5

Browse files
committed
lifetime-analysis-lifetimebound
1 parent b86aaac commit 335b2b5

File tree

12 files changed

+758
-206
lines changed

12 files changed

+758
-206
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===- LifetimeAnnotations.h - -*--------------- 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+
// Helper functions to inspect and infer lifetime annotations.
9+
//===----------------------------------------------------------------------===//
10+
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMEANNOTATIONS_H
11+
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMEANNOTATIONS_H
12+
13+
#include "clang/AST/DeclCXX.h"
14+
15+
namespace clang {
16+
namespace lifetimes {
17+
18+
/// Returns the most recent declaration of the method to ensure all
19+
/// lifetime-bound attributes from redeclarations are considered.
20+
const FunctionDecl *getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD);
21+
22+
/// Returns the most recent declaration of the method to ensure all
23+
/// lifetime-bound attributes from redeclarations are considered.
24+
const CXXMethodDecl *
25+
getDeclWithMergedLifetimeBoundAttrs(const CXXMethodDecl *CMD);
26+
27+
// Return true if this is an "normal" assignment operator.
28+
// We assume that a normal assignment operator always returns *this, that is,
29+
// an lvalue reference that is the same type as the implicit object parameter
30+
// (or the LHS for a non-member operator==).
31+
bool isNormalAssignmentOperator(const FunctionDecl *FD);
32+
33+
/// Returns true if this is an assignment operator where the parameter
34+
/// has the lifetimebound attribute.
35+
bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD);
36+
37+
/// Returns true if the implicit object parameter (this) should be considered
38+
/// lifetimebound, either due to an explicit lifetimebound attribute on the
39+
/// method or because it's a normal assignment operator.
40+
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD);
41+
} // namespace lifetimes
42+
} // namespace clang
43+
44+
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMEANNOTATIONS_H

clang/include/clang/Analysis/Analyses/LifetimeSafety.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,14 @@ template <typename Tag> struct ID {
7575
}
7676
};
7777

78-
template <typename Tag>
79-
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) {
80-
return OS << ID.Value;
81-
}
82-
8378
using LoanID = ID<struct LoanTag>;
8479
using OriginID = ID<struct OriginTag>;
80+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
81+
return OS << ID.Value;
82+
}
83+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
84+
return OS << ID.Value;
85+
}
8586

8687
// Using LLVM's immutable collections is efficient for dataflow analysis
8788
// as it avoids deep copies during state transitions.

clang/lib/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_clang_library(clangAnalysis
2121
FixitUtil.cpp
2222
IntervalPartition.cpp
2323
IssueHash.cpp
24+
LifetimeAnnotations.cpp
2425
LifetimeSafety.cpp
2526
LiveVariables.cpp
2627
MacroExpansionContext.cpp
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
//===----------------------------------------------------------------------===//
8+
#include "clang/Analysis/Analyses/LifetimeAnnotations.h"
9+
#include "clang/AST/ASTContext.h"
10+
#include "clang/AST/Attr.h"
11+
#include "clang/AST/Decl.h"
12+
#include "clang/AST/DeclCXX.h"
13+
#include "clang/AST/Type.h"
14+
#include "clang/AST/TypeLoc.h"
15+
16+
namespace clang {
17+
namespace lifetimes {
18+
19+
const FunctionDecl *
20+
getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD) {
21+
return FD != nullptr ? FD->getMostRecentDecl() : nullptr;
22+
}
23+
24+
const CXXMethodDecl *
25+
getDeclWithMergedLifetimeBoundAttrs(const CXXMethodDecl *CMD) {
26+
const FunctionDecl *FD = CMD;
27+
return cast_if_present<CXXMethodDecl>(
28+
getDeclWithMergedLifetimeBoundAttrs(FD));
29+
}
30+
31+
bool isNormalAssignmentOperator(const FunctionDecl *FD) {
32+
OverloadedOperatorKind OO = FD->getDeclName().getCXXOverloadedOperator();
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+
49+
bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD) {
50+
CMD = getDeclWithMergedLifetimeBoundAttrs(CMD);
51+
return CMD && isNormalAssignmentOperator(CMD) && CMD->param_size() == 1 &&
52+
CMD->getParamDecl(0)->hasAttr<clang::LifetimeBoundAttr>();
53+
}
54+
55+
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
56+
FD = getDeclWithMergedLifetimeBoundAttrs(FD);
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.
63+
AttributedTypeLoc ATL;
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+
71+
return isNormalAssignmentOperator(FD);
72+
}
73+
74+
} // namespace lifetimes
75+
} // namespace clang

0 commit comments

Comments
 (0)