summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2013-08-29 16:06:04 +0000
committerPavel Labath <labath@google.com>2013-08-29 16:06:04 +0000
commit2c65dfaab5e1323d46aea73366e15e856fe24e83 (patch)
treefe2c8f28b9ac3d3c09e737fbc71c3e7e2661ad5f /clang
parent70e7e19e57c8e561fac2a1e2b9bde528e424fc22 (diff)
downloadbcm5719-llvm-2c65dfaab5e1323d46aea73366e15e856fe24e83.tar.gz
bcm5719-llvm-2c65dfaab5e1323d46aea73366e15e856fe24e83.zip
[analyzer] Fix handling of "empty" structs with base classes
Summary: RegionStoreManager had an optimization which replaces references to empty structs with UnknownVal. Unfortunately, this check didn't take into account possible field members in base classes. To address this, I changed this test to "is empty and has no base classes". I don't consider it worth the trouble to go through base classes and check if all of them are empty. Reviewers: jordan_rose CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1547 llvm-svn: 189590
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp10
-rw-r--r--clang/test/Analysis/array-struct-region.cpp23
2 files changed, 32 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 2a3319bc042..8bc16bd4191 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1832,10 +1832,18 @@ NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
}
+static bool isRecordEmpty(const RecordDecl *RD) {
+ if (!RD->field_empty())
+ return false;
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD))
+ return CRD->getNumBases() == 0;
+ return true;
+}
+
SVal RegionStoreManager::getBindingForStruct(RegionBindingsConstRef B,
const TypedValueRegion *R) {
const RecordDecl *RD = R->getValueType()->castAs<RecordType>()->getDecl();
- if (RD->field_empty())
+ if (isRecordEmpty(RD))
return UnknownVal();
return createLazyBinding(B, R);
diff --git a/clang/test/Analysis/array-struct-region.cpp b/clang/test/Analysis/array-struct-region.cpp
index 12ae5d3eba6..a776d7da50b 100644
--- a/clang/test/Analysis/array-struct-region.cpp
+++ b/clang/test/Analysis/array-struct-region.cpp
@@ -173,4 +173,27 @@ void testImmediateUseOp() {
clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
}
+namespace EmptyClass {
+ struct Base {
+ int& x;
+
+ Base(int& x) : x(x) {}
+ };
+
+ struct Derived : public Base {
+ Derived(int& x) : Base(x) {}
+
+ void operator=(int a) { x = a; }
+ };
+
+ Derived ref(int& a) { return Derived(a); }
+
+ // There used to be a warning here, because analyzer treated Derived as empty.
+ int test() {
+ int a;
+ ref(a) = 42;
+ return a; // no warning
+ }
+}
+
#endif
OpenPOWER on IntegriCloud