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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to