baloghadamsoftware created this revision.
baloghadamsoftware added a reviewer: NoQ.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, martong, steakhal, Charusso, 
gamesh411, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, 
szepet, xazax.hun, whisperity.
Herald added a reviewer: Szelethus.
baloghadamsoftware requested review of this revision.

The handling of iterators implemented as pointers were incorrectly handled in 
the increment and decrement operations because these operations did not handle 
the lvalue of the iterator correctly. This patch fixes that issue and extends 
the test coverage for such kind of iterators by adding an option to the 
simulated `std::vector` to implement its iterator as a pointer.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88216

Files:
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/diagnostics/explicit-suppression.cpp
  clang/test/Analysis/invalidated-iterator.cpp
  clang/test/Analysis/iterator-modeling.cpp
  clang/test/Analysis/iterator-range.cpp
  clang/test/Analysis/mismatched-iterator.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp

Index: clang/test/Analysis/smart-ptr-text-output.cpp
===================================================================
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:993 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap<A>'}}
   // expected-note@-2 {{Returning from 'swap<A>'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
Index: clang/test/Analysis/mismatched-iterator.cpp
===================================================================
--- clang/test/Analysis/mismatched-iterator.cpp
+++ clang/test/Analysis/mismatched-iterator.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR %s -verify
 
 #include "Inputs/system-header-simulator-cxx.h"
 
Index: clang/test/Analysis/iterator-range.cpp
===================================================================
--- clang/test/Analysis/iterator-range.cpp
+++ clang/test/Analysis/iterator-range.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -analyzer-output=text %s -verify
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -analyzer-output=text %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR -analyzer-output=text %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR -analyzer-output=text %s -verify
 
 #include "Inputs/system-header-simulator-cxx.h"
 
@@ -9,30 +11,30 @@
 
 void deref_begin(const std::vector<int> &V) {
   auto i = V.begin();
-  *i; // no-warning
+  int n = *i; // no-warning
 }
 
 void deref_begind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
-  *i; // no-warning
+  auto i = std::next(V.begin());
+  int n = *i; // no-warning
 }
 
 template <typename Iter> Iter return_any_iterator(const Iter &It);
 
 void deref_unknown(const std::vector<int> &V) {
   auto i = return_any_iterator(V.begin());
-  *i; // no-warning
+  int n = *i; // no-warning
 }
 
 void deref_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
-  *i; // no-warning
+  auto i = std::prev(V.end());
+  int n = *i; // no-warning
 }
 
 void deref_end(const std::vector<int> &V) {
   auto i = V.end();
-  *i; // expected-warning{{Past-the-end iterator dereferenced}}
-      // expected-note@-1{{Past-the-end iterator dereferenced}}
+  int n = *i; // expected-warning{{Past-the-end iterator dereferenced}}
+              // expected-note@-1{{Past-the-end iterator dereferenced}}
 }
 
 // Prefix increment - operator++()
@@ -43,7 +45,7 @@
 }
 
 void incr_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   ++i; // no-warning
 }
 
@@ -53,7 +55,7 @@
 }
 
 void incr_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   ++i; // no-warning
 }
 
@@ -71,7 +73,7 @@
 }
 
 void behind_begin_incr(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   i++; // no-warning
 }
 
@@ -81,7 +83,7 @@
 }
 
 void ahead_of_end_incr(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   i++; // no-warning
 }
 
@@ -100,7 +102,7 @@
 }
 
 void decr_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   --i; // no-warning
 }
 
@@ -110,7 +112,7 @@
 }
 
 void decr_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   --i; // no-warning
 }
 
@@ -128,7 +130,7 @@
 }
 
 void behind_begin_decr(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   i--; // no-warning
 }
 
@@ -138,7 +140,7 @@
 }
 
 void ahead_of_end_decr(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   i--; // no-warning
 }
 
@@ -155,7 +157,7 @@
 }
 
 void incr_by_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   i += 2; // no-warning
 }
 
@@ -165,13 +167,13 @@
 }
 
 void incr_by_2_ahead_by_2_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   --i;
   i += 2; // no-warning
 }
 
 void incr_by_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
           // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
 }
@@ -190,7 +192,7 @@
 }
 
 void incr_by_2_copy_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = i + 2; // no-warning
 }
 
@@ -200,13 +202,13 @@
 }
 
 void incr_by_2_copy_ahead_by_2_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   --i;
   auto j = i + 2; // no-warning
 }
 
 void incr_by_2_copy_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
                   // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
 }
