================
@@ -105,6 +107,125 @@ bool implicitObjectParamIsLifetimeBound(const
FunctionDecl *FD) {
return isNormalAssignmentOperator(FD);
}
+static std::optional<LifetimeBoundParamInfo>
+getExplicitLifetimeBoundParamInfo(const FunctionDecl *FD, unsigned I) {
+ FD = getDeclWithMergedLifetimeBoundAttrs(FD);
+ if (!FD)
+ return std::nullopt;
+
+ const ParmVarDecl *PVD = nullptr;
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
+ if (I == 0)
+ return getImplicitObjectParamLifetimeBoundAttr(Method)
+ ? std::optional<LifetimeBoundParamInfo>(
+ LifetimeBoundParamInfo(Method))
+ : std::nullopt;
+ if ((I - 1) < Method->getNumParams())
+ PVD = Method->getParamDecl(I - 1);
+ } else if (I < FD->getNumParams()) {
+ PVD = FD->getParamDecl(I);
+ }
+
+ if (PVD && PVD->hasAttr<clang::LifetimeBoundAttr>())
+ return LifetimeBoundParamInfo(PVD);
+ return std::nullopt;
+}
+
+static bool isExprInCallArg(const Expr *Arg, const Expr *Source) {
+ if (!Arg || !Source)
+ return false;
+
+ Arg = Arg->IgnoreParenImpCasts();
+ Source = Source->IgnoreParenImpCasts();
+ if (Arg == Source || Arg->getSourceRange() == Source->getSourceRange())
+ return true;
+
+ for (const Stmt *Child : Arg->children())
+ if (const auto *ChildExpr = dyn_cast_or_null<Expr>(Child))
+ if (isExprInCallArg(ChildExpr, Source))
+ return true;
+
+ return false;
+}
+
+std::pair<const FunctionDecl *, llvm::SmallVector<const Expr *, 4>>
+getFunctionCallInfo(const Expr *Call) {
+ const FunctionDecl *FD = nullptr;
+ llvm::SmallVector<const Expr *, 4> Args;
+ if (!Call)
+ return {FD, Args};
+
+ Call = Call->IgnoreParenImpCasts();
+ if (const auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
+ FD = CCE->getConstructor();
+ Args.append(CCE->getArgs(), CCE->getArgs() + CCE->getNumArgs());
+ } else if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
+ FD = MCE->getMethodDecl();
+ Args.push_back(MCE->getImplicitObjectArgument());
+ Args.append(MCE->getArgs(), MCE->getArgs() + MCE->getNumArgs());
+ } else if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
+ FD = OCE->getDirectCallee();
+ Args.append(OCE->getArgs(), OCE->getArgs() + OCE->getNumArgs());
+ // For `static operator()`, the first argument is the object argument,
+ // remove it from the argument list to avoid off-by-one errors.
+ if (FD && OCE->getOperator() == OO_Call && FD->isStatic())
+ Args.erase(Args.begin());
+ } else if (const auto *CE = dyn_cast<CallExpr>(Call)) {
+ FD = CE->getDirectCallee();
+ Args.append(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
+ }
+
+ return {FD, Args};
+}
+
+std::optional<LifetimeBoundParamInfo>
+getTrackedArgInfo(const FunctionDecl *FD, llvm::ArrayRef<const Expr *> Args,
+ unsigned I) {
+ FD = getDeclWithMergedLifetimeBoundAttrs(FD);
+ if (!FD || I >= Args.size())
+ return std::nullopt;
+
+ if (std::optional<LifetimeBoundParamInfo> Info =
+ getExplicitLifetimeBoundParamInfo(FD, I))
+ return Info;
+
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
+ if (I == 0 &&
+ (isNormalAssignmentOperator(Method) ||
+ shouldTrackImplicitObjectArg(*Args[0], Method,
+ /*RunningUnderLifetimeSafety=*/true)))
+ return LifetimeBoundParamInfo(Method);
+ return std::nullopt;
+ }
+
+ if (I == 0 && shouldTrackFirstArgument(FD))
+ return LifetimeBoundParamInfo(FD->getParamDecl(I));
+ if (I == 1 && shouldTrackSecondArgument(FD))
+ return LifetimeBoundParamInfo(FD->getParamDecl(I));
+
+ return std::nullopt;
+}
+
+std::optional<LifetimeBoundParamInfo>
+getTrackingInfoForCallArg(const Expr *Call, const Expr *Source) {
+ if (!Call || !Source)
+ return std::nullopt;
+
+ auto [FD, Args] = getFunctionCallInfo(Call);
+ if (!FD)
+ return std::nullopt;
+
+ for (unsigned I = 0; I < Args.size(); ++I)
+ if (isExprInCallArg(Args[I], Source))
----------------
iitianpushkar wrote:
I really do not think direct equality is enough because `Source` can be nested
inside the arg expression.
For ex, in `identity(&i)`, the argument is `&i` but the alias source can be
`i`. These are not equal after ignoring paren/implicit casts but `i` is still
contained inside `&i`, so we need the containment check.
https://github.com/llvm/llvm-project/pull/206337
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits