aboutsummaryrefslogtreecommitdiff
path: root/test/Analysis/array-struct-region.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-09-01 17:39:09 +0000
committerJordan Rose <jordan_rose@apple.com>2012-09-01 17:39:09 +0000
commit02df4f0aef142f00d4637cd851e54da2a123ca8e (patch)
treea7e564ed0f2f841da34570bc09c3362bdd7a0399 /test/Analysis/array-struct-region.cpp
parent5699f62df144545702b91e91836a63db4e5f2627 (diff)
[analyzer] Treat all struct values as regions (even rvalues).
This allows us to correctly symbolicate the fields of structs returned by value, as well as get the proper 'this' value for when methods are called on structs returned by value. This does require a moderately ugly hack in the StoreManager: if we assign a "struct value" to a struct region, that now appears as a Loc value being bound to a region of struct type. We handle this by simply "dereferencing" the struct value region, which should create a LazyCompoundVal. This should fix recent crashes analyzing LLVM and on our internal buildbot. <rdar://problem/12137950> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163066 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Analysis/array-struct-region.cpp')
-rw-r--r--test/Analysis/array-struct-region.cpp87
1 files changed, 87 insertions, 0 deletions
diff --git a/test/Analysis/array-struct-region.cpp b/test/Analysis/array-struct-region.cpp
new file mode 100644
index 0000000000..3581566bdc
--- /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