diff options
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CXX/drs/dr16xx.cpp | 118 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr21xx.cpp | 24 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/constructors.cpp | 56 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/implicit-exception-spec.cpp | 22 | ||||
-rw-r--r-- | clang/test/SemaCXX/implicit-exception-spec.cpp | 58 |
5 files changed, 277 insertions, 1 deletions
diff --git a/clang/test/CXX/drs/dr16xx.cpp b/clang/test/CXX/drs/dr16xx.cpp index c9f084db73a..08ae92570ce 100644 --- a/clang/test/CXX/drs/dr16xx.cpp +++ b/clang/test/CXX/drs/dr16xx.cpp @@ -3,6 +3,13 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +namespace dr1611 { // dr1611: dup 1658 + struct A { A(int); }; + struct B : virtual A { virtual void f() = 0; }; + struct C : B { C() : A(0) {} void f(); }; + C c; +} + namespace dr1684 { // dr1684: 3.6 #if __cplusplus >= 201103L struct NonLiteral { // expected-note {{because}} @@ -101,3 +108,114 @@ namespace dr1653 { // dr1653: 4 c++17 b -= 1; // ok } } + +namespace dr1658 { // dr1658: 5 + namespace DefCtor { + class A { A(); }; // expected-note 0-2{{here}} + class B { ~B(); }; // expected-note 0-2{{here}} + + // The stars align! An abstract class does not construct its virtual bases. + struct C : virtual A { C(); virtual void foo() = 0; }; + C::C() = default; // ok, not deleted, expected-error 0-1{{extension}} + struct D : virtual B { D(); virtual void foo() = 0; }; + D::D() = default; // ok, not deleted, expected-error 0-1{{extension}} + + // In all other cases, we are not so lucky. + struct E : A { E(); virtual void foo() = 0; }; +#if __cplusplus < 201103L + E::E() = default; // expected-error {{private default constructor}} expected-error {{extension}} expected-note {{here}} +#else + E::E() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible default constructor}} +#endif + struct F : virtual A { F(); }; +#if __cplusplus < 201103L + F::F() = default; // expected-error {{private default constructor}} expected-error {{extension}} expected-note {{here}} +#else + F::F() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible default constructor}} +#endif + + struct G : B { G(); virtual void foo() = 0; }; +#if __cplusplus < 201103L + G::G() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}} +#else + G::G() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}} +#endif + struct H : virtual B { H(); }; +#if __cplusplus < 201103L + H::H() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}} +#else + H::H() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}} +#endif + } + + namespace Dtor { + class B { ~B(); }; // expected-note 0-2{{here}} + + struct D : virtual B { ~D(); virtual void foo() = 0; }; + D::~D() = default; // ok, not deleted, expected-error 0-1{{extension}} + + struct G : B { ~G(); virtual void foo() = 0; }; +#if __cplusplus < 201103L + G::~G() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}} +#else + G::~G() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}} +#endif + struct H : virtual B { ~H(); }; +#if __cplusplus < 201103L + H::~H() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}} +#else + H::~H() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}} +#endif + } + + namespace MemInit { + struct A { A(int); }; // expected-note {{here}} + struct B : virtual A { + B() {} + virtual void f() = 0; + }; + struct C : virtual A { + C() {} // expected-error {{must explicitly initialize}} + }; + } + + namespace CopyCtorParamType { + struct A { A(A&); }; + struct B : virtual A { virtual void f() = 0; }; + struct C : virtual A { virtual void f(); }; + struct D : A { virtual void f() = 0; }; + + struct X { + friend B::B(const B&) throw(); + friend C::C(C&); + friend D::D(D&); + }; + } + + namespace CopyCtor { + class A { A(const A&); A(A&&); }; // expected-note 0-4{{here}} expected-error 0-1{{extension}} + + struct C : virtual A { C(const C&); C(C&&); virtual void foo() = 0; }; // expected-error 0-1{{extension}} + C::C(const C&) = default; // expected-error 0-1{{extension}} + C::C(C&&) = default; // expected-error 0-2{{extension}} + + struct E : A { E(const E&); E(E&&); virtual void foo() = 0; }; // expected-error 0-1{{extension}} +#if __cplusplus < 201103L + E::E(const E&) = default; // expected-error {{private copy constructor}} expected-error {{extension}} expected-note {{here}} + E::E(E&&) = default; // expected-error {{private move constructor}} expected-error 2{{extension}} expected-note {{here}} +#else + E::E(const E&) = default; // expected-error {{would delete}} expected-note@-5{{inaccessible copy constructor}} + E::E(E&&) = default; // expected-error {{would delete}} expected-note@-6{{inaccessible move constructor}} +#endif + struct F : virtual A { F(const F&); F(F&&); }; // expected-error 0-1{{extension}} +#if __cplusplus < 201103L + F::F(const F&) = default; // expected-error {{private copy constructor}} expected-error {{extension}} expected-note {{here}} + F::F(F&&) = default; // expected-error {{private move constructor}} expected-error 2{{extension}} expected-note {{here}} +#else + F::F(const F&) = default; // expected-error {{would delete}} expected-note@-5{{inaccessible copy constructor}} + F::F(F&&) = default; // expected-error {{would delete}} expected-note@-6{{inaccessible move constructor}} +#endif + } + + // assignment case is superseded by dr2180 +} diff --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp new file mode 100644 index 00000000000..78fc0bec40b --- /dev/null +++ b/clang/test/CXX/drs/dr21xx.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors + +namespace dr2180 { // dr2180: yes + class A { + A &operator=(const A &); // expected-note 0-2{{here}} + A &operator=(A &&); // expected-note 0-2{{here}} expected-error 0-1{{extension}} + }; + + struct B : virtual A { + B &operator=(const B &); + B &operator=(B &&); // expected-error 0-1{{extension}} + virtual void foo() = 0; + }; +#if __cplusplus < 201103L + B &B::operator=(const B&) = default; // expected-error {{private member}} expected-error {{extension}} expected-note {{here}} + B &B::operator=(B&&) = default; // expected-error {{private member}} expected-error 2{{extension}} expected-note {{here}} +#else + B &B::operator=(const B&) = default; // expected-error {{would delete}} expected-note@-9{{inaccessible copy assignment}} + B &B::operator=(B&&) = default; // expected-error {{would delete}} expected-note@-10{{inaccessible move assignment}} +#endif +} diff --git a/clang/test/CodeGenCXX/constructors.cpp b/clang/test/CodeGenCXX/constructors.cpp index ecbe5bb45b6..a8981403834 100644 --- a/clang/test/CodeGenCXX/constructors.cpp +++ b/clang/test/CodeGenCXX/constructors.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s --implicit-check-not=should_not_appear_in_output struct Member { int x; Member(); Member(int); Member(const Member &); }; struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); }; @@ -109,3 +109,57 @@ namespace test1 { // CHECK: [[THIS:%.*]] = load [[B:%.*]]*, [[B:%.*]]** // CHECK-NEXT: ret void } + +// Ensure that we +// a) emit the ABI-required but useless complete object and deleting destructor +// symbols for an abstract class, and +// b) do *not* emit references to virtual base destructors for an abstract class +// +// Our approach to this is to give these functions a body that simply traps. +// +// FIXME: We should ideally not create these symbols at all, but Clang can +// actually generate references to them in other TUs in some cases, so we can't +// stop emitting them without breaking ABI. See: +// +// https://github.com/itanium-cxx-abi/cxx-abi/issues/10 +namespace abstract { + // Note, the destructor of this class is not instantiated here. + template<typename T> struct should_not_appear_in_output { + ~should_not_appear_in_output() { int arr[-(int)sizeof(T)]; } + }; + + struct X { ~X(); }; + + struct A : virtual should_not_appear_in_output<int>, X { + virtual ~A() = 0; + }; + + // CHECK-LABEL: define void @_ZN8abstract1AD2Ev( + // CHECK: call {{.*}}@_ZN8abstract1XD2Ev( + // CHECK: ret + + // CHECK-LABEL: define void @_ZN8abstract1AD1Ev( + // CHECK: call {{.*}}@llvm.trap( + // CHECK: unreachable + + // CHECK-LABEL: define void @_ZN8abstract1AD0Ev( + // CHECK: call {{.*}}@llvm.trap( + // CHECK: unreachable + A::~A() {} + + struct B : virtual should_not_appear_in_output<int>, X { + virtual void f() = 0; + ~B(); + }; + + // CHECK-LABEL: define void @_ZN8abstract1BD2Ev( + // CHECK: call {{.*}}@_ZN8abstract1XD2Ev( + // CHECK: ret + + // CHECK-LABEL: define void @_ZN8abstract1BD1Ev( + // CHECK: call {{.*}}@llvm.trap( + // CHECK: unreachable + + // CHECK-NOT: @_ZN8abstract1BD0Ev( + B::~B() {} +} diff --git a/clang/test/CodeGenCXX/implicit-exception-spec.cpp b/clang/test/CodeGenCXX/implicit-exception-spec.cpp new file mode 100644 index 00000000000..cf363bd685a --- /dev/null +++ b/clang/test/CodeGenCXX/implicit-exception-spec.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK %s + +struct A { + A(); + A(const A&); + A(A&&); +}; +struct B : virtual A { + virtual void f() = 0; +}; +struct C : B { + void f(); +}; + +// CHECK-DAG: define {{.*}} @_ZN1BC2Ev({{.*}} #[[NOUNWIND:[0-9]*]] +C c1; +// CHECK-DAG: define {{.*}} @_ZN1BC2ERKS_({{.*}} #[[NOUNWIND]] +C c2(c1); +// CHECK-DAG: define {{.*}} @_ZN1BC2EOS_({{.*}} #[[NOUNWIND]] +C c3(static_cast<C&&>(c1)); + +// CHECK-DAG: #[[NOUNWIND]] = {{{.*}} nounwind diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp index fc86d1810ba..f400c222de8 100644 --- a/clang/test/SemaCXX/implicit-exception-spec.cpp +++ b/clang/test/SemaCXX/implicit-exception-spec.cpp @@ -92,3 +92,61 @@ namespace ImplicitDtorExceptionSpec { } e; }; } + +struct nothrow_t {} nothrow; +void *operator new(decltype(sizeof(0)), nothrow_t) noexcept; + +namespace PotentiallyConstructed { + template<bool NE> struct A { + A() noexcept(NE); + A(const A&) noexcept(NE); + A(A&&) noexcept(NE); + A &operator=(const A&) noexcept(NE); + A &operator=(A&&) noexcept(NE); + ~A() noexcept(NE); + }; + + template<bool NE> struct B : virtual A<NE> {}; + + template<bool NE> struct C : virtual A<NE> { + virtual void f() = 0; // expected-note 2{{unimplemented}} + }; + + template<bool NE> struct D final : C<NE> { + void f(); + }; + + template<typename T, bool A, bool B, bool C, bool D, bool E, bool F> void check() { + T *p = nullptr; + T &a = *p; + static_assert(noexcept(a = a) == D, ""); + static_assert(noexcept(a = static_cast<T&&>(a)) == E, ""); + static_assert(noexcept(delete &a) == F, ""); // expected-warning 2{{abstract}} + + // These are last because the first failure here causes instantiation to bail out. + static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}} + static_assert(noexcept(new (nothrow) T(a)) == B, ""); + static_assert(noexcept(new (nothrow) T(static_cast<T&&>(a))) == C, ""); + } + + template void check<A<false>, 0, 0, 0, 0, 0, 0>(); + template void check<A<true >, 1, 1, 1, 1, 1, 1>(); + template void check<B<false>, 0, 0, 0, 0, 0, 0>(); + template void check<B<true >, 1, 1, 1, 1, 1, 1>(); + template void check<C<false>, 1, 1, 1, 0, 0, 0>(); // expected-note {{instantiation}} + template void check<C<true >, 1, 1, 1, 1, 1, 1>(); // expected-note {{instantiation}} + template void check<D<false>, 0, 0, 0, 0, 0, 0>(); + template void check<D<true >, 1, 1, 1, 1, 1, 1>(); + + // ... the above trick doesn't work for this case... + struct Cfalse : virtual A<false> { + virtual void f() = 0; + + Cfalse() noexcept; + Cfalse(const Cfalse&) noexcept; + Cfalse(Cfalse&&) noexcept; + }; + Cfalse::Cfalse() noexcept = default; + Cfalse::Cfalse(const Cfalse&) noexcept = default; + Cfalse::Cfalse(Cfalse&&) noexcept = default; +} |