aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/LifetimeAnnotations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/LifetimeAnnotations.cpp')
-rw-r--r--clang/lib/Analysis/LifetimeAnnotations.cpp75
1 files changed, 75 insertions, 0 deletions
diff --git a/clang/lib/Analysis/LifetimeAnnotations.cpp b/clang/lib/Analysis/LifetimeAnnotations.cpp
new file mode 100644
index 0000000..e791224
--- /dev/null
+++ b/clang/lib/Analysis/LifetimeAnnotations.cpp
@@ -0,0 +1,75 @@
+//===- LifetimeAnnotations.cpp - -*--------------- C++------------------*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Analysis/Analyses/LifetimeAnnotations.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+
+namespace clang {
+namespace lifetimes {
+
+const FunctionDecl *
+getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD) {
+ return FD != nullptr ? FD->getMostRecentDecl() : nullptr;
+}
+
+const CXXMethodDecl *
+getDeclWithMergedLifetimeBoundAttrs(const CXXMethodDecl *CMD) {
+ const FunctionDecl *FD = CMD;
+ return cast_if_present<CXXMethodDecl>(
+ getDeclWithMergedLifetimeBoundAttrs(FD));
+}
+
+bool isNormalAssignmentOperator(const FunctionDecl *FD) {
+ OverloadedOperatorKind OO = FD->getDeclName().getCXXOverloadedOperator();
+ bool IsAssignment = OO == OO_Equal || isCompoundAssignmentOperator(OO);
+ if (!IsAssignment)
+ return false;
+ QualType RetT = FD->getReturnType();
+ if (!RetT->isLValueReferenceType())
+ return false;
+ ASTContext &Ctx = FD->getASTContext();
+ QualType LHST;
+ auto *MD = dyn_cast<CXXMethodDecl>(FD);
+ if (MD && MD->isCXXInstanceMember())
+ LHST = Ctx.getLValueReferenceType(MD->getFunctionObjectParameterType());
+ else
+ LHST = FD->getParamDecl(0)->getType();
+ return Ctx.hasSameType(RetT, LHST);
+}
+
+bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD) {
+ CMD = getDeclWithMergedLifetimeBoundAttrs(CMD);
+ return CMD && isNormalAssignmentOperator(CMD) && CMD->param_size() == 1 &&
+ CMD->getParamDecl(0)->hasAttr<clang::LifetimeBoundAttr>();
+}
+
+bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
+ FD = getDeclWithMergedLifetimeBoundAttrs(FD);
+ const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
+ if (!TSI)
+ return false;
+ // Don't declare this variable in the second operand of the for-statement;
+ // GCC miscompiles that by ending its lifetime before evaluating the
+ // third operand. See gcc.gnu.org/PR86769.
+ AttributedTypeLoc ATL;
+ for (TypeLoc TL = TSI->getTypeLoc();
+ (ATL = TL.getAsAdjusted<AttributedTypeLoc>());
+ TL = ATL.getModifiedLoc()) {
+ if (ATL.getAttrAs<clang::LifetimeBoundAttr>())
+ return true;
+ }
+
+ return isNormalAssignmentOperator(FD);
+}
+
+} // namespace lifetimes
+} // namespace clang