[analyzer] Be more forgiving about calling methods on struct rvalues.

The problem is that the value of 'this' in a C++ member function call
should always be a region (or NULL). However, if the object is an rvalue,
it has no associated region (only a conjured symbol or LazyCompoundVal).
For now, we handle this in two ways:

1) Actually respect MaterializeTemporaryExpr. Before, it was relying on
   CXXConstructExpr to create temporary regions for all struct values.
   Now it just does the right thing: if the value is not in a temporary
   region, create one.

2) Have CallEvent recognize the case where its 'this' pointer is a
   non-region, and just return UnknownVal to keep from confusing clients.

The long-term problem is being tracked internally in <rdar://problem/12137950>,
but this makes many test cases pass.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163220 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/array-struct-region.cpp b/test/Analysis/array-struct-region.cpp
new file mode 100644
index 0000000..3581566
--- /dev/null
+++ b/test/Analysis/array-struct-region.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+  int field;
+
+#if __cplusplus
+  const struct S *getThis() const { return this; }
+#endif
+};
+
+struct S getS();
+
+
+void testAssignment() {
+  struct S s = getS();
+
+  if (s.field != 42) return;
+  clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
+
+  s.field = 0;
+  clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}}
+
+#if __cplusplus
+  clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
+#endif
+}
+
+
+void testImmediateUse() {
+  int x = getS().field;
+
+  if (x != 42) return;
+  clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+
+#if __cplusplus
+  clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}}
+#endif
+}
+
+int getConstrainedField(struct S s) {
+  if (s.field != 42) return 42;
+  return s.field;
+}
+
+int getAssignedField(struct S s) {
+  s.field = 42;
+  return s.field;
+}
+
+void testArgument() {
+  clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
+  clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
+}
+
+
+//--------------------
+// C++-only tests
+//--------------------
+
+#if __cplusplus
+void testReferenceAssignment() {
+  const S &s = getS();
+
+  if (s.field != 42) return;
+  clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
+}
+
+
+int getConstrainedFieldRef(const S &s) {
+  if (s.field != 42) return 42;
+  return s.field;
+}
+
+bool checkThis(const S &s) {
+  return s.getThis() == &s;
+}
+
+void testReferenceArgument() {
+  clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}}
+  clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}}
+}
+#endif
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index 4a2cbb8..374f3f7 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -116,8 +116,13 @@
 
   struct S { int &x; };
 
-  extern S *getS();
-  clang_analyzer_eval(&getS()->x != 0); // expected-warning{{TRUE}}
+  // FIXME: Should be TRUE. Fields of return-by-value structs are not yet
+  // symbolicated. Tracked by <rdar://problem/12137950>.
+  extern S getS();
+  clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
+
+  extern S *getSP();
+  clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
 }
 
 
@@ -150,10 +155,3 @@
     return *x; // should warn here!
   }
 }
-
-void testReferenceFieldAddress() {
-  struct S { int &x; };
-
-  extern S getS();
-  clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
-}