@@ -226,13 +228,13 @@
 }
 
 void decr_by_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
           // expected-note@-1{{Iterator decremented ahead of its valid range}}
 }
 
 void decr_by_2_behind_begin_by_2(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   ++i;
   i -= 2; // no-warning
 }
@@ -243,7 +245,7 @@
 }
 
 void decr_by_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   i -= 2; // no-warning
 }
 
@@ -261,13 +263,13 @@
 }
 
 void decr_by_2_copy_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
                   // expected-note@-1{{Iterator decremented ahead of its valid range}}
 }
 
 void decr_by_2_copy_behind_begin_by_2(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   ++i;
   auto j = i - 2; // no-warning
 }
@@ -278,7 +280,7 @@
 }
 
 void decr_by_2_copy_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = i - 2; // no-warning
 }
 
@@ -299,7 +301,7 @@
 }
 
 void subscript_zero_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = i[0]; // no-warning
 }
 
@@ -309,7 +311,7 @@
 }
 
 void subscript_zero_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = i[0]; // no-warning
 }
 
@@ -327,7 +329,7 @@
 }
 
 void subscript_negative_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = i[-1]; // no-warning
 }
 
@@ -337,7 +339,7 @@
 }
 
 void subscript_negative_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = i[-1]; // no-warning
 }
 
@@ -355,7 +357,7 @@
 }
 
 void subscript_positive_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = i[1]; // no-warning
 }
 
@@ -365,7 +367,7 @@
 }
 
 void subscript_positive_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = i[1]; // no-warning FIXME: expected warning Past-the-end iterator dereferenced
 }
 
@@ -387,7 +389,7 @@
 }
 
 void advance_plus_1_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   std::advance(i, 1); // no-warning
 }
 
@@ -397,7 +399,7 @@
 }
 
 void advance_plus_1_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   std::advance(i, 1); // no-warning
 }
 
@@ -416,7 +418,7 @@
 }
 
 void advance_minus_1_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   std::advance(i, -1); // no-warning
 }
 
@@ -426,7 +428,7 @@
 }
 
 void advance_minus_1_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   std::advance(i, -1); // no-warning
 }
 
@@ -443,7 +445,7 @@
 }
 
 void advance_plus_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   std::advance(i, 2); // no-warning
 }
 
@@ -453,7 +455,7 @@
 }
 
 void advance_plus_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
                       // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
 }
@@ -473,7 +475,7 @@
 }
 
 void advance_minus_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
                        // expected-note@-1{{Iterator decremented ahead of its valid range}}
 }
@@ -484,7 +486,7 @@
 }
 
 void advance_minus_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   std::advance(i, -2); // no-warning
 }
 
@@ -501,7 +503,7 @@
 }
 
 void advance_0_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   std::advance(i, 0); // no-warning
 }
 
@@ -511,7 +513,7 @@
 }
 
 void advance_0_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   std::advance(i, 0); // no-warning
 }
 
@@ -532,7 +534,7 @@
 }
 
 void next_plus_1_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::next(i); // no-warning
 }
 
@@ -542,7 +544,7 @@
 }
 
 void next_plus_1_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::next(i); // no-warning
 }
 
@@ -561,7 +563,7 @@
 }
 
 void next_minus_1_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::next(i, -1); // no-warning
 }
 
@@ -571,7 +573,7 @@
 }
 
 void next_minus_1_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::next(i, -1); // no-warning
 }
 
@@ -588,7 +590,7 @@
 }
 
 void next_plus_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::next(i, 2); // no-warning
 }
 
@@ -598,7 +600,7 @@
 }
 
 void next_plus_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
                             // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
 }
@@ -618,7 +620,7 @@
 }
 
 void next_minus_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
                              // expected-note@-1{{Iterator decremented ahead of its valid range}}
 }
@@ -629,7 +631,7 @@
 }
 
 void next_minus_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::next(i, -2); // no-warning
 }
 
@@ -646,7 +648,7 @@
 }
 
 void next_0_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::next(i, 0); // no-warning
 }
 
@@ -656,7 +658,7 @@
 }
 
 void next_0_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::next(i, 0); // no-warning
 }
 
@@ -678,7 +680,7 @@
 }
 
 void prev_plus_1_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::prev(i); // no-warning
 }
 
@@ -688,7 +690,7 @@
 }
 
 void prev_plus_1_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::prev(i); // no-warning
 }
 
@@ -705,7 +707,7 @@
 }
 
 void prev_minus_1_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::prev(i, -1); // no-warning
 }
 
@@ -715,7 +717,7 @@
 }
 
 void prev_minus_1_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::prev(i, -1); // no-warning
 }
 
@@ -734,7 +736,7 @@
 }
 
 void prev_plus_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}}
                             // expected-note@-1{{Iterator decremented ahead of its valid range}}
 }
@@ -745,7 +747,7 @@
 }
 
 void prev_plus_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::prev(i, 2); // no-warning
 }
 
@@ -762,7 +764,7 @@
 }
 
 void prev_minus_2_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::prev(i, -2); // no-warning
 }
 
@@ -772,7 +774,7 @@
 }
 
 void prev_minus_2_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
                              // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
 }
@@ -791,7 +793,7 @@
 }
 
 void prev_0_behind_begin(const std::vector<int> &V) {
-  auto i = ++V.begin();
+  auto i = std::next(V.begin());
   auto j = std::prev(i, 0); // no-warning
 }
 
@@ -801,7 +803,7 @@
 }
 
 void prev_0_ahead_of_end(const std::vector<int> &V) {
-  auto i = --V.end();
+  auto i = std::prev(V.end());
   auto j = std::prev(i, 0); // no-warning
 }
 
@@ -847,12 +849,12 @@
 // Container modification - test path notes
 
 void deref_end_after_pop_back(std::vector<int> &V) {
-  const auto i = --V.end();
+  const auto i = std::prev(V.end());
 
   V.pop_back(); // expected-note{{Container 'V' shrank from the back by 1 position}}
 
-  *i; // expected-warning{{Past-the-end iterator dereferenced}}
-      // expected-note@-1{{Past-the-end iterator dereferenced}}
+  int n = *i; // expected-warning{{Past-the-end iterator dereferenced}}
+              // expected-note@-1{{Past-the-end iterator dereferenced}}
 }
 
 template<typename T>
Index: clang/test/Analysis/iterator-modeling.cpp
===================================================================
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -8,6 +8,10 @@
 
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_ADVANCE_INLINE_LEVEL=2 %s -verify -analyzer-config display-checker-name=false
 
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR %s -verify -analyzer-config display-checker-name=false
+
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR %s -verify -analyzer-config display-checker-name=false
+
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true %s 2>&1 | FileCheck %s
 
 #include "Inputs/system-header-simulator-cxx.h"
@@ -60,7 +64,10 @@
 
   auto j = ++i;
 
+  clang_analyzer_eval(clang_analyzer_iterator_container(i) == &v); // expected-warning{{TRUE}}
   clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning-re {{$v.begin() + 1{{$}}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_container(j) == &v); // expected-warning{{TRUE}}
   clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning-re {{$v.begin() + 1{{$}}}}
 }
 
@@ -390,7 +397,8 @@
 }
 
 void vector_move_assignment(std::vector<int> &V1, std::vector<int> &V2) {
-  auto i0 = V1.cbegin(), i1 = V2.cbegin(), i2 = --V2.cend(), i3 = V2.cend();
+  auto i0 = V1.cbegin(), i1 = V2.cbegin(), i2 = std::prev(V2.cend()),
+    i3 = V2.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V2), "$V2.begin()");
 
@@ -544,7 +552,7 @@
 /// std::vector-like containers: The past-the-end iterator is invalidated.
 
 void vector_push_back(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -604,7 +612,7 @@
 /// std::vector-like containers: The past-the-end iterator is invalidated.
 
 void vector_emplace_back(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -664,7 +672,7 @@
 ///                              past-the-end iterator, are invalidated.
 
 void vector_pop_back(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -996,7 +1004,7 @@
 }
 
 void vector_insert_behind_begin(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1029,7 +1037,7 @@
 }
 
 void vector_insert_ahead_of_end(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1045,7 +1053,7 @@
 }
 
 void vector_insert_end(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1323,7 +1331,7 @@
 }
 
 void vector_emplace_behind_begin(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1356,7 +1364,7 @@
 }
 
 void vector_emplace_ahead_of_end(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1372,7 +1380,7 @@
 }
 
 void vector_emplace_end(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1614,7 +1622,7 @@
 ///                              the erase, including the past-the-end iterator.
 
 void vector_erase_begin(std::vector<int> &V) {
-  auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1629,7 +1637,7 @@
 }
 
 void vector_erase_behind_begin(std::vector<int> &V, int n) {
-  auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1662,7 +1670,7 @@
 }
 
 void vector_erase_ahead_of_end(std::vector<int> &V) {
-  auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend();
+  auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend();
 
   clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
   clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
@@ -1889,141 +1897,49 @@
   }
 }
 
-template<typename T>
-struct cont_with_ptr_iterator {
-  typedef T* iterator;
-  T* begin() const;
-  T* end() const;
+struct iter_wrapper {
+  std::vector<int>::iterator i;
 };
 
-void begin_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.begin();
-
-  clang_analyzer_eval(clang_analyzer_iterator_container(i) == &c); // expected-warning{{TRUE}}
-  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
-
-  if (i != c.begin()) {
-    clang_analyzer_warnIfReached();
-  }
-  }
-
-void prefix_increment_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.begin();
-
-  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
-
-  auto j = ++i;
-
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin() + 1}}
-  clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.begin() + 1}}
-}
-
-void prefix_decrement_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.end();
-
-  clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()");
-
-  auto j = --i;
-
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.end() - 1}}
-  clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.end() - 1}}
-}
-
-void postfix_increment_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.begin();
-
-  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
-
-  auto j = i++;
-
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin() + 1}}
-  clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.begin()}}
-}
-
-void postfix_decrement_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.end();
-
-  clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()");
-
-  auto j = i--;
-
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.end() - 1}}
-  clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.end()}}
-}
-
-void plus_equal_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.begin();
-
-  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
-
-  i += 2;
-
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin() + 2}}
-}
-
-void minus_equal_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i = c.end();
-
-  clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()");
-
-  i -= 2;
-
-  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.end() - 2}}
-}
-
-void minus_equal_ptr_iterator_variable(const cont_with_ptr_iterator<int> &c,
-                                       int n) {
-  auto i = c.end();
+void member_iterator_incr(std::vector<int> V) {
+  iter_wrapper iw;
+  iw.i = V.begin();
 
-  i -= n; // no-crash
-}
-
-void plus_lhs_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i1 = c.begin();
-
-  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
 
-  auto i2 = i1 + 2;
+  iw.i++;
 
-  clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}}
-  clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.begin()}}
-  clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}}
+  clang_analyzer_express(clang_analyzer_iterator_position(iw.i)); // expected-warning-re {{$V.begin() + 1{{$}}}}
 }
 
-void plus_rhs_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i1 = c.begin();
-
-  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
-
-  auto i2 = 2 + i1;
-
-  clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}}
-  clang_analyzer_express(clang_analyzer_iterator_position(i1));     // expected-warning{{$c.begin()}}
-  clang_analyzer_express(clang_analyzer_iterator_position(i2));     // expected-warning{{$c.begin() + 2}}
-}
+struct iter_wrapper_wrapper {
+  iter_wrapper iw;
+};
 
-void minus_ptr_iterator(const cont_with_ptr_iterator<int> &c) {
-  auto i1 = c.end();
+void member_member_iterator_incr(std::vector<int> V) {
+  iter_wrapper_wrapper iww;
+  iww.iw.i = V.begin();
 
-  clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()");
+  clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
 
-  auto i2 = i1 - 2;
+  iww.iw.i++;
 
-  clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}}
-  clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.end()}}
-  clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.end() - 2}}
+  clang_analyzer_express(clang_analyzer_iterator_position(iww.iw.i)); // expected-warning-re {{$V.begin() + 1{{$}}}}
 }
 
-void ptr_iter_diff(cont_with_ptr_iterator<int> &c) {
-  auto i0 = c.begin(), i1 = c.end();
-  ptrdiff_t len = i1 - i0; // no-crash
-}
+template<typename Cont>
+struct ContainerAdapter {
+  Cont C;
+  ContainerAdapter(Cont c) : C(c) {}
+  typename Cont::iterator begin() { return C.begin(); }
+};
 
-void ptr_iter_cmp_nullptr(cont_with_ptr_iterator<int> &c) {
-  auto i0 = c.begin();
-  if (i0 != nullptr) // no-crash
-    ++i0;
+void adapter_test(std::vector<int> V) {
+  ContainerAdapter<std::vector<int>> A(V);
+  auto i = A.begin();
+  auto j = V.begin();
+  clang_analyzer_eval(clang_analyzer_iterator_container(i) == &A); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_container(j) == &V); // expected-warning{{TRUE}}
 }
 
 void clang_analyzer_printState();
@@ -2038,7 +1954,7 @@
   // CHECK-NEXT:     "i0 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}"
   // CHECK-NEXT:   ]}
 
-  *i0;
+  int n = *i0;
   const auto i1 = V.cend();
   clang_analyzer_printState();
 
@@ -2048,5 +1964,5 @@
   // CHECK-NEXT:     "i1 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}"
   // CHECK-NEXT:   ]}
 
-  *i1;
+  n = *i1;
 }
Index: clang/test/Analysis/invalidated-iterator.cpp
===================================================================
--- clang/test/Analysis/invalidated-iterator.cpp
+++ clang/test/Analysis/invalidated-iterator.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.InvalidatedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.InvalidatedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.InvalidatedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.InvalidatedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR %s -verify
 
 #include "Inputs/system-header-simulator-cxx.h"
 
@@ -7,13 +9,13 @@
 
 void normal_dereference(std::vector<int> &V) {
   auto i = V.cbegin();
-  *i; // no-warning
+  int n = *i; // no-warning
 }
 
 void invalidated_dereference(std::vector<int> &V) {
   auto i = V.cbegin();
   V.erase(i);
-  *i; // expected-warning{{Invalidated iterator accessed}}
+  int n = *i; // expected-warning{{Invalidated iterator accessed}}
 }
 
 void normal_prefix_increment(std::vector<int> &V) {
@@ -28,12 +30,12 @@
 }
 
 void normal_prefix_decrement(std::vector<int> &V) {
-  auto i = ++V.cbegin();
+  auto i = std::next(V.cbegin());
   --i; // no-warning
 }
 
 void invalidated_prefix_decrement(std::vector<int> &V) {
-  auto i = ++V.cbegin();
+  auto i = std::next(V.cbegin());
   V.erase(i);
   --i; // expected-warning{{Invalidated iterator accessed}}
 }
@@ -50,12 +52,12 @@
 }
 
 void normal_postfix_decrement(std::vector<int> &V) {
-  auto i = ++V.cbegin();
+  auto i = std::next(V.cbegin());
   i--; // no-warning
 }
 
 void invalidated_postfix_decrement(std::vector<int> &V) {
-  auto i = ++V.cbegin();
+  auto i = std::next(V.cbegin());
   V.erase(i);
   i--; // expected-warning{{Invalidated iterator accessed}}
 }
@@ -106,13 +108,13 @@
 
 void normal_subscript(std::vector<int> &V) {
   auto i = V.cbegin();
-  i[1]; // no-warning
+  int n = i[1]; // no-warning
 }
 
 void invalidated_subscript(std::vector<int> &V) {
   auto i = V.cbegin();
   V.erase(i);
-  i[1]; // expected-warning{{Invalidated iterator accessed}}
+  int n = i[1]; // expected-warning{{Invalidated iterator accessed}}
 }
 
 void assignment(std::vector<int> &V) {
Index: clang/test/Analysis/diagnostics/explicit-suppression.cpp
===================================================================
--- clang/test/Analysis/diagnostics/explicit-suppression.cpp
+++ clang/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -19,6 +19,6 @@
 void testCopyNull(C *I, C *E) {
   std::copy(I, E, (C *)0);
 #ifndef SUPPRESSED
-  // expected-warning@../Inputs/system-header-simulator-cxx.h:709 {{Called C++ object pointer is null}}
+  // expected-warning@../Inputs/system-header-simulator-cxx.h:722 {{Called C++ object pointer is null}}
 #endif
 }
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===================================================================
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -32,6 +32,14 @@
     typedef typename Iterator::reference reference;
     typedef typename Iterator::iterator_category iterator_category;
   };
+
+  template <typename T> struct iterator_traits<T*> {
+    typedef ptrdiff_t difference_type;
+    typedef T value_type;
+    typedef T* pointer;
+    typedef T& reference;
+    typedef random_access_iterator_tag iterator_category;
+  };
 }
 
 template <typename T, typename Ptr, typename Ref> struct __vector_iterator {
@@ -280,8 +288,13 @@
   public:
     typedef T value_type;
     typedef size_t size_type;
+    #ifdef STD_VECTOR_ITERATOR_PTR
+    typedef T* iterator;
+    typedef const T* const_iterator;
+    #else
     typedef __vector_iterator<T, T *, T &> iterator;
     typedef __vector_iterator<T, const T *, const T &> const_iterator;
+    #endif
 
     vector() : _start(0), _finish(0), _end_of_storage(0) {}
     template <typename InputIterator>
@@ -795,7 +808,8 @@
 void advance(InputIterator& it, Distance n)
 #if !defined(STD_ADVANCE_INLINE_LEVEL) || STD_ADVANCE_INLINE_LEVEL > 1
 {
-  __advance(it, n, typename InputIterator::iterator_category());
+  __advance(it, n,
+            typename iterator_traits<InputIterator>::iterator_category());
 }
 #else
     ;
Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -111,7 +111,8 @@
                               OverloadedOperatorKind Op, const SVal &RetVal,
                               const SVal &Iterator, const SVal &Amount) const;
   void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
-                           OverloadedOperatorKind OK, SVal Offset) const;
+                           OverloadedOperatorKind OK, SVal Offset,
+                           Optional<SVal> OperandLValue) const;
   void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
                      SVal Amount) const;
   void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
@@ -121,6 +122,7 @@
   void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
                          const MemRegion *Cont) const;
   bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
+  Optional<SVal> getOperandLValue(CheckerContext &C, Expr *Operand) const;
   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
                   const char *Sep) const override;
 
@@ -254,10 +256,23 @@
   if (!isIncrementOperator(OK) && !isDecrementOperator(OK))
     return;
 
+  // Since binding happens before this checker hook, the iterator position
+  // is removed from the lvalue operand of this operation. We have to find that
+  // lvalue to allow `handlePtrIncrOrDecr()` to assign the new iterator
+  // position to it. For the prefix version it is the same as the result of
+  // the expression.
+  Optional<SVal> OperandLValue = None;
+  if (OK == UO_PreInc || OK == UO_PreDec) {
+    ProgramStateRef State = C.getState();
+    OperandLValue = State->getSVal(UO, C.getLocationContext());
+  } else {
+    OperandLValue = getOperandLValue(C, UO->getSubExpr());
+  }
+
   auto &SVB = C.getSValBuilder();
   handlePtrIncrOrDecr(C, UO->getSubExpr(),
                       isIncrementOperator(OK) ? OO_Plus : OO_Minus,
-                      SVB.makeArrayIndex(1));
+                      SVB.makeArrayIndex(1), OperandLValue);
 }
 
 void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
@@ -284,8 +299,17 @@
     if (!AmountExpr->getType()->isIntegralOrEnumerationType())
       return;
     const SVal &AmountVal = IsIterOnLHS ? RVal : LVal;
+
+    // Since binding happens before this checker hook, the iterator position
+    // is removed from the lvalue operand of this operation (assignments only).
+    // We have to find that lvalue to allow `handlePtrIncrOrDecr()` to assign
+    // the new iterator position to it.
+    Optional<SVal> OperandLValue = None;
+    if (BinaryOperator::isAssignmentOp(OK)) {
+      OperandLValue = State->getSVal(BO, C.getLocationContext());
+    }
     handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK),
-                        AmountVal);
+                        AmountVal, OperandLValue);
   }
 }
 
@@ -629,7 +653,8 @@
 void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
                                            const Expr *Iterator,
                                            OverloadedOperatorKind OK,
-                                           SVal Offset) const {
+                                           SVal Offset,
+                                           Optional<SVal> OperandLValue) const {
   if (!Offset.getAs<DefinedSVal>())
     return;
 
@@ -639,7 +664,7 @@
   QualType ElementType = PtrType->getPointeeType();
 
   ProgramStateRef State = C.getState();
-  SVal OldVal = State->getSVal(Iterator, C.getLocationContext());
+  SVal OldVal = State->getSValAsScalarOrLoc(Iterator, C.getLocationContext());
 
   const IteratorPosition *OldPos = getIteratorPosition(State, OldVal);
   if (!OldPos)
@@ -664,6 +689,9 @@
            "Iterator should have position after successful advancement");
 
     ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos);
+    if (OperandLValue.hasValue()) {
+      NewState = setIteratorPosition(NewState, *OperandLValue, *NewPos);
+    }
     C.addTransition(NewState);
   } else {
     assignToContainer(C, Iterator, NewVal, OldPos->getContainer());
@@ -728,6 +756,20 @@
   return PosBefore->getOffset() == PosAfter->getOffset();
 }
 
+Optional<SVal>
+IteratorModeling::getOperandLValue(CheckerContext &C, Expr *Operand) const {
+  ProgramStateRef State = C.getState();
+  auto *LCtx = C.getLocationContext();
+
+  if (const auto *DRE = dyn_cast<DeclRefExpr>(Operand->IgnoreParenImpCasts())) {
+    if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+      return State->getLValue(VD, LCtx);
+    }
+  }
+
+  return None;
+}
+
 void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State,
                                   const char *NL, const char *Sep) const {
   auto SymbolMap = State->get<IteratorSymbolMap>();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to