tbaeder updated this revision to Diff 551131.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D157385/new/
https://reviews.llvm.org/D157385
Files:
clang/include/clang/Analysis/CFG.h
clang/lib/Analysis/CFG.cpp
clang/lib/Analysis/ThreadSafety.cpp
clang/test/Analysis/scopes-cfg-output.cpp
Index: clang/test/Analysis/scopes-cfg-output.cpp
===================================================================
--- clang/test/Analysis/scopes-cfg-output.cpp
+++ clang/test/Analysis/scopes-cfg-output.cpp
@@ -1419,3 +1419,15 @@
}
}
}
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: CFGScopeBegin(i)
+// CHECK-NEXT: 2: int i __attribute__((cleanup(cleanup_int)));
+// CHECK-NEXT: 3: CleanupFunction (cleanup_int)
+// CHECK-NEXT: 4: CFGScopeEnd(i)
+void cleanup_int(int *i) {
+}
+
+void test_cleanup_functions() {
+ int i __attribute__((cleanup(cleanup_int)));
+}
Index: clang/lib/Analysis/ThreadSafety.cpp
===================================================================
--- clang/lib/Analysis/ThreadSafety.cpp
+++ clang/lib/Analysis/ThreadSafety.cpp
@@ -2426,6 +2426,16 @@
AD.getTriggerStmt()->getEndLoc());
break;
}
+
+ case CFGElement::CleanupFunction: {
+ const CFGCleanupFunction &CF = BI.castAs<CFGCleanupFunction>();
+
+ LocksetBuilder.handleCall(nullptr, CF.getFunctionDecl(),
+ SxBuilder.createVariable(CF.getVarDecl()),
+ CF.getVarDecl()->getLocation());
+ break;
+ }
+
case CFGElement::TemporaryDtor: {
auto TD = BI.castAs<CFGTemporaryDtor>();
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -881,6 +881,10 @@
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
}
+ void appendCleanupFunction(CFGBlock *B, VarDecl *VD) {
+ B->appendCleanupFunction(VD, cfg->getBumpVectorContext());
+ }
+
void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
}
@@ -1346,7 +1350,8 @@
return {};
}
- bool hasTrivialDestructor(VarDecl *VD);
+ bool hasTrivialDestructor(VarDecl *VD) const;
+ bool needsAutomaticDestruction(const VarDecl *VD) const;
};
} // namespace
@@ -1865,7 +1870,7 @@
DeclsNonTrivial.reserve(B.distance(E));
for (VarDecl* D : llvm::make_range(B, E))
- if (!hasTrivialDestructor(D))
+ if (needsAutomaticDestruction(D))
DeclsNonTrivial.push_back(D);
for (VarDecl *VD : llvm::reverse(DeclsNonTrivial)) {
@@ -1879,18 +1884,24 @@
Ty = getReferenceInitTemporaryType(VD->getInit());
Ty = Context->getBaseElementType(Ty);
- if (Ty->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
+ bool IsCXXRecordType = (Ty->getAsCXXRecordDecl() != nullptr);
+ if (IsCXXRecordType &&
+ Ty->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
Block = createNoReturnBlock();
}
autoCreateBlock();
+ bool HasCleanupAttr = VD->hasAttr<CleanupAttr>();
+
// Add LifetimeEnd after automatic obj with non-trivial destructors,
// as they end their lifetime when the destructor returns. For trivial
// objects, we end lifetime with scope end.
if (BuildOpts.AddLifetime)
appendLifetimeEnds(Block, VD, S);
- if (BuildOpts.AddImplicitDtors)
+ if (HasCleanupAttr)
+ appendCleanupFunction(Block, VD);
+ if (BuildOpts.AddImplicitDtors && !hasTrivialDestructor(VD))
appendAutomaticObjDtor(Block, VD, S);
}
}
@@ -2095,7 +2106,12 @@
return Scope;
}
-bool CFGBuilder::hasTrivialDestructor(VarDecl *VD) {
+bool CFGBuilder::needsAutomaticDestruction(const VarDecl *VD) const {
+ return !hasTrivialDestructor(const_cast<VarDecl *>(VD)) ||
+ VD->hasAttr<CleanupAttr>();
+}
+
+bool CFGBuilder::hasTrivialDestructor(VarDecl *VD) const {
// Check for const references bound to temporary. Set type to pointee.
QualType QT = VD->getType();
if (QT->isReferenceType()) {
@@ -2149,7 +2165,7 @@
return Scope;
if (!BuildOpts.AddLifetime && !BuildOpts.AddScopes &&
- hasTrivialDestructor(VD)) {
+ !needsAutomaticDestruction(VD)) {
assert(BuildOpts.AddImplicitDtors);
return Scope;
}
@@ -5287,8 +5303,9 @@
case CFGElement::CXXRecordTypedCall:
case CFGElement::ScopeBegin:
case CFGElement::ScopeEnd:
- llvm_unreachable("getDestructorDecl should only be used with "
- "ImplicitDtors");
+ case CFGElement::CleanupFunction:
+ llvm_unreachable("getDestructorDecl should only be used with "
+ "ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
QualType ty = var->getType();
@@ -5830,6 +5847,12 @@
break;
}
+ case CFGElement::Kind::CleanupFunction: {
+ OS << "CleanupFunction ("
+ << E.castAs<CFGCleanupFunction>().getFunctionDecl()->getName() << ")\n";
+ break;
+ }
+
case CFGElement::Kind::LifetimeEnds:
Helper.handleDecl(E.castAs<CFGLifetimeEnds>().getVarDecl(), OS);
OS << " (Lifetime ends)\n";
Index: clang/include/clang/Analysis/CFG.h
===================================================================
--- clang/include/clang/Analysis/CFG.h
+++ clang/include/clang/Analysis/CFG.h
@@ -14,10 +14,11 @@
#ifndef LLVM_CLANG_ANALYSIS_CFG_H
#define LLVM_CLANG_ANALYSIS_CFG_H
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/Analysis/ConstructionContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/ConstructionContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GraphTraits.h"
@@ -74,7 +75,8 @@
MemberDtor,
TemporaryDtor,
DTOR_BEGIN = AutomaticObjectDtor,
- DTOR_END = TemporaryDtor
+ DTOR_END = TemporaryDtor,
+ CleanupFunction,
};
protected:
@@ -383,6 +385,32 @@
}
};
+class CFGCleanupFunction final : public CFGElement {
+public:
+ CFGCleanupFunction() = default;
+ CFGCleanupFunction(const VarDecl *VD)
+ : CFGElement(Kind::CleanupFunction, VD) {
+ assert(VD->hasAttr<CleanupAttr>());
+ }
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ /// Returns the function to be called when cleaning up the var decl.
+ const FunctionDecl *getFunctionDecl() const {
+ const CleanupAttr *A = getVarDecl()->getAttr<CleanupAttr>();
+ return A->getFunctionDecl();
+ }
+
+private:
+ friend class CFGElement;
+
+ static bool isKind(const CFGElement E) {
+ return E.getKind() == Kind::CleanupFunction;
+ }
+};
+
/// Represents C++ object destructor implicitly generated for automatic object
/// or temporary bound to const reference at the point of leaving its local
/// scope.
@@ -1142,6 +1170,10 @@
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
}
+ void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C) {
+ Elements.push_back(CFGCleanupFunction(VD), C);
+ }
+
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
Elements.push_back(CFGLifetimeEnds(VD, S), C);
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits