comex updated this revision to Diff 220926.
comex added a comment.

In D67647#1674795 <https://reviews.llvm.org/D67647#1674795>, @dblaikie wrote:

> Right - I was suggesting that could be changed. Would it be OK to you to 
> change arguments() to return ArrayRef? Or would you rather avoid that to 
> avoid baking in more dependence on that alias violation?


I'd rather avoid that for the reason you said.

> Same reason I've pushed back on adding things like "empty()" or "size()", 
> etc. Which are fine (& have been added in STLExtras) as free functions.

Okay, I'll just do that then.  Added as `index(Range, N)`, matching range-v3 
(though not the actual C++20 draft).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67647/new/

https://reviews.llvm.org/D67647

Files:
  clang/include/clang/AST/Stmt.h
  clang/lib/Analysis/Consumed.cpp
  llvm/include/llvm/ADT/STLExtras.h
  llvm/include/llvm/ADT/iterator_range.h

Index: llvm/include/llvm/ADT/iterator_range.h
===================================================================
--- llvm/include/llvm/ADT/iterator_range.h
+++ llvm/include/llvm/ADT/iterator_range.h
@@ -20,9 +20,17 @@
 
 #include <iterator>
 #include <utility>
+#include <cassert>
 
 namespace llvm {
 
+template <typename T>
+constexpr bool is_random_iterator() {
+  return std::is_same<
+    typename std::iterator_traits<T>::iterator_category,
+    std::random_access_iterator_tag>::value;
+}
+
 /// A range adaptor for a pair of iterators.
 ///
 /// This just wraps two iterators into a range-compatible interface. Nothing
@@ -58,11 +66,31 @@
   return iterator_range<T>(std::move(p.first), std::move(p.second));
 }
 
+/// Non-random-iterator version
 template <typename T>
-iterator_range<decltype(adl_begin(std::declval<T>()))> drop_begin(T &&t,
-                                                                  int n) {
-  return make_range(std::next(adl_begin(t), n), adl_end(t));
+auto drop_begin(T &&t, int n) ->
+  typename std::enable_if<!is_random_iterator<decltype(adl_begin(t))>(),
+  iterator_range<decltype(adl_begin(t))>>::type {
+  auto begin = adl_begin(t);
+  auto end = adl_end(t);
+  for (int i = 0; i < n; i++) {
+    assert(begin != end);
+    ++begin;
+  }
+  return make_range(begin, end);
 }
+
+/// Optimized version for random iterators
+template <typename T>
+auto drop_begin(T &&t, int n) ->
+  typename std::enable_if<is_random_iterator<decltype(adl_begin(t))>(),
+  iterator_range<decltype(adl_begin(t))>>::type {
+  auto begin = adl_begin(t);
+  auto end = adl_end(t);
+  assert(end - begin >= n && "Dropping more elements than exist!");
+  return make_range(std::next(begin, n), end);
+}
+
 }
 
 #endif
Index: llvm/include/llvm/ADT/STLExtras.h
===================================================================
--- llvm/include/llvm/ADT/STLExtras.h
+++ llvm/include/llvm/ADT/STLExtras.h
@@ -1573,6 +1573,14 @@
 }
 template <class T> constexpr T *to_address(T *P) { return P; }
 
+template <typename R>
+auto index(R &&TheRange,
+  typename std::iterator_traits<detail::IterOfRange<R>>::difference_type N)
+  -> decltype(TheRange.begin()[N]) {
+  assert(N < TheRange.end() - TheRange.begin() && "Index out of range!");
+  return TheRange.begin()[N];
+}
+
 } // end namespace llvm
 
 #endif // LLVM_ADT_STLEXTRAS_H
Index: clang/lib/Analysis/Consumed.cpp
===================================================================
--- clang/lib/Analysis/Consumed.cpp
+++ clang/lib/Analysis/Consumed.cpp
@@ -494,8 +494,10 @@
   void checkCallability(const PropagationInfo &PInfo,
                         const FunctionDecl *FunDecl,
                         SourceLocation BlameLoc);
-  bool handleCall(const CallExpr *Call, const Expr *ObjArg,
-                  const FunctionDecl *FunD);
+
+  using ArgRange = llvm::iterator_range<CallExpr::const_arg_iterator>;
+  bool handleCall(const Expr *Call, const Expr *ObjArg,
+                  ArgRange args, const FunctionDecl *FunD);
 
   void VisitBinaryOperator(const BinaryOperator *BinOp);
   void VisitCallExpr(const CallExpr *Call);
@@ -608,22 +610,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,
+                                     ArgRange 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 +637,7 @@
 
       if (ParamState != ExpectedState)
         Analyzer.WarningsHandler.warnParamTypestateMismatch(
-          Call->getArg(Index)->getExprLoc(),
+          Arg->getExprLoc(),
           stateToString(ExpectedState), stateToString(ParamState));
     }
 
@@ -749,7 +750,7 @@
     return;
   }
 
-  handleCall(Call, nullptr, FunDecl);
+  handleCall(Call, nullptr, Call->arguments(), FunDecl);
   propagateReturnType(Call, FunDecl);
 }
 
@@ -805,7 +806,7 @@
   if (!MD)
     return;
 
-  handleCall(Call, Call->getImplicitObjectArgument(), MD);
+  handleCall(Call, Call->getImplicitObjectArgument(), Call->arguments(), MD);
   propagateReturnType(Call, MD);
 }
 
@@ -813,18 +814,20 @@
     const CXXOperatorCallExpr *Call) {
   const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
   if (!FunDecl) return;
+  ArgRange Args = Call->arguments();
 
   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(llvm::index(Args, 1));
+    if (!handleCall(Call, llvm::index(Args, 0), llvm::drop_begin(Args, 1),
+                    FunDecl))
+      setInfo(llvm::index(Args, 0), CS);
     return;
   }
 
-  if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
-    handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
+  if (isa<CXXMethodDecl>(FunDecl))
+    handleCall(Call, llvm::index(Args, 0), llvm::drop_begin(Args, 1), FunDecl);
   else
-    handleCall(Call, Call->getArg(0), FunDecl);
+    handleCall(Call, nullptr, Args, FunDecl);
 
   propagateReturnType(Call, FunDecl);
 }
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -1041,7 +1041,8 @@
   template<typename T, typename TPtr = T *, typename StmtPtr = Stmt *>
   struct CastIterator
       : llvm::iterator_adaptor_base<CastIterator<T, TPtr, StmtPtr>, StmtPtr *,
-                                    std::random_access_iterator_tag, TPtr> {
+                                    std::random_access_iterator_tag, TPtr,
+                                    int, void, TPtr> {
     using Base = typename CastIterator::iterator_adaptor_base;
 
     CastIterator() : Base(nullptr) {}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to