[analyzer] Don't assert on a temporary of pointer-to-member type.
While we don't do anything intelligent with pointers-to-members today, it's perfectly legal to need a temporary of pointer-to-member type to, say, pass by const reference. Tweak an assertion to allow this. PR15742 and PR15747 llvm-svn: 179563
This commit is contained in:
parent
b9116e6966
commit
27ae8a2800
|
@ -181,7 +181,8 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
|
||||||
} else {
|
} else {
|
||||||
// We need to create a region no matter what. For sanity, make sure we don't
|
// We need to create a region no matter what. For sanity, make sure we don't
|
||||||
// try to stuff a Loc into a non-pointer temporary region.
|
// try to stuff a Loc into a non-pointer temporary region.
|
||||||
assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()));
|
assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()) ||
|
||||||
|
Result->getType()->isMemberPointerType());
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramStateManager &StateMgr = State->getStateManager();
|
ProgramStateManager &StateMgr = State->getStateManager();
|
||||||
|
|
|
@ -8,6 +8,9 @@ struct A {
|
||||||
operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; }
|
operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; }
|
||||||
|
|
||||||
A *m_ptr;
|
A *m_ptr;
|
||||||
|
|
||||||
|
A *getPtr();
|
||||||
|
typedef A * (A::*MemberFnPointer)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
void testConditionalUse() {
|
void testConditionalUse() {
|
||||||
|
@ -22,6 +25,40 @@ void testConditionalUse() {
|
||||||
clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}}
|
clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}}
|
||||||
clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}}
|
clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}}
|
||||||
clang_analyzer_eval(obj); // expected-warning{{FALSE}}
|
clang_analyzer_eval(obj); // expected-warning{{FALSE}}
|
||||||
|
|
||||||
|
clang_analyzer_eval(&A::getPtr); // expected-warning{{TRUE}}
|
||||||
|
clang_analyzer_eval(A::MemberFnPointer(0)); // expected-warning{{FALSE}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void testComparison() {
|
||||||
|
clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
|
||||||
|
|
||||||
|
// FIXME: Should be TRUE.
|
||||||
|
clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace PR15742 {
|
||||||
|
template <class _T1, class _T2> struct A {
|
||||||
|
A (const _T1 &, const _T2 &);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void *NPIdentifier;
|
||||||
|
|
||||||
|
template <class T> class B {
|
||||||
|
public:
|
||||||
|
typedef A<NPIdentifier, bool (T::*) (const NPIdentifier *, unsigned,
|
||||||
|
NPIdentifier *)> MethodMapMember;
|
||||||
|
};
|
||||||
|
|
||||||
|
class C : public B<C> {
|
||||||
|
public:
|
||||||
|
bool Find(const NPIdentifier *, unsigned, NPIdentifier *);
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitStaticData () {
|
||||||
|
C::MethodMapMember(0, &C::Find); // don't crash
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
Loading…
Reference in New Issue