llvm_unreachable("unreachable");
}
+static bool regionMatchesCXXRecordType(SVal V, QualType Ty) {
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR)
+ return true;
+
+ const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
+ if (!TVR)
+ return true;
+
+ const CXXRecordDecl *RD = TVR->getValueType()->getAsCXXRecordDecl();
+ if (!RD)
+ return true;
+
+ const CXXRecordDecl *Expected = Ty->getPointeeCXXRecordDecl();
+ if (!Expected)
+ Expected = Ty->getAsCXXRecordDecl();
+
+ return Expected->getCanonicalDecl() == RD->getCanonicalDecl();
+}
+
SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
+ // Sanity check to avoid doing the wrong thing in the face of
+ // reinterpret_cast.
+ if (!regionMatchesCXXRecordType(Derived, Cast->getSubExpr()->getType()))
+ return UnknownVal();
+
// Walk through the cast path to create nested CXXBaseRegions.
SVal Result = Derived;
for (CastExpr::path_const_iterator I = Cast->path_begin(),
wrapper->set();
clang_analyzer_eval(wrapper->x == 42); // expected-warning{{TRUE}}
}
+
+namespace PR14872 {
+ class Base1 {};
+ class Derived1 : public Base1 {};
+
+ Derived1 *f1();
+
+ class Base2 {};
+ class Derived2 : public Base2 {};
+
+ void f2(Base2 *foo);
+
+ void f3(void** out)
+ {
+ Base1 *v;
+ v = f1();
+ *out = v;
+ }
+
+ void test()
+ {
+ Derived2 *p;
+ f3(reinterpret_cast<void**>(&p));
+ // Don't crash when upcasting here.
+ // In this case, 'p' actually refers to a Derived1.
+ f2(p);
+ }
+}