Re-apply "[analyzer] Model trivial copy/move ctors with an aggregate bind."

With the optimization in the previous commit, this should be safe again.

Originally applied in r173951, then reverted in r174069.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174212 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/ctor-inlining.mm b/test/Analysis/ctor-inlining.mm
index be5d81a..1603ff3 100644
--- a/test/Analysis/ctor-inlining.mm
+++ b/test/Analysis/ctor-inlining.mm
@@ -1,8 +1,15 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
 
 void clang_analyzer_eval(bool);
 void clang_analyzer_checkInlined(bool);
 
+// A simplified version of std::move.
+template <typename T>
+T &&move(T &obj) {
+  return static_cast<T &&>(obj);
+}
+
+
 struct Wrapper {
   __strong id obj;
 };
@@ -117,3 +124,96 @@
     clang_analyzer_eval(result); // expected-warning{{TRUE}}
   }
 }
+
+namespace PODUninitialized {
+  class POD {
+  public:
+    int x, y;
+  };
+
+  class PODWrapper {
+  public:
+    POD p;
+  };
+
+  class NonPOD {
+  public:
+    int x, y;
+
+    NonPOD() {}
+    NonPOD(const NonPOD &Other)
+      : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+    {
+    }
+    NonPOD(NonPOD &&Other)
+    : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+    {
+    }
+  };
+
+  class NonPODWrapper {
+  public:
+    class Inner {
+    public:
+      int x, y;
+
+      Inner() {}
+      Inner(const Inner &Other)
+        : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+      {
+      }
+      Inner(Inner &&Other)
+      : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+      {
+      }
+    };
+
+    Inner p;
+  };
+
+  void testPOD() {
+    POD p;
+    p.x = 1;
+    POD p2 = p; // no-warning
+    clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
+    POD p3 = move(p); // no-warning
+    clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
+
+    // Use rvalues as well.
+    clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
+
+    PODWrapper w;
+    w.p.y = 1;
+    PODWrapper w2 = w; // no-warning
+    clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
+    PODWrapper w3 = move(w); // no-warning
+    clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
+
+    // Use rvalues as well.
+    clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}}
+  }
+
+  void testNonPOD() {
+    NonPOD p;
+    p.x = 1;
+    NonPOD p2 = p;
+  }
+
+  void testNonPODMove() {
+    NonPOD p;
+    p.x = 1;
+    NonPOD p2 = move(p);
+  }
+
+  void testNonPODWrapper() {
+    NonPODWrapper w;
+    w.p.y = 1;
+    NonPODWrapper w2 = w;
+  }
+
+  void testNonPODWrapperMove() {
+    NonPODWrapper w;
+    w.p.y = 1;
+    NonPODWrapper w2 = move(w);
+  }
+}
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index 547be02..e885878 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -16,7 +16,7 @@
 }
 
 const Trivial &getTrivialRef() {
-  return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct Trivial' returned to caller}}
+  return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'const struct Trivial' returned to caller}}
 }
 
 
@@ -25,6 +25,6 @@
 }
 
 const NonTrivial &getNonTrivialRef() {
-  return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct NonTrivial' returned to caller}}
+  return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'const struct NonTrivial' returned to caller}}
 }