Sema: avoid reuse of Exprs when synthesizing operator=

Summary:
Previously, Sema was reusing parts of the AST when synthesizing an assignment
operator, turning it into a AS-dag. This caused problems for the static
analyzer, which assumed an expression appears in the tree only once.

Here I make sure to always create a fresh Expr, when inserting something into
the AST, fixing PR16745 in the process.

Reviewers: doug.gregor

CC: cfe-commits, jordan_rose

Differential Revision: http://llvm-reviews.chandlerc.com/D1425

llvm-svn: 189659
diff --git a/clang/test/Analysis/operator-calls.cpp b/clang/test/Analysis/operator-calls.cpp
index 7461d75..4bd7c12 100644
--- a/clang/test/Analysis/operator-calls.cpp
+++ b/clang/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
 void clang_analyzer_eval(bool);
 
 struct X0 { };
@@ -85,3 +85,48 @@
     clang_analyzer_eval(+(coin ? getLargeOpaque() : getLargeOpaque())); // expected-warning{{UNKNOWN}}
   }
 }
+
+namespace SynthesizedAssignment {
+  struct A {
+    int a;
+    A& operator=(A& other) { a = -other.a; return *this; }
+    A& operator=(A&& other) { a = other.a+1; return *this; }
+  };
+
+  struct B {
+    int x;
+    A a[3];
+    B& operator=(B&) = default;
+    B& operator=(B&&) = default;
+  };
+
+  // This used to produce a warning about the iteration variable in the
+  // synthesized assignment operator being undefined.
+  void testNoWarning() {
+    B v, u;
+    u = v;
+  }
+
+  void testNoWarningMove() {
+    B v, u;
+    u = static_cast<B &&>(v);
+  }
+
+  void testConsistency() {
+    B v, u;
+    v.a[1].a = 47;
+    v.a[2].a = 42;
+    u = v;
+    clang_analyzer_eval(u.a[1].a == -47); // expected-warning{{TRUE}}
+    clang_analyzer_eval(u.a[2].a == -42); // expected-warning{{TRUE}}
+  }
+
+  void testConsistencyMove() {
+    B v, u;
+    v.a[1].a = 47;
+    v.a[2].a = 42;
+    u = static_cast<B &&>(v);
+    clang_analyzer_eval(u.a[1].a == 48); // expected-warning{{TRUE}}
+    clang_analyzer_eval(u.a[2].a == 43); // expected-warning{{TRUE}}
+  }
+}