| // RUN: %clangxx_msan %s -O0 -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && %run %t 2>&1 | FileCheck %s | 
 | // RUN: %clangxx_msan %s -O1 -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && %run %t 2>&1 | FileCheck %s | 
 | // RUN: %clangxx_msan %s -O2 -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && %run %t 2>&1 | FileCheck %s | 
 |  | 
 | #include <sanitizer/msan_interface.h> | 
 | #include <assert.h> | 
 |  | 
 | class Base { | 
 |  public: | 
 |    int b; | 
 |    Base() { b = 1; } | 
 |    ~Base(); | 
 | }; | 
 |  | 
 | class TrivialBaseBefore { | 
 | public: | 
 |   int tb0; | 
 |   TrivialBaseBefore() { tb0 = 1; } | 
 | }; | 
 |  | 
 | class TrivialBaseAfter { | 
 | public: | 
 |   int tb1; | 
 |   TrivialBaseAfter() { tb1 = 1; } | 
 | }; | 
 |  | 
 | class Derived : public TrivialBaseBefore, public Base, public TrivialBaseAfter { | 
 | public: | 
 |   int d; | 
 |   Derived() { d = 1; } | 
 |   ~Derived(); | 
 | }; | 
 |  | 
 | Derived *g; | 
 |  | 
 | Base::~Base() { | 
 |   // ok to access its own members and earlier bases | 
 |   assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == -1); | 
 |   assert(__msan_test_shadow(&g->b, sizeof(g->b)) == -1); | 
 |   // not ok to access others | 
 |   assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == 0); | 
 |   assert(__msan_test_shadow(&g->d, sizeof(g->d)) == 0); | 
 | } | 
 |  | 
 | Derived::~Derived() { | 
 |   // ok to access everything | 
 |   assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == -1); | 
 |   assert(__msan_test_shadow(&g->b, sizeof(g->b)) == -1); | 
 |   assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == -1); | 
 |   assert(__msan_test_shadow(&g->d, sizeof(g->d)) == -1); | 
 | } | 
 |  | 
 | int main() { | 
 |   g = new Derived(); | 
 |   // ok to access everything | 
 |   assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == -1); | 
 |   assert(__msan_test_shadow(&g->b, sizeof(g->b)) == -1); | 
 |   assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == -1); | 
 |   assert(__msan_test_shadow(&g->d, sizeof(g->d)) == -1); | 
 |  | 
 |   g->~Derived(); | 
 |   // not ok to access everything | 
 |   assert(__msan_test_shadow(&g->tb0, sizeof(g->tb0)) == 0); | 
 |   assert(__msan_test_shadow(&g->b, sizeof(g->b)) == 0); | 
 |   assert(__msan_test_shadow(&g->tb1, sizeof(g->tb1)) == 0); | 
 |   assert(__msan_test_shadow(&g->d, sizeof(g->d)) == 0); | 
 |  | 
 |   __msan_print_shadow(&g->tb0, sizeof(g->tb0)); | 
 |   // CHECK: Member fields were destroyed | 
 |   // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} | 
 |   // CHECK: {{#1 0x.* in .*~Derived.*cpp:}}[[@LINE-56]]: | 
 |   // CHECK: {{#2 0x.* in .*~Derived.*cpp:}}[[@LINE-21]]: | 
 |  | 
 |   __msan_print_shadow(&g->b, sizeof(g->b)); | 
 |   // CHECK: Member fields were destroyed | 
 |   // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} | 
 |   // CHECK: {{#1 0x.* in .*~Base.*cpp:}}[[@LINE-67]]: | 
 |   // CHECK: {{#2 0x.* in .*~Base.*cpp:}}[[@LINE-35]]: | 
 |  | 
 |   __msan_print_shadow(&g->tb1, sizeof(g->tb1)); | 
 |   // CHECK: Member fields were destroyed | 
 |   // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} | 
 |   // CHECK: {{#1 0x.* in .*~Derived.*cpp:}}[[@LINE-62]]: | 
 |   // CHECK: {{#2 0x.* in .*~Derived.*cpp:}}[[@LINE-33]]: | 
 |  | 
 |   return 0; | 
 | } |