comex created this revision.
comex added a reviewer: dblaikie.
Herald added subscribers: cfe-commits, dmgreen, kristof.beyls.
Herald added a project: clang.
Currently, `handleCall` takes a `CallExpr` as an argument and retrieves the
arguments from there. This changes it to take the argument list as a separate
argument of type `ArrayRef`.
The main motivation that I want `VisitCXXConstructExpr` to also be able to
invoke `handleCall`, even though `CXXConstructExpr` is not a subclass of
`CallExpr`. But actually adding that will wait for a future patch.
However, this also fixes a minor bug in `VisitCXXOperatorCallExpr`:
if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
else
handleCall(Call, Call->getArg(0), FunDecl);
`Call` here is a `CXXOperatorCallExpr`, and `CXXMemberCallExpr` is a sibling
class, so the cast will never succeed. CXXMemberCallExprs go through a
separate visitor, `VisitCXXMemberCallExpr`.
On the other hand, this logic may be intended to reflect the fact that C++
operators can be declared as either methods or free functions. The correct way
to differentiate these is shown at the beginning of handleCall:
unsigned Offset = 0;
if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
Offset = 1; // first argument is 'this'
For `CXXOperatorCallExpr`s, if the decl is a `CXXMethodDecl`, the first
argument is `this`; otherwise there is no `this`.
Going back to the other first: currently, since the `dyn_cast` always fails, it
always passes `Call->getArg(0)` as `ObjArg` (i.e. the expression representing
`this`), even for operators declared as free functions. However, this is
harmless, because `ObjArg` is only used if the function is marked as one of
`set_typestate` or `test_typestate`, or `callable_when`, yet those attributes
are only allowed on methods. `Call->getArg(0)` will crash if there are zero
arguments, but the only kind of non-method operator function allowed to have
zero arguments is a user-defined literal, and those do not produce
`CXXOperatorCallExpr`s.
The bug could be fixed by changing the first snippet to check for
`CXXMethodDecl` like the second one, but this refactor makes things cleaner by
only having to check in one place.
Repository:
rC Clang
https://reviews.llvm.org/D67647
Files:
lib/Analysis/Consumed.cpp
Index: lib/Analysis/Consumed.cpp
===================================================================
--- lib/Analysis/Consumed.cpp
+++ lib/Analysis/Consumed.cpp
@@ -494,8 +494,8 @@
void checkCallability(const PropagationInfo &PInfo,
const FunctionDecl *FunDecl,
SourceLocation BlameLoc);
- bool handleCall(const CallExpr *Call, const Expr *ObjArg,
- const FunctionDecl *FunD);
+ bool handleCall(const Expr *Call, const Expr *ObjArg,
+ ArrayRef<const Expr *> Args, const FunctionDecl *FunD);
void VisitBinaryOperator(const BinaryOperator *BinOp);
void VisitCallExpr(const CallExpr *Call);
@@ -608,22 +608,21 @@
// Factors out common behavior for function, method, and operator calls.
// Check parameters and set parameter state if necessary.
// Returns true if the state of ObjArg is set, or false otherwise.
-bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
+bool ConsumedStmtVisitor::handleCall(const Expr *Call,
+ const Expr *ObjArg,
+ ArrayRef<const Expr *> Args,
const FunctionDecl *FunD) {
- unsigned Offset = 0;
- if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
- Offset = 1; // first argument is 'this'
-
// check explicit parameters
- for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
+ unsigned Index = 0;
+ for (const Expr *Arg : Args) {
// Skip variable argument lists.
- if (Index - Offset >= FunD->getNumParams())
+ if (Index >= FunD->getNumParams())
break;
- const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
+ const ParmVarDecl *Param = FunD->getParamDecl(Index++);
QualType ParamType = Param->getType();
- InfoEntry Entry = findInfo(Call->getArg(Index));
+ InfoEntry Entry = findInfo(Arg);
if (Entry == PropagationMap.end() || Entry->second.isTest())
continue;
@@ -636,7 +635,7 @@
if (ParamState != ExpectedState)
Analyzer.WarningsHandler.warnParamTypestateMismatch(
- Call->getArg(Index)->getExprLoc(),
+ Arg->getExprLoc(),
stateToString(ExpectedState), stateToString(ParamState));
}
@@ -749,7 +748,9 @@
return;
}
- handleCall(Call, nullptr, FunDecl);
+ handleCall(Call, nullptr,
+ llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs()),
+ FunDecl);
propagateReturnType(Call, FunDecl);
}
@@ -805,7 +806,8 @@
if (!MD)
return;
- handleCall(Call, Call->getImplicitObjectArgument(), MD);
+ handleCall(Call, Call->getImplicitObjectArgument(),
+ llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs()), MD);
propagateReturnType(Call, MD);
}
@@ -813,18 +815,19 @@
const CXXOperatorCallExpr *Call) {
const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
if (!FunDecl) return;
+ ArrayRef<const Expr *> Args(Call->getArgs(), Call->getNumArgs());
if (Call->getOperator() == OO_Equal) {
- ConsumedState CS = getInfo(Call->getArg(1));
- if (!handleCall(Call, Call->getArg(0), FunDecl))
- setInfo(Call->getArg(0), CS);
+ ConsumedState CS = getInfo(Args[1]);
+ if (!handleCall(Call, Args[0], Args.drop_front(1), FunDecl))
+ setInfo(Args[0], CS);
return;
}
- if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
- handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
+ if (isa<CXXMethodDecl>(FunDecl))
+ handleCall(Call, Args[0], Args.drop_front(1), FunDecl);
else
- handleCall(Call, Call->getArg(0), FunDecl);
+ handleCall(Call, nullptr, Args, FunDecl);
propagateReturnType(Call, FunDecl);
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits