return svalBuilder.getRegionValueSymbolVal(R);
}
+static bool mayHaveLazyBinding(QualType Ty) {
+ return Ty->isArrayType() || Ty->isStructureOrClassType();
+}
+
SVal RegionStoreManager::getBindingForStruct(Store store,
const TypedValueRegion* R) {
- assert(R->getValueType()->isStructureOrClassType());
-
- // If we already have a lazy binding, don't create a new one.
- RegionBindings B = GetRegionBindings(store);
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
- return *V;
+ const RecordDecl *RD = R->getValueType()->castAs<RecordType>()->getDecl();
+ if (RD->field_empty())
+ return UnknownVal();
+
+ // If we already have a lazy binding, don't create a new one,
+ // unless the first field might have a lazy binding of its own.
+ // (Right now we can't tell the difference.)
+ QualType FirstFieldType = RD->field_begin()->getType();
+ if (!mayHaveLazyBinding(FirstFieldType)) {
+ RegionBindings B = GetRegionBindings(store);
+ BindingKey K = BindingKey::Make(R, BindingKey::Default);
+ if (const nonloc::LazyCompoundVal *V =
+ dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
+ return *V;
+ }
}
return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
SVal RegionStoreManager::getBindingForArray(Store store,
const TypedValueRegion * R) {
- assert(Ctx.getAsConstantArrayType(R->getValueType()));
+ const ConstantArrayType *Ty = Ctx.getAsConstantArrayType(R->getValueType());
+ assert(Ty && "Only constant array types can have compound bindings.");
- // If we already have a lazy binding, don't create a new one.
- RegionBindings B = GetRegionBindings(store);
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
- return *V;
+ // If we already have a lazy binding, don't create a new one,
+ // unless the first element might have a lazy binding of its own.
+ // (Right now we can't tell the difference.)
+ if (!mayHaveLazyBinding(Ty->getElementType())) {
+ RegionBindings B = GetRegionBindings(store);
+ BindingKey K = BindingKey::Make(R, BindingKey::Default);
+ if (const nonloc::LazyCompoundVal *V =
+ dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
+ return *V;
+ }
}
return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -analyzer-ipa=all -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -analyzer-ipa=all -verify %s
void clang_analyzer_eval(int);
clang_analyzer_eval(p->y == 5); // expected-warning{{TRUE}}
}
+
+// PR13264 / <rdar://problem/11802440>
+struct point { int x; int y; };
+struct circle { struct point o; int r; };
+struct circle get_circle() {
+ struct circle result;
+ result.r = 5;
+ result.o = (struct point){0, 0};
+ return result;
+}
+
+void struct_in_struct() {
+ struct circle c;
+ c = get_circle();
+ // This used to think c.r was undefined because c.o is a LazyCompoundVal.
+ clang_analyzer_eval(c.r == 5); // expected-warning{{TRUE}}
+}
+
+// We also test with floats because we don't model floats right now,
+// and the original bug report used a float.
+struct circle_f { struct point o; float r; };
+struct circle_f get_circle_f() {
+ struct circle_f result;
+ result.r = 5.0;
+ result.o = (struct point){0, 0};
+ return result;
+}
+
+float struct_in_struct_f() {
+ struct circle_f c;
+ c = get_circle_f();
+
+ return c.r; // no-warning
+}
+