1) emit base destructors as aliases to their unique base class destructors under some careful conditions. This is enabled for the same targets that can support complete-to-base aliases, i.e. not darwin. 2) Emit non-variadic complete constructors for classes with no virtual bases as calls to the base constructor. This is enabled on all targets and in theory can trigger in situations that the alias optimization can't (mostly involving virtual bases, mostly not yet supported). These are bundled together because I didn't think it worthwhile to split them, not because they really need to be. llvm-svn: 96842
136 lines
3.3 KiB
C++
136 lines
3.3 KiB
C++
// RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s
|
|
|
|
// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
|
|
// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
|
|
// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
|
|
// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
|
|
// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
|
|
|
|
struct A {
|
|
int a;
|
|
|
|
~A();
|
|
};
|
|
|
|
// Base with non-trivial destructor
|
|
struct B : A {
|
|
~B();
|
|
};
|
|
|
|
B::~B() { }
|
|
|
|
// Field with non-trivial destructor
|
|
struct C {
|
|
A a;
|
|
|
|
~C();
|
|
};
|
|
|
|
C::~C() { }
|
|
|
|
// PR5084
|
|
template<typename T>
|
|
class A1 {
|
|
~A1();
|
|
};
|
|
|
|
template<> A1<char>::~A1();
|
|
|
|
// PR5529
|
|
namespace PR5529 {
|
|
struct A {
|
|
~A();
|
|
};
|
|
|
|
A::~A() { }
|
|
struct B : A {
|
|
virtual ~B();
|
|
};
|
|
|
|
B::~B() {}
|
|
}
|
|
|
|
// FIXME: there's a known problem in the codegen here where, if one
|
|
// destructor throws, the remaining destructors aren't run. Fix it,
|
|
// then make this code check for it.
|
|
namespace test0 {
|
|
void foo();
|
|
struct VBase { ~VBase(); };
|
|
struct Base { ~Base(); };
|
|
struct Member { ~Member(); };
|
|
|
|
struct A : Base {
|
|
Member M;
|
|
~A();
|
|
};
|
|
|
|
// The function-try-block won't suppress -mconstructor-aliases here.
|
|
A::~A() try { } catch (int i) {}
|
|
|
|
// complete destructor alias tested above
|
|
|
|
// CHECK: define void @_ZN5test01AD2Ev
|
|
// CHECK: invoke void @_ZN5test06MemberD1Ev
|
|
// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
|
|
// CHECK: invoke void @_ZN5test04BaseD2Ev
|
|
// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
|
|
|
|
struct B : Base, virtual VBase {
|
|
Member M;
|
|
~B();
|
|
};
|
|
B::~B() try { } catch (int i) {}
|
|
// It will suppress the delegation optimization here, though.
|
|
|
|
// CHECK: define void @_ZN5test01BD1Ev
|
|
// CHECK: invoke void @_ZN5test06MemberD1Ev
|
|
// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
|
|
// CHECK: invoke void @_ZN5test04BaseD2Ev
|
|
// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
|
|
// CHECK: invoke void @_ZN5test05VBaseD2Ev
|
|
// CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]]
|
|
|
|
// CHECK: define void @_ZN5test01BD2Ev
|
|
// CHECK: invoke void @_ZN5test06MemberD1Ev
|
|
// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
|
|
// CHECK: invoke void @_ZN5test04BaseD2Ev
|
|
// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
|
|
}
|
|
|
|
// Test base-class aliasing.
|
|
namespace test1 {
|
|
struct A { ~A(); char ***m; }; // non-trivial destructor
|
|
struct B { ~B(); }; // non-trivial destructor
|
|
struct Empty { }; // trivial destructor, empty
|
|
struct NonEmpty { int x; }; // trivial destructor, non-empty
|
|
|
|
struct M : A { ~M(); };
|
|
M::~M() {} // alias tested above
|
|
|
|
struct N : A, Empty { ~N(); };
|
|
N::~N() {} // alias tested above
|
|
|
|
struct O : Empty, A { ~O(); };
|
|
O::~O() {} // alias tested above
|
|
|
|
struct P : NonEmpty, A { ~P(); };
|
|
P::~P() {} // CHECK: define void @_ZN5test11PD2Ev
|
|
|
|
struct Q : A, B { ~Q(); };
|
|
Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev
|
|
|
|
struct R : A { ~R(); };
|
|
R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev
|
|
|
|
struct S : A { ~S(); int x; };
|
|
S::~S() {} // alias tested above
|
|
|
|
struct T : A { ~T(); B x; };
|
|
T::~T() {} // CHECK: define void @_ZN5test11TD2Ev
|
|
|
|
// The VTT parameter prevents this. We could still make this work
|
|
// for calling conventions that are safe against extra parameters.
|
|
struct U : A, virtual B { ~U(); };
|
|
U::~U() {} // CHECK: define void @_ZN5test11UD2Ev
|
|
}
|