// RUN: %clang_cc1 -fms-extensions -fexceptions -fcxx-exceptions -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>&1 | FileCheck %s struct Base { virtual ~Base() {} virtual void BaseFunc() {} }; #pragma vtordisp(0) struct Container { static void f() try { #pragma vtordisp(2) struct HasVtorDisp : virtual Base { virtual ~HasVtorDisp() {} virtual void Func() {} }; int x[sizeof(HasVtorDisp)]; // HasVtorDisp: vtordisp because of pragma right before it. // // CHECK: *** Dumping AST Record Layout // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct HasVtorDisp // CHECK-NEXT: 0 | (HasVtorDisp vftable pointer) // CHECK-NEXT: 8 | (HasVtorDisp vbtable pointer) // CHECK-NEXT: 20 | (vtordisp for vbase Base) // CHECK-NEXT: 24 | struct Base (virtual base) // CHECK-NEXT: 24 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=32, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] } catch (...) { } }; struct NoVtorDisp1 : virtual Base { virtual ~NoVtorDisp1() {} virtual void Func() {} }; int x1[sizeof(NoVtorDisp1)]; // NoVtroDisp1: no vtordisp because of pragma disabling it. // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct NoVtorDisp1 // CHECK-NEXT: 0 | (NoVtorDisp1 vftable pointer) // CHECK-NEXT: 8 | (NoVtorDisp1 vbtable pointer) // CHECK-NEXT: 16 | struct Base (virtual base) // CHECK-NEXT: 16 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=24, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] struct Container2 { static void f1() { // Local pragma #1 - must be disabled on exit from f1(). #pragma vtordisp(push, 2) struct HasVtorDisp1 : virtual Base { virtual ~HasVtorDisp1() {} virtual void Func() {} }; int x2[sizeof(HasVtorDisp1)]; // HasVtorDisp1: vtordisp because of pragma right before it. // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct HasVtorDisp1 // CHECK-NEXT: 0 | (HasVtorDisp1 vftable pointer) // CHECK-NEXT: 8 | (HasVtorDisp1 vbtable pointer) // CHECK-NEXT: 20 | (vtordisp for vbase Base) // CHECK-NEXT: 24 | struct Base (virtual base) // CHECK-NEXT: 24 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=32, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] struct InnerContainer { static void g1() { struct HasVtorDisp2 : virtual Base { virtual ~HasVtorDisp2() {} virtual void Func() {} }; int x3[sizeof(HasVtorDisp2)]; // HasVtorDisp2: vtordisp because of vtordisp(2) in f1(). // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct HasVtorDisp2 // CHECK-NEXT: 0 | (HasVtorDisp2 vftable pointer) // CHECK-NEXT: 8 | (HasVtorDisp2 vbtable pointer) // CHECK-NEXT: 20 | (vtordisp for vbase Base) // CHECK-NEXT: 24 | struct Base (virtual base) // CHECK-NEXT: 24 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=32, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] // Local pragma #2 - must be disabled on exit from g1(). #pragma vtordisp(push, 0) struct NoVtorDisp2 : virtual Base { virtual ~NoVtorDisp2() {} virtual void Func() {} }; int x4[sizeof(NoVtorDisp2)]; // NoVtroDisp2: no vtordisp because of vtordisp(0) in g1(). // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct NoVtorDisp2 // CHECK-NEXT: 0 | (NoVtorDisp2 vftable pointer) // CHECK-NEXT: 8 | (NoVtorDisp2 vbtable pointer) // CHECK-NEXT: 16 | struct Base (virtual base) // CHECK-NEXT: 16 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=24, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] } static void g2() { struct HasVtorDisp3 : virtual Base { virtual ~HasVtorDisp3() {} virtual void Func() {} }; int x5[sizeof(HasVtorDisp3)]; // HasVtorDisp3: vtordisp because of vtordisp(2) in f1(), // local vtordisp(0) in g1() is disabled. // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct HasVtorDisp3 // CHECK-NEXT: 0 | (HasVtorDisp3 vftable pointer) // CHECK-NEXT: 8 | (HasVtorDisp3 vbtable pointer) // CHECK-NEXT: 20 | (vtordisp for vbase Base) // CHECK-NEXT: 24 | struct Base (virtual base) // CHECK-NEXT: 24 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=32, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] } }; struct HasVtorDisp4 : virtual Base { virtual ~HasVtorDisp4() {} virtual void Func() {} }; int x6[sizeof(HasVtorDisp4)]; // HasVtorDisp4: vtordisp because of vtordisp(2) in f1(), // local vtordisp(0) in g1() is disabled, // g2() has no pragmas - stack is not affected. // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct HasVtorDisp4 // CHECK-NEXT: 0 | (HasVtorDisp4 vftable pointer) // CHECK-NEXT: 8 | (HasVtorDisp4 vbtable pointer) // CHECK-NEXT: 20 | (vtordisp for vbase Base) // CHECK-NEXT: 24 | struct Base (virtual base) // CHECK-NEXT: 24 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=32, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] InnerContainer::g1(); InnerContainer::g2(); } static void f2() { struct NoVtorDisp3 : virtual Base { virtual ~NoVtorDisp3() {} virtual void Func() {} }; int x7[sizeof(NoVtorDisp3)]; // NoVtroDisp3: no vtordisp because of global pragma (0), // local vtordisp(2) is disabled on exit from f1(). // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct NoVtorDisp3 // CHECK-NEXT: 0 | (NoVtorDisp3 vftable pointer) // CHECK-NEXT: 8 | (NoVtorDisp3 vbtable pointer) // CHECK-NEXT: 16 | struct Base (virtual base) // CHECK-NEXT: 16 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=24, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] } }; struct Container3 { #pragma vtordisp(2) struct HasVtorDisp5 : virtual Base { virtual ~HasVtorDisp5() {} virtual void Func() {} }; int x8[sizeof(HasVtorDisp5)]; // HasVtorDisp5: vtordisp because of pragma right before it. // // CHECK: *** Dumping AST Record Layout // CHECK-NEXT: 0 | struct Container3::HasVtorDisp5 // CHECK-NEXT: 0 | (HasVtorDisp5 vftable pointer) // CHECK-NEXT: 8 | (HasVtorDisp5 vbtable pointer) // CHECK-NEXT: 20 | (vtordisp for vbase Base) // CHECK-NEXT: 24 | struct Base (virtual base) // CHECK-NEXT: 24 | (Base vftable pointer) // CHECK-NEXT: | [sizeof=32, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] }; int main() { Container::f(); Container2::f1(); Container2::f2(); Container3 cont3; return 0; };