[analyzer] Correctly devirtualize virtual method calls in destructors.
C++11 [class.cdtor]p4: When a virtual function is called directly or
indirectly from a constructor or from a destructor, including during
the construction or destruction of the class’s non-static data members,
and the object to which the call applies is the object under
construction or destruction, the function called is the final overrider
in the constructor's or destructor's class and not one overriding it in
a more-derived class.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161915 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index 6209948..1f45925 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -173,3 +173,57 @@
// Force a bug to be emitted.
*(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
}
+
+
+namespace DestructorVirtualCalls {
+ class A {
+ public:
+ int *out1, *out2, *out3;
+
+ virtual int get() { return 1; }
+
+ ~A() {
+ *out1 = get();
+ }
+ };
+
+ class B : public A {
+ public:
+ virtual int get() { return 2; }
+
+ ~B() {
+ *out2 = get();
+ }
+ };
+
+ class C : public B {
+ public:
+ virtual int get() { return 3; }
+
+ ~C() {
+ *out3 = get();
+ }
+ };
+
+ void test() {
+ int a, b, c;
+
+ // New scope for the C object.
+ {
+ C obj;
+ clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
+
+ // Sanity check for devirtualization.
+ A *base = &obj;
+ clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
+
+ obj.out1 = &a;
+ obj.out2 = &b;
+ obj.out3 = &c;
+ }
+
+ clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
+ }
+